All of lore.kernel.org
 help / color / mirror / Atom feed
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
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,
	rostedt@goodmis.org, Tanushree Shah <tshah@linux.ibm.com>
Subject: [RFC PATCH v4 4/5] perf data: Add --to-trace-dat option for converting perf.data tracepoint events into trace.dat format
Date: Sat, 22 Aug 2026 11:57:23 +0530	[thread overview]
Message-ID: <20260822062729.882005-5-tshah@linux.ibm.com> (raw)
In-Reply-To: <20260822062729.882005-1-tshah@linux.ibm.com>

Add new command-line option to perf data convert for generating
trace.dat output files.

The --to-trace-dat option:
- Accepts output filename for trace.dat format
- Mutually exclusive with --to-ctf and --to-json
- Calls trace_convert__perf2dat() to perform conversion

Usage:
  $ perf record -e sched:* -a sleep 1
  $ perf data convert --to-trace-dat=trace.dat
  $ trace-cmd report trace.dat

Document the new option in Documentation/perf-data.txt alongside
the existing --to-ctf and --to-json entries.

Honor the --time filtering option in trace_convert__perf2dat() the
same way the JSON and CTF converters do, using
perf_time__parse_for_ranges() and perf_time__ranges_skip_sample()
to skip samples outside the requested time range.

Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
---
 tools/perf/Documentation/perf-data.txt |  7 +++++
 tools/perf/builtin-data.c              | 43 ++++++++++++++++++++++++++
 tools/perf/util/data-convert-trace.c   | 21 +++++++++++++
 tools/perf/util/trace-dat.c            | 20 +++++++++---
 tools/perf/util/trace-dat.h            |  1 +
 5 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt
index 20f178d61ed7..578ba6357183 100644
--- a/tools/perf/Documentation/perf-data.txt
+++ b/tools/perf/Documentation/perf-data.txt
@@ -30,6 +30,13 @@ OPTIONS for 'convert'
 --to-json::
 	Triggers JSON conversion. Specify the JSON filename to output.
 
