diff --git a/lib/librte_eal/common/eal_common_trace.c b/lib/librte_eal/common/eal_common_trace.c
index fe9e363f7..3a158b2ce 100644
--- a/lib/librte_eal/common/eal_common_trace.c
+++ b/lib/librte_eal/common/eal_common_trace.c
@@ -16,6 +16,7 @@
 #include "eal_trace.h"
 
 RTE_DEFINE_PER_LCORE(volatile int, trace_point_sz);
+RTE_DEFINE_PER_LCORE(void *, trace_mem);
 RTE_DEFINE_PER_LCORE(char, ctf_field[TRACE_CTF_FIELD_SIZE]);
 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 registration failed */
 	if (trace.register_errno) {
 		rte_errno = trace.register_errno;
@@ -83,6 +87,7 @@ eal_trace_fini(void)
 {
 	if (rte_trace_global_is_disabled())
 		return;
+	trace_mem_per_thread_free();
 	trace_metadata_destroy();
 }
 
@@ -333,6 +338,98 @@ rte_trace_from_name(const char *name)
 	return NULL;
 }
 
+static inline size_t
+list_sz(uint32_t index)
+{
+	return sizeof(struct thread_mem_meta) * (index + 1);
+}
+
+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_global_is_disabled())
+		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, list_sz(count));
+
+	/* Provide dummy space for fastpath 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_global_is_disabled())
+		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_t handle, const char *name, uint32_t level,
 			 void (*fn)(void))
diff --git a/lib/librte_eal/common/eal_common_trace_utils.c b/lib/librte_eal/common/eal_common_trace_utils.c
index 340ab62e4..dbeb36668 100644
--- a/lib/librte_eal/common/eal_common_trace_utils.c
+++ b/lib/librte_eal/common/eal_common_trace_utils.c
@@ -14,6 +14,26 @@
 #include "eal_filesystem.h"
 #include "eal_trace.h"
 
+const char *
+trace_mode_to_string(enum rte_trace_mode_e 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)
 {
diff --git a/lib/librte_eal/common/eal_trace.h b/lib/librte_eal/common/eal_trace.h
index b6aa660bd..c2d00bbb8 100644
--- a/lib/librte_eal/common/eal_trace.h
+++ b/lib/librte_eal/common/eal_trace.h
@@ -6,10 +6,15 @@
 #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_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)
@@ -22,6 +27,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;
@@ -30,6 +37,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;
@@ -37,8 +54,11 @@ struct trace {
 	bool global_status;
 	enum rte_trace_mode_e mode;
 	rte_uuid_t uuid;
+	uint32_t buff_len;
 	uint32_t level;
 	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;
@@ -58,6 +78,12 @@ trace_id_get(rte_trace_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);
 
@@ -66,12 +92,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_e 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);
diff --git a/lib/librte_eal/common/include/rte_trace.h b/lib/librte_eal/common/include/rte_trace.h
index da70dfdbb..358b1b7ca 100644
--- a/lib/librte_eal/common/include/rte_trace.h
+++ b/lib/librte_eal/common/include/rte_trace.h
@@ -518,6 +518,19 @@ _tp _args \
 
 #endif /* __DOXYGEN__ */
 
+/** @internal Macro to define maximum emit length of string datatype. */
+#define __RTE_TRACE_EMIT_STRING_LEN_MAX 32
+
+/**
+ * @internal @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Allocate trace memory buffer per thread.
+ *
+ */
+__rte_experimental
+void __rte_trace_mem_per_thread_alloc(void);
+
 /**
  * @internal @warning
  * @b EXPERIMENTAL: this API may change without prior notice
diff --git a/lib/librte_eal/common/include/rte_trace_provider.h b/lib/librte_eal/common/include/rte_trace_provider.h
index b4da87ba1..2257de85b 100644
--- a/lib/librte_eal/common/include/rte_trace_provider.h
+++ b/lib/librte_eal/common/include/rte_trace_provider.h
@@ -9,6 +9,10 @@
 #ifndef _RTE_TRACE_PROVIDER_H_
 #define _RTE_TRACE_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_ENABLE_MASK (1ULL << 63)
@@ -20,5 +24,20 @@
 #define __RTE_TRACE_FIELD_LEVEL_SHIFT (32)
 #define __RTE_TRACE_FIELD_LEVEL_MASK (0xffULL << __RTE_TRACE_FIELD_LEVEL_SHIFT)
 
+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_PROVIDER_H_ */
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 841ebc5f9..8999faeb7 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -338,7 +338,9 @@ EXPERIMENTAL {
 
 	# added in 20.05
 	rte_thread_getname;
+	__rte_trace_mem_per_thread_alloc;
 	__rte_trace_point_register;
+	per_lcore_trace_mem;
 	rte_trace_global_is_enabled;
 	rte_trace_global_is_disabled;
 	rte_trace_is_id_invalid;
