• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

llnl / dftracer-utils / 28356348514

29 Jun 2026 07:40AM UTC coverage: 52.174% (-0.1%) from 52.278%
28356348514

Pull #83

github

web-flow
Merge 278203630 into 2efed6649
Pull Request #83: refactor and improve code QoL

37276 of 92891 branches covered (40.13%)

Branch coverage included in aggregate %.

671 of 1173 new or added lines in 58 files covered. (57.2%)

66 existing lines in 30 files now uncovered.

33619 of 42991 relevant lines covered (78.2%)

20387.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.21
/src/dftracer/utils/python/utilities/statistics_query.cpp
1
#define PY_SSIZE_T_CLEAN
2
#include <dftracer/utils/core/coro/task.h>
3
#include <dftracer/utils/core/runtime.h>
4
#include <dftracer/utils/python/py_dict_helpers.h>
5
#include <dftracer/utils/python/py_runtime_mixin.h>
6
#include <dftracer/utils/python/py_type_helpers.h>
7
#include <dftracer/utils/python/runtime.h>
8
#include <dftracer/utils/python/utilities/statistics_query.h>
9
#include <dftracer/utils/utilities/composites/dft/internal/utils.h>
10
#include <dftracer/utils/utilities/composites/dft/statistics/statistics_aggregator_utility.h>
11
#include <dftracer/utils/utilities/composites/dft/statistics/statistics_query_utility.h>
12

13
#include <string>
14

15
using dftracer::utils::Runtime;
16
using dftracer::utils::coro::CoroTask;
17
using namespace dftracer::utils::utilities::composites::dft::statistics;
18

19
static Runtime *get_runtime(StatisticsQueryObject *self) {
16✔
20
    return resolve_runtime(self);
16✔
21
}
22

23
static void StatisticsQuery_dealloc(StatisticsQueryObject *self) {
16✔
24
    runtime_backed_dealloc(self);
16✔
25
}
16✔
26

27
static PyObject *StatisticsQuery_new(PyTypeObject *type, PyObject *args,
16✔
28
                                     PyObject *kwds) {
29
    return runtime_backed_new<StatisticsQueryObject>(type, args, kwds);
16✔
30
}
31

32
static int StatisticsQuery_init(StatisticsQueryObject *self, PyObject *args,
16✔
33
                                PyObject *kwds) {
34
    return runtime_backed_init(self, args, kwds);
16✔
35
}
36

37
static PyObject *StatisticsQuery_query(StatisticsQueryObject *self,
16✔
38
                                       PyObject *args, PyObject *kwds) {
39
    static const char *kwlist[] = {"file_path", "query_type", "top_n",
40
                                   "index_dir", NULL};
41
    const char *file_path;
42
    const char *query_type_str = "summary";
16✔
43
    Py_ssize_t top_n = 10;
16✔
44
    const char *index_dir = "";
16✔
45

46
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|sns", (char **)kwlist,
16!
47
                                     &file_path, &query_type_str, &top_n,
48
                                     &index_dir)) {
49
        return NULL;
×
50
    }
51

52
    StatisticsQueryType qt;
53
    if (strcmp(query_type_str, "summary") == 0) {
16✔
54
        qt = StatisticsQueryType::SUMMARY;
6✔
55
    } else if (strcmp(query_type_str, "categories") == 0) {
13✔
56
        qt = StatisticsQueryType::CATEGORIES;
4✔
57
    } else if (strcmp(query_type_str, "names") == 0) {
8✔
58
        qt = StatisticsQueryType::NAMES;
2✔
59
    } else if (strcmp(query_type_str, "pid_tids") == 0) {
5✔
60
        qt = StatisticsQueryType::PID_TIDS;
×
61
    } else if (strcmp(query_type_str, "time_range") == 0) {
4!
62
        qt = StatisticsQueryType::TIME_RANGE;
×
63
    } else if (strcmp(query_type_str, "duration_stats") == 0) {
4✔
64
        qt = StatisticsQueryType::DURATION_STATS;
2✔
65
    } else if (strcmp(query_type_str, "top_n_names") == 0) {
3✔
66
        qt = StatisticsQueryType::TOP_N_NAMES;
2✔
67
    } else if (strcmp(query_type_str, "top_n_categories") == 0) {
1!
68
        qt = StatisticsQueryType::TOP_N_CATEGORIES;
×
69
    } else if (strcmp(query_type_str, "detailed") == 0) {
×
70
        qt = StatisticsQueryType::DETAILED;
×
71
    } else {
72
        PyErr_Format(PyExc_ValueError, "unknown query_type: '%s'",
×
73
                     query_type_str);
74
        return NULL;
×
75
    }
