mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] tracing: Print a signed histogram key as signed
@ 2026-09-17  4:59 Donggeun Yoo
  0 siblings, 0 replies; only message in thread
From: Donggeun Yoo @ 2026-09-17  4:59 UTC (permalink / raw)
  To: rostedt, mhiramat
  Cc: mathieu.desnoyers, namhyung, zanussi, linux-trace-kernel,
	linux-kernel, donggeunyoo.kernel

A histogram sorts its rows by the key named in sort=, and for a key over a
signed event field it sorts them signed: create_tracing_map_fields() picks
the comparison function with

	else
		cmp_fn = tracing_map_cmp_num(field->size,
					     field->is_signed);

hist_trigger_print_key() does not look at is_signed at all. Every numeric
key is printed with %llu, so a sorted histogram over a signed field comes
out looking unsorted. syscalls/sys_exit_lseek carries "long ret", which
SYSCALL_FIELD() marks signed and which is negative on every error:

  # echo 'hist:keys=ret:sort=ret' > events/syscalls/sys_exit_lseek/trigger
  # echo 1 > events/syscalls/sys_exit_lseek/enable
  # (five lseek(2) calls returning -ESPIPE, -EINVAL, -EBADF, 0 and 100)
  # cat events/syscalls/sys_exit_lseek/hist

  { ret: 18446744073709551587 } hitcount:          1
  { ret: 18446744073709551594 } hitcount:          1
  { ret: 18446744073709551607 } hitcount:          1
  { ret:          0 } hitcount:          1
  { ret:        100 } hitcount:          1

The rows are in ascending order and the numbers are not, because the three
leading ones are -29, -22 and -9 rendered as their two's complement.

Take the rendering from the same place the sort order comes from: the event
field when the key has one, and the hist_field itself when it does not. The
same histogram then reads

  { ret:        -29 } hitcount:          1
  { ret:        -22 } hitcount:          1
  { ret:         -9 } hitcount:          1
  { ret:          0 } hitcount:          1
  { ret:        100 } hitcount:          1

A ".buckets" key stays unsigned here, and not because it is right.
hist_field_bucket() divides as unsigned, so the group holding S64_MAX also
holds S64_MIN, reported at

  https://lore.kernel.org/all/20260914054614.82A9B1F000FF@smtp.kernel.org/

Printing that group signed would name a range that does not contain
S64_MIN, so the grouping has to be fixed with it, in a patch of its own.

Fixes: 7ef224d1d0e3 ("tracing: Add 'hist' event trigger command")
Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
---
Independent of "tracing: Clamp the printed end of a histogram bucket at
U64_MAX",
https://lore.kernel.org/all/20260914132346.2234731-1-donggeunyoo.kernel@gmail.com/,
which is still pending in the same function: the two touch different
branches of it, apply in either order, and give the same tree.

QEMU x86_64, v7.3-rc3-82-g238650ef6c7c, one kernel per arm and one
initramfs.  Sixteen histograms, over syscalls/sys_exit_lseek and over a
user_events record carrying an s64, a u64, an s32 and a u32 - one per arm
of hist_trigger_print_key() that a key can reach.

  changed   keys=ret:sort=ret
            keys=sv,uv,s32v
            keys=sv:sort=sv
            keys=sv+0
  same      keys=uv+0
            keys=u32v,common_pid
            keys=sv.hex
            keys=sv.log2
            keys=ret.buckets=10
            keys=sv.buckets=10
            keys=sv.buckets=8
            keys=s32v.buckets=10
            keys=sv.buckets=10:sort=sv
            keys=uv.buckets=10
            keys=u32v.buckets=10
            keys=common_timestamp.buckets

Every histogram that changes is a key over something signed; the other
twelve are byte-identical.  The values written cover zero, both signs, and
both ends of the 64-bit range.

 kernel/trace/trace_events_hist.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 8af97fd4ee2d..b128fee0af24 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -279,6 +279,14 @@ static u64 hist_field_pstring(struct hist_field *hist_field,
 	return (u64)(unsigned long)*addr;
 }
 
+static bool hist_field_is_signed(struct hist_field *hist_field)
+{
+	if (hist_field->field)
+		return hist_field->field->is_signed;
+
+	return hist_field->is_signed;
+}
+
 static u64 hist_field_log2(struct hist_field *hist_field,
 			   struct tracing_map_elt *elt,
 			   struct trace_buffer *buffer,
@@ -5568,7 +5576,11 @@ static void hist_trigger_print_key(struct seq_file *m,
 				   (char *)(key + key_field->offset));
 		} else {
 			uval = *(u64 *)(key + key_field->offset);
-			seq_printf(m, "%s: %10llu", field_name, uval);
+			if (hist_field_is_signed(key_field))
+				seq_printf(m, "%s: %10lld", field_name,
+					   (s64)uval);
+			else
+				seq_printf(m, "%s: %10llu", field_name, uval);
 		}
 	}
 
-- 
2.53.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-17  4:59 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17  4:59 [PATCH] tracing: Print a signed histogram key as signed Donggeun Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®