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

rtla/timerlat: Introduce enum timerlat_tracing_mode

After the introduction of BPF-based sample collection, rtla-timerlat
effectively runs in one of three modes:

- Pure BPF mode, with tracefs only being used to set up the timerlat
tracer. Sample processing and stop on threshold are handled by BPF.

- tracefs mode. BPF is unsupported or kernel is lacking the necessary
trace event (osnoise:timerlat_sample). Stop on theshold is handled by
timerlat tracer stopping tracing in all instances.

- BPF/tracefs mixed mode - BPF is used for sample collection for top or
histogram, tracefs is used for trace output and/or auto-analysis. Stop
on threshold is handled both through BPF program, which stops sample
collection for top/histogram and wakes up rtla, and by timerlat
tracer, which stops tracing for trace output/auto-analysis instances.

Add enum timerlat_tracing_mode, with three values:

- TRACING_MODE_BPF
- TRACING_MODE_TRACEFS
- TRACING_MODE_MIXED

Those represent the modes described above. A field of this type is added
to struct timerlat_params, named "mode", replacing the no_bpf variable.
params->mode is set in timerlat_{top,hist}_parse_args to
TRACING_MODE_BPF or TRACING_MODE_MIXED based on whether trace output
and/or auto-analysis is requested. timerlat_{top,hist}_main then checks
if BPF is not unavailable or disabled, in that case, it sets
params->mode to TRACING_MODE_TRACEFS.

A condition is added to timerlat_apply_config that skips setting
timerlat tracer thresholds if params->mode is TRACING_MODE_BPF (those
are unnecessary, since they only turn off tracing, which is already
turned off in that case, since BPF is used to collect samples).

Cc: John Kacur <jkacur@redhat.com>
Cc: Luis Goncalves <lgoncalv@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Chang Yin <cyin@redhat.com>
Cc: Costa Shulyupin <costa.shul@redhat.com>
Cc: Crystal Wood <crwood@redhat.com>
Cc: Gabriele Monaco <gmonaco@redhat.com>
Link: https://lore.kernel.org/20250626123405.1496931-2-tglozar@redhat.com
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Tomas Glozar and committed by
Steven Rostedt (Google)
8b6cbcac d7b8f8e2