76

77
    std::string file_path_str(file_path);
16!
78
    std::string index_dir_str(index_dir);
16!
79
    TraceStatistics stats;
16!
80
    StatisticsQueryOutput output;
16✔
81
    auto qt_copy = qt;
16✔
82
    auto top_n_copy = static_cast<std::uint64_t>(top_n);
16✔
83

84
    if (!run_blocking([&] {
24!
85
            Runtime *rt = get_runtime(self);
16!
86

87
            StatisticsAggregatorInput agg_input;
16✔
88
            agg_input.file_path = file_path_str;
16!
89
            agg_input.index_dir = index_dir_str;
16!
90
            agg_input.index_path = dftracer::utils::utilities::composites::dft::
8!
91
                internal::determine_index_path(file_path_str, index_dir_str);
16!
92

93
            auto *stats_p = &stats;
24✔
94
            auto agg_task = [stats_p, agg_input]() -> CoroTask<void> {
72!
95
                StatisticsAggregatorUtility util;
24!
96
                *stats_p = co_await util.process(agg_input);
32!
97
            };
48!
98
            rt->submit(agg_task(), "stats-agg").get();
16!
99

100
            StatisticsQueryInput query_input;
16!
101
            query_input.stats = std::move(stats);
16✔
102
            query_input.query_type = qt_copy;
16✔
103
            query_input.top_n = top_n_copy;
16✔
104

105
            auto *out_p = &output;
16✔
106
            auto query_task = [out_p, query_input]() -> CoroTask<void> {
72!
107
                StatisticsQueryUtility util;
24!
108
                *out_p = co_await util.process(query_input);
32!
109
            };
48!
110
            rt->submit(query_task(), "stats-query").get();
16!
111
        })) {
16✔
UNCOV
112
        return NULL;
×
113
    }
114

115
    PyObject *results_list =
8✔
116
        PyList_New(static_cast<Py_ssize_t>(output.results.size()));
16!
117
    if (!results_list) return NULL;
16✔
118

119
    for (std::size_t i = 0; i < output.results.size(); ++i) {
62✔
120
        PyObject *tup = PyTuple_New(2);
46!
121
        if (!tup) {
46!
122
            Py_DECREF(results_list);
×
123
            return NULL;
×
124
        }
125
        PyTuple_SET_ITEM(tup, 0,
46!
126
                         PyUnicode_FromString(output.results[i].first.c_str()));
127
        PyTuple_SET_ITEM(tup, 1,
46!
128
                         PyLong_FromUnsignedLongLong(output.results[i].second));
129
        PyList_SET_ITEM(results_list, static_cast<Py_ssize_t>(i), tup);
46!
130
    }
23✔
131

132
    PyObject *d = PyDict_New();
16!
133
    if (!d) {
16!
134
        Py_DECREF(results_list);
×
135
        return NULL;
×
136
    }
137

138
    int rc = 0;
16✔
139
    rc |= dict_set_str(d, "query_type", output.query_type_name.c_str());
16!
140
    rc |= dict_set_u64(d, "total_events", output.total_events);
16!
141
    rc |= dict_set_u64(d, "min_timestamp_us", output.min_timestamp_us);
16!
142
    rc |= dict_set_u64(d, "max_timestamp_us", output.max_timestamp_us);
16!
143
    rc |= dict_set_f64(d, "time_span_seconds", output.time_span_seconds);
16!
144
    rc |= dict_set_u64(d, "duration_count", output.duration_count);
16!
145
    rc |= dict_set_f64(d, "duration_mean_us", output.duration_mean_us);
16!
146
    rc |= dict_set_f64(d, "duration_stddev_us", output.duration_stddev_us);
16!
147
    rc |= dict_set_u64(d, "duration_min_us", output.duration_min_us);
