xref: /spdk/lib/trace_parser/trace.cpp (revision ee32a82bfd3ff5b1a10ed775ee06f0eaffce60eb)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2021 Intel Corporation.
3d919a197SKonrad Sztyber  *   All rights reserved.
4d919a197SKonrad Sztyber  */
5d919a197SKonrad Sztyber 
6d919a197SKonrad Sztyber #include "spdk/stdinc.h"
7ffaec5f9SKonrad Sztyber #include "spdk/likely.h"
855f64c36SKonrad Sztyber #include "spdk/log.h"
9d919a197SKonrad Sztyber #include "spdk/trace_parser.h"
1041ba2b30SKonrad Sztyber #include "spdk/util.h"
11*ee32a82bSAnisa Su #include "spdk/env.h"
12d919a197SKonrad Sztyber 
1355f64c36SKonrad Sztyber #include <exception>
144ba77072SKonrad Sztyber #include <map>
1555f64c36SKonrad Sztyber #include <new>
1655f64c36SKonrad Sztyber 
174ba77072SKonrad Sztyber struct entry_key {
184ba77072SKonrad Sztyber 	entry_key(uint16_t _lcore, uint64_t _tsc) : lcore(_lcore), tsc(_tsc) {}
194ba77072SKonrad Sztyber 	uint16_t lcore;
204ba77072SKonrad Sztyber 	uint64_t tsc;
214ba77072SKonrad Sztyber };
224ba77072SKonrad Sztyber 
234ba77072SKonrad Sztyber class compare_entry_key
244ba77072SKonrad Sztyber {
254ba77072SKonrad Sztyber public:
264ba77072SKonrad Sztyber 	bool operator()(const entry_key &first, const entry_key &second) const
274ba77072SKonrad Sztyber 	{
284ba77072SKonrad Sztyber 		if (first.tsc == second.tsc) {
294ba77072SKonrad Sztyber 			return first.lcore < second.lcore;
304ba77072SKonrad Sztyber 		} else {
314ba77072SKonrad Sztyber 			return first.tsc < second.tsc;
324ba77072SKonrad Sztyber 		}
334ba77072SKonrad Sztyber 	}
344ba77072SKonrad Sztyber };
354ba77072SKonrad Sztyber 
364ba77072SKonrad Sztyber typedef std::map<entry_key, spdk_trace_entry *, compare_entry_key> entry_map;
374ba77072SKonrad Sztyber 
38ffaec5f9SKonrad Sztyber struct argument_context {
39ffaec5f9SKonrad Sztyber 	spdk_trace_entry	*entry;
40ffaec5f9SKonrad Sztyber 	spdk_trace_entry_buffer	*buffer;
41ffaec5f9SKonrad Sztyber 	uint16_t		lcore;
42ffaec5f9SKonrad Sztyber 	size_t			offset;
43ffaec5f9SKonrad Sztyber 
44ffaec5f9SKonrad Sztyber 	argument_context(spdk_trace_entry *entry, uint16_t lcore) :
45ffaec5f9SKonrad Sztyber 		entry(entry), lcore(lcore)
46ffaec5f9SKonrad Sztyber 	{
47ffaec5f9SKonrad Sztyber 		buffer = reinterpret_cast<spdk_trace_entry_buffer *>(entry);
48ffaec5f9SKonrad Sztyber 
49ffaec5f9SKonrad Sztyber 		/* The first argument resides within the spdk_trace_entry structure, so the initial
50ffaec5f9SKonrad Sztyber 		 * offset needs to be adjusted to the start of the spdk_trace_entry.args array
51ffaec5f9SKonrad Sztyber 		 */
52ffaec5f9SKonrad Sztyber 		offset = offsetof(spdk_trace_entry, args) -
53ffaec5f9SKonrad Sztyber 			 offsetof(spdk_trace_entry_buffer, data);
54ffaec5f9SKonrad Sztyber 	}
55ffaec5f9SKonrad Sztyber };
56ffaec5f9SKonrad Sztyber 
57f243f624SKonrad Sztyber struct object_stats {
58f243f624SKonrad Sztyber 	std::map<uint64_t, uint64_t>	index;
59f243f624SKonrad Sztyber 	std::map<uint64_t, uint64_t>	start;
60f243f624SKonrad Sztyber 	uint64_t			counter;
61f243f624SKonrad Sztyber 
62f243f624SKonrad Sztyber 	object_stats() : counter(0) {}
63f243f624SKonrad Sztyber };
64f243f624SKonrad Sztyber 
6555f64c36SKonrad Sztyber struct spdk_trace_parser {
6655f64c36SKonrad Sztyber 	spdk_trace_parser(const spdk_trace_parser_opts *opts);
6755f64c36SKonrad Sztyber 	~spdk_trace_parser();
6855f64c36SKonrad Sztyber 	spdk_trace_parser(const spdk_trace_parser &) = delete;
6955f64c36SKonrad Sztyber 	spdk_trace_parser &operator=(const spdk_trace_parser &) = delete;
7023dbcec5SJim Harris 	const spdk_trace_file *file() const { return _trace_file; }
716727cc38SKonrad Sztyber 	uint64_t tsc_offset() const { return _tsc_offset; }
72279b7babSKonrad Sztyber 	bool next_entry(spdk_trace_parser_entry *entry);
73189b0f09SKonrad Sztyber 	uint64_t entry_count(uint16_t lcore) const;
7455f64c36SKonrad Sztyber private:
75ffaec5f9SKonrad Sztyber 	spdk_trace_entry_buffer *get_next_buffer(spdk_trace_entry_buffer *buf, uint16_t lcore);
76ffaec5f9SKonrad Sztyber 	bool build_arg(argument_context *argctx, const spdk_trace_argument *arg, int argid,
77ffaec5f9SKonrad Sztyber 		       spdk_trace_parser_entry *pe);
78*ee32a82bSAnisa Su 	void populate_events(spdk_trace_history *history, int num_entries, bool overflowed);
7955f64c36SKonrad Sztyber 	bool init(const spdk_trace_parser_opts *opts);
8055f64c36SKonrad Sztyber 	void cleanup();
8155f64c36SKonrad Sztyber 
8214e26b9dSJim Harris 	spdk_trace_file		*_trace_file;
8355f64c36SKonrad Sztyber 	size_t			_map_size;
8455f64c36SKonrad Sztyber 	int			_fd;
854ba77072SKonrad Sztyber 	uint64_t		_tsc_offset;
864ba77072SKonrad Sztyber 	entry_map		_entries;
87279b7babSKonrad Sztyber 	entry_map::iterator	_iter;
88f243f624SKonrad Sztyber 	object_stats		_stats[SPDK_TRACE_MAX_OBJECT];
8955f64c36SKonrad Sztyber };
9055f64c36SKonrad Sztyber 
91189b0f09SKonrad Sztyber uint64_t
92189b0f09SKonrad Sztyber spdk_trace_parser::entry_count(uint16_t lcore) const
93189b0f09SKonrad Sztyber {
94189b0f09SKonrad Sztyber 	spdk_trace_history *history;
95189b0f09SKonrad Sztyber 
96189b0f09SKonrad Sztyber 	if (lcore >= SPDK_TRACE_MAX_LCORE) {
97189b0f09SKonrad Sztyber 		return 0;
98189b0f09SKonrad Sztyber 	}
99189b0f09SKonrad Sztyber 
10014e26b9dSJim Harris 	history = spdk_get_per_lcore_history(_trace_file, lcore);
101189b0f09SKonrad Sztyber 
10218c8b52aSJim Harris 	return history == NULL ? 0 : history->num_entries;
103189b0f09SKonrad Sztyber }
104189b0f09SKonrad Sztyber 
105ffaec5f9SKonrad Sztyber spdk_trace_entry_buffer *
106ffaec5f9SKonrad Sztyber spdk_trace_parser::get_next_buffer(spdk_trace_entry_buffer *buf, uint16_t lcore)
107279b7babSKonrad Sztyber {
108ffaec5f9SKonrad Sztyber 	spdk_trace_history *history;
109ffaec5f9SKonrad Sztyber 
11014e26b9dSJim Harris 	history = spdk_get_per_lcore_history(_trace_file, lcore);
111ffaec5f9SKonrad Sztyber 	assert(history);
112ffaec5f9SKonrad Sztyber 
113ffaec5f9SKonrad Sztyber 	if (spdk_unlikely(static_cast<void *>(buf) ==
114ffaec5f9SKonrad Sztyber 			  static_cast<void *>(&history->entries[history->num_entries - 1]))) {
115ffaec5f9SKonrad Sztyber 		return reinterpret_cast<spdk_trace_entry_buffer *>(&history->entries[0]);
116ffaec5f9SKonrad Sztyber 	} else {
117ffaec5f9SKonrad Sztyber 		return buf + 1;
118ffaec5f9SKonrad Sztyber 	}
119ffaec5f9SKonrad Sztyber }
120ffaec5f9SKonrad Sztyber 
121ffaec5f9SKonrad Sztyber bool
122ffaec5f9SKonrad Sztyber spdk_trace_parser::build_arg(argument_context *argctx, const spdk_trace_argument *arg, int argid,
123ffaec5f9SKonrad Sztyber 			     spdk_trace_parser_entry *pe)
124ffaec5f9SKonrad Sztyber {
125ffaec5f9SKonrad Sztyber 	spdk_trace_entry *entry = argctx->entry;
126ffaec5f9SKonrad Sztyber 	spdk_trace_entry_buffer *buffer = argctx->buffer;
127ffaec5f9SKonrad Sztyber 	size_t curlen, argoff;
128ffaec5f9SKonrad Sztyber 
129ffaec5f9SKonrad Sztyber 	argoff = 0;
13067eb86e3SJim Harris 	pe->args[argid].is_related = false;
131cdb0726bSJim Harris 	/* Make sure that if we only copy a 4-byte integer, that the upper bytes have already been
132cdb0726bSJim Harris 	 * zeroed.
133cdb0726bSJim Harris 	 */
134b4ba6cdfSJim Harris 	pe->args[argid].u.integer = 0;
135ffaec5f9SKonrad Sztyber 	while (argoff < arg->size) {
136ffaec5f9SKonrad Sztyber 		if (argctx->offset == sizeof(buffer->data)) {
137ffaec5f9SKonrad Sztyber 			buffer = get_next_buffer(buffer, argctx->lcore);
138ffaec5f9SKonrad Sztyber 			if (spdk_unlikely(buffer->tpoint_id != SPDK_TRACE_MAX_TPOINT_ID ||
139ffaec5f9SKonrad Sztyber 					  buffer->tsc != entry->tsc)) {
140ffaec5f9SKonrad Sztyber 				return false;
141ffaec5f9SKonrad Sztyber 			}
142ffaec5f9SKonrad Sztyber 
143ffaec5f9SKonrad Sztyber 			argctx->offset = 0;
144ffaec5f9SKonrad Sztyber 			argctx->buffer = buffer;
145ffaec5f9SKonrad Sztyber 		}
146ffaec5f9SKonrad Sztyber 
147ffaec5f9SKonrad Sztyber 		curlen = spdk_min(sizeof(buffer->data) - argctx->offset, arg->size - argoff);
1487025ceb9SMarcin Spiewak 		if (argoff < sizeof(pe->args[0].u.string)) {
149b4ba6cdfSJim Harris 			memcpy(&pe->args[argid].u.string[argoff], &buffer->data[argctx->offset],
1507025ceb9SMarcin Spiewak 			       spdk_min(curlen, sizeof(pe->args[0].u.string) - argoff));
151ffaec5f9SKonrad Sztyber 		}
152ffaec5f9SKonrad Sztyber 
153ffaec5f9SKonrad Sztyber 		argctx->offset += curlen;
154ffaec5f9SKonrad Sztyber 		argoff += curlen;
155ffaec5f9SKonrad Sztyber 	}
156ffaec5f9SKonrad Sztyber 
157ffaec5f9SKonrad Sztyber 	return true;
158ffaec5f9SKonrad Sztyber }
159ffaec5f9SKonrad Sztyber 
160ffaec5f9SKonrad Sztyber bool
161ffaec5f9SKonrad Sztyber spdk_trace_parser::next_entry(spdk_trace_parser_entry *pe)
162ffaec5f9SKonrad Sztyber {
163ffaec5f9SKonrad Sztyber 	spdk_trace_tpoint *tpoint;
164ffaec5f9SKonrad Sztyber 	spdk_trace_entry *entry;
165f243f624SKonrad Sztyber 	object_stats *stats;
16670c17160SKrzysztof Karas 	std::map<uint64_t, uint64_t>::iterator related_kv;
167ffaec5f9SKonrad Sztyber 
168279b7babSKonrad Sztyber 	if (_iter == _entries.end()) {
169279b7babSKonrad Sztyber 		return false;
170279b7babSKonrad Sztyber 	}
171279b7babSKonrad Sztyber 
172ffaec5f9SKonrad Sztyber 	pe->entry = entry = _iter->second;
173ffaec5f9SKonrad Sztyber 	pe->lcore = _iter->first.lcore;
17470c17160SKrzysztof Karas 	/* Set related index to the max value to indicate "empty" state */
17570c17160SKrzysztof Karas 	pe->related_index = UINT64_MAX;
17670c17160SKrzysztof Karas 	pe->related_type = OBJECT_NONE;
17723dbcec5SJim Harris 	tpoint = &_trace_file->tpoint[entry->tpoint_id];
178f243f624SKonrad Sztyber 	stats = &_stats[tpoint->object_type];
179f243f624SKonrad Sztyber 
180f243f624SKonrad Sztyber 	if (tpoint->new_object) {
181f243f624SKonrad Sztyber 		stats->index[entry->object_id] = stats->counter++;
182f243f624SKonrad Sztyber 		stats->start[entry->object_id] = entry->tsc;
183f243f624SKonrad Sztyber 	}
184f243f624SKonrad Sztyber 
185f243f624SKonrad Sztyber 	if (tpoint->object_type != OBJECT_NONE) {
186f243f624SKonrad Sztyber 		if (spdk_likely(stats->start.find(entry->object_id) != stats->start.end())) {
187f243f624SKonrad Sztyber 			pe->object_index = stats->index[entry->object_id];
188f243f624SKonrad Sztyber 			pe->object_start = stats->start[entry->object_id];
189f243f624SKonrad Sztyber 		} else {
190f243f624SKonrad Sztyber 			pe->object_index = UINT64_MAX;
191f243f624SKonrad Sztyber 			pe->object_start = UINT64_MAX;
192f243f624SKonrad Sztyber 		}
193f243f624SKonrad Sztyber 	}
194ffaec5f9SKonrad Sztyber 
195ffaec5f9SKonrad Sztyber 	argument_context argctx(entry, pe->lcore);
196ffaec5f9SKonrad Sztyber 	for (uint8_t i = 0; i < tpoint->num_args; ++i) {
197ffaec5f9SKonrad Sztyber 		if (!build_arg(&argctx, &tpoint->args[i], i, pe)) {
198ffaec5f9SKonrad Sztyber 			SPDK_ERRLOG("Failed to parse tracepoint argument\n");
199ffaec5f9SKonrad Sztyber 			return false;
200ffaec5f9SKonrad Sztyber 		}
201ffaec5f9SKonrad Sztyber 	}
202279b7babSKonrad Sztyber 
20370c17160SKrzysztof Karas 	for (uint8_t i = 0; i < SPDK_TRACE_MAX_RELATIONS; ++i) {
20470c17160SKrzysztof Karas 		/* The relations are stored inside a tpoint, which means there might be
20570c17160SKrzysztof Karas 		 * multiple objects bound to a single tpoint. */
20670c17160SKrzysztof Karas 		if (tpoint->related_objects[i].object_type == OBJECT_NONE) {
20770c17160SKrzysztof Karas 			break;
20870c17160SKrzysztof Karas 		}
20970c17160SKrzysztof Karas 		stats = &_stats[tpoint->related_objects[i].object_type];
21070c17160SKrzysztof Karas 		related_kv = stats->index.find(reinterpret_cast<uint64_t>
211b4ba6cdfSJim Harris 					       (pe->args[tpoint->related_objects[i].arg_index].u.pointer));
21270c17160SKrzysztof Karas 		/* To avoid parsing the whole array, object index and type are stored
21370c17160SKrzysztof Karas 		 * directly inside spdk_trace_parser_entry. */
21470c17160SKrzysztof Karas 		if (related_kv != stats->index.end()) {
21570c17160SKrzysztof Karas 			pe->related_index = related_kv->second;
21670c17160SKrzysztof Karas 			pe->related_type = tpoint->related_objects[i].object_type;
21767eb86e3SJim Harris 			pe->args[tpoint->related_objects[i].arg_index].is_related = true;
21870c17160SKrzysztof Karas 			break;
21970c17160SKrzysztof Karas 		}
22070c17160SKrzysztof Karas 	}
22170c17160SKrzysztof Karas 
222279b7babSKonrad Sztyber 	_iter++;
223279b7babSKonrad Sztyber 	return true;
224279b7babSKonrad Sztyber }
225279b7babSKonrad Sztyber 
2264ba77072SKonrad Sztyber void
227*ee32a82bSAnisa Su spdk_trace_parser::populate_events(spdk_trace_history *history, int num_entries, bool overflowed)
2284ba77072SKonrad Sztyber {
2294ba77072SKonrad Sztyber 	int i, num_entries_filled;
2304ba77072SKonrad Sztyber 	spdk_trace_entry *e;
2314ba77072SKonrad Sztyber 	int first, last, lcore;
2324ba77072SKonrad Sztyber 
2334ba77072SKonrad Sztyber 	lcore = history->lcore;
2344ba77072SKonrad Sztyber 	e = history->entries;
2354ba77072SKonrad Sztyber 
2364ba77072SKonrad Sztyber 	num_entries_filled = num_entries;
2374ba77072SKonrad Sztyber 	while (e[num_entries_filled - 1].tsc == 0) {
2384ba77072SKonrad Sztyber 		num_entries_filled--;
2394ba77072SKonrad Sztyber 	}
2404ba77072SKonrad Sztyber 
2414ba77072SKonrad Sztyber 	if (num_entries == num_entries_filled) {
2424ba77072SKonrad Sztyber 		first = last = 0;
2434ba77072SKonrad Sztyber 		for (i = 1; i < num_entries; i++) {
2444ba77072SKonrad Sztyber 			if (e[i].tsc < e[first].tsc) {
2454ba77072SKonrad Sztyber 				first = i;
2464ba77072SKonrad Sztyber 			}
2474ba77072SKonrad Sztyber 			if (e[i].tsc > e[last].tsc) {
2484ba77072SKonrad Sztyber 				last = i;
2494ba77072SKonrad Sztyber 			}
2504ba77072SKonrad Sztyber 		}
2514ba77072SKonrad Sztyber 	} else {
2524ba77072SKonrad Sztyber 		first = 0;
2534ba77072SKonrad Sztyber 		last = num_entries_filled - 1;
2544ba77072SKonrad Sztyber 	}
2554ba77072SKonrad Sztyber 
2564ba77072SKonrad Sztyber 	/*
257*ee32a82bSAnisa Su 	 * We keep track of the highest first TSC out of all reactors iff. any
258*ee32a82bSAnisa Su 	 * have overflowed their circular buffer.
259cc6920a4SJosh Soref 	 *  We will ignore any events that occurred before this TSC on any
2604ba77072SKonrad Sztyber 	 *  other reactors.  This will ensure we only print data for the
2614ba77072SKonrad Sztyber 	 *  subset of time where we have data across all reactors.
2624ba77072SKonrad Sztyber 	 */
263*ee32a82bSAnisa Su 	if (e[first].tsc > _tsc_offset && overflowed) {
2644ba77072SKonrad Sztyber 		_tsc_offset = e[first].tsc;
2654ba77072SKonrad Sztyber 	}
2664ba77072SKonrad Sztyber 
2674ba77072SKonrad Sztyber 	i = first;
2684ba77072SKonrad Sztyber 	while (1) {
2694ba77072SKonrad Sztyber 		if (e[i].tpoint_id != SPDK_TRACE_MAX_TPOINT_ID) {
2704ba77072SKonrad Sztyber 			_entries[entry_key(lcore, e[i].tsc)] = &e[i];
2714ba77072SKonrad Sztyber 		}
2724ba77072SKonrad Sztyber 		if (i == last) {
2734ba77072SKonrad Sztyber 			break;
2744ba77072SKonrad Sztyber 		}
2754ba77072SKonrad Sztyber 		i++;
2764ba77072SKonrad Sztyber 		if (i == num_entries_filled) {
2774ba77072SKonrad Sztyber 			i = 0;
2784ba77072SKonrad Sztyber 		}
2794ba77072SKonrad Sztyber 	}
2804ba77072SKonrad Sztyber }
2814ba77072SKonrad Sztyber 
28255f64c36SKonrad Sztyber bool
28355f64c36SKonrad Sztyber spdk_trace_parser::init(const spdk_trace_parser_opts *opts)
28455f64c36SKonrad Sztyber {
2854ba77072SKonrad Sztyber 	spdk_trace_history *history;
28655f64c36SKonrad Sztyber 	struct stat st;
287*ee32a82bSAnisa Su 	int rc, i, entry_num;
288*ee32a82bSAnisa Su 	bool overflowed;
28955f64c36SKonrad Sztyber 
29055f64c36SKonrad Sztyber 	switch (opts->mode) {
29155f64c36SKonrad Sztyber 	case SPDK_TRACE_PARSER_MODE_FILE:
29255f64c36SKonrad Sztyber 		_fd = open(opts->filename, O_RDONLY);
29355f64c36SKonrad Sztyber 		break;
29455f64c36SKonrad Sztyber 	case SPDK_TRACE_PARSER_MODE_SHM:
29555f64c36SKonrad Sztyber 		_fd = shm_open(opts->filename, O_RDONLY, 0600);
29655f64c36SKonrad Sztyber 		break;
29755f64c36SKonrad Sztyber 	default:
29855f64c36SKonrad Sztyber 		SPDK_ERRLOG("Invalid mode: %d\n", opts->mode);
29955f64c36SKonrad Sztyber 		return false;
30055f64c36SKonrad Sztyber 	}
30155f64c36SKonrad Sztyber 
30255f64c36SKonrad Sztyber 	if (_fd < 0) {
30355f64c36SKonrad Sztyber 		SPDK_ERRLOG("Could not open trace file: %s (%d)\n", opts->filename, errno);
30455f64c36SKonrad Sztyber 		return false;
30555f64c36SKonrad Sztyber 	}
30655f64c36SKonrad Sztyber 
30755f64c36SKonrad Sztyber 	rc = fstat(_fd, &st);
30855f64c36SKonrad Sztyber 	if (rc < 0) {
30955f64c36SKonrad Sztyber 		SPDK_ERRLOG("Could not get size of trace file: %s\n", opts->filename);
31055f64c36SKonrad Sztyber 		return false;
31155f64c36SKonrad Sztyber 	}
31255f64c36SKonrad Sztyber 
31314e26b9dSJim Harris 	if ((size_t)st.st_size < sizeof(*_trace_file)) {
31455f64c36SKonrad Sztyber 		SPDK_ERRLOG("Invalid trace file: %s\n", opts->filename);
31555f64c36SKonrad Sztyber 		return false;
31655f64c36SKonrad Sztyber 	}
31755f64c36SKonrad Sztyber 
31855f64c36SKonrad Sztyber 	/* Map the header of trace file */
31914e26b9dSJim Harris 	_map_size = sizeof(*_trace_file);
32014e26b9dSJim Harris 	_trace_file = static_cast<spdk_trace_file *>(mmap(NULL, _map_size, PROT_READ,
32155f64c36SKonrad Sztyber 			MAP_SHARED, _fd, 0));
32214e26b9dSJim Harris 	if (_trace_file == MAP_FAILED) {
32355f64c36SKonrad Sztyber 		SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename);
32414e26b9dSJim Harris 		_trace_file = NULL;
32555f64c36SKonrad Sztyber 		return false;
32655f64c36SKonrad Sztyber 	}
32755f64c36SKonrad Sztyber 
32855f64c36SKonrad Sztyber 	/* Remap the entire trace file */
32914e26b9dSJim Harris 	_map_size = spdk_get_trace_file_size(_trace_file);
33014e26b9dSJim Harris 	munmap(_trace_file, sizeof(*_trace_file));
33155f64c36SKonrad Sztyber 	if ((size_t)st.st_size < _map_size) {
33255f64c36SKonrad Sztyber 		SPDK_ERRLOG("Trace file %s is not valid\n", opts->filename);
33314e26b9dSJim Harris 		_trace_file = NULL;
33455f64c36SKonrad Sztyber 		return false;
33555f64c36SKonrad Sztyber 	}
33614e26b9dSJim Harris 	_trace_file = static_cast<spdk_trace_file *>(mmap(NULL, _map_size, PROT_READ,
33755f64c36SKonrad Sztyber 			MAP_SHARED, _fd, 0));
33814e26b9dSJim Harris 	if (_trace_file == MAP_FAILED) {
33955f64c36SKonrad Sztyber 		SPDK_ERRLOG("Could not mmap trace file: %s\n", opts->filename);
34014e26b9dSJim Harris 		_trace_file = NULL;
34155f64c36SKonrad Sztyber 		return false;
34255f64c36SKonrad Sztyber 	}
34355f64c36SKonrad Sztyber 
3444ba77072SKonrad Sztyber 	if (opts->lcore == SPDK_TRACE_MAX_LCORE) {
345*ee32a82bSAnisa Su 		/* Check if any reactors have overwritten their circular buffer. */
3464ba77072SKonrad Sztyber 		for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
34714e26b9dSJim Harris 			history = spdk_get_per_lcore_history(_trace_file, i);
34818c8b52aSJim Harris 			if (history == NULL || history->num_entries == 0 || history->entries[0].tsc == 0) {
3494ba77072SKonrad Sztyber 				continue;
3504ba77072SKonrad Sztyber 			}
351*ee32a82bSAnisa Su 			entry_num = history->num_entries - 1;
352*ee32a82bSAnisa Su 			overflowed = true;
353*ee32a82bSAnisa Su 			while (entry_num >= 0) {
354*ee32a82bSAnisa Su 				if (history->entries[entry_num].tsc == 0) {
355*ee32a82bSAnisa Su 					overflowed = false;
356*ee32a82bSAnisa Su 					break;
357*ee32a82bSAnisa Su 				}
358*ee32a82bSAnisa Su 				entry_num--;
359*ee32a82bSAnisa Su 			}
360*ee32a82bSAnisa Su 			if (overflowed) {
361*ee32a82bSAnisa Su 				break;
362*ee32a82bSAnisa Su 			}
3634ba77072SKonrad Sztyber 
364*ee32a82bSAnisa Su 		}
365*ee32a82bSAnisa Su 		for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
366*ee32a82bSAnisa Su 			history = spdk_get_per_lcore_history(_trace_file, i);
367*ee32a82bSAnisa Su 			if (history == NULL || history->num_entries == 0 || history->entries[0].tsc == 0) {
368*ee32a82bSAnisa Su 				continue;
369*ee32a82bSAnisa Su 			}
370*ee32a82bSAnisa Su 			populate_events(history, history->num_entries, overflowed);
3714ba77072SKonrad Sztyber 		}
3724ba77072SKonrad Sztyber 	} else {
37314e26b9dSJim Harris 		history = spdk_get_per_lcore_history(_trace_file, opts->lcore);
37418c8b52aSJim Harris 		if (history == NULL) {
37518c8b52aSJim Harris 			SPDK_ERRLOG("Trace file %s has no trace history for lcore %d\n",
37618c8b52aSJim Harris 				    opts->filename, opts->lcore);
37718c8b52aSJim Harris 			return false;
37818c8b52aSJim Harris 		}
3794ba77072SKonrad Sztyber 		if (history->num_entries > 0 && history->entries[0].tsc != 0) {
380*ee32a82bSAnisa Su 			populate_events(history, history->num_entries, false);
3814ba77072SKonrad Sztyber 		}
3824ba77072SKonrad Sztyber 	}
3834ba77072SKonrad Sztyber 
384279b7babSKonrad Sztyber 	_iter = _entries.begin();
38555f64c36SKonrad Sztyber 	return true;
38655f64c36SKonrad Sztyber }
38755f64c36SKonrad Sztyber 
38855f64c36SKonrad Sztyber void
38955f64c36SKonrad Sztyber spdk_trace_parser::cleanup()
39055f64c36SKonrad Sztyber {
39114e26b9dSJim Harris 	if (_trace_file != NULL) {
39214e26b9dSJim Harris 		munmap(_trace_file, _map_size);
39355f64c36SKonrad Sztyber 	}
39455f64c36SKonrad Sztyber 
39555f64c36SKonrad Sztyber 	if (_fd > 0) {
39655f64c36SKonrad Sztyber 		close(_fd);
39755f64c36SKonrad Sztyber 	}
39855f64c36SKonrad Sztyber }
39955f64c36SKonrad Sztyber 
40055f64c36SKonrad Sztyber spdk_trace_parser::spdk_trace_parser(const spdk_trace_parser_opts *opts) :
40114e26b9dSJim Harris 	_trace_file(NULL),
40255f64c36SKonrad Sztyber 	_map_size(0),
4034ba77072SKonrad Sztyber 	_fd(-1),
4044ba77072SKonrad Sztyber 	_tsc_offset(0)
40555f64c36SKonrad Sztyber {
40655f64c36SKonrad Sztyber 	if (!init(opts)) {
40755f64c36SKonrad Sztyber 		cleanup();
40855f64c36SKonrad Sztyber 		throw std::exception();
40955f64c36SKonrad Sztyber 	}
41055f64c36SKonrad Sztyber }
41155f64c36SKonrad Sztyber 
41255f64c36SKonrad Sztyber spdk_trace_parser::~spdk_trace_parser()
41355f64c36SKonrad Sztyber {
41455f64c36SKonrad Sztyber 	cleanup();
41555f64c36SKonrad Sztyber }
41655f64c36SKonrad Sztyber 
417d919a197SKonrad Sztyber struct spdk_trace_parser *
418d919a197SKonrad Sztyber spdk_trace_parser_init(const struct spdk_trace_parser_opts *opts)
419d919a197SKonrad Sztyber {
42055f64c36SKonrad Sztyber 	try {
42155f64c36SKonrad Sztyber 		return new spdk_trace_parser(opts);
42255f64c36SKonrad Sztyber 	} catch (...) {
423d919a197SKonrad Sztyber 		return NULL;
424d919a197SKonrad Sztyber 	}
42555f64c36SKonrad Sztyber }
426d919a197SKonrad Sztyber 
427d919a197SKonrad Sztyber void
428d919a197SKonrad Sztyber spdk_trace_parser_cleanup(struct spdk_trace_parser *parser)
42955f64c36SKonrad Sztyber {
43055f64c36SKonrad Sztyber 	delete parser;
43155f64c36SKonrad Sztyber }
43241ba2b30SKonrad Sztyber 
43323dbcec5SJim Harris const struct spdk_trace_file *
43423dbcec5SJim Harris spdk_trace_parser_get_file(const struct spdk_trace_parser *parser)
43541ba2b30SKonrad Sztyber {
43623dbcec5SJim Harris 	return parser->file();
43741ba2b30SKonrad Sztyber }
4386727cc38SKonrad Sztyber 
4396727cc38SKonrad Sztyber uint64_t
4406727cc38SKonrad Sztyber spdk_trace_parser_get_tsc_offset(const struct spdk_trace_parser *parser)
4416727cc38SKonrad Sztyber {
4426727cc38SKonrad Sztyber 	return parser->tsc_offset();
4436727cc38SKonrad Sztyber }
444279b7babSKonrad Sztyber 
445279b7babSKonrad Sztyber bool
446279b7babSKonrad Sztyber spdk_trace_parser_next_entry(struct spdk_trace_parser *parser,
447279b7babSKonrad Sztyber 			     struct spdk_trace_parser_entry *entry)
448279b7babSKonrad Sztyber {
449279b7babSKonrad Sztyber 	return parser->next_entry(entry);
450279b7babSKonrad Sztyber }
451189b0f09SKonrad Sztyber 
452189b0f09SKonrad Sztyber uint64_t
453189b0f09SKonrad Sztyber spdk_trace_parser_get_entry_count(const struct spdk_trace_parser *parser, uint16_t lcore)
454189b0f09SKonrad Sztyber {
455189b0f09SKonrad Sztyber 	return parser->entry_count(lcore);
456189b0f09SKonrad Sztyber }
457