diff --git a/app/trace/trace.cpp b/app/trace/trace.cpp index 0fa2f7128..7432d0932 100644 --- a/app/trace/trace.cpp +++ b/app/trace/trace.cpp @@ -123,9 +123,21 @@ print_size(uint32_t size) } static void -print_object_id(uint8_t type, uint64_t id) +print_object_id(const struct spdk_trace_tpoint *d, struct spdk_trace_parser_entry *entry) { - printf("id: %c%-15jd ", g_flags->object[type].id_prefix, id); + /* Set size to 128 and 256 bytes to make sure we can fit all the characters we need */ + char related_id[128] = {'\0'}; + char ids[256] = {'\0'}; + + if (entry->related_type != OBJECT_NONE) { + snprintf(related_id, sizeof(related_id), " (%c%jd)", + g_flags->object[entry->related_type].id_prefix, + entry->related_index); + } + + snprintf(ids, sizeof(ids), "%c%jd%s", g_flags->object[d->object_type].id_prefix, + entry->object_index, related_id); + printf("id: %-17s", ids); } static void @@ -159,11 +171,11 @@ print_event(struct spdk_trace_parser_entry *entry, uint64_t tsc_rate, uint64_t t print_size(e->size); if (d->new_object) { - print_object_id(d->object_type, entry->object_index); + print_object_id(d, entry); } else if (d->object_type != OBJECT_NONE) { if (entry->object_index != UINT64_MAX) { us = get_us_from_tsc(e->tsc - entry->object_start, tsc_rate); - print_object_id(d->object_type, entry->object_index); + print_object_id(d, entry); print_float("time", us); } else { printf("id: N/A"); diff --git a/include/spdk/trace.h b/include/spdk/trace.h index e8e28227d..13fae6797 100644 --- a/include/spdk/trace.h +++ b/include/spdk/trace.h @@ -91,6 +91,7 @@ struct spdk_trace_object { #define SPDK_TRACE_ARG_TYPE_STR 2 #define SPDK_TRACE_MAX_ARGS_COUNT 5 +#define SPDK_TRACE_MAX_RELATIONS 16 struct spdk_trace_argument { char name[14]; @@ -106,6 +107,11 @@ struct spdk_trace_tpoint { uint8_t new_object; uint8_t num_args; struct spdk_trace_argument args[SPDK_TRACE_MAX_ARGS_COUNT]; + /** Relations between tracepoint and trace object */ + struct { + uint8_t object_type; + uint8_t arg_index; + } related_objects[SPDK_TRACE_MAX_RELATIONS]; }; struct spdk_trace_history { @@ -375,6 +381,17 @@ struct spdk_trace_register_fn *spdk_trace_get_first_register_fn(void); struct spdk_trace_register_fn *spdk_trace_get_next_register_fn(struct spdk_trace_register_fn *register_fn); +/** + * Bind trace type to a given trace object. This allows for matching traces + * with the same parent trace object. + * + * \param tpoint_id Type of trace to be bound + * \param object_type Tracepoint object type to bind to + * \param arg_index Index of argument containing context information + */ +void spdk_trace_tpoint_register_relation(uint16_t tpoint_id, uint8_t object_type, + uint8_t arg_index); + /** * Enable trace on specific tpoint group * diff --git a/include/spdk/trace_parser.h b/include/spdk/trace_parser.h index 5cf371294..7f7df4f21 100644 --- a/include/spdk/trace_parser.h +++ b/include/spdk/trace_parser.h @@ -115,6 +115,10 @@ struct spdk_trace_parser_entry { uint64_t object_start; /** Logical core number */ uint16_t lcore; + /** Related object index */ + uint64_t related_index; + /** Related object type */ + uint8_t related_type; /** Tracepoint arguments */ union { uint64_t integer; diff --git a/lib/trace/Makefile b/lib/trace/Makefile index 75c4f3460..ed26013dd 100644 --- a/lib/trace/Makefile +++ b/lib/trace/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -SO_VER := 4 +SO_VER := 5 SO_MINOR := 0 C_SRCS = trace.c trace_flags.c trace_rpc.c diff --git a/lib/trace/spdk_trace.map b/lib/trace/spdk_trace.map index 303863f71..1e74c0fa5 100644 --- a/lib/trace/spdk_trace.map +++ b/lib/trace/spdk_trace.map @@ -22,6 +22,7 @@ spdk_trace_disable_tpoint_group; spdk_trace_mask_usage; spdk_trace_add_register_fn; + spdk_trace_tpoint_register_relation; # public variables g_trace_histories; diff --git a/lib/trace/trace_flags.c b/lib/trace/trace_flags.c index 3c11739d7..c2701c6d6 100644 --- a/lib/trace/trace_flags.c +++ b/lib/trace/trace_flags.c @@ -36,6 +36,7 @@ #include "spdk/env.h" #include "spdk/trace.h" #include "spdk/log.h" +#include "spdk/util.h" struct spdk_trace_flags *g_trace_flags = NULL; static struct spdk_trace_register_fn *g_reg_fn_head = NULL; @@ -370,6 +371,36 @@ spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t ow spdk_trace_register_description_ext(&opts, 1); } +void +spdk_trace_tpoint_register_relation(uint16_t tpoint_id, uint8_t object_type, uint8_t arg_index) +{ + struct spdk_trace_tpoint *tpoint; + uint16_t i; + + assert(object_type != OBJECT_NONE); + assert(tpoint_id != OBJECT_NONE); + + if (g_trace_flags == NULL) { + SPDK_ERRLOG("trace is not initialized\n"); + return; + } + + /* We do not check whether a tpoint_id exists here, because + * there is no order in which trace definitions are registered. + * This way we can create relations between tpoint and objects + * that will be declared later. */ + tpoint = &g_trace_flags->tpoint[tpoint_id]; + for (i = 0; i < SPDK_COUNTOF(tpoint->related_objects); ++i) { + if (tpoint->related_objects[i].object_type == OBJECT_NONE) { + tpoint->related_objects[i].object_type = object_type; + tpoint->related_objects[i].arg_index = arg_index; + return; + } + } + SPDK_ERRLOG("Unable to register new relation for tpoint %" PRIu16 ", object %" PRIu8 "\n", + tpoint_id, object_type); +} + void spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) { diff --git a/lib/trace_parser/trace.cpp b/lib/trace_parser/trace.cpp index 18abdab30..9238a9f34 100644 --- a/lib/trace_parser/trace.cpp +++ b/lib/trace_parser/trace.cpp @@ -186,6 +186,7 @@ spdk_trace_parser::next_entry(spdk_trace_parser_entry *pe) spdk_trace_tpoint *tpoint; spdk_trace_entry *entry; object_stats *stats; + std::map::iterator related_kv; if (_iter == _entries.end()) { return false; @@ -193,6 +194,9 @@ spdk_trace_parser::next_entry(spdk_trace_parser_entry *pe) pe->entry = entry = _iter->second; pe->lcore = _iter->first.lcore; + /* Set related index to the max value to indicate "empty" state */ + pe->related_index = UINT64_MAX; + pe->related_type = OBJECT_NONE; tpoint = &_histories->flags.tpoint[entry->tpoint_id]; stats = &_stats[tpoint->object_type]; @@ -219,6 +223,24 @@ spdk_trace_parser::next_entry(spdk_trace_parser_entry *pe) } } + for (uint8_t i = 0; i < SPDK_TRACE_MAX_RELATIONS; ++i) { + /* The relations are stored inside a tpoint, which means there might be + * multiple objects bound to a single tpoint. */ + if (tpoint->related_objects[i].object_type == OBJECT_NONE) { + break; + } + stats = &_stats[tpoint->related_objects[i].object_type]; + related_kv = stats->index.find(reinterpret_cast + (pe->args[tpoint->related_objects[i].arg_index].pointer)); + /* To avoid parsing the whole array, object index and type are stored + * directly inside spdk_trace_parser_entry. */ + if (related_kv != stats->index.end()) { + pe->related_index = related_kv->second; + pe->related_type = tpoint->related_objects[i].object_type; + break; + } + } + _iter++; return true; } diff --git a/scripts/bpf/trace.py b/scripts/bpf/trace.py index cfcc302ab..13809e84f 100755 --- a/scripts/bpf/trace.py +++ b/scripts/bpf/trace.py @@ -19,6 +19,7 @@ TRACE_MAX_LCORE = 128 TRACE_MAX_GROUP_ID = 16 TRACE_MAX_TPOINT_ID = TRACE_MAX_GROUP_ID * 64 TRACE_MAX_ARGS_COUNT = 5 +TRACE_MAX_RELATIONS = 16 TRACE_INVALID_OBJECT = (1 << 64) - 1 OBJECT_NONE = 0 OWNER_NONE = 0 @@ -278,6 +279,11 @@ class CTpointArgument(ct.Structure): ('size', ct.c_uint8)] +class CTpointRelatedObject(ct.Structure): + _fields_ = [('object_type', ct.c_uint8), + ('arg_index', ct.c_uint8)] + + class CTracepoint(ct.Structure): _fields_ = [('name', ct.c_char * 24), ('tpoint_id', ct.c_uint16), @@ -285,7 +291,8 @@ class CTracepoint(ct.Structure): ('object_type', ct.c_uint8), ('new_object', ct.c_uint8), ('num_args', ct.c_uint8), - ('args', CTpointArgument * TRACE_MAX_ARGS_COUNT)] + ('args', CTpointArgument * TRACE_MAX_ARGS_COUNT), + ('related_objects', CTpointRelatedObject * TRACE_MAX_RELATIONS)] class CTraceFlags(ct.Structure): @@ -315,6 +322,8 @@ class CTraceParserEntry(ct.Structure): ('object_index', ct.c_uint64), ('object_start', ct.c_uint64), ('lcore', ct.c_uint16), + ('related_index', ct.c_uint64), + ('related_type', ct.c_uint8), ('args', CTraceParserArgument * TRACE_MAX_ARGS_COUNT)]