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.

perf record --off-cpu: Add --off-cpu-thresh option

Specify the threshold for dumping offcpu samples with --off-cpu-thresh,
the unit is milliseconds. Default value is 500ms.

Example:

perf record --off-cpu --off-cpu-thresh 824

The example above collects direct off-cpu samples where the off-cpu time
is longer than 824ms.

Committer testing:

After commenting out the end off-cpu dump to have just the ones that are
added right after the task is scheduled back, and using a threshould of
1000ms, we see some periods (the 5th column, just before "offcpu-time"
in the 'perf script' output) that are over 1000.000.000 nanoseconds:

root@number:~# perf record --off-cpu --off-cpu-thresh 10000
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 3.902 MB perf.data (34335 samples) ]
root@number:~# perf script
<SNIP>
Isolated Web Co 59932 [028] 63839.594437: 1000049427 offcpu-time:
7fe63c7976c2 __syscall_cancel_arch_end+0x0 (/usr/lib64/libc.so.6)
7fe63c78c04c __futex_abstimed_wait_common+0x7c (/usr/lib64/libc.so.6)
7fe63c78e928 pthread_cond_timedwait@@GLIBC_2.3.2+0x178 (/usr/lib64/libc.so.6)
5599974a9fe7 mozilla::detail::ConditionVariableImpl::wait_for(mozilla::detail::MutexImpl&, mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> const&)+0xe7 (/usr/lib64/fir>
100000000 [unknown] ([unknown])

swapper 0 [025] 63839.594459: 195724 cycles:P: ffffffffac328270 read_tsc+0x0 ([kernel.kallsyms])
Isolated Web Co 59932 [010] 63839.594466: 1000055278 offcpu-time:
7fe63c7976c2 __syscall_cancel_arch_end+0x0 (/usr/lib64/libc.so.6)
7fe63c78ba24 __syscall_cancel+0x14 (/usr/lib64/libc.so.6)
7fe63c804c4e __poll+0x1e (/usr/lib64/libc.so.6)
7fe633b0d1b8 PollWrapper(_GPollFD*, unsigned int, int) [clone .lto_priv.0]+0xf8 (/usr/lib64/firefox/libxul.so)
10000002c [unknown] ([unknown])

swapper 0 [027] 63839.594475: 134433 cycles:P: ffffffffad4c45d9 irqentry_enter+0x19 ([kernel.kallsyms])
swapper 0 [028] 63839.594499: 215838 cycles:P: ffffffffac39199a switch_mm_irqs_off+0x10a ([kernel.kallsyms])
MediaPD~oder #1 1407676 [027] 63839.594514: 134433 cycles:P: 7f982ef5e69f dct_IV(int*, int, int*)+0x24f (/usr/lib64/libfdk-aac.so.2.0.0)
swapper 0 [024] 63839.594524: 267411 cycles:P: ffffffffad4c6ee6 poll_idle+0x56 ([kernel.kallsyms])
MediaSu~sor #75 1093827 [026] 63839.594555: 332652 cycles:P: 55be753ad030 moz_xmalloc+0x200 (/usr/lib64/firefox/firefox)
swapper 0 [027] 63839.594616: 160548 cycles:P: ffffffffad144840 menu_select+0x570 ([kernel.kallsyms])
Isolated Web Co 14019 [027] 63839.595120: 1000050178 offcpu-time:
7fc9537cc6c2 __syscall_cancel_arch_end+0x0 (/usr/lib64/libc.so.6)
7fc9537c104c __futex_abstimed_wait_common+0x7c (/usr/lib64/libc.so.6)
7fc9537c3928 pthread_cond_timedwait@@GLIBC_2.3.2+0x178 (/usr/lib64/libc.so.6)
7fc95372a3c8 pt_TimedWait+0xb8 (/usr/lib64/libnspr4.so)
7fc95372a8d8 PR_WaitCondVar+0x68 (/usr/lib64/libnspr4.so)
7fc94afb1f7c WatchdogMain(void*)+0xac (/usr/lib64/firefox/libxul.so)
7fc947498660 [unknown] ([unknown])
7fc9535fce88 [unknown] ([unknown])
7fc94b620e60 WatchdogManager::~WatchdogManager()+0x0 (/usr/lib64/firefox/libxul.so)
fff8548387f8b48 [unknown] ([unknown])

swapper 0 [003] 63839.595712: 212948 cycles:P: ffffffffacd5b865 acpi_os_read_port+0x55 ([kernel.kallsyms])
<SNIP>

Suggested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Suggested-by: Ian Rogers <irogers@google.com>
Suggested-by: Namhyung Kim <namhyung@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Gautam Menghani <gautam@linux.ibm.com>
Tested-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20241108204137.2444151-2-howardchu95@gmail.com
Link: https://lore.kernel.org/r/20250501022809.449767-10-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Howard Chu and committed by
Arnaldo Carvalho de Melo
9557c000 74069a01

+41 -1
+9
tools/perf/Documentation/perf-record.txt
··· 842 842 only, as of now. So the applications built without the frame 843 843 pointer might see bogus addresses. 844 844 845 + off-cpu profiling consists two types of samples: direct samples, which 846 + share the same behavior as regular samples, and the accumulated 847 + samples, stored in BPF stack trace map, presented after all the regular 848 + samples. 849 + 850 + --off-cpu-thresh:: 851 + Once a task's off-cpu time reaches this threshold (in milliseconds), it 852 + generates a direct off-cpu sample. The default is 500ms. 853 + 845 854 --setup-filter=<action>:: 846 855 Prepare BPF filter to be used by regular users. The action should be 847 856 either "pin" or "unpin". The filter can be used after it's pinned.
+26
tools/perf/builtin-record.c
··· 3162 3162 return ret; 3163 3163 } 3164 3164 3165 + static int record__parse_off_cpu_thresh(const struct option *opt, 3166 + const char *str, 3167 + int unset __maybe_unused) 3168 + { 3169 + struct record_opts *opts = opt->value; 3170 + char *endptr; 3171 + u64 off_cpu_thresh_ms; 3172 + 3173 + if (!str) 3174 + return -EINVAL; 3175 + 3176 + off_cpu_thresh_ms = strtoull(str, &endptr, 10); 3177 + 3178 + /* the threshold isn't string "0", yet strtoull() returns 0, parsing failed */ 3179 + if (*endptr || (off_cpu_thresh_ms == 0 && strcmp(str, "0"))) 3180 + return -EINVAL; 3181 + else 3182 + opts->off_cpu_thresh_ns = off_cpu_thresh_ms * NSEC_PER_MSEC; 3183 + 3184 + return 0; 3185 + } 3186 + 3165 3187 void __weak arch__add_leaf_frame_record_opts(struct record_opts *opts __maybe_unused) 3166 3188 { 3167 3189 } ··· 3377 3355 .ctl_fd = -1, 3378 3356 .ctl_fd_ack = -1, 3379 3357 .synth = PERF_SYNTH_ALL, 3358 + .off_cpu_thresh_ns = OFFCPU_THRESH, 3380 3359 }, 3381 3360 }; 3382 3361 ··· 3605 3582 OPT_BOOLEAN(0, "off-cpu", &record.off_cpu, "Enable off-cpu analysis"), 3606 3583 OPT_STRING(0, "setup-filter", &record.filter_action, "pin|unpin", 3607 3584 "BPF filter action"), 3585 + OPT_CALLBACK(0, "off-cpu-thresh", &record.opts, "ms", 3586 + "Dump off-cpu samples if off-cpu time exceeds this threshold (in milliseconds). (Default: 500ms)", 3587 + record__parse_off_cpu_thresh), 3608 3588 OPT_END() 3609 3589 }; 3610 3590
+3
tools/perf/util/bpf_off_cpu.c
··· 14 14 #include "util/strlist.h" 15 15 #include <bpf/bpf.h> 16 16 #include <internal/xyarray.h> 17 + #include <linux/time64.h> 17 18 18 19 #include "bpf_skel/off_cpu.skel.h" 19 20 ··· 292 291 bpf_map_update_elem(fd, &cgrp->id, &val, BPF_ANY); 293 292 } 294 293 } 294 + 295 + skel->bss->offcpu_thresh_ns = opts->off_cpu_thresh_ns; 295 296 296 297 err = off_cpu_bpf__attach(skel); 297 298 if (err) {
+1 -1
tools/perf/util/bpf_skel/off_cpu.bpf.c
··· 124 124 125 125 int perf_subsys_id = -1; 126 126 127 - __u64 offcpu_thresh_ns = 500000000ull; 127 + __u64 offcpu_thresh_ns; 128 128 129 129 /* 130 130 * Old kernel used to call it task_struct->state and now it's '__state'.
+1
tools/perf/util/off_cpu.h
··· 16 16 PERF_SAMPLE_PERIOD | PERF_SAMPLE_RAW | \ 17 17 PERF_SAMPLE_CGROUP) 18 18 19 + #define OFFCPU_THRESH 500000000ULL 19 20 20 21 #ifdef HAVE_BPF_SKEL 21 22 int off_cpu_prepare(struct evlist *evlist, struct target *target,
+1
tools/perf/util/record.h
··· 80 80 int synth; 81 81 int threads_spec; 82 82 const char *threads_user_spec; 83 + u64 off_cpu_thresh_ns; 83 84 }; 84 85 85 86 extern const char * const *record_usage;