16!
148
    rc |= dict_set_u64(d, "duration_max_us", output.duration_max_us);
16!
149
    // Steals (and always releases) the results_list reference.
150
    rc |= dict_set_steal(d, "results", results_list);
16!
151

152
    if (rc != 0) {
16!
153
        Py_DECREF(d);
×
154
        return NULL;
×
155
    }
156

157
    return d;
16✔
158
}
16✔
159

160
static PyObject *StatisticsQuery_call(PyObject *self, PyObject *args,
2✔
161
                                      PyObject *kwds) {
162
    return StatisticsQuery_query((StatisticsQueryObject *)self, args, kwds);
2✔
163
}
164

165
static PyMethodDef StatisticsQuery_methods[] = {
166
    {"process", (PyCFunction)StatisticsQuery_query,
167
     METH_VARARGS | METH_KEYWORDS,
168
     "process(file_path, query_type='summary', top_n=10, index_dir='')\n"
169
     "--\n"
170
     "\n"
171
     "Query statistics from an indexed trace file.\n"
172
     "\n"
173
     "Args:\n"
174
     "    file_path (str): Path to the trace file.\n"
175
     "    query_type (str): Query type (default 'summary'). One of\n"
176
     "        'summary', 'categories', 'names', 'pid_tids',\n"
177
     "        'time_range', 'duration_stats', 'top_n_names',\n"
178
     "        'top_n_categories', 'detailed'.\n"
179
     "    top_n (int): Top results for ranked queries (default 10).\n"
180
     "    index_dir (str): Directory for .dftindex stores (default '').\n"
181
     "\n"
182
     "Returns:\n"
183
     "    dict: Query results.\n"},
184
    {NULL}};
185

186
PyTypeObject StatisticsQueryUtilityType = {
187
    PyVarObject_HEAD_INIT(
188
        NULL, 0) "dftracer_utils_ext.StatisticsQueryUtility", /* tp_name */
189
    sizeof(StatisticsQueryObject),                            /* tp_basicsize */
190
    0,                                                        /* tp_itemsize */
191
    (destructor)StatisticsQuery_dealloc,                      /* tp_dealloc */
192
    0,                                        /* tp_vectorcall_offset */
193
    0,                                        /* tp_getattr */
194
    0,                                        /* tp_setattr */
195
    0,                                        /* tp_as_async */
196
    0,                                        /* tp_repr */
197
    0,                                        /* tp_as_number */
198
    0,                                        /* tp_as_sequence */
199
    0,                                        /* tp_as_mapping */
200
    0,                                        /* tp_hash */
201
    StatisticsQuery_call,                     /* tp_call */
202
    0,                                        /* tp_str */
203
    0,                                        /* tp_getattro */
204
    0,                                        /* tp_setattro */
205
    0,                                        /* tp_as_buffer */
206
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
207
    "StatisticsQueryUtility(runtime: Runtime | None = None)\n"
208
    "--\n\n"
209
    "Query pre-computed statistics from an indexed trace file.\n\n"
210
    "Args:\n"
211
    "    runtime (Runtime or None): Runtime for thread pool control.\n",
212
    0,                              /* tp_traverse */
213
    0,                              /* tp_clear */
214
    0,                              /* tp_richcompare */
215
    0,                              /* tp_weaklistoffset */
216
    0,                              /* tp_iter */
217
    0,                              /* tp_iternext */
218
    StatisticsQuery_methods,        /* tp_methods */
219
    0,                              /* tp_members */
220
    0,                              /* tp_getset */
221
    0,                              /* tp_base */
222
    0,                              /* tp_dict */
223
    0,                              /* tp_descr_get */
224
    0,                              /* tp_descr_set */
225
    0,                              /* tp_dictoffset */
226
    (initproc)StatisticsQuery_init, /* tp_init */
227
    0,                              /* tp_alloc */
228
    StatisticsQuery_new,            /* tp_new */
229
};
230

231
int init_statistics_query(PyObject *m) {
2✔
232
    if (register_type(m, &StatisticsQueryUtilityType,
2✔
233
                      "StatisticsQueryUtility") < 0)
2✔
UNCOV
234
        return -1;
×
235

236
    return 0;
2✔
237
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc