lib/trace: chain entries to extend their buffer size
This patch adds the ability to chain multiple trace entries together to extend the size of the argument buffer. This means that a tracepoint is no longer limited to the size of a single entry, so it can have any number of arguments, and their size is also not constrained to a single entry. Some limitations are still there: a tracepoint can have up to 5 arguments and strings are limited to 255 bytes. These constraints stem from the definitions of tracepoint structures, which could be easily modified to extend the limits if needed. To record a tracepoint requiring larger buffer, aside from reserving `spdk_trace_entry` structure, a series of `spdk_trace_entry_buffer` structures are allocated too. Each of them acts as a buffer for the arguments. To allow trace tools to treat the buffer structures similarly to regular entries, they also have the `tpoint_id` and `tsc` fields. The id is always assigned to `SPDK_TRACE_MAX_TPOINT_ID` to make sure that a buffer is never mistaken for an entry, while the value of `tsc` is always shared with the initial entry. This also provides a way for the trace tools to verify if an entry is part of a chained buffer. Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Change-Id: I51ceea6b6e57df95d4b8bd797f04edbc4936c180 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8405 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ziye Yang <ziye.yang@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
parent
0cf270910a
commit
6cc3169677
@ -40,6 +40,7 @@
|
||||
#define _SPDK_TRACE_H_
|
||||
|
||||
#include "spdk/stdinc.h"
|
||||
#include "spdk/assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -56,6 +57,15 @@ struct spdk_trace_entry {
|
||||
uint8_t args[40];
|
||||
};
|
||||
|
||||
struct spdk_trace_entry_buffer {
|
||||
uint64_t tsc;
|
||||
uint16_t tpoint_id;
|
||||
uint8_t data[54];
|
||||
};
|
||||
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_trace_entry_buffer) == sizeof(struct spdk_trace_entry),
|
||||
"Invalid size of trace entry buffer");
|
||||
|
||||
/* If type changes from a uint8_t, change this value. */
|
||||
#define SPDK_TRACE_MAX_OWNER (UCHAR_MAX + 1)
|
||||
|
||||
|
@ -57,11 +57,12 @@ _spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, uint32_
|
||||
{
|
||||
struct spdk_trace_history *lcore_history;
|
||||
struct spdk_trace_entry *next_entry;
|
||||
struct spdk_trace_entry_buffer *buffer;
|
||||
struct spdk_trace_tpoint *tpoint;
|
||||
struct spdk_trace_argument *argument;
|
||||
const char *strval;
|
||||
unsigned lcore, i, offset;
|
||||
unsigned lcore, i, offset, num_entries, arglen, argoff, curlen;
|
||||
uint64_t intval;
|
||||
void *argval;
|
||||
va_list vl;
|
||||
|
||||
lcore = spdk_env_get_current_core();
|
||||
@ -91,31 +92,74 @@ _spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, uint32_
|
||||
next_entry->size = size;
|
||||
next_entry->object_id = object_id;
|
||||
|
||||
num_entries = 1;
|
||||
buffer = (struct spdk_trace_entry_buffer *)next_entry;
|
||||
/* The initial offset needs to be adjusted by the fields present in the first entry
|
||||
* (poller_id, size, etc.).
|
||||
*/
|
||||
offset = offsetof(struct spdk_trace_entry, args) -
|
||||
offsetof(struct spdk_trace_entry_buffer, data);
|
||||
|
||||
va_start(vl, num_args);
|
||||
for (i = 0, offset = 0; i < tpoint->num_args; ++i) {
|
||||
for (i = 0; i < tpoint->num_args; ++i) {
|
||||
argument = &tpoint->args[i];
|
||||
switch (argument->type) {
|
||||
case SPDK_TRACE_ARG_TYPE_STR:
|
||||
strval = va_arg(vl, const char *);
|
||||
snprintf(&next_entry->args[offset], argument->size, "%s", strval);
|
||||
argval = va_arg(vl, void *);
|
||||
arglen = strnlen((const char *)argval, argument->size - 1) + 1;
|
||||
break;
|
||||
case SPDK_TRACE_ARG_TYPE_INT:
|
||||
case SPDK_TRACE_ARG_TYPE_PTR:
|
||||
intval = va_arg(vl, uint64_t);
|
||||
memcpy(&next_entry->args[offset], &intval, sizeof(intval));
|
||||
argval = &intval;
|
||||
arglen = sizeof(uint64_t);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Invalid trace argument type");
|
||||
break;
|
||||
}
|
||||
|
||||
offset += argument->size;
|
||||
/* Copy argument's data. For some argument types (strings) user is allowed to pass a
|
||||
* value that is either larger or smaller than what's defined in the tracepoint's
|
||||
* description. If the value is larger, we'll truncate it, while if it's smaller,
|
||||
* we'll only fill portion of the buffer, without touching the rest. For instance,
|
||||
* if the definition marks an argument as 40B and user passes 12B string, we'll only
|
||||
* copy 13B (accounting for the NULL terminator).
|
||||
*/
|
||||
argoff = 0;
|
||||
while (argoff < argument->size) {
|
||||
/* Current buffer is full, we need to acquire another one */
|
||||
if (offset == sizeof(buffer->data)) {
|
||||
buffer = (struct spdk_trace_entry_buffer *) get_trace_entry(
|
||||
lcore_history,
|
||||
lcore_history->next_entry + num_entries);
|
||||
buffer->tpoint_id = SPDK_TRACE_MAX_TPOINT_ID;
|
||||
buffer->tsc = tsc;
|
||||
num_entries++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
curlen = spdk_min(sizeof(buffer->data) - offset, argument->size - argoff);
|
||||
if (argoff < arglen) {
|
||||
memcpy(&buffer->data[offset], (uint8_t *)argval + argoff,
|
||||
spdk_min(curlen, arglen - argoff));
|
||||
}
|
||||
|
||||
offset += curlen;
|
||||
argoff += curlen;
|
||||
}
|
||||
|
||||
/* Make sure that truncated strings are NULL-terminated */
|
||||
if (argument->type == SPDK_TRACE_ARG_TYPE_STR) {
|
||||
assert(offset > 0);
|
||||
buffer->data[offset - 1] = '\0';
|
||||
}
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
/* Ensure all elements of the trace entry are visible to outside trace tools */
|
||||
spdk_smp_wmb();
|
||||
lcore_history->next_entry++;
|
||||
lcore_history->next_entry += num_entries;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -281,7 +281,7 @@ static void
|
||||
trace_register_description(const struct spdk_trace_tpoint_opts *opts)
|
||||
{
|
||||
struct spdk_trace_tpoint *tpoint;
|
||||
size_t i, remaining_size, max_name_length;
|
||||
size_t i, max_name_length;
|
||||
|
||||
assert(opts->tpoint_id != 0);
|
||||
assert(opts->tpoint_id < SPDK_TRACE_MAX_TPOINT_ID);
|
||||
@ -300,8 +300,6 @@ trace_register_description(const struct spdk_trace_tpoint_opts *opts)
|
||||
tpoint->new_object = opts->new_object;
|
||||
|
||||
max_name_length = sizeof(tpoint->args[0].name);
|
||||
remaining_size = sizeof(((struct spdk_trace_entry *)0)->args);
|
||||
|
||||
for (i = 0; i < SPDK_TRACE_MAX_ARGS_COUNT; ++i) {
|
||||
if (!opts->args[i].name || opts->args[i].name[0] == '\0') {
|
||||
break;
|
||||
@ -322,9 +320,6 @@ trace_register_description(const struct spdk_trace_tpoint_opts *opts)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(remaining_size >= opts->args[i].size && "tpoint exceeds max size");
|
||||
remaining_size -= opts->args[i].size;
|
||||
|
||||
if (strnlen(opts->args[i].name, max_name_length) == max_name_length) {
|
||||
SPDK_ERRLOG("argument name (%s) is too long\n", opts->args[i].name);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user