+--to-trace-dat::
+	Triggers trace.dat conversion. Converts perf.data tracepoint events
+	to trace.dat format v7, compatible with trace-cmd and KernelShark.
+	Only PERF_TYPE_TRACEPOINT events are converted. Specify the
+	trace.dat filename to output. Requires libtraceevent support.
+	Mutually exclusive with --to-ctf and --to-json.
+
 --tod::
 	Convert time to wall clock time.
 
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c
index 1dd73ed6bdcb..c9c863197d02 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -30,6 +30,11 @@ static const char *data_usage[] = {
 
 static const char *to_json;
 static const char *to_ctf;
+
+#ifdef HAVE_LIBTRACEEVENT
+static const char *trace_dat_output;
+#endif
+
 static struct perf_data_convert_opts opts = {
 	.force = false,
 	.all = false,
@@ -46,6 +51,10 @@ static const struct option data_options[] = {
 		OPT_BOOLEAN(0, "all", &opts.all, "Convert all events"),
 		OPT_STRING(0, "time", &opts.time_str, "str",
 			   "Time span of interest (start,stop)"),
+#ifdef HAVE_LIBTRACEEVENT
+		OPT_STRING(0, "to-trace-dat", &trace_dat_output,
+			   "file", "Convert to trace.dat format using perf.data tracepoints"),
+#endif
 		OPT_END()
 	};
 
@@ -63,10 +72,44 @@ static int cmd_data_convert(int argc, const char **argv)
 		pr_err("You cannot specify both --to-ctf and --to-json.\n");
 		return -1;
 	}
+#ifdef HAVE_LIBTRACEEVENT
+	if (trace_dat_output && (to_json || to_ctf)) {
+		pr_err("You cannot specify --to-trace-dat with --to-ctf or --to-json.\n");
+		return -1;
+	}
+#endif
+
+#ifdef HAVE_LIBBABELTRACE_SUPPORT
+	#ifdef HAVE_LIBTRACEEVENT
+	if (!to_json && !to_ctf && !trace_dat_output) {
+		pr_err("You must specify one of --to-ctf, --to-json, or --to-trace-dat.\n");
+		return -1;
+	}
+	#else
 	if (!to_json && !to_ctf) {
 		pr_err("You must specify one of --to-ctf or --to-json.\n");
 		return -1;
 	}
+	#endif
+#else
+	#ifdef HAVE_LIBTRACEEVENT
+	if (!to_json && !trace_dat_output) {
+		pr_err("You must specify --to-json or --to-trace-dat.\n");
+		return -1;
+	}
+	#else
+	if (!to_json) {
+		pr_err("You must specify --to-json.\n");
+		return -1;
+	}
+	#endif
+#endif
+
+#ifdef HAVE_LIBTRACEEVENT
+	if (trace_dat_output)
+		return trace_convert__perf2dat(input_name ? input_name : "perf.data",
+					       trace_dat_output, &opts);
+#endif
 
 	if (to_json)
 		return bt_convert__perf2json(input_name, to_json, &opts);
diff --git a/tools/perf/util/data-convert-trace.c b/tools/perf/util/data-convert-trace.c
index 445479fae888..425b3aaa3f02 100644
--- a/tools/perf/util/data-convert-trace.c
+++ b/tools/perf/util/data-convert-trace.c
@@ -22,6 +22,7 @@
 #include "evsel.h"
 #include "tool.h"
 #include "debug.h"
+#include "time-utils.h"
 #include "trace-dat.h"
 #include "trace-event.h"
 #include "event.h"
@@ -31,6 +32,10 @@
 struct trace_convert {
 	struct perf_tool tool;
 	u64 events_count;
+	struct perf_time_interval *ptime_range;
+	int range_size;
+	int range_num;
+	u64 skipped;
 };
 
 /* Session handle and init flag used for lazy CPU buffer init in pipe mode */
@@ -86,6 +91,11 @@ static int process_sample_event(const struct perf_tool *tool,
 		cpu_buffers_initialized = true;
 	}
 
+	if (perf_time__ranges_skip_sample(tc->ptime_range, tc->range_num, sample->time)) {
+		tc->skipped++;
+		return 0;
+	}
+
 	if (trace_dat__collect_cpu_event(sample->cpu, sample->time,
 				sample->raw_data, sample->raw_size) < 0) {
 		pr_err("Failed to collect CPU event\n");
@@ -185,6 +195,15 @@ int trace_convert__perf2dat(const char *input, const char *to_trace,
 	/* Stash session for lazy CPU buffer init on first sample (pipe and normal mode) */
 	trace_dat_session = session;
 
+	if (opts->time_str) {
+		ret = perf_time__parse_for_ranges(opts->time_str, session,
+				&tc.ptime_range,
+				&tc.range_size,
+				&tc.range_num);
+		if (ret < 0)
+			goto out_delete;
+	}
+
 	/* Process all events - collects raw data per-cpu */
 	ret = perf_session__process_events(session);
 	if (ret < 0) {
@@ -230,6 +249,8 @@ int trace_convert__perf2dat(const char *input, const char *to_trace,
 out_delete:
 	if (cpu_buffers_initialized)
 		trace_dat__free_cpu_buffers();
+	if (tc.ptime_range)
+		zfree(&tc.ptime_range);
 	perf_session__delete(session);
 	trace_dat_session = NULL;
 out_close:
diff --git a/tools/perf/util/trace-dat.c b/tools/perf/util/trace-dat.c
index f71e03716e27..1b236745bcac 100644
--- a/tools/perf/util/trace-dat.c
+++ b/tools/perf/util/trace-dat.c
@@ -194,6 +194,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 	int page_size_used = 0;
 	int ret = 0;
 	int i, j;
+	unsigned long long page_base_ts;
 
 	file_offset = ftell(fp);
 	*file_offset_out = file_offset;
@@ -212,6 +213,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 	}
 
 	base_ts = cpu_events->events[0].ts;
+	page_base_ts = base_ts;
 
 	for (i = 0; i < cpu_events->count; i++) {
 		struct cpu_event *event = &cpu_events->events[i];
@@ -234,8 +236,10 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 
 			extend_size = TRACE_DAT_RECORD_TIME_EXTEND_SIZE;
 			extend = calloc(1, extend_size);
-			if (!extend)
-				return -ENOMEM;
+			if (!extend) {
+				ret = -ENOMEM;
+				goto out_free;
+			}
 
 			if (tep_is_file_bigendian(pevent)) {
 				extend_hdr = (time_delta & TRACE_DAT_RECORD_TIME_MASK) |
@@ -245,7 +249,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 				extend_hdr = ((time_delta & TRACE_DAT_RECORD_TIME_MASK) <<
 					TRACE_DAT_RECORD_TIME_SHIFT) |
 					TRACE_DAT_RECORD_TYPE_TIME_EXTEND;
-				delta_upper = time_delta >> TRACE_DAT_RECORD_TIME_SHIFT;
+				delta_upper = time_delta >> 27;
 			}
 			extend_hdr  = to_file_u32(pevent, extend_hdr);   /* still needed */
 			delta_upper = to_file_u32(pevent, delta_upper);   /* still needed */
@@ -288,7 +292,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 		/* Check page fit BEFORE allocating data record */
 		if (page_size_used + needed_size >
 			trace_dat_page_size - TRACE_DAT_RECORD_HEADER_SIZE) {
-			ret = trace_dat__write_page(fp, pevent, base_ts,
+			ret = trace_dat__write_page(fp, pevent, page_base_ts,
 					page_records, page_rec_sizes,
 					nr_page_recs);
 
@@ -298,6 +302,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 			nr_page_recs = 0;
 			page_size_used = 0;
 			base_ts = event->ts;
+			page_base_ts = event->ts;
 
 			if (ret < 0) {
 				free(extend);
@@ -312,6 +317,7 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 			extend = NULL;
 			extend_size = 0;
 			time_delta = 0;
+			base_ts = event->ts;
 		}
 
 		if (tep_is_file_bigendian(pevent))
@@ -387,10 +393,11 @@ static int trace_dat__write_cpu_dat(FILE *fp, struct tep_handle *pevent,
 		page_rec_sizes[nr_page_recs] = data_rec_size;
 		nr_page_recs++;
 		page_size_used += data_rec_size;
+		base_ts = event->ts;
 	}
 
 	if (nr_page_recs > 0) {
-		ret = trace_dat__write_page(fp, pevent, base_ts,
+		ret = trace_dat__write_page(fp, pevent, page_base_ts,
 				page_records, page_rec_sizes, nr_page_recs);
 	}
 out_free:
@@ -861,6 +868,9 @@ void trace_dat__free_cpu_buffers(void)
 	for (cpu = 0; cpu < trace_dat_nr_cpus; cpu++) {
 		int i;
 
+		if (!trace_cpu_data[cpu].events)
+			continue;
+
 		for (i = 0; i < trace_cpu_data[cpu].count; i++)
 			free(trace_cpu_data[cpu].events[i].raw);
 		free(trace_cpu_data[cpu].events);
diff --git a/tools/perf/util/trace-dat.h b/tools/perf/util/trace-dat.h
index 5985083b275a..40041dac60d4 100644
--- a/tools/perf/util/trace-dat.h
+++ b/tools/perf/util/trace-dat.h
@@ -11,6 +11,7 @@
 #include <stdbool.h>
 #include <event-parse.h>
 #include <byteswap.h>
+#include <stdint.h>
 #include "util.h"
 
 /* trace.dat file format version */
-- 
2.47.1


  parent reply	other threads:[~2026-08-22  6:28 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-22  6:27 [RFC PATCH v4 0/5] Add perf.data tracepoint events to trace.dat conversion Tanushree Shah
2026-08-22  6:27 ` [RFC PATCH v4 1/5] perf/trace-dat: Add trace.dat export infrastructure Tanushree Shah
2026-08-22  6:40   ` sashiko-bot
2026-08-22  6:27 ` [RFC PATCH v4 2/5] perf/trace-event: Write trace.dat metadata sections during parsing Tanushree Shah
2026-08-22  6:44   ` sashiko-bot
2026-08-22  6:27 ` [RFC PATCH v4 3/5] perf data-convert: Add perf.data to trace.dat conversion backend Tanushree Shah
2026-08-22  6:38   ` sashiko-bot
2026-08-22  6:27 ` Tanushree Shah [this message]
2026-08-22  6:44   ` [RFC PATCH v4 4/5] perf data: Add --to-trace-dat option for converting perf.data tracepoint events into trace.dat format sashiko-bot
2026-08-22  6:27 ` [RFC PATCH v4 5/5] perf test: Add test validating trace.dat generated by 'perf data convert --to-trace-dat' Tanushree Shah
2026-08-22  6:36   ` sashiko-bot

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=20260822062729.882005-5-tshah@linux.ibm.com \
    --to=tshah@linux.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-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=rostedt@goodmis.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.