Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

trace/trace_event_perf: remove duplicate samples on the first tracepoint event

When a tracepoint event is created with attr.freq = 1,
'hwc->period_left' is not initialized correctly. As a result,
in the perf_swevent_overflow() function, when the first time the event occurs,
it calculates the event overflow and the perf_swevent_set_period() returns 3,
this leads to the event are recorded for three duplicate times.

Step to reproduce:
1. Enable the tracepoint event & starting tracing
$ echo 1 > /sys/kernel/tracing/events/module/module_free
$ echo 1 > /sys/kernel/tracing/tracing_on

2. Record with perf
$ perf record -a --strict-freq -F 1 -e "module:module_free"

3. Trigger module_free event.
$ modprobe -i sunrpc
$ modprobe -r sunrpc

Result:
- Trace pipe result:
$ cat trace_pipe
modprobe-174509 [003] ..... 6504.868896: module_free: sunrpc

- perf sample:
modprobe 174509 [003] 6504.868980: module:module_free: sunrpc
modprobe 174509 [003] 6504.868980: module:module_free: sunrpc
modprobe 174509 [003] 6504.868980: module:module_free: sunrpc

By setting period_left via perf_swevent_set_period() as other sw_event did,
This problem could be solved.

After patch:
- Trace pipe result:
$ cat trace_pipe
modprobe 1153096 [068] 613468.867774: module:module_free: xfs

- perf sample
modprobe 1153096 [068] 613468.867794: module:module_free: xfs

Link: https://lore.kernel.org/20240913021347.595330-1-yeoreum.yun@arm.com
Fixes: bd2b5b12849a ("perf_counter: More aggressive frequency adjustment")
Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Levi Yun and committed by
Steven Rostedt (Google)
afe5960d 0850e1bc

+6
+6
kernel/trace/trace_event_perf.c
··· 352 352 int perf_trace_add(struct perf_event *p_event, int flags) 353 353 { 354 354 struct trace_event_call *tp_event = p_event->tp_event; 355 + struct hw_perf_event *hwc = &p_event->hw; 355 356 356 357 if (!(flags & PERF_EF_START)) 357 358 p_event->hw.state = PERF_HES_STOPPED; 359 + 360 + if (is_sampling_event(p_event)) { 361 + hwc->last_period = hwc->sample_period; 362 + perf_swevent_set_period(p_event); 363 + } 358 364 359 365 /* 360 366 * If TRACE_REG_PERF_ADD returns false; no custom action was performed