From: Tanushree Shah <tshah@linux.ibm.com>
To: acme@kernel.org, jolsa@kernel.org, adrian.hunter@intel.com,
vmolnaro@redhat.com, mpetlan@redhat.com, tmricht@linux.ibm.com,
maddy@linux.ibm.com, irogers@google.com, namhyung@kernel.org,
linux-kernel@vger.kernel.org
Cc: linux-perf-users@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
atrajeev@linux.ibm.com, hbathini@linux.ibm.com,
Tejas.Manhas1@ibm.com, Tanushree.Shah@ibm.com,
Shivani.Nittor@ibm.com, Tanushree Shah <tshah@linux.ibm.com>
Subject: [RFC PATCH 2/4] perf/trace-event: Write trace.dat metadata sections during parsing
Date: Mon, 8 Jun 2026 18:29:50 +0530 [thread overview]
Message-ID: <20260608125951.90425-4-tshah@linux.ibm.com> (raw)
In-Reply-To: <20260608125951.90425-2-tshah@linux.ibm.com>
Perf already captures the tracing metadata as a part of
data section in perf.data
When trace_dat_fp is set, write trace.dat compatible metadata
sections using the perf provided raw buffers.
Sections written:
- Initial format header (magic, version, endian, long_size,
page_size, compression, options_offset placeholder)
- Section 16: HEADER INFO (header_page + header_event)
- Section 17: FTRACE EVENT FORMATS
- Section 18: EVENT FORMATS (per system/event format files)
- Section 19: KALLSYMS
- Section 21: CMDLINES
- Section 15: STRINGS (written last after all sections)
Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
---
tools/perf/util/trace-event-read.c | 259 ++++++++++++++++++++++++++++-
1 file changed, 252 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index ecbbb93f0185..815577703c2e 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -19,6 +19,7 @@
#include "trace-event.h"
#include "debug.h"
#include "util.h"
+#include "trace-dat.h"
static int input_fd;
@@ -145,10 +146,9 @@ static char *read_string(void)
static int read_proc_kallsyms(struct tep_handle *pevent)
{
unsigned int size;
+ char *buf;
size = read4(pevent);
- if (!size)
- return 0;
/*
* Just skip it, now that we configure libtraceevent to use the
* tools/perf/ symbol resolver.
@@ -160,11 +160,56 @@ static int read_proc_kallsyms(struct tep_handle *pevent)
* payload", so that older tools can continue reading it and interpret
* it as "no kallsyms payload is present".
*/
- lseek(input_fd, size, SEEK_CUR);
+ /* Write kallsyms section with empty payload if no data */
+ if (!size) {
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS;
+ unsigned short flags = 0;
+ unsigned long long section_size = sizeof(unsigned int);
+ unsigned int kallsyms_data = 0;
+ unsigned int string_id = STRID_KALLSYMS;
+
+ trace_dat_kallsyms_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(&kallsyms_data, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ }
+ return 0;
+ }
+ buf = malloc(size);
+ if (buf == NULL)
+ return -1;
+ if (read(input_fd, buf, size) < 0) {
+ free(buf);
+ return -1;
+ }
trace_data_size += size;
+ /* Write kallsyms section with data */
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS;
+ unsigned int string_id = STRID_KALLSYMS;
+ unsigned long long section_size = sizeof(unsigned int) + size;
+ unsigned short flags = 0;
+
+ trace_dat_kallsyms_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(&size, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(buf, 1, size, trace_dat_fp)) {
+ free(buf);
+ return -EIO;
+ }
+ }
+ free(buf);
return 0;
}
+
static int read_ftrace_printk(struct tep_handle *pevent)
{
unsigned int size;
@@ -195,6 +240,13 @@ static int read_ftrace_printk(struct tep_handle *pevent)
static int read_header_files(struct tep_handle *pevent)
{
unsigned long long size;
+ unsigned long long header_page_size;
+ unsigned long long header_event_size;
+ char *header_event;
+ unsigned short section_id;
+ unsigned short flags;
+ unsigned int string_id;
+ unsigned long long section_size;
char *header_page;
char buf[BUFSIZ];
int ret = 0;
@@ -209,6 +261,7 @@ static int read_header_files(struct tep_handle *pevent)
size = read8(pevent);
+ header_page_size = size;
header_page = malloc(size);
if (header_page == NULL)
return -1;
@@ -227,19 +280,59 @@ static int read_header_files(struct tep_handle *pevent)
*/
tep_set_long_size(pevent, tep_get_header_page_size(pevent));
}
- free(header_page);
- if (do_read(buf, 13) < 0)
+ if (do_read(buf, 13) < 0) {
+ free(header_page);
return -1;
+ }
if (memcmp(buf, "header_event", 13) != 0) {
pr_debug("did not read header event");
+ free(header_page);
return -1;
}
size = read8(pevent);
- skip(size);
+ if (trace_dat_fp) {
+ header_event_size = size;
+ header_event = malloc(size);
+ if (header_event == NULL) {
+ free(header_page);
+ return -1;
+ }
+ if (do_read(header_event, size) < 0) {
+ free(header_page);
+ free(header_event);
+ return -1;
+ }
+ /* Write header_page and header_event to trace.dat */
+ section_id = TRACE_DAT_SECTION_HEADER;
+ flags = 0;
+ string_id = STRID_HEADERS;
+ section_size = 12 + 8 + header_page_size + 13 + 8 +
+ header_event_size;
+
+ trace_dat_header_info_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite("header_page\0", 1, 12, trace_dat_fp) ||
+ !fwrite(&header_page_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(header_page, 1, header_page_size, trace_dat_fp) ||
+ !fwrite("header_event\0", 1, 13, trace_dat_fp) ||
+ !fwrite(&header_event_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(header_event, 1, header_event_size, trace_dat_fp)) {
+ free(header_page);
+ free(header_event);
+ return -EIO;
+ }
+ free(header_event);
+ } else {
+ skip(size);
+ }
+ free(header_page);
return ret;
}
@@ -259,6 +352,13 @@ static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
pr_debug("error reading ftrace file.\n");
goto out;
}
+ if (trace_dat_fp) {
+ if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(buf, 1, size, trace_dat_fp)) {
+ free(buf);
+ return -EIO;
+ }
+ }
ret = parse_ftrace_file(pevent, buf, size);
if (ret < 0)
@@ -283,6 +383,13 @@ static int read_event_file(struct tep_handle *pevent, char *sys,
ret = do_read(buf, size);
if (ret < 0)
goto out;
+ if (trace_dat_fp) {
+ if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(buf, 1, size, trace_dat_fp)) {
+ free(buf);
+ return -EIO;
+ }
+ }
ret = parse_event_file(pevent, buf, size, sys);
if (ret < 0)
@@ -298,8 +405,31 @@ static int read_ftrace_files(struct tep_handle *pevent)
int count;
int i;
int ret;
+ long section_size_pos = 0;
+ long count_pos = 0;
+ unsigned long long section_size = 0;
+ long end_pos;
count = read4(pevent);
+ /* Write ftrace formats section to trace.dat output file */
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_FTRACE;
+ unsigned short flags = 0;
+ unsigned int string_id = STRID_FTRACE_FORMATS;
+
+ trace_dat_ftrace_format_offset = ftell(trace_dat_fp);
+
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ section_size_pos = ftell(trace_dat_fp);
+ if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ count_pos = ftell(trace_dat_fp);
+ if (!fwrite(&count, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ }
for (i = 0; i < count; i++) {
size = read8(pevent);
@@ -307,6 +437,16 @@ static int read_ftrace_files(struct tep_handle *pevent)
if (ret)
return ret;
}
+ /* Fill in section size after writing all ftrace files */
+ if (trace_dat_fp) {
+ end_pos = ftell(trace_dat_fp);
+ section_size = end_pos - count_pos;
+ fseek(trace_dat_fp, section_size_pos, SEEK_SET);
+ if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ fseek(trace_dat_fp, end_pos, SEEK_SET);
+ }
+
return 0;
}
@@ -318,8 +458,30 @@ static int read_event_files(struct tep_handle *pevent)
int count;
int i,x;
int ret;
+ long section_size_pos = 0;
+ long sys_count_pos = 0;
+ unsigned long long section_size = 0;
+ long end_pos;
systems = read4(pevent);
+ /* Write event formats section to trace.dat output file */
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_EVENTS;
+ unsigned short flags = 0;
+ unsigned int string_id = STRID_EVENT_FORMATS;
+
+ trace_dat_events_format_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ section_size_pos = ftell(trace_dat_fp);
+ if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ sys_count_pos = ftell(trace_dat_fp);
+ if (!fwrite(&systems, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ }
for (i = 0; i < systems; i++) {
sys = read_string();
@@ -327,6 +489,11 @@ static int read_event_files(struct tep_handle *pevent)
return -1;
count = read4(pevent);
+ if (trace_dat_fp) {
+ if (!fwrite(sys, 1, strlen(sys) + 1, trace_dat_fp) ||
+ !fwrite(&count, sizeof(unsigned int), 1, trace_dat_fp))
+ return -EIO;
+ }
for (x=0; x < count; x++) {
size = read8(pevent);
@@ -338,6 +505,16 @@ static int read_event_files(struct tep_handle *pevent)
}
free(sys);
}
+ /* Fill in section size after writing all event files */
+ if (trace_dat_fp) {
+ end_pos = ftell(trace_dat_fp);
+ section_size = end_pos - sys_count_pos;
+ fseek(trace_dat_fp, section_size_pos, SEEK_SET);
+ if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ fseek(trace_dat_fp, end_pos, SEEK_SET);
+ }
+
return 0;
}
@@ -349,8 +526,25 @@ static int read_saved_cmdline(struct tep_handle *pevent)
/* it can have 0 size */
size = read8(pevent);
- if (!size)
+ /* Write cmdlines section with empty payload if no data */
+ if (!size) {
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_CMDLINE;
+ unsigned short flags = 0;
+ unsigned int string_id = STRID_CMDLINES;
+ unsigned long long section_size = sizeof(unsigned long long);
+ unsigned long long section_data = 0;
+
+ trace_dat_cmdline_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(§ion_data, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ }
return 0;
+ }
buf = malloc(size + 1);
if (buf == NULL) {
@@ -363,6 +557,23 @@ static int read_saved_cmdline(struct tep_handle *pevent)
pr_debug("error reading saved cmdlines\n");
goto out;
}
+ /* Write cmdlines section with data */
+ if (trace_dat_fp) {
+ unsigned short section_id = TRACE_DAT_SECTION_CMDLINE;
+ unsigned short flags = 0;
+ unsigned int string_id = STRID_CMDLINES;
+ unsigned long long section_size = sizeof(unsigned long long) + size;
+
+ trace_dat_cmdline_offset = ftell(trace_dat_fp);
+ if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) ||
+ !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) ||
+ !fwrite(buf, 1, size, trace_dat_fp))
+ return -EIO;
+ }
+
buf[ret] = '\0';
parse_saved_cmdline(pevent, buf, size);
@@ -387,6 +598,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
int file_page_size;
struct tep_handle *pevent = NULL;
int err;
+ char magic_buf[10];
repipe = __repipe;
input_fd = fd;
@@ -398,12 +610,17 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
return -1;
}
+ if (trace_dat_fp)
+ memcpy(magic_buf, buf, 3);
+
if (do_read(buf, 7) < 0)
return -1;
if (memcmp(buf, "tracing", 7) != 0) {
pr_debug("not a trace file (missing 'tracing' tag)");
return -1;
}
+ if (trace_dat_fp)
+ memcpy(magic_buf + 3, buf, 7);
version = read_string();
if (version == NULL)
@@ -440,6 +657,28 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
tep_set_long_size(pevent, file_long_size);
tep_set_page_size(pevent, file_page_size);
+ /* Write initial file header to trace.dat */
+ if (trace_dat_fp) {
+ unsigned char endian = file_bigendian;
+ unsigned char long_size = file_long_size;
+ unsigned int page_size = file_page_size;
+ unsigned long long placeholder = 0;
+ char trace_dat_version = TRACE_DAT_VERSION;
+
+ if (!fwrite(magic_buf, 1, 10, trace_dat_fp) || /* magic + "tracing" */
+ !fwrite(&trace_dat_version, 1, 2, trace_dat_fp) ||
+ !fwrite(&endian, 1, 1, trace_dat_fp) ||
+ !fwrite(&long_size, 1, 1, trace_dat_fp) ||
+ !fwrite(&page_size, sizeof(unsigned int), 1, trace_dat_fp) ||
+ !fwrite("none", 1, 4, trace_dat_fp) ||
+ !fwrite("\0", 1, 1, trace_dat_fp) ||
+ !fwrite("\0", 1, 1, trace_dat_fp))
+ return -EIO;
+ trace_dat_options_offset = ftell(trace_dat_fp);
+ if (!fwrite(&placeholder, sizeof(unsigned long long), 1, trace_dat_fp))
+ return -EIO;
+ }
+
err = read_header_files(pevent);
if (err)
goto out;
@@ -460,6 +699,12 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
if (err)
goto out;
}
+ /* Write strings section to trace.dat output file */
+ if (trace_dat_fp) {
+ err = trace_dat__write_strings_section();
+ if (err)
+ goto out;
+ }
size = trace_data_size;
repipe = false;
--
2.53.0
next prev parent reply other threads:[~2026-06-08 13:01 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-08 12:59 [RFC PATCH 0/4] perf: Add perf.data tracepoint events to trace.dat conversion Tanushree Shah
2026-06-08 12:59 ` [RFC PATCH 1/4] perf/trace-dat: Add trace.dat export infrastructure Tanushree Shah
2026-06-08 12:59 ` Tanushree Shah [this message]
2026-06-08 12:59 ` [RFC PATCH 3/4] perf data-convert: Add perf.data to trace.dat conversion backend Tanushree Shah
2026-06-08 12:59 ` [RFC PATCH 4/4] perf data: Add --to-trace-dat option for converting perf.data tracepoint events into trace.dat format Tanushree Shah
2026-06-08 15:18 ` [RFC PATCH 0/4] perf: Add perf.data tracepoint events to trace.dat conversion Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260608125951.90425-4-tshah@linux.ibm.com \
--to=tshah@linux.ibm.com \
--cc=Shivani.Nittor@ibm.com \
--cc=Tanushree.Shah@ibm.com \
--cc=Tejas.Manhas1@ibm.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=atrajeev@linux.ibm.com \
--cc=hbathini@linux.ibm.com \
--cc=irogers@google.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mpetlan@redhat.com \
--cc=namhyung@kernel.org \
--cc=tmricht@linux.ibm.com \
--cc=vmolnaro@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox