[PATCH v3 2/3] perf sched latency: Auto-scale latency and runtime display units

From: Aaron Tomlin

Date: Sat Jul 25 2026 - 23:26:29 EST


Currently, 'perf sched latency' displays task runtime and delay values
exclusively in milliseconds (ms). This can be hard to read when
latencies are very small (in the microsecond or nanosecond range) or
unusually large (seconds).

Introduce auto-scaling for latency and runtime display columns. Values
are dynamically scaled and output with the most appropriate unit:
nanoseconds (ns), microseconds (us), milliseconds (ms), or seconds (s).

Additionally, rename column headers from "Runtime ms", "Avg delay ms",
and "Max delay ms" to "Runtime", "Avg delay", and "Max delay"
respectively, and adjust spacing to maintain column alignment.

Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
---
tools/perf/builtin-sched.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b3cf678573e0..8c83dc423b57 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -246,6 +246,17 @@ struct perf_sched {
struct perf_data *data;
};

+static int scnprintf_latency_unit(char *buf, size_t size, u64 nsecs)
+{
+ if (nsecs < 1000)
+ return scnprintf(buf, size, "%6" PRIu64 " ns", nsecs);
+ if (nsecs < NSEC_PER_MSEC)
+ return scnprintf(buf, size, "%6.3f us", (double)nsecs / NSEC_PER_USEC);
+ if (nsecs < NSEC_PER_SEC)
+ return scnprintf(buf, size, "%6.3f ms", (double)nsecs / NSEC_PER_MSEC);
+ return scnprintf(buf, size, "%6.3f s ", (double)nsecs / NSEC_PER_SEC);
+}
+
/* per thread run time data */
struct thread_runtime {
u64 last_time; /* time of previous sched in/out event */
@@ -1405,6 +1416,8 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
int i;
int ret;
u64 avg;
+ char runtime_lat[32];
+ char avg_lat[32], max_lat[32];
char max_lat_start[32], max_lat_end[32];

if (!work_list->nb_atoms)
@@ -1430,14 +1443,17 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
printf(" ");

avg = work_list->total_lat / work_list->nb_atoms;
+ scnprintf_latency_unit(runtime_lat, sizeof(runtime_lat), work_list->total_runtime);
+ scnprintf_latency_unit(avg_lat, sizeof(avg_lat), avg);
+ scnprintf_latency_unit(max_lat, sizeof(max_lat), work_list->max_lat);
timestamp__scnprintf_usec(work_list->max_lat_start, max_lat_start, sizeof(max_lat_start));
timestamp__scnprintf_usec(work_list->max_lat_end, max_lat_end, sizeof(max_lat_end));

- printf("|%11.3f ms |%9" PRIu64 " | avg:%8.3f ms | max:%8.3f ms | max start: %12s s | max end: %12s s\n",
- (double)work_list->total_runtime / NSEC_PER_MSEC,
- work_list->nb_atoms, (double)avg / NSEC_PER_MSEC,
- (double)work_list->max_lat / NSEC_PER_MSEC,
- max_lat_start, max_lat_end);
+ printf("|%14s |%9" PRIu64 " | avg:%11s | max:%11s | max start: %12s s | max end: %12s s\n",
+ runtime_lat,
+ work_list->nb_atoms, avg_lat, max_lat,
+ max_lat_start, max_lat_end);
+
}

static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -3599,6 +3615,7 @@ static int perf_sched__lat(struct perf_sched *sched)
{
int rc = -1;
struct rb_node *next;
+ char total_runtime_str[32];

setup_pager();

@@ -3612,7 +3629,7 @@ static int perf_sched__lat(struct perf_sched *sched)
perf_sched__sort_lat(sched);

printf("\n -------------------------------------------------------------------------------------------------------------------------------------------\n");
- printf(" Task | Runtime ms | Count | Avg delay ms | Max delay ms | Max delay start | Max delay end |\n");
+ printf(" Task | Runtime | Count | Avg delay | Max delay | Max delay start | Max delay end |\n");
printf(" -------------------------------------------------------------------------------------------------------------------------------------------\n");

next = rb_first_cached(&sched->sorted_atom_root);
@@ -3626,8 +3643,9 @@ static int perf_sched__lat(struct perf_sched *sched)
}

printf(" -----------------------------------------------------------------------------------------------------------------\n");
- printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
- (double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count);
+ scnprintf_latency_unit(total_runtime_str, sizeof(total_runtime_str), sched->all_runtime);
+ printf(" TOTAL: |%14s |%9" PRIu64 " |\n",
+ total_runtime_str, sched->all_count);

printf(" ---------------------------------------------------\n");

--
2.54.0