Commit 6cc31696 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

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: default avatarKonrad 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: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarZiye Yang <ziye.yang@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
parent 0cf27091
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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)

+52 −8
Original line number Diff line number Diff line
@@ -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
+1 −6
Original line number Diff line number Diff line
@@ -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);
		}