[PATCH] btt: add the option -n to output latency with nanosecond precision

[email protected] Thu, 12 Jun 2025 16:07:49 +0800
Newsgroups org.kernel.vger.linux-btrace
Message-ID <[email protected]>
From: Kou Wenqi <[email protected]>

In the output of "btt -p" the timestamp precision is in nanoseconds.
8,0  :     0.000000000 Q          0+375
           0.000005237 G          0+375
           0.000015011 I          0+375
           0.000079403 D          0+375
           0.082000679 C          0+375

In outputs like "btt -q" the precision of timestamps and latencies
is in microseconds.
0.000000 0.082001

Add the -n option to btt to set the precision of timestamps and
latencies in outputs like "btt -q" to nanoseconds, aligning
them with the output of "btt -p".

This is particularly useful for pinpointing the exact timestamps
of the highest-latency Qs.

Signed-off-by: Kou Wenqi <[email protected]>
---
 btt/args.c        | 12 +++++++++++-
 btt/bt_timeline.c |  1 +
 btt/globals.h     |  1 +
 btt/latency.c     | 10 ++++++++--
 doc/btt.1         | 11 ++++++++++-
 5 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/btt/args.c b/btt/args.c
index 5c5078a..beac03b 100644
--- a/btt/args.c
+++ b/btt/args.c
@@ -29,7 +29,7 @@
 
 #define SETBUFFER_SIZE	(64 * 1024)
 
-#define S_OPTS	"aAB:d:D:e:hi:I:l:L:m:M:o:p:P:q:Q:rs:S:t:T:u:VvXz:Z"
+#define S_OPTS	"aAB:d:D:e:hi:I:l:L:m:M:no:p:P:q:Q:rs:S:t:T:u:VvXz:Z"
 static struct option l_opts[] = {
 	{
 		.name = "seek-absolute",
@@ -109,6 +109,12 @@ static struct option l_opts[] = {
 		.flag = NULL,
 		.val = 'M'
 	},
+	{
+		.name = "output-latency-with-nanosecond-precision",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'n'
+	},
 	{
 		.name = "output-file",
 		.has_arg = required_argument,
@@ -224,6 +230,7 @@ static char usage_str[] = \
 	"[ -L <freq>        | --periodic-latencies=<freq> ]\n" \
 	"[ -m <output name> | --seeks-per-second=<output name> ]\n" \
 	"[ -M <dev map>     | --dev-maps=<dev map>\n" \
+	"[ -n               | --output-latency-with-nanosecond-precision ]\n" \
 	"[ -o <output name> | --output-file=<output name> ]\n" \
 	"[ -p <output name> | --per-io-dump=<output name> ]\n" \
 	"[ -P <output name> | --per-io-trees=<output name> ]\n" \
@@ -333,6 +340,9 @@ void handle_args(int argc, char *argv[])
 			if (dev_map_read(optarg))
 				exit(1);
 			break;
+		case 'n':
+			output_latency_with_nanosecond_precision = 1;
+			break;
 		case 'o':
 			output_name = optarg;
 			break;
diff --git a/btt/bt_timeline.c b/btt/bt_timeline.c
index 295e5ee..cc847b0 100644
--- a/btt/bt_timeline.c
+++ b/btt/bt_timeline.c
@@ -38,6 +38,7 @@ unsigned long n_traces;
 struct avgs_info all_avgs;
 unsigned int n_devs;
 time_t genesis, last_vtrace;
+int output_latency_with_nanosecond_precision;
 LIST_HEAD(all_devs);
 LIST_HEAD(all_procs);
 LIST_HEAD(all_ios);
diff --git a/btt/globals.h b/btt/globals.h
index 22a1cb0..800b2af 100644
--- a/btt/globals.h
+++ b/btt/globals.h
@@ -191,6 +191,7 @@ extern __u64 iostat_interval, iostat_last_stamp;
 extern time_t genesis, last_vtrace;
 extern double t_astart, t_aend;
 extern __u64 q_histo[N_HIST_BKTS], d_histo[N_HIST_BKTS];
+extern int output_latency_with_nanosecond_precision;
 
 /* args.c */
 void handle_args(int argc, char *argv[]);
diff --git a/btt/latency.c b/btt/latency.c
index 51e6881..5c4e52f 100644
--- a/btt/latency.c
+++ b/btt/latency.c
@@ -22,8 +22,14 @@
 
 static inline void latency_out(FILE *ofp, __u64 tstamp, __u64 latency)
 {
-	if (ofp)
-		fprintf(ofp, "%lf %lf\n", TO_SEC(tstamp), TO_SEC(latency));
+	if (ofp) {
+		if (output_latency_with_nanosecond_precision)
+			fprintf(ofp, "%d.%09lu %d.%09lu\n",
+				(int)SECONDS(tstamp), (unsigned long)NANO_SECONDS(tstamp),
+				(int)SECONDS(latency), (unsigned long)NANO_SECONDS(latency));
+		else
+			fprintf(ofp, "%lf %lf\n", TO_SEC(tstamp), TO_SEC(latency));
+	}
 }
 
 FILE *latency_open(struct d_info *dip, char *name, char *post)
diff --git a/doc/btt.1 b/doc/btt.1
index 28cf912..c143f35 100644
--- a/doc/btt.1
+++ b/doc/btt.1
@@ -32,7 +32,9 @@ btt \- analyse block i/o traces produces by blktrace
 .br
 [ \-m <\fIoutput name\fR> | \-\-seeks\-per\-second=<\fIoutput name\fR> ]
 .br
-[ \-M <\fIdev map\fR>     | \-\-dev\-maps=<\fIdev map\fR>
+[ \-M <\fIdev map\fR>     | \-\-dev\-maps=<\fIdev map\fR> ]
+.br
+[ \-n               | \-\-output\-latency\-with\-nanosecond\-precision ]
 .br
 [ \-o <\fIoutput name\fR> | \-\-output\-file=<\fIoutput name\fR> ]
 .br
@@ -222,6 +224,13 @@ The \-M option takes in a file generated by the provided script
 (gen_disk_info.py), and allows for better output of device names.
 .RE
 
+.B \-n
+.br
+.B \-\-output\-latency\-with\-nanosecond\-precision
+.RS 4
+Output latency with nanosecond precision.
+.RE
+
 .B \-o <\fIoutput name\fR>
 .br
 .B \-\-output\-file=<\fIoutput name\fR>
-- 
2.43.0