trace: implement memory allocation

Trace memory will be allocated per thread to enable lockless trace
events updates to the memory. The allocator will first attempt to
allocate from hugepage, then if not available from hugepage or
finally fallback to malloc memory.

Later in the patches series, this API will be hooked to DPDK fast path
and control plane thread creation API. It is possible for non
DPDK thread to use trace events. In that case, trace memory
will be allocated on the first event emission.

Signed-off-by: Jerin Jacob <jerinj@marvell.com>
Acked-by: David Marchand <david.marchand@redhat.com>
This commit is contained in:
Jerin Jacob 2020-04-23 00:33:26 +05:30 committed by David Marchand
parent ffed0853e6
commit 29d985cad8
6 changed files with 173 additions and 0 deletions

View File

@ -16,6 +16,7 @@
#include "eal_trace.h"
RTE_DEFINE_PER_LCORE(volatile int, trace_point_sz);
RTE_DEFINE_PER_LCORE(void *, trace_mem);
static RTE_DEFINE_PER_LCORE(char, ctf_field[TRACE_CTF_FIELD_SIZE]);
static RTE_DEFINE_PER_LCORE(int, ctf_count);
@ -37,6 +38,9 @@ trace_list_head_get(void)
int
eal_trace_init(void)
{
/* Trace memory should start with 8B aligned for natural alignment */
RTE_BUILD_BUG_ON((offsetof(struct __rte_trace_header, mem) % 8) != 0);
/* One of the trace point registration failed */
if (trace.register_errno) {
rte_errno = trace.register_errno;
@ -85,6 +89,7 @@ eal_trace_fini(void)
{
if (!rte_trace_is_enabled())
return;
trace_mem_per_thread_free();
trace_metadata_destroy();
}
@ -227,6 +232,95 @@ rte_trace_point_lookup(const char *name)
return NULL;
}
void
__rte_trace_mem_per_thread_alloc(void)
{
struct trace *trace = trace_obj_get();
struct __rte_trace_header *header;
uint32_t count;
if (!rte_trace_is_enabled())
return;
if (RTE_PER_LCORE(trace_mem))
return;
rte_spinlock_lock(&trace->lock);
count = trace->nb_trace_mem_list;
/* Allocate room for storing the thread trace mem meta */
trace->lcore_meta = realloc(trace->lcore_meta,
sizeof(trace->lcore_meta[0]) * (count + 1));
/* Provide dummy space for fast path to consume */
if (trace->lcore_meta == NULL) {
trace_crit("trace mem meta memory realloc failed");
header = NULL;
goto fail;
}
/* First attempt from huge page */
header = rte_malloc(NULL, trace_mem_sz(trace->buff_len), 8);
if (header) {
trace->lcore_meta[count].area = TRACE_AREA_HUGEPAGE;
goto found;
}
/* Second attempt from heap */
header = malloc(trace_mem_sz(trace->buff_len));
if (header == NULL) {
trace_crit("trace mem malloc attempt failed");
header = NULL;
goto fail;
}
/* Second attempt from heap is success */
trace->lcore_meta[count].area = TRACE_AREA_HEAP;
/* Initialize the trace header */
found:
header->offset = 0;
header->len = trace->buff_len;
header->stream_header.magic = TRACE_CTF_MAGIC;
rte_uuid_copy(header->stream_header.uuid, trace->uuid);
header->stream_header.lcore_id = rte_lcore_id();
/* Store the thread name */
char *name = header->stream_header.thread_name;
memset(name, 0, __RTE_TRACE_EMIT_STRING_LEN_MAX);
rte_thread_getname(pthread_self(), name,
__RTE_TRACE_EMIT_STRING_LEN_MAX);
trace->lcore_meta[count].mem = header;
trace->nb_trace_mem_list++;
fail:
RTE_PER_LCORE(trace_mem) = header;
rte_spinlock_unlock(&trace->lock);
}
void
trace_mem_per_thread_free(void)
{
struct trace *trace = trace_obj_get();
uint32_t count;
void *mem;
if (!rte_trace_is_enabled())
return;
rte_spinlock_lock(&trace->lock);
for (count = 0; count < trace->nb_trace_mem_list; count++) {
mem = trace->lcore_meta[count].mem;
if (trace->lcore_meta[count].area == TRACE_AREA_HUGEPAGE)
rte_free(mem);
else if (trace->lcore_meta[count].area == TRACE_AREA_HEAP)
free(mem);
}
rte_spinlock_unlock(&trace->lock);
}
int
__rte_trace_point_register(rte_trace_point_t *handle, const char *name,
void (*register_fn)(void))

View File

@ -14,6 +14,26 @@
#include "eal_filesystem.h"
#include "eal_trace.h"
const char *
trace_mode_to_string(enum rte_trace_mode mode)
{
switch (mode) {
case RTE_TRACE_MODE_OVERWRITE: return "overwrite";
case RTE_TRACE_MODE_DISCARD: return "discard";
default: return "unknown";
}
}
const char *
trace_area_to_string(enum trace_area_e area)
{
switch (area) {
case TRACE_AREA_HEAP: return "heap";
case TRACE_AREA_HUGEPAGE: return "hugepage";
default: return "unknown";
}
}
static bool
trace_entry_compare(const char *name)
{

View File

@ -6,11 +6,16 @@
#define __EAL_TRACE_H
#include <rte_cycles.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_spinlock.h>
#include <rte_trace.h>
#include <rte_trace_point.h>
#include <rte_uuid.h>
#include "eal_private.h"
#include "eal_thread.h"
#define trace_err(fmt, args...) \
RTE_LOG(ERR, EAL, "%s():%u " fmt "\n", __func__, __LINE__, ## args)
@ -21,6 +26,8 @@
#define TRACE_DIR_STR_LEN (sizeof("YYYY-mm-dd-AM-HH-MM-SS") + TRACE_PREFIX_LEN)
#define TRACE_CTF_FIELD_SIZE 384
#define TRACE_POINT_NAME_SIZE 64
#define TRACE_CTF_MAGIC 0xC1FC1FC1
struct trace_point {
STAILQ_ENTRY(trace_point) next;
@ -29,6 +36,16 @@ struct trace_point {
char ctf_field[TRACE_CTF_FIELD_SIZE];
};
enum trace_area_e {
TRACE_AREA_HEAP,
TRACE_AREA_HUGEPAGE,
};
struct thread_mem_meta {
void *mem;
enum trace_area_e area;
};
struct trace {
char dir[PATH_MAX];
int dir_offset;
@ -38,6 +55,8 @@ struct trace {
rte_uuid_t uuid;
uint32_t buff_len;
uint32_t nb_trace_points;
uint32_t nb_trace_mem_list;
struct thread_mem_meta *lcore_meta;
uint64_t epoch_sec;
uint64_t epoch_nsec;
uint64_t uptime_ticks;
@ -57,6 +76,12 @@ trace_id_get(rte_trace_point_t *trace)
__RTE_TRACE_FIELD_ID_SHIFT;
}
static inline size_t
trace_mem_sz(uint32_t len)
{
return len + sizeof(struct __rte_trace_header);
}
/* Trace object functions */
struct trace *trace_obj_get(void);
@ -65,12 +90,15 @@ STAILQ_HEAD(trace_point_head, trace_point);
struct trace_point_head *trace_list_head_get(void);
/* Util functions */
const char *trace_mode_to_string(enum rte_trace_mode mode);
const char *trace_area_to_string(enum trace_area_e area);
bool trace_has_duplicate_entry(void);
void trace_uuid_generate(void);
int trace_metadata_create(void);
void trace_metadata_destroy(void);
int trace_mkdir(void);
int trace_epoch_time_save(void);
void trace_mem_per_thread_free(void);
/* EAL interface */
int eal_trace_init(void);

View File

@ -227,6 +227,15 @@ __rte_trace_point_fp_is_enabled(void)
#endif
}
/**
* @internal
*
* Allocate trace memory buffer per thread.
*
*/
__rte_experimental
void __rte_trace_mem_per_thread_alloc(void);
/**
* @internal
*

View File

@ -9,6 +9,10 @@
#ifndef _RTE_TRACE_POINT_PROVIDER_H_
#define _RTE_TRACE_POINT_PROVIDER_H_
#include <rte_per_lcore.h>
#include <rte_string_fns.h>
#include <rte_uuid.h>
#define __RTE_TRACE_EVENT_HEADER_ID_SHIFT (48)
#define __RTE_TRACE_FIELD_SIZE_SHIFT 0
@ -18,4 +22,20 @@
#define __RTE_TRACE_FIELD_ENABLE_MASK (1ULL << 63)
#define __RTE_TRACE_FIELD_ENABLE_DISCARD (1ULL << 62)
struct __rte_trace_stream_header {
uint32_t magic;
rte_uuid_t uuid;
uint32_t lcore_id;
char thread_name[__RTE_TRACE_EMIT_STRING_LEN_MAX];
} __rte_packed;
struct __rte_trace_header {
uint32_t offset;
uint32_t len;
struct __rte_trace_stream_header stream_header;
uint8_t mem[];
};
RTE_DECLARE_PER_LCORE(void *, trace_mem);
#endif /* _RTE_TRACE_POINT_PROVIDER_H_ */

View File

@ -337,7 +337,9 @@ EXPERIMENTAL {
rte_thread_is_intr;
# added in 20.05
__rte_trace_mem_per_thread_alloc;
__rte_trace_point_register;
per_lcore_trace_mem;
per_lcore_trace_point_sz;
rte_log_can_log;
rte_thread_getname;