Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/likely.h"
8 : : #include "spdk/log.h"
9 : : #include "spdk/trace_parser.h"
10 : : #include "spdk/util.h"
11 : :
12 : : #include <exception>
13 : : #include <map>
14 : : #include <new>
15 : :
16 : : struct entry_key {
17 : 1128291 : entry_key(uint16_t _lcore, uint64_t _tsc) : lcore(_lcore), tsc(_tsc) {}
18 : : uint16_t lcore;
19 : : uint64_t tsc;
20 : : };
21 : :
22 : : class compare_entry_key
23 : : {
24 : : public:
25 : 28514917 : bool operator()(const entry_key &first, const entry_key &second) const
26 : : {
27 [ - + ]: 28514917 : if (first.tsc == second.tsc) {
28 : 0 : return first.lcore < second.lcore;
29 : : } else {
30 : 28514917 : return first.tsc < second.tsc;
31 : : }
32 : : }
33 : : };
34 : :
35 : : typedef std::map<entry_key, spdk_trace_entry *, compare_entry_key> entry_map;
36 : :
37 : : struct argument_context {
38 : : spdk_trace_entry *entry;
39 : : spdk_trace_entry_buffer *buffer;
40 : : uint16_t lcore;
41 : : size_t offset;
42 : :
43 : 1128291 : argument_context(spdk_trace_entry *entry, uint16_t lcore) :
44 : 1128291 : entry(entry), lcore(lcore)
45 : : {
46 : 1128291 : buffer = reinterpret_cast<spdk_trace_entry_buffer *>(entry);
47 : :
48 : : /* The first argument resides within the spdk_trace_entry structure, so the initial
49 : : * offset needs to be adjusted to the start of the spdk_trace_entry.args array
50 : : */
51 : 1128291 : offset = offsetof(spdk_trace_entry, args) -
52 : : offsetof(spdk_trace_entry_buffer, data);
53 : 1128291 : }
54 : : };
55 : :
56 : : struct object_stats {
57 : : std::map<uint64_t, uint64_t> index;
58 : : std::map<uint64_t, uint64_t> start;
59 : : uint64_t counter;
60 : :
61 : 512 : object_stats() : counter(0) {}
62 : : };
63 : :
64 : : struct spdk_trace_parser {
65 : : spdk_trace_parser(const spdk_trace_parser_opts *opts);
66 : : ~spdk_trace_parser();
67 : : spdk_trace_parser(const spdk_trace_parser &) = delete;
68 : : spdk_trace_parser &operator=(const spdk_trace_parser &) = delete;
69 : 2 : const spdk_trace_file *file() const { return _trace_file; }
70 : 2 : uint64_t tsc_offset() const { return _tsc_offset; }
71 : : bool next_entry(spdk_trace_parser_entry *entry);
72 : : uint64_t entry_count(uint16_t lcore) const;
73 : : private:
74 : : spdk_trace_entry_buffer *get_next_buffer(spdk_trace_entry_buffer *buf, uint16_t lcore);
75 : : bool build_arg(argument_context *argctx, const spdk_trace_argument *arg, int argid,
76 : : spdk_trace_parser_entry *pe);
77 : : void populate_events(spdk_trace_history *history, int num_entries);
78 : : bool init(const spdk_trace_parser_opts *opts);
79 : : void cleanup();
80 : :
81 : : spdk_trace_file *_trace_file;
82 : : size_t _map_size;
83 : : int _fd;
84 : : uint64_t _tsc_offset;
85 : : entry_map _entries;
86 : : entry_map::iterator _iter;
87 : : object_stats _stats[SPDK_TRACE_MAX_OBJECT];
88 : : };
89 : :
90 : : uint64_t
91 : 2048 : spdk_trace_parser::entry_count(uint16_t lcore) const
92 : : {
93 : : spdk_trace_history *history;
94 : :
95 [ - + ]: 2048 : if (lcore >= SPDK_TRACE_MAX_LCORE) {
96 : 0 : return 0;
97 : : }
98 : :
99 : 2048 : history = spdk_get_per_lcore_history(_trace_file, lcore);
100 : :
101 [ + + ]: 2048 : return history == NULL ? 0 : history->num_entries;
102 : : }
103 : :
104 : : spdk_trace_entry_buffer *
105 : 158732 : spdk_trace_parser::get_next_buffer(spdk_trace_entry_buffer *buf, uint16_t lcore)
106 : : {
107 : : spdk_trace_history *history;
108 : :
109 : 158732 : history = spdk_get_per_lcore_history(_trace_file, lcore);
110 [ - + ]: 158732 : assert(history);
111 : :
112 [ - + ]: 158732 : if (spdk_unlikely(static_cast<void *>(buf) ==
113 : : static_cast<void *>(&history->entries[history->num_entries - 1]))) {
114 : 0 : return reinterpret_cast<spdk_trace_entry_buffer *>(&history->entries[0]);
115 : : } else {
116 : 158732 : return buf + 1;
117 : : }
118 : : }
119 : :
120 : : bool
121 : 883561 : spdk_trace_parser::build_arg(argument_context *argctx, const spdk_trace_argument *arg, int argid,
122 : : spdk_trace_parser_entry *pe)
123 : : {
124 : 883561 : spdk_trace_entry *entry = argctx->entry;
125 : 883561 : spdk_trace_entry_buffer *buffer = argctx->buffer;
126 : : size_t curlen, argoff;
127 : :
128 : 883561 : argoff = 0;
129 : 883561 : pe->args[argid].is_related = false;
130 : : /* Make sure that if we only copy a 4-byte integer, that the upper bytes have already been
131 : : * zeroed.
132 : : */
133 : 883561 : pe->args[argid].u.integer = 0;
134 [ + + ]: 1767122 : while (argoff < arg->size) {
135 [ + + ]: 883561 : if (argctx->offset == sizeof(buffer->data)) {
136 : 158732 : buffer = get_next_buffer(buffer, argctx->lcore);
137 [ + - - + : 158732 : if (spdk_unlikely(buffer->tpoint_id != SPDK_TRACE_MAX_TPOINT_ID ||
- + ]
138 : : buffer->tsc != entry->tsc)) {
139 : 0 : return false;
140 : : }
141 : :
142 : 158732 : argctx->offset = 0;
143 : 158732 : argctx->buffer = buffer;
144 : : }
145 : :
146 : 883561 : curlen = spdk_min(sizeof(buffer->data) - argctx->offset, arg->size - argoff);
147 [ + - ]: 883561 : if (argoff < sizeof(pe->args[0].u.string)) {
148 [ - + - + ]: 883561 : memcpy(&pe->args[argid].u.string[argoff], &buffer->data[argctx->offset],
149 : 883561 : spdk_min(curlen, sizeof(pe->args[0].u.string) - argoff));
150 : : }
151 : :
152 : 883561 : argctx->offset += curlen;
153 : 883561 : argoff += curlen;
154 : : }
155 : :
156 : 883561 : return true;
157 : : }
158 : :
159 : : bool
160 : 1128293 : spdk_trace_parser::next_entry(spdk_trace_parser_entry *pe)
161 : : {
162 : : spdk_trace_tpoint *tpoint;
163 : : spdk_trace_entry *entry;
164 : : object_stats *stats;
165 : 1128293 : std::map<uint64_t, uint64_t>::iterator related_kv;
166 : :
167 [ + + ]: 1128293 : if (_iter == _entries.end()) {
168 : 2 : return false;
169 : : }
170 : :
171 : 1128291 : pe->entry = entry = _iter->second;
172 : 1128291 : pe->lcore = _iter->first.lcore;
173 : : /* Set related index to the max value to indicate "empty" state */
174 : 1128291 : pe->related_index = UINT64_MAX;
175 : 1128291 : pe->related_type = OBJECT_NONE;
176 : 1128291 : tpoint = &_trace_file->tpoint[entry->tpoint_id];
177 : 1128291 : stats = &_stats[tpoint->object_type];
178 : :
179 [ + + ]: 1128291 : if (tpoint->new_object) {
180 [ + - ]: 322375 : stats->index[entry->object_id] = stats->counter++;
181 [ + - ]: 322375 : stats->start[entry->object_id] = entry->tsc;
182 : : }
183 : :
184 [ + + ]: 1128291 : if (tpoint->object_type != OBJECT_NONE) {
185 [ + - + - ]: 931342 : if (spdk_likely(stats->start.find(entry->object_id) != stats->start.end())) {
186 [ + - ]: 931342 : pe->object_index = stats->index[entry->object_id];
187 [ + - ]: 931342 : pe->object_start = stats->start[entry->object_id];
188 : : } else {
189 : 0 : pe->object_index = UINT64_MAX;
190 : 0 : pe->object_start = UINT64_MAX;
191 : : }
192 : : }
193 : :
194 : 1128291 : argument_context argctx(entry, pe->lcore);
195 [ + + ]: 2011852 : for (uint8_t i = 0; i < tpoint->num_args; ++i) {
196 [ + - - + ]: 883561 : if (!build_arg(&argctx, &tpoint->args[i], i, pe)) {
197 [ # # ]: 0 : SPDK_ERRLOG("Failed to parse tracepoint argument\n");
198 : 0 : return false;
199 : : }
200 : : }
201 : :
202 [ + - ]: 1139991 : for (uint8_t i = 0; i < SPDK_TRACE_MAX_RELATIONS; ++i) {
203 : : /* The relations are stored inside a tpoint, which means there might be
204 : : * multiple objects bound to a single tpoint. */
205 [ + + ]: 1139991 : if (tpoint->related_objects[i].object_type == OBJECT_NONE) {
206 : 891039 : break;
207 : : }
208 : 248952 : stats = &_stats[tpoint->related_objects[i].object_type];
209 [ + - ]: 497904 : related_kv = stats->index.find(reinterpret_cast<uint64_t>
210 [ # # ]: 248952 : (pe->args[tpoint->related_objects[i].arg_index].u.pointer));
211 : : /* To avoid parsing the whole array, object index and type are stored
212 : : * directly inside spdk_trace_parser_entry. */
213 [ + + ]: 248952 : if (related_kv != stats->index.end()) {
214 : 237252 : pe->related_index = related_kv->second;
215 : 237252 : pe->related_type = tpoint->related_objects[i].object_type;
216 : 237252 : pe->args[tpoint->related_objects[i].arg_index].is_related = true;
217 : 237252 : break;
218 : : }
219 : : }
220 : :
221 : 1128291 : _iter++;
222 : 1128291 : return true;
223 : : }
224 : :
225 : : void
226 : 8 : spdk_trace_parser::populate_events(spdk_trace_history *history, int num_entries)
227 : : {
228 : : int i, num_entries_filled;
229 : : spdk_trace_entry *e;
230 : : int first, last, lcore;
231 : :
232 : 8 : lcore = history->lcore;
233 : 8 : e = history->entries;
234 : :
235 : 8 : num_entries_filled = num_entries;
236 [ - + ]: 8 : while (e[num_entries_filled - 1].tsc == 0) {
237 : 0 : num_entries_filled--;
238 : : }
239 : :
240 [ + - ]: 8 : if (num_entries == num_entries_filled) {
241 : 8 : first = last = 0;
242 [ + + ]: 1287023 : for (i = 1; i < num_entries; i++) {
243 [ - + ]: 1287015 : if (e[i].tsc < e[first].tsc) {
244 : 0 : first = i;
245 : : }
246 [ + + ]: 1287015 : if (e[i].tsc > e[last].tsc) {
247 : 1128283 : last = i;
248 : : }
249 : : }
250 : : } else {
251 : 0 : first = 0;
252 : 0 : last = num_entries_filled - 1;
253 : : }
254 : :
255 : : /*
256 : : * We keep track of the highest first TSC out of all reactors.
257 : : * We will ignore any events that occurred before this TSC on any
258 : : * other reactors. This will ensure we only print data for the
259 : : * subset of time where we have data across all reactors.
260 : : */
261 [ + + ]: 8 : if (e[first].tsc > _tsc_offset) {
262 : 3 : _tsc_offset = e[first].tsc;
263 : : }
264 : :
265 : 8 : i = first;
266 : : while (1) {
267 [ + + ]: 1287023 : if (e[i].tpoint_id != SPDK_TRACE_MAX_TPOINT_ID) {
268 [ + - ]: 1128291 : _entries[entry_key(lcore, e[i].tsc)] = &e[i];
269 : : }
270 [ + + ]: 1287023 : if (i == last) {
271 : 8 : break;
272 : : }
273 : 1287015 : i++;
274 [ - + ]: 1287015 : if (i == num_entries_filled) {
275 : 0 : i = 0;
276 : : }
277 : : }
278 : 8 : }
279 : :
280 : : bool
281 : 2 : spdk_trace_parser::init(const spdk_trace_parser_opts *opts)
282 : : {
283 : : spdk_trace_history *history;
284 : 0 : struct stat st;
285 : : int rc, i;
286 : :
287 [ + - - ]: 2 : switch (opts->mode) {
288 : 2 : case SPDK_TRACE_PARSER_MODE_FILE:
289 [ - + + - ]: 2 : _fd = open(opts->filename, O_RDONLY);
290 : 2 : break;
291 : 0 : case SPDK_TRACE_PARSER_MODE_SHM:
292 [ # # ]: 0 : _fd = shm_open(opts->filename, O_RDONLY, 0600);
293 : 0 : break;
294 : 0 : default:
295 [ # # ]: 0 : SPDK_ERRLOG("Invalid mode: %d\n", opts->mode);
296 : 0 : return false;
297 : : }
298 : :
299 [ - + ]: 2 : if (_fd < 0) {
300 [ # # ]: 0 : SPDK_ERRLOG("Could not open trace file: %s (%d)\n", opts->filename, errno);
301 : 0 : return false;
302 : : }
303 : :
304 : 2 : rc = fstat(_fd, &st);
305 [ - + ]: 2 : if (rc < 0) {
306 [ # # ]: 0 : SPDK_ERRLOG("Could not get size of trace file: %s\n", opts->filename);
307 : 0 : return false;
308 : : }
309 : :
310 [ - + ]: 2 : if ((size_t)st.st_size < sizeof(*_trace_file)) {
311 [ # # ]: 0 : SPDK_ERRLOG("Invalid trace file: %s\n", opts->filename);
312 : 0 : return false;
313 : : }
314 : :
315 : : /* Map the header of trace file */
316 : 2 : _map_size = sizeof(*_trace_file);
317 : 2 : _trace_file = static_cast<spdk_trace_file *>(mmap(NULL, _map_size, PROT_READ,
318 : : MAP_SHARED, _fd, 0));
319 [ - + ]: 2 : if (_trace_file == MAP_FAILED) {
320 [ # # ]: 0 : SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename);
321 : 0 : _trace_file = NULL;
322 : 0 : return false;
323 : : }
324 : :
325 : : /* Remap the entire trace file */
326 : 2 : _map_size = spdk_get_trace_file_size(_trace_file);
327 : 2 : munmap(_trace_file, sizeof(*_trace_file));
328 [ - + ]: 2 : if ((size_t)st.st_size < _map_size) {
329 [ # # ]: 0 : SPDK_ERRLOG("Trace file %s is not valid\n", opts->filename);
330 : 0 : _trace_file = NULL;
331 : 0 : return false;
332 : : }
333 : 2 : _trace_file = static_cast<spdk_trace_file *>(mmap(NULL, _map_size, PROT_READ,
334 : : MAP_SHARED, _fd, 0));
335 [ - + ]: 2 : if (_trace_file == MAP_FAILED) {
336 [ # # ]: 0 : SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename);
337 : 0 : _trace_file = NULL;
338 : 0 : return false;
339 : : }
340 : :
341 [ + - ]: 2 : if (opts->lcore == SPDK_TRACE_MAX_LCORE) {
342 [ + + ]: 2050 : for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
343 : 2048 : history = spdk_get_per_lcore_history(_trace_file, i);
344 [ + + + - : 2048 : if (history == NULL || history->num_entries == 0 || history->entries[0].tsc == 0) {
- + ]
345 : 2040 : continue;
346 : : }
347 : :
348 [ + - ]: 8 : populate_events(history, history->num_entries);
349 : : }
350 : : } else {
351 : 0 : history = spdk_get_per_lcore_history(_trace_file, opts->lcore);
352 [ # # ]: 0 : if (history == NULL) {
353 [ # # ]: 0 : SPDK_ERRLOG("Trace file %s has no trace history for lcore %d\n",
354 : : opts->filename, opts->lcore);
355 : 0 : return false;
356 : : }
357 [ # # # # ]: 0 : if (history->num_entries > 0 && history->entries[0].tsc != 0) {
358 [ # # ]: 0 : populate_events(history, history->num_entries);
359 : : }
360 : : }
361 : :
362 : 2 : _iter = _entries.begin();
363 : 2 : return true;
364 : : }
365 : :
366 : : void
367 : 2 : spdk_trace_parser::cleanup()
368 : : {
369 [ + - ]: 2 : if (_trace_file != NULL) {
370 : 2 : munmap(_trace_file, _map_size);
371 : : }
372 : :
373 [ + - ]: 2 : if (_fd > 0) {
374 : 2 : close(_fd);
375 : : }
376 : 2 : }
377 : :
378 : 2 : spdk_trace_parser::spdk_trace_parser(const spdk_trace_parser_opts *opts) :
379 : 2 : _trace_file(NULL),
380 : 2 : _map_size(0),
381 : 2 : _fd(-1),
382 [ + + - - : 514 : _tsc_offset(0)
# # ]
383 : : {
384 [ + - - + ]: 2 : if (!init(opts)) {
385 [ # # ]: 0 : cleanup();
386 : 0 : throw std::exception();
387 : : }
388 [ - - # # ]: 2 : }
389 : :
390 [ + - # # ]: 1028 : spdk_trace_parser::~spdk_trace_parser()
391 : : {
392 : 2 : cleanup();
393 [ + + # # ]: 516 : }
394 : :
395 : : struct spdk_trace_parser *
396 : 2 : spdk_trace_parser_init(const struct spdk_trace_parser_opts *opts)
397 : : {
398 : : try {
399 [ + - + - : 2 : return new spdk_trace_parser(opts);
- - ]
400 : 0 : } catch (...) {
401 : 0 : return NULL;
402 : 0 : }
403 : : }
404 : :
405 : : void
406 : 2 : spdk_trace_parser_cleanup(struct spdk_trace_parser *parser)
407 : : {
408 [ + - ]: 2 : delete parser;
409 : 2 : }
410 : :
411 : : const struct spdk_trace_file *
412 : 2 : spdk_trace_parser_get_file(const struct spdk_trace_parser *parser)
413 : : {
414 : 2 : return parser->file();
415 : : }
416 : :
417 : : uint64_t
418 : 2 : spdk_trace_parser_get_tsc_offset(const struct spdk_trace_parser *parser)
419 : : {
420 : 2 : return parser->tsc_offset();
421 : : }
422 : :
423 : : bool
424 : 1128293 : spdk_trace_parser_next_entry(struct spdk_trace_parser *parser,
425 : : struct spdk_trace_parser_entry *entry)
426 : : {
427 : 1128293 : return parser->next_entry(entry);
428 : : }
429 : :
430 : : uint64_t
431 : 2048 : spdk_trace_parser_get_entry_count(const struct spdk_trace_parser *parser, uint16_t lcore)
432 : : {
433 : 2048 : return parser->entry_count(lcore);
434 : : }
|