+104 -60
+15 -9
tools/tracing/rtla/src/timerlat.c
··· 40 40 CPU_SET(i, &params->monitored_cpus); 41 41 } 42 42 43 - retval = osnoise_set_stop_us(tool->context, params->stop_us); 44 - if (retval) { 45 - err_msg("Failed to set stop us\n"); 46 - goto out_err; 47 - } 43 + if (params->mode != TRACING_MODE_BPF) { 44 + /* 45 + * In tracefs and mixed mode, timerlat tracer handles stopping 46 + * on threshold 47 + */ 48 + retval = osnoise_set_stop_us(tool->context, params->stop_us); 49 + if (retval) { 50 + err_msg("Failed to set stop us\n"); 51 + goto out_err; 52 + } 48 53 49 - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 50 - if (retval) { 51 - err_msg("Failed to set stop total us\n"); 52 - goto out_err; 54 + retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 55 + if (retval) { 56 + err_msg("Failed to set stop total us\n"); 57 + goto out_err; 58 + } 53 59 } 54 60 55 61
+18
tools/tracing/rtla/src/timerlat.h
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include "osnoise.h" 3 3 4 + /* 5 + * Define timerlat tracing mode. 6 + * 7 + * There are three tracing modes: 8 + * - tracefs-only, used when BPF is unavailable. 9 + * - BPF-only, used when BPF is available and neither trace saving nor 10 + * auto-analysis are enabled. 11 + * - mixed mode, used when BPF is available and either trace saving or 12 + * auto-analysis is enabled (which rely on sample collection through 13 + * tracefs). 14 + */ 15 + enum timerlat_tracing_mode { 16 + TRACING_MODE_BPF, 17 + TRACING_MODE_TRACEFS, 18 + TRACING_MODE_MIXED, 19 + }; 20 + 4 21 struct timerlat_params { 5 22 /* Common params */ 6 23 char *cpus; ··· 47 30 cpu_set_t hk_cpu_set; 48 31 struct sched_attr sched_param; 49 32 struct trace_events *events; 33 + enum timerlat_tracing_mode mode; 50 34 union { 51 35 struct { 52 36 /* top only */
+30 -21
tools/tracing/rtla/src/timerlat_hist.c
··· 802 802 params->bucket_size = 1; 803 803 params->entries = 256; 804 804 805 + /* default to BPF mode */ 806 + params->mode = TRACING_MODE_BPF; 807 + 805 808 while (1) { 806 809 static struct option long_options[] = { 807 810 {"auto", required_argument, 0, 'a'}, ··· 1057 1054 if (params->kernel_workload && params->user_workload) 1058 1055 timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!"); 1059 1056 1057 + /* 1058 + * If auto-analysis or trace output is enabled, switch from BPF mode to 1059 + * mixed mode 1060 + */ 1061 + if (params->mode == TRACING_MODE_BPF && params->trace_output && !params->no_aa) 1062 + params->mode = TRACING_MODE_MIXED; 1063 + 1060 1064 return params; 1061 1065 } 1062 1066 ··· 1159 1149 pthread_t timerlat_u; 1160 1150 int retval; 1161 1151 int nr_cpus, i; 1162 - bool no_bpf = false; 1163 1152 1164 1153 params = timerlat_hist_parse_args(argc, argv); 1165 1154 if (!params) ··· 1170 1161 goto out_exit; 1171 1162 } 1172 1163 1173 - retval = timerlat_hist_apply_config(tool, params); 1174 - if (retval) { 1175 - err_msg("Could not apply config\n"); 1176 - goto out_free; 1177 - } 1178 - 1179 1164 trace = &tool->trace; 1180 1165 /* 1181 1166 * Save trace instance into global variable so that SIGINT can stop ··· 1178 1175 */ 1179 1176 hist_inst = trace; 1180 1177 1178 + /* 1179 + * Try to enable BPF, unless disabled explicitly. 1180 + * If BPF enablement fails, fall back to tracefs mode. 1181 + */ 1181 1182 if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 1182 1183 debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 1183 - no_bpf = true; 1184 - } 1185 - 1186 - if (!no_bpf && !tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 1184 + params->mode = TRACING_MODE_TRACEFS; 1185 + } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 1187 1186 debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 1188 - no_bpf = true; 1189 - } 1190 - 1191 - if (!no_bpf) { 1187 + params->mode = TRACING_MODE_TRACEFS; 1188 + } else { 1192 1189 retval = timerlat_bpf_init(params); 1193 1190 if (retval) { 1194 1191 debug_msg("Could not enable BPF\n"); 1195 - no_bpf = true; 1192 + params->mode = TRACING_MODE_TRACEFS; 1196 1193 } 1194 + } 1195 + 1196 + retval = timerlat_hist_apply_config(tool, params); 1197 + if (retval) { 1198 + err_msg("Could not apply config\n"); 1199 + goto out_free; 1197 1200 } 1198 1201 1199 1202 retval = enable_timerlat(trace); ··· 1329 1320 trace_instance_start(&record->trace); 1330 1321 if (!params->no_aa) 1331 1322 trace_instance_start(&aa->trace); 1332 - if (no_bpf) { 1323 + if (params->mode == TRACING_MODE_TRACEFS) { 1333 1324 trace_instance_start(trace); 1334 1325 } else { 1335 1326 retval = timerlat_bpf_attach(); ··· 1342 1333 tool->start_time = time(NULL); 1343 1334 timerlat_hist_set_signals(params); 1344 1335 1345 - if (no_bpf) { 1336 + if (params->mode == TRACING_MODE_TRACEFS) { 1346 1337 while (!stop_tracing) { 1347 1338 sleep(params->sleep_time); 1348 1339 ··· 1371 1362 } else 1372 1363 timerlat_bpf_wait(-1); 1373 1364 1374 - if (!no_bpf) { 1365 + if (params->mode != TRACING_MODE_TRACEFS) { 1375 1366 timerlat_bpf_detach(); 1376 1367 retval = timerlat_hist_bpf_pull_data(tool); 1377 1368 if (retval) { ··· 1418 1409 osnoise_destroy_tool(aa); 1419 1410 osnoise_destroy_tool(record); 1420 1411 osnoise_destroy_tool(tool); 1412 + if (params->mode != TRACING_MODE_TRACEFS) 1413 + timerlat_bpf_destroy(); 1421 1414 free(params); 1422 1415 free_cpu_idle_disable_states(); 1423 - if (!no_bpf) 1424 - timerlat_bpf_destroy(); 1425 1416 out_exit: 1426 1417 exit(return_value); 1427 1418 }
+41 -30
tools/tracing/rtla/src/timerlat_top.c
··· 559 559 /* display data in microseconds */ 560 560 params->output_divisor = 1000; 561 561 562 + /* default to BPF mode */ 563 + params->mode = TRACING_MODE_BPF; 564 + 562 565 while (1) { 563 566 static struct option long_options[] = { 564 567 {"auto", required_argument, 0, 'a'}, ··· 793 790 if (params->kernel_workload && params->user_workload) 794 791 timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!"); 795 792 793 + /* 794 + * If auto-analysis or trace output is enabled, switch from BPF mode to 795 + * mixed mode 796 + */ 797 + if (params->mode == TRACING_MODE_BPF && params->trace_output && !params->no_aa) 798 + params->mode = TRACING_MODE_MIXED; 799 + 796 800 return params; 797 801 } 798 802 ··· 1004 994 char *max_lat; 1005 995 int retval; 1006 996 int nr_cpus, i; 1007 - bool no_bpf = false; 1008 997 1009 998 params = timerlat_top_parse_args(argc, argv); 1010 999 if (!params) ··· 1015 1006 goto out_exit; 1016 1007 } 1017 1008 1009 + trace = &top->trace; 1010 + /* 1011 + * Save trace instance into global variable so that SIGINT can stop 1012 + * the timerlat tracer. 1013 + * Otherwise, rtla could loop indefinitely when overloaded. 1014 + */ 1015 + top_inst = trace; 1016 + 1017 + /* 1018 + * Try to enable BPF, unless disabled explicitly. 1019 + * If BPF enablement fails, fall back to tracefs mode. 1020 + */ 1021 + if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 1022 + debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 1023 + params->mode = TRACING_MODE_TRACEFS; 1024 + } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 1025 + debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 1026 + params->mode = TRACING_MODE_TRACEFS; 1027 + } else { 1028 + retval = timerlat_bpf_init(params); 1029 + if (retval) { 1030 + debug_msg("Could not enable BPF\n"); 1031 + params->mode = TRACING_MODE_TRACEFS; 1032 + } 1033 + } 1034 + 1018 1035 retval = timerlat_top_apply_config(top, params); 1019 1036 if (retval) { 1020 1037 err_msg("Could not apply config\n"); 1021 1038 goto out_free; 1022 - } 1023 - 1024 - trace = &top->trace; 1025 - /* 1026 - * Save trace instance into global variable so that SIGINT can stop 1027 - * the timerlat tracer. 1028 - * Otherwise, rtla could loop indefinitely when overloaded. 1029 - */ 1030 - top_inst = trace; 1031 - 1032 - if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { 1033 - debug_msg("RTLA_NO_BPF set, disabling BPF\n"); 1034 - no_bpf = true; 1035 - } 1036 - 1037 - if (!no_bpf && !tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { 1038 - debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); 1039 - no_bpf = true; 1040 - } 1041 - 1042 - if (!no_bpf) { 1043 - retval = timerlat_bpf_init(params); 1044 - if (retval) { 1045 - debug_msg("Could not enable BPF\n"); 1046 - no_bpf = true; 1047 - } 1048 1039 } 1049 1040 1050 1041 retval = enable_timerlat(trace); ··· 1175 1166 trace_instance_start(&record->trace); 1176 1167 if (!params->no_aa) 1177 1168 trace_instance_start(&aa->trace); 1178 - if (no_bpf) { 1169 + if (params->mode == TRACING_MODE_TRACEFS) { 1179 1170 trace_instance_start(trace); 1180 1171 } else { 1181 1172 retval = timerlat_bpf_attach(); ··· 1188 1179 top->start_time = time(NULL); 1189 1180 timerlat_top_set_signals(params); 1190 1181 1191 - if (no_bpf) 1182 + if (params->mode == TRACING_MODE_TRACEFS) 1192 1183 retval = timerlat_top_main_loop(top, record, params, &params_u); 1193 1184 else 1194 1185 retval = timerlat_top_bpf_main_loop(top, record, params, &params_u); ··· 1196 1187 if (retval) 1197 1188 goto out_top; 1198 1189 1199 - if (!no_bpf) 1190 + if (params->mode != TRACING_MODE_TRACEFS) 1200 1191 timerlat_bpf_detach(); 1201 1192 1202 1193 if (params->user_workload && !params_u.stopped_running) { ··· 1248 1239 osnoise_destroy_tool(aa); 1249 1240 osnoise_destroy_tool(record); 1250 1241 osnoise_destroy_tool(top); 1242 + if (params->mode != TRACING_MODE_TRACEFS) 1243 + timerlat_bpf_destroy(); 1251 1244 free(params); 1252 1245 free_cpu_idle_disable_states(); 1253 1246 out_exit: