xref: /spdk/app/trace/trace.cpp (revision 1128edc110b007b6bd6651a4555e2c432c93baac)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
3bdece622SDaniel Verkamp  *   All rights reserved.
4bdece622SDaniel Verkamp  */
5bdece622SDaniel Verkamp 
6b961d9ccSBen Walker #include "spdk/stdinc.h"
799531396SKonrad Sztyber #include "spdk/env.h"
899531396SKonrad Sztyber #include "spdk/json.h"
92731216dSKonrad Sztyber #include "spdk/likely.h"
1099531396SKonrad Sztyber #include "spdk/string.h"
1199531396SKonrad Sztyber #include "spdk/util.h"
12bdece622SDaniel Verkamp 
13bdece622SDaniel Verkamp #include <map>
14bdece622SDaniel Verkamp 
15bdece622SDaniel Verkamp extern "C" {
1669390766SKonrad Sztyber #include "spdk/trace_parser.h"
173f229f0eSJim Harris #include "spdk/util.h"
18bdece622SDaniel Verkamp }
19bdece622SDaniel Verkamp 
20a5fcb030SYongjin Lee enum print_format_type {
21a5fcb030SYongjin Lee 	PRINT_FMT_JSON,
22a5fcb030SYongjin Lee 	PRINT_FMT_DEFAULT,
23a5fcb030SYongjin Lee };
24a5fcb030SYongjin Lee 
2569390766SKonrad Sztyber static struct spdk_trace_parser *g_parser;
2623dbcec5SJim Harris static const struct spdk_trace_file *g_file;
2799531396SKonrad Sztyber static struct spdk_json_write_ctx *g_json;
28c199f56dSJim Harris static bool g_print_tsc = false;
29bdece622SDaniel Verkamp 
3099531396SKonrad Sztyber /* This is a bit ugly, but we don't want to include env_dpdk in the app, while spdk_util, which we
3199531396SKonrad Sztyber  * do need, uses some of the functions implemented there.  We're not actually using the functions
3299531396SKonrad Sztyber  * that depend on those, so just define them as no-ops to allow the app to link.
3399531396SKonrad Sztyber  */
3499531396SKonrad Sztyber extern "C" {
3599531396SKonrad Sztyber 	void *
spdk_realloc(void * buf,size_t size,size_t align)3699531396SKonrad Sztyber 	spdk_realloc(void *buf, size_t size, size_t align)
3799531396SKonrad Sztyber 	{
3899531396SKonrad Sztyber 		assert(false);
3999531396SKonrad Sztyber 
4099531396SKonrad Sztyber 		return NULL;
4199531396SKonrad Sztyber 	}
4299531396SKonrad Sztyber 
4399531396SKonrad Sztyber 	void
spdk_free(void * buf)4499531396SKonrad Sztyber 	spdk_free(void *buf)
4599531396SKonrad Sztyber 	{
4699531396SKonrad Sztyber 		assert(false);
4799531396SKonrad Sztyber 	}
4870f3606bSJohn Levon 
4970f3606bSJohn Levon 	uint64_t
spdk_get_ticks(void)5070f3606bSJohn Levon 	spdk_get_ticks(void)
5170f3606bSJohn Levon 	{
5270f3606bSJohn Levon 		return 0;
5370f3606bSJohn Levon 	}
5499531396SKonrad Sztyber } /* extern "C" */
5599531396SKonrad Sztyber 
56bdece622SDaniel Verkamp static void usage(void);
57bdece622SDaniel Verkamp 
58ea0afee0SJim Harris static char *g_exe_name;
59bdece622SDaniel Verkamp 
60bdece622SDaniel Verkamp static float
get_us_from_tsc(uint64_t tsc,uint64_t tsc_rate)61bdece622SDaniel Verkamp get_us_from_tsc(uint64_t tsc, uint64_t tsc_rate)
62bdece622SDaniel Verkamp {
63bdece622SDaniel Verkamp 	return ((float)tsc) * 1000 * 1000 / tsc_rate;
64bdece622SDaniel Verkamp }
65bdece622SDaniel Verkamp 
66441431d2SKonrad Sztyber static const char *
format_argname(const char * name)67441431d2SKonrad Sztyber format_argname(const char *name)
68441431d2SKonrad Sztyber {
69441431d2SKonrad Sztyber 	static char namebuf[16];
70441431d2SKonrad Sztyber 
71441431d2SKonrad Sztyber 	snprintf(namebuf, sizeof(namebuf), "%s: ", name);
72441431d2SKonrad Sztyber 	return namebuf;
73441431d2SKonrad Sztyber }
74441431d2SKonrad Sztyber 
75bdece622SDaniel Verkamp static void
print_ptr(const char * arg_string,uint64_t arg)76bdece622SDaniel Verkamp print_ptr(const char *arg_string, uint64_t arg)
77bdece622SDaniel Verkamp {
78441431d2SKonrad Sztyber 	printf("%-7.7s0x%-14jx ", format_argname(arg_string), arg);
79bdece622SDaniel Verkamp }
80bdece622SDaniel Verkamp 
81bdece622SDaniel Verkamp static void
print_uint64(const char * arg_string,uint64_t arg)82bdece622SDaniel Verkamp print_uint64(const char *arg_string, uint64_t arg)
83bdece622SDaniel Verkamp {
84bdece622SDaniel Verkamp 	/*
85bdece622SDaniel Verkamp 	 * Print arg as signed, since -1 is a common value especially
86bdece622SDaniel Verkamp 	 *  for FLUSH WRITEBUF when writev() returns -1 due to full
87bdece622SDaniel Verkamp 	 *  socket buffer.
88bdece622SDaniel Verkamp 	 */
89441431d2SKonrad Sztyber 	printf("%-7.7s%-16jd ", format_argname(arg_string), arg);
90bdece622SDaniel Verkamp }
91bdece622SDaniel Verkamp 
92bdece622SDaniel Verkamp static void
print_string(const char * arg_string,const char * arg)933e158bd5SKonrad Sztyber print_string(const char *arg_string, const char *arg)
94dd1c38ccSJim Harris {
953e158bd5SKonrad Sztyber 	printf("%-7.7s%-16.16s ", format_argname(arg_string), arg);
96dd1c38ccSJim Harris }
97dd1c38ccSJim Harris 
98dd1c38ccSJim Harris static void
print_size(uint32_t size)99bdece622SDaniel Verkamp print_size(uint32_t size)
100bdece622SDaniel Verkamp {
101bdece622SDaniel Verkamp 	if (size > 0) {
102bdece622SDaniel Verkamp 		printf("size: %6u ", size);
103bdece622SDaniel Verkamp 	} else {
104bdece622SDaniel Verkamp 		printf("%13s", " ");
105bdece622SDaniel Verkamp 	}
106bdece622SDaniel Verkamp }
107bdece622SDaniel Verkamp 
108bdece622SDaniel Verkamp static void
print_object_id(const struct spdk_trace_tpoint * d,struct spdk_trace_parser_entry * entry)10970c17160SKrzysztof Karas print_object_id(const struct spdk_trace_tpoint *d, struct spdk_trace_parser_entry *entry)
110bdece622SDaniel Verkamp {
11170c17160SKrzysztof Karas 	/* Set size to 128 and 256 bytes to make sure we can fit all the characters we need */
11270c17160SKrzysztof Karas 	char related_id[128] = {'\0'};
11370c17160SKrzysztof Karas 	char ids[256] = {'\0'};
11470c17160SKrzysztof Karas 
11570c17160SKrzysztof Karas 	if (entry->related_type != OBJECT_NONE) {
11670c17160SKrzysztof Karas 		snprintf(related_id, sizeof(related_id), " (%c%jd)",
11723dbcec5SJim Harris 			 g_file->object[entry->related_type].id_prefix,
11870c17160SKrzysztof Karas 			 entry->related_index);
11970c17160SKrzysztof Karas 	}
12070c17160SKrzysztof Karas 
12123dbcec5SJim Harris 	snprintf(ids, sizeof(ids), "%c%jd%s", g_file->object[d->object_type].id_prefix,
12270c17160SKrzysztof Karas 		 entry->object_index, related_id);
12370c17160SKrzysztof Karas 	printf("id:    %-17s", ids);
124bdece622SDaniel Verkamp }
125bdece622SDaniel Verkamp 
126bdece622SDaniel Verkamp static void
print_float(const char * arg_string,float arg)127bdece622SDaniel Verkamp print_float(const char *arg_string, float arg)
128bdece622SDaniel Verkamp {
129441431d2SKonrad Sztyber 	printf("%-7s%-16.3f ", format_argname(arg_string), arg);
130bdece622SDaniel Verkamp }
131bdece622SDaniel Verkamp 
1322731216dSKonrad Sztyber static void
print_event(struct spdk_trace_parser_entry * entry,uint64_t tsc_rate,uint64_t tsc_offset)13369390766SKonrad Sztyber print_event(struct spdk_trace_parser_entry *entry, uint64_t tsc_rate, uint64_t tsc_offset)
1342731216dSKonrad Sztyber {
13569390766SKonrad Sztyber 	struct spdk_trace_entry		*e = entry->entry;
136*1128edc1SJim Harris 	struct spdk_trace_owner		*owner;
13769390766SKonrad Sztyber 	const struct spdk_trace_tpoint	*d;
138bdece622SDaniel Verkamp 	float				us;
1392731216dSKonrad Sztyber 	size_t				i;
140bdece622SDaniel Verkamp 
14123dbcec5SJim Harris 	d = &g_file->tpoint[e->tpoint_id];
142bdece622SDaniel Verkamp 	us = get_us_from_tsc(e->tsc - tsc_offset, tsc_rate);
143bdece622SDaniel Verkamp 
14423dbcec5SJim Harris 	printf("%-*s ", (int)sizeof(g_file->tname[entry->lcore]), g_file->tname[entry->lcore]);
14569390766SKonrad Sztyber 	printf("%2d: %10.3f ", entry->lcore, us);
146c199f56dSJim Harris 	if (g_print_tsc) {
147c199f56dSJim Harris 		printf("(%9ju) ", e->tsc - tsc_offset);
148c199f56dSJim Harris 	}
149*1128edc1SJim Harris 	owner = spdk_get_trace_owner(g_file, e->owner_id);
150*1128edc1SJim Harris 	/* For now, only try to print first 64 bytes of description. */
151*1128edc1SJim Harris 	if (e->owner_id > 0 && owner->tsc < e->tsc) {
152*1128edc1SJim Harris 		printf("%-*s ", 64, owner->description);
153bdece622SDaniel Verkamp 	} else {
154*1128edc1SJim Harris 		printf("%-*s ", 64, "");
155bdece622SDaniel Verkamp 	}
156bdece622SDaniel Verkamp 
157bdece622SDaniel Verkamp 	printf("%-*s ", (int)sizeof(d->name), d->name);
158bdece622SDaniel Verkamp 	print_size(e->size);
159bdece622SDaniel Verkamp 
160aa37b4f9SJim Harris 	if (d->new_object) {
16170c17160SKrzysztof Karas 		print_object_id(d, entry);
162bdece622SDaniel Verkamp 	} else if (d->object_type != OBJECT_NONE) {
16369390766SKonrad Sztyber 		if (entry->object_index != UINT64_MAX) {
16469390766SKonrad Sztyber 			us = get_us_from_tsc(e->tsc - entry->object_start, tsc_rate);
16570c17160SKrzysztof Karas 			print_object_id(d, entry);
166441431d2SKonrad Sztyber 			print_float("time", us);
167bdece622SDaniel Verkamp 		} else {
168ec06abe1SJim Harris 			printf("id:    %-17s", "N/A");
169bdece622SDaniel Verkamp 		}
170e8881867SJim Harris 	} else if (e->object_id != 0) {
1712731216dSKonrad Sztyber 		print_ptr("object", e->object_id);
172bdece622SDaniel Verkamp 	}
1737ca41133SKonrad Sztyber 
1742731216dSKonrad Sztyber 	for (i = 0; i < d->num_args; ++i) {
17567eb86e3SJim Harris 		if (entry->args[i].is_related) {
17667eb86e3SJim Harris 			/* This argument was already implicitly shown by its
17767eb86e3SJim Harris 			 * associated related object ID.
17867eb86e3SJim Harris 			 */
17967eb86e3SJim Harris 			continue;
18067eb86e3SJim Harris 		}
18169390766SKonrad Sztyber 		switch (d->args[i].type) {
18269390766SKonrad Sztyber 		case SPDK_TRACE_ARG_TYPE_PTR:
183b4ba6cdfSJim Harris 			print_ptr(d->args[i].name, (uint64_t)entry->args[i].u.pointer);
18469390766SKonrad Sztyber 			break;
18569390766SKonrad Sztyber 		case SPDK_TRACE_ARG_TYPE_INT:
186b4ba6cdfSJim Harris 			print_uint64(d->args[i].name, entry->args[i].u.integer);
18769390766SKonrad Sztyber 			break;
18869390766SKonrad Sztyber 		case SPDK_TRACE_ARG_TYPE_STR:
189b4ba6cdfSJim Harris 			print_string(d->args[i].name, entry->args[i].u.string);
19069390766SKonrad Sztyber 			break;
19169390766SKonrad Sztyber 		}
1927ca41133SKonrad Sztyber 	}
193bdece622SDaniel Verkamp 	printf("\n");
194bdece622SDaniel Verkamp }
195bdece622SDaniel Verkamp 
196bdece622SDaniel Verkamp static void
print_event_json(struct spdk_trace_parser_entry * entry,uint64_t tsc_rate,uint64_t tsc_offset)19769390766SKonrad Sztyber print_event_json(struct spdk_trace_parser_entry *entry, uint64_t tsc_rate, uint64_t tsc_offset)
19899531396SKonrad Sztyber {
19969390766SKonrad Sztyber 	struct spdk_trace_entry *e = entry->entry;
20069390766SKonrad Sztyber 	const struct spdk_trace_tpoint *d;
2012731216dSKonrad Sztyber 	size_t i;
20299531396SKonrad Sztyber 
20323dbcec5SJim Harris 	d = &g_file->tpoint[e->tpoint_id];
20499531396SKonrad Sztyber 
20599531396SKonrad Sztyber 	spdk_json_write_object_begin(g_json);
20669390766SKonrad Sztyber 	spdk_json_write_named_uint64(g_json, "lcore", entry->lcore);
20799531396SKonrad Sztyber 	spdk_json_write_named_uint64(g_json, "tpoint", e->tpoint_id);
20899531396SKonrad Sztyber 	spdk_json_write_named_uint64(g_json, "tsc", e->tsc);
20999531396SKonrad Sztyber 
21026d44a12SJim Harris 	if (g_file->owner_type[d->owner_type].id_prefix) {
21199531396SKonrad Sztyber 		spdk_json_write_named_string_fmt(g_json, "poller", "%c%02d",
21226d44a12SJim Harris 						 g_file->owner_type[d->owner_type].id_prefix,
213a6e5d032SJim Harris 						 e->owner_id);
21499531396SKonrad Sztyber 	}
21599531396SKonrad Sztyber 	if (e->size != 0) {
21699531396SKonrad Sztyber 		spdk_json_write_named_uint32(g_json, "size", e->size);
21799531396SKonrad Sztyber 	}
21899531396SKonrad Sztyber 	if (d->new_object || d->object_type != OBJECT_NONE || e->object_id != 0) {
21999531396SKonrad Sztyber 		char object_type;
22099531396SKonrad Sztyber 
22199531396SKonrad Sztyber 		spdk_json_write_named_object_begin(g_json, "object");
22299531396SKonrad Sztyber 		if (d->new_object) {
22323dbcec5SJim Harris 			object_type =  g_file->object[d->object_type].id_prefix;
224e7da88ddSNick Connolly 			spdk_json_write_named_string_fmt(g_json, "id", "%c%" PRIu64, object_type,
22569390766SKonrad Sztyber 							 entry->object_index);
22699531396SKonrad Sztyber 		} else if (d->object_type != OBJECT_NONE) {
22723dbcec5SJim Harris 			object_type =  g_file->object[d->object_type].id_prefix;
22869390766SKonrad Sztyber 			if (entry->object_index != UINT64_MAX) {
229e7da88ddSNick Connolly 				spdk_json_write_named_string_fmt(g_json, "id", "%c%" PRIu64,
23099531396SKonrad Sztyber 								 object_type,
23169390766SKonrad Sztyber 								 entry->object_index);
23299531396SKonrad Sztyber 				spdk_json_write_named_uint64(g_json, "time",
23369390766SKonrad Sztyber 							     e->tsc - entry->object_start);
23499531396SKonrad Sztyber 			}
23599531396SKonrad Sztyber 		}
23699531396SKonrad Sztyber 		spdk_json_write_named_uint64(g_json, "value", e->object_id);
23799531396SKonrad Sztyber 		spdk_json_write_object_end(g_json);
23899531396SKonrad Sztyber 	}
239ed54725aSKrzysztof Karas 
240ed54725aSKrzysztof Karas 	/* Print related objects array */
241ed54725aSKrzysztof Karas 	if (entry->related_index != UINT64_MAX) {
242ed54725aSKrzysztof Karas 		spdk_json_write_named_string_fmt(g_json, "related", "%c%" PRIu64,
24323dbcec5SJim Harris 						 g_file->object[entry->related_type].id_prefix,
244ed54725aSKrzysztof Karas 						 entry->related_index);
245ed54725aSKrzysztof Karas 	}
246ed54725aSKrzysztof Karas 
24799531396SKonrad Sztyber 	if (d->num_args > 0) {
24899531396SKonrad Sztyber 		spdk_json_write_named_array_begin(g_json, "args");
2492731216dSKonrad Sztyber 		for (i = 0; i < d->num_args; ++i) {
25069390766SKonrad Sztyber 			switch (d->args[i].type) {
25169390766SKonrad Sztyber 			case SPDK_TRACE_ARG_TYPE_PTR:
252b4ba6cdfSJim Harris 				spdk_json_write_uint64(g_json, (uint64_t)entry->args[i].u.pointer);
25369390766SKonrad Sztyber 				break;
25469390766SKonrad Sztyber 			case SPDK_TRACE_ARG_TYPE_INT:
255b4ba6cdfSJim Harris 				spdk_json_write_uint64(g_json, entry->args[i].u.integer);
25669390766SKonrad Sztyber 				break;
25769390766SKonrad Sztyber 			case SPDK_TRACE_ARG_TYPE_STR:
258b4ba6cdfSJim Harris 				spdk_json_write_string(g_json, entry->args[i].u.string);
25969390766SKonrad Sztyber 				break;
26069390766SKonrad Sztyber 			}
26199531396SKonrad Sztyber 		}
26299531396SKonrad Sztyber 		spdk_json_write_array_end(g_json);
26399531396SKonrad Sztyber 	}
26499531396SKonrad Sztyber 
26599531396SKonrad Sztyber 	spdk_json_write_object_end(g_json);
26699531396SKonrad Sztyber }
26799531396SKonrad Sztyber 
26899531396SKonrad Sztyber static void
print_tpoint_definitions(void)26999531396SKonrad Sztyber print_tpoint_definitions(void)
27099531396SKonrad Sztyber {
27169390766SKonrad Sztyber 	const struct spdk_trace_tpoint *tpoint;
27299531396SKonrad Sztyber 	size_t i, j;
27399531396SKonrad Sztyber 
27499531396SKonrad Sztyber 	/* We only care about these when printing JSON */
27599531396SKonrad Sztyber 	if (!g_json) {
27699531396SKonrad Sztyber 		return;
27799531396SKonrad Sztyber 	}
27899531396SKonrad Sztyber 
27923dbcec5SJim Harris 	spdk_json_write_named_uint64(g_json, "tsc_rate", g_file->tsc_rate);
28099531396SKonrad Sztyber 	spdk_json_write_named_array_begin(g_json, "tpoints");
28199531396SKonrad Sztyber 
28223dbcec5SJim Harris 	for (i = 0; i < SPDK_COUNTOF(g_file->tpoint); ++i) {
28323dbcec5SJim Harris 		tpoint = &g_file->tpoint[i];
28499531396SKonrad Sztyber 		if (tpoint->tpoint_id == 0) {
28599531396SKonrad Sztyber 			continue;
28699531396SKonrad Sztyber 		}
28799531396SKonrad Sztyber 
28899531396SKonrad Sztyber 		spdk_json_write_object_begin(g_json);
28999531396SKonrad Sztyber 		spdk_json_write_named_string(g_json, "name", tpoint->name);
29099531396SKonrad Sztyber 		spdk_json_write_named_uint32(g_json, "id", tpoint->tpoint_id);
29199531396SKonrad Sztyber 		spdk_json_write_named_bool(g_json, "new_object", tpoint->new_object);
29299531396SKonrad Sztyber 
29399531396SKonrad Sztyber 		spdk_json_write_named_array_begin(g_json, "args");
29499531396SKonrad Sztyber 		for (j = 0; j < tpoint->num_args; ++j) {
29599531396SKonrad Sztyber 			spdk_json_write_object_begin(g_json);
29699531396SKonrad Sztyber 			spdk_json_write_named_string(g_json, "name", tpoint->args[j].name);
29799531396SKonrad Sztyber 			spdk_json_write_named_uint32(g_json, "type", tpoint->args[j].type);
29899531396SKonrad Sztyber 			spdk_json_write_named_uint32(g_json, "size", tpoint->args[j].size);
29999531396SKonrad Sztyber 			spdk_json_write_object_end(g_json);
30099531396SKonrad Sztyber 		}
30199531396SKonrad Sztyber 		spdk_json_write_array_end(g_json);
30299531396SKonrad Sztyber 		spdk_json_write_object_end(g_json);
30399531396SKonrad Sztyber 	}
30499531396SKonrad Sztyber 
30599531396SKonrad Sztyber 	spdk_json_write_array_end(g_json);
30699531396SKonrad Sztyber }
30799531396SKonrad Sztyber 
30899531396SKonrad Sztyber static int
print_json(void * cb_ctx,const void * data,size_t size)30999531396SKonrad Sztyber print_json(void *cb_ctx, const void *data, size_t size)
31099531396SKonrad Sztyber {
31199531396SKonrad Sztyber 	ssize_t rc;
31299531396SKonrad Sztyber 
31399531396SKonrad Sztyber 	while (size > 0) {
31499531396SKonrad Sztyber 		rc = write(STDOUT_FILENO, data, size);
31599531396SKonrad Sztyber 		if (rc < 0) {
31699531396SKonrad Sztyber 			fprintf(stderr, "%s: %s\n", g_exe_name, spdk_strerror(errno));
31799531396SKonrad Sztyber 			abort();
31899531396SKonrad Sztyber 		}
31999531396SKonrad Sztyber 
32099531396SKonrad Sztyber 		size -= rc;
32199531396SKonrad Sztyber 	}
32299531396SKonrad Sztyber 
32399531396SKonrad Sztyber 	return 0;
32499531396SKonrad Sztyber }
32599531396SKonrad Sztyber 
326a5fcb030SYongjin Lee static int
trace_print(int lcore)327753e344fSMarcin Spiewak trace_print(int lcore)
328a5fcb030SYongjin Lee {
329a5fcb030SYongjin Lee 	struct spdk_trace_parser_entry	entry;
330a5fcb030SYongjin Lee 	int		i;
331a5fcb030SYongjin Lee 	uint64_t	tsc_offset, entry_count;
332a5fcb030SYongjin Lee 	uint64_t	tsc_rate = g_file->tsc_rate;
333a5fcb030SYongjin Lee 
334a5fcb030SYongjin Lee 	printf("TSC Rate: %ju\n", tsc_rate);
335a5fcb030SYongjin Lee 	for (i = 0; i < SPDK_TRACE_MAX_LCORE; ++i) {
336a5fcb030SYongjin Lee 		if (lcore == SPDK_TRACE_MAX_LCORE || i == lcore) {
337a5fcb030SYongjin Lee 			entry_count = spdk_trace_parser_get_entry_count(g_parser, i);
338a5fcb030SYongjin Lee 			if (entry_count > 0) {
339a5fcb030SYongjin Lee 				printf("Trace Size of lcore (%d): %ju\n", i, entry_count);
340a5fcb030SYongjin Lee 			}
341a5fcb030SYongjin Lee 		}
342a5fcb030SYongjin Lee 	}
343a5fcb030SYongjin Lee 
344a5fcb030SYongjin Lee 	tsc_offset = spdk_trace_parser_get_tsc_offset(g_parser);
345a5fcb030SYongjin Lee 	while (spdk_trace_parser_next_entry(g_parser, &entry)) {
346a5fcb030SYongjin Lee 		if (entry.entry->tsc < tsc_offset) {
347a5fcb030SYongjin Lee 			continue;
348a5fcb030SYongjin Lee 		}
349a5fcb030SYongjin Lee 		print_event(&entry, tsc_rate, tsc_offset);
350a5fcb030SYongjin Lee 	}
351a5fcb030SYongjin Lee 
352a5fcb030SYongjin Lee 	return 0;
353a5fcb030SYongjin Lee }
354a5fcb030SYongjin Lee 
355a5fcb030SYongjin Lee static int
trace_print_json(void)356a5fcb030SYongjin Lee trace_print_json(void)
357a5fcb030SYongjin Lee {
358a5fcb030SYongjin Lee 	struct spdk_trace_parser_entry	entry;
359a5fcb030SYongjin Lee 	uint64_t	tsc_offset;
360a5fcb030SYongjin Lee 	uint64_t	tsc_rate = g_file->tsc_rate;
361a5fcb030SYongjin Lee 
362a5fcb030SYongjin Lee 	g_json = spdk_json_write_begin(print_json, NULL, 0);
363a5fcb030SYongjin Lee 	if (g_json == NULL) {
364a5fcb030SYongjin Lee 		fprintf(stderr, "Failed to allocate JSON write context\n");
365a5fcb030SYongjin Lee 		return -1;
366a5fcb030SYongjin Lee 	}
367a5fcb030SYongjin Lee 
368a5fcb030SYongjin Lee 	spdk_json_write_object_begin(g_json);
369a5fcb030SYongjin Lee 	print_tpoint_definitions();
370a5fcb030SYongjin Lee 	spdk_json_write_named_array_begin(g_json, "entries");
371a5fcb030SYongjin Lee 
372a5fcb030SYongjin Lee 	tsc_offset = spdk_trace_parser_get_tsc_offset(g_parser);
373a5fcb030SYongjin Lee 	while (spdk_trace_parser_next_entry(g_parser, &entry)) {
374a5fcb030SYongjin Lee 		if (entry.entry->tsc < tsc_offset) {
375a5fcb030SYongjin Lee 			continue;
376a5fcb030SYongjin Lee 		}
377a5fcb030SYongjin Lee 		print_event_json(&entry, tsc_rate, tsc_offset);
378a5fcb030SYongjin Lee 	}
379a5fcb030SYongjin Lee 
380a5fcb030SYongjin Lee 	spdk_json_write_array_end(g_json);
381a5fcb030SYongjin Lee 	spdk_json_write_object_end(g_json);
382a5fcb030SYongjin Lee 	spdk_json_write_end(g_json);
383a5fcb030SYongjin Lee 
384a5fcb030SYongjin Lee 	return 0;
385a5fcb030SYongjin Lee }
386a5fcb030SYongjin Lee 
3878dd1cd21SBen Walker static void
usage(void)3888dd1cd21SBen Walker usage(void)
389bdece622SDaniel Verkamp {
390bdece622SDaniel Verkamp 	fprintf(stderr, "usage:\n");
391ea0afee0SJim Harris 	fprintf(stderr, "   %s <option> <lcore#>\n", g_exe_name);
392bdece622SDaniel Verkamp 	fprintf(stderr, "                 '-c' to display single lcore history\n");
393c199f56dSJim Harris 	fprintf(stderr, "                 '-t' to display TSC offset for each event\n");
394b7b7c046SJim Harris 	fprintf(stderr, "                 '-s' to specify spdk_trace shm name for a\n");
395b7b7c046SJim Harris 	fprintf(stderr, "                      currently running process\n");
39660fc7458SDaniel Verkamp 	fprintf(stderr, "                 '-i' to specify the shared memory ID\n");
39760fc7458SDaniel Verkamp 	fprintf(stderr, "                 '-p' to specify the trace PID\n");
398b7b7c046SJim Harris 	fprintf(stderr, "                      (If -s is specified, then one of\n");
399b7b7c046SJim Harris 	fprintf(stderr, "                       -i or -p must be specified)\n");
400b7b7c046SJim Harris 	fprintf(stderr, "                 '-f' to specify a tracepoint file name\n");
401b7b7c046SJim Harris 	fprintf(stderr, "                      (-s and -f are mutually exclusive)\n");
402d5901de3SJim Harris #if defined(__linux__)
403d5901de3SJim Harris 	fprintf(stderr, "                 Without -s or -f, %s will look for\n", g_exe_name);
404d5901de3SJim Harris 	fprintf(stderr, "                      newest trace file in /dev/shm\n");
405d5901de3SJim Harris #endif
40699531396SKonrad Sztyber 	fprintf(stderr, "                 '-j' to use JSON to format the output\n");
407bdece622SDaniel Verkamp }
408bdece622SDaniel Verkamp 
409d5901de3SJim Harris #if defined(__linux__)
410d5901de3SJim Harris static time_t g_mtime = 0;
411d5901de3SJim Harris static char g_newest_file[PATH_MAX] = {};
412d5901de3SJim Harris 
413d5901de3SJim Harris static int
get_newest(const char * path,const struct stat * sb,int tflag,struct FTW * ftw)414d5901de3SJim Harris get_newest(const char *path, const struct stat *sb, int tflag, struct FTW *ftw)
415d5901de3SJim Harris {
416d5901de3SJim Harris 	if (tflag == FTW_F && sb->st_mtime > g_mtime &&
417d5901de3SJim Harris 	    strstr(path, SPDK_TRACE_SHM_NAME_BASE) != NULL) {
418d5901de3SJim Harris 		g_mtime = sb->st_mtime;
419d5901de3SJim Harris 		strncpy(g_newest_file, path, PATH_MAX - 1);
420d5901de3SJim Harris 	}
421d5901de3SJim Harris 	return 0;
422d5901de3SJim Harris }
423d5901de3SJim Harris #endif
424d5901de3SJim Harris 
4258dd1cd21SBen Walker int
main(int argc,char ** argv)4268dd1cd21SBen Walker main(int argc, char **argv)
427bdece622SDaniel Verkamp {
42869390766SKonrad Sztyber 	struct spdk_trace_parser_opts	opts;
429a5fcb030SYongjin Lee 	enum print_format_type	print_format = PRINT_FMT_DEFAULT;
430c943e9ffSDaniel Verkamp 	int				lcore = SPDK_TRACE_MAX_LCORE;
431b7b7c046SJim Harris 	const char			*app_name = NULL;
432b7b7c046SJim Harris 	const char			*file_name = NULL;
433a5fcb030SYongjin Lee 	int				op;
434a5fcb030SYongjin Lee 	int				rc = 0;
435bdece622SDaniel Verkamp 	char				shm_name[64];
43660fc7458SDaniel Verkamp 	int				shm_id = -1, shm_pid = -1;
437bdece622SDaniel Verkamp 
438ea0afee0SJim Harris 	g_exe_name = argv[0];
43999531396SKonrad Sztyber 	while ((op = getopt(argc, argv, "c:f:i:jp:s:t")) != -1) {
440bdece622SDaniel Verkamp 		switch (op) {
441bdece622SDaniel Verkamp 		case 'c':
442bdece622SDaniel Verkamp 			lcore = atoi(optarg);
443c943e9ffSDaniel Verkamp 			if (lcore > SPDK_TRACE_MAX_LCORE) {
444bdece622SDaniel Verkamp 				fprintf(stderr, "Selected lcore: %d "
445bdece622SDaniel Verkamp 					"exceeds maximum %d\n", lcore,
446c943e9ffSDaniel Verkamp 					SPDK_TRACE_MAX_LCORE);
447bdece622SDaniel Verkamp 				exit(1);
448bdece622SDaniel Verkamp 			}
449bdece622SDaniel Verkamp 			break;
450bdece622SDaniel Verkamp 		case 'i':
45160fc7458SDaniel Verkamp 			shm_id = atoi(optarg);
45260fc7458SDaniel Verkamp 			break;
45360fc7458SDaniel Verkamp 		case 'p':
45460fc7458SDaniel Verkamp 			shm_pid = atoi(optarg);
455bdece622SDaniel Verkamp 			break;
456bdece622SDaniel Verkamp 		case 's':
457bdece622SDaniel Verkamp 			app_name = optarg;
458bdece622SDaniel Verkamp 			break;
459b7b7c046SJim Harris 		case 'f':
460b7b7c046SJim Harris 			file_name = optarg;
461b7b7c046SJim Harris 			break;
462c199f56dSJim Harris 		case 't':
463c199f56dSJim Harris 			g_print_tsc = true;
464c199f56dSJim Harris 			break;
46599531396SKonrad Sztyber 		case 'j':
466a5fcb030SYongjin Lee 			print_format = PRINT_FMT_JSON;
46799531396SKonrad Sztyber 			break;
468bdece622SDaniel Verkamp 		default:
469bdece622SDaniel Verkamp 			usage();
470bdece622SDaniel Verkamp 			exit(1);
471bdece622SDaniel Verkamp 		}
472bdece622SDaniel Verkamp 	}
473bdece622SDaniel Verkamp 
474b7b7c046SJim Harris 	if (file_name != NULL && app_name != NULL) {
475b7b7c046SJim Harris 		fprintf(stderr, "-f and -s are mutually exclusive\n");
476b7b7c046SJim Harris 		usage();
477b7b7c046SJim Harris 		exit(1);
478b7b7c046SJim Harris 	}
479b7b7c046SJim Harris 
480b7b7c046SJim Harris 	if (file_name == NULL && app_name == NULL) {
481d5901de3SJim Harris #if defined(__linux__)
482d5901de3SJim Harris 		nftw("/dev/shm", get_newest, 1, 0);
483d5901de3SJim Harris 		if (strlen(g_newest_file) > 0) {
484d5901de3SJim Harris 			file_name = g_newest_file;
485d5901de3SJim Harris 			printf("Using newest trace file found: %s\n", file_name);
486d5901de3SJim Harris 		} else {
487d5901de3SJim Harris 			fprintf(stderr, "No shm file found and -f not specified\n");
488d5901de3SJim Harris 			usage();
489d5901de3SJim Harris 			exit(1);
490d5901de3SJim Harris 		}
491d5901de3SJim Harris #else
492b7b7c046SJim Harris 		fprintf(stderr, "One of -f and -s must be specified\n");
493b7b7c046SJim Harris 		usage();
494b7b7c046SJim Harris 		exit(1);
495d5901de3SJim Harris #endif
496b7b7c046SJim Harris 	}
497b7b7c046SJim Harris 
49869390766SKonrad Sztyber 	if (!file_name) {
49960fc7458SDaniel Verkamp 		if (shm_id >= 0) {
50060fc7458SDaniel Verkamp 			snprintf(shm_name, sizeof(shm_name), "/%s_trace.%d", app_name, shm_id);
50160fc7458SDaniel Verkamp 		} else {
50260fc7458SDaniel Verkamp 			snprintf(shm_name, sizeof(shm_name), "/%s_trace.pid%d", app_name, shm_pid);
50360fc7458SDaniel Verkamp 		}
50420476c65SJim Harris 		file_name = shm_name;
505b7b7c046SJim Harris 	}
50669390766SKonrad Sztyber 
50769390766SKonrad Sztyber 	opts.filename = file_name;
50869390766SKonrad Sztyber 	opts.lcore = lcore;
50969390766SKonrad Sztyber 	opts.mode = app_name == NULL ? SPDK_TRACE_PARSER_MODE_FILE : SPDK_TRACE_PARSER_MODE_SHM;
51069390766SKonrad Sztyber 	g_parser = spdk_trace_parser_init(&opts);
51169390766SKonrad Sztyber 	if (g_parser == NULL) {
51269390766SKonrad Sztyber 		fprintf(stderr, "Failed to initialize trace parser\n");
51369390766SKonrad Sztyber 		exit(1);
514bdece622SDaniel Verkamp 	}
51521ceba88SJim Harris 
51623dbcec5SJim Harris 	g_file = spdk_trace_parser_get_file(g_parser);
517a5fcb030SYongjin Lee 	switch (print_format) {
518a5fcb030SYongjin Lee 	case PRINT_FMT_JSON:
519a5fcb030SYongjin Lee 		rc = trace_print_json();
520a5fcb030SYongjin Lee 		break;
521a5fcb030SYongjin Lee 	case PRINT_FMT_DEFAULT:
522a5fcb030SYongjin Lee 	default:
523753e344fSMarcin Spiewak 		rc = trace_print(lcore);
524a5fcb030SYongjin Lee 		break;
52599531396SKonrad Sztyber 	}
52699531396SKonrad Sztyber 
52769390766SKonrad Sztyber 	spdk_trace_parser_cleanup(g_parser);
528bdece622SDaniel Verkamp 
529a5fcb030SYongjin Lee 	return rc;
530bdece622SDaniel Verkamp }
531