Spdk/lib/trace/trace.c
Jim Harris 488570ebd4 Replace most BSD 3-clause license text with SPDX identifier.
Many open source projects have moved to using SPDX identifiers
to specify license information, reducing the amount of
boilerplate code in every source file.  This patch replaces
the bulk of SPDK .c, .cpp and Makefiles with the BSD-3-Clause
identifier.

Almost all of these files share the exact same license text,
and this patch only modifies the files that contain the
most common license text.  There can be slight variations
because the third clause contains company names - most say
"Intel Corporation", but there are instances for Nvidia,
Samsung, Eideticom and even "the copyright holder".

Used a bash script to automate replacement of the license text
with SPDX identifier which is checked into scripts/spdx.sh.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: Iaa88ab5e92ea471691dc298cfe41ebfb5d169780
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12904
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Dong Yi <dongx.yi@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: <qun.wan@intel.com>
2022-06-09 07:35:12 +00:00

256 lines
7.1 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "spdk/stdinc.h"
#include "spdk/env.h"
#include "spdk/string.h"
#include "spdk/trace.h"
#include "spdk/util.h"
#include "spdk/barrier.h"
#include "spdk/log.h"
static int g_trace_fd = -1;
static char g_shm_name[64];
struct spdk_trace_histories *g_trace_histories;
static inline struct spdk_trace_entry *
get_trace_entry(struct spdk_trace_history *history, uint64_t offset)
{
return &history->entries[offset & (history->num_entries - 1)];
}
void
_spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, uint32_t size,
uint64_t object_id, int num_args, ...)
{
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;
unsigned lcore, i, offset, num_entries, arglen, argoff, curlen;
uint64_t intval;
void *argval;
va_list vl;
lcore = spdk_env_get_current_core();
if (lcore >= SPDK_TRACE_MAX_LCORE) {
return;
}
lcore_history = spdk_get_per_lcore_history(g_trace_histories, lcore);
if (tsc == 0) {
tsc = spdk_get_ticks();
}
lcore_history->tpoint_count[tpoint_id]++;
tpoint = &g_trace_flags->tpoint[tpoint_id];
/* Make sure that the number of arguments passed matches tracepoint definition */
if (tpoint->num_args != num_args) {
assert(0 && "Unexpected number of tracepoint arguments");
return;
}
/* Get next entry index in the circular buffer */
next_entry = get_trace_entry(lcore_history, lcore_history->next_entry);
next_entry->tsc = tsc;
next_entry->tpoint_id = tpoint_id;
next_entry->poller_id = poller_id;
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; i < tpoint->num_args; ++i) {
argument = &tpoint->args[i];
switch (argument->type) {
case SPDK_TRACE_ARG_TYPE_STR:
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);
argval = &intval;
arglen = sizeof(uint64_t);
break;
default:
assert(0 && "Invalid trace argument type");
return;
}
/* 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) {
assert(argval != NULL);
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 += num_entries;
}
int
spdk_trace_init(const char *shm_name, uint64_t num_entries)
{
int i = 0;
int histories_size;
uint64_t lcore_offsets[SPDK_TRACE_MAX_LCORE + 1];
/* 0 entries requested - skip trace initialization */
if (num_entries == 0) {
return 0;
}
lcore_offsets[0] = sizeof(struct spdk_trace_flags);
for (i = 1; i < (int)SPDK_COUNTOF(lcore_offsets); i++) {
lcore_offsets[i] = spdk_get_trace_history_size(num_entries) + lcore_offsets[i - 1];
}
histories_size = lcore_offsets[SPDK_TRACE_MAX_LCORE];
snprintf(g_shm_name, sizeof(g_shm_name), "%s", shm_name);
g_trace_fd = shm_open(shm_name, O_RDWR | O_CREAT, 0600);
if (g_trace_fd == -1) {
SPDK_ERRLOG("could not shm_open spdk_trace\n");
SPDK_ERRLOG("errno=%d %s\n", errno, spdk_strerror(errno));
return 1;
}
if (ftruncate(g_trace_fd, histories_size) != 0) {
SPDK_ERRLOG("could not truncate shm\n");
goto trace_init_err;
}
g_trace_histories = mmap(NULL, histories_size, PROT_READ | PROT_WRITE,
MAP_SHARED, g_trace_fd, 0);
if (g_trace_histories == MAP_FAILED) {
SPDK_ERRLOG("could not mmap shm\n");
goto trace_init_err;
}
/* TODO: On FreeBSD, mlock on shm_open'd memory doesn't seem to work. Docs say that kern.ipc.shm_use_phys=1
* should allow it, but forcing that doesn't seem to work either. So for now just skip mlock on FreeBSD
* altogether.
*/
#if defined(__linux__)
if (mlock(g_trace_histories, histories_size) != 0) {
SPDK_ERRLOG("Could not mlock shm for tracing - %s.\n", spdk_strerror(errno));
if (errno == ENOMEM) {
SPDK_ERRLOG("Check /dev/shm for old tracing files that can be deleted.\n");
}
goto trace_init_err;
}
#endif
memset(g_trace_histories, 0, histories_size);
g_trace_flags = &g_trace_histories->flags;
g_trace_flags->tsc_rate = spdk_get_ticks_hz();
for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
struct spdk_trace_history *lcore_history;
g_trace_flags->lcore_history_offsets[i] = lcore_offsets[i];
lcore_history = spdk_get_per_lcore_history(g_trace_histories, i);
lcore_history->lcore = i;
lcore_history->num_entries = num_entries;
}
g_trace_flags->lcore_history_offsets[SPDK_TRACE_MAX_LCORE] = lcore_offsets[SPDK_TRACE_MAX_LCORE];
spdk_trace_flags_init();
return 0;
trace_init_err:
if (g_trace_histories != MAP_FAILED) {
munmap(g_trace_histories, histories_size);
}
close(g_trace_fd);
g_trace_fd = -1;
shm_unlink(shm_name);
g_trace_histories = NULL;
return 1;
}
void
spdk_trace_cleanup(void)
{
bool unlink;
int i;
struct spdk_trace_history *lcore_history;
if (g_trace_histories == NULL) {
return;
}
/*
* Only unlink the shm if there were no trace_entry recorded. This ensures the file
* can be used after this process exits/crashes for debugging.
* Note that we have to calculate this value before g_trace_histories gets unmapped.
*/
for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
lcore_history = spdk_get_per_lcore_history(g_trace_histories, i);
unlink = lcore_history->entries[0].tsc == 0;
if (!unlink) {
break;
}
}
munmap(g_trace_histories, sizeof(struct spdk_trace_histories));
g_trace_histories = NULL;
close(g_trace_fd);
if (unlink) {
shm_unlink(g_shm_name);
}
}