Skip to content

Commit 582a1ef

Browse files
committed
Merge tag 'trace-rtla-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull RTLA updates from Steven Rostedt: - Remove unused function declarations Some functions were removed in recent code consolidation 6.18, but their prototypes were not removed from headers. Remove them. - Set stop threshold after enabling instances Prefer recording samples without stopping on them on the start of tracing to stopping on samples that are never recorded. This fixes flakiness of some RTLA tests and unifies behavior of sample collection between tracefs mode and BPF mode. - Consolidate usage help message implementation RTLA tools (osnoise-top, osnoise-hist, timerlat-top, timerlat-hist) each implement usage help individually. Move common logic between them into a new function to reduce code duplication. - Add BPF actions feature Add option --bpf-action to attach a BPF program (passed as filename of its ELF representation) to be executed via BPF tail call at latency threshold. - Consolidate command line option parsing Each RTLA tool implements the parsing of command line options individually. Now that we have a common structure for parameters, unify the parsing of those options common among all four tools into one function. - De-duplicate cgroup common code Two functions in utils.c, setting cgroup for comm and setting cgroup for pid, duplicate code for constructing the cgroup path. Extract it to a new helper function. - String and error handling fixes and cleanups There were several instances of unsafe string and error handling that could cause invalid memory access; fix them. Also, remove a few unused headers, update .gitignore, and deduplicate code. * tag 'trace-rtla-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (30 commits) rtla: Fix parse_cpu_set() bug introduced by strtoi() rtla: Fix parse_cpu_set() return value documentation rtla: Ensure null termination after read operations in utils.c rtla: Make stop_tracing variable volatile rtla: Add generated output files to gitignore rtla: Fix NULL pointer dereference in actions_parse rtla: Remove unused headers rtla: Remove redundant memset after calloc rtla: Use standard exit codes for result enum rtla: Replace atoi() with a robust strtoi() rtla: Introduce for_each_action() helper tools/rtla: Deduplicate cgroup path opening code tools/rtla: Consolidate -H/--house-keeping option parsing tools/rtla: Consolidate -P/--priority option parsing tools/rtla: Consolidate -e/--event option parsing tools/rtla: Consolidate -d/--duration option parsing tools/rtla: Consolidate -D/--debug option parsing tools/rtla: Consolidate -C/--cgroup option parsing tools/rtla: Consolidate -c/--cpus option parsing tools/rtla: Add common_parse_options() ...
2 parents f75c03a + 6ea8a20 commit 582a1ef

26 files changed

Lines changed: 507 additions & 356 deletions

Documentation/tools/rtla/common_timerlat_options.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,22 @@
6464

6565
Set timerlat to run without workload, waiting for the user to dispatch a per-cpu
6666
task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd.
67-
See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code.
67+
See linux/tools/rtla/example/timerlat_load.py for an example of user-load code.
68+
69+
**--bpf-action** *bpf-program*
70+
71+
Loads a BPF program from an ELF file and executes it when a latency threshold is exceeded.
72+
73+
The BPF program must be a valid ELF file loadable with libbpf. The program must contain
74+
a function named ``action_handler``, stored in an ELF section with the ``tp_`` prefix.
75+
The prefix is used by libbpf to set BPF program type to BPF_PROG_TYPE_TRACEPOINT.
76+
77+
The program receives a ``struct trace_event_raw_timerlat_sample`` parameter
78+
containing timerlat sample data.
79+
80+
An example is provided in ``tools/tracing/rtla/example/timerlat_bpf_action.c``.
81+
This example demonstrates how to create a BPF program that prints latency information using
82+
bpf_trace_printk() when a threshold is exceeded.
83+
84+
**Note**: BPF actions require BPF support to be available. If BPF is not available
85+
or disabled, the tool falls back to tracefs mode and BPF actions are not supported.

tools/tracing/rtla/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ fixdep
55
feature
66
FEATURE-DUMP
77
*.skel.h
8+
custom_filename.txt
9+
osnoise_irq_noise_hist.txt
10+
osnoise_trace.txt
11+
timerlat_trace.txt

tools/tracing/rtla/Makefile

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,21 @@ src/timerlat.bpf.o: src/timerlat.bpf.c
7373

7474
src/timerlat.skel.h: src/timerlat.bpf.o
7575
$(QUIET_GENSKEL)$(SYSTEM_BPFTOOL) gen skeleton $< > $@
76+
77+
example/timerlat_bpf_action.o: example/timerlat_bpf_action.c
78+
$(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -c $(filter %.c,$^) -o $@
79+
80+
tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c
81+
$(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -c $(filter %.c,$^) -o $@
7682
else
7783
src/timerlat.skel.h:
7884
$(Q)echo '/* BPF skeleton is disabled */' > src/timerlat.skel.h
85+
86+
example/timerlat_bpf_action.o: example/timerlat_bpf_action.c
87+
$(Q)echo "BPF skeleton support is disabled, skipping example/timerlat_bpf_action.o"
88+
89+
tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c
90+
$(Q)echo "BPF skeleton support is disabled, skipping tests/bpf/bpf_action_map.o"
7991
endif
8092

8193
$(RTLA): $(RTLA_IN)
@@ -96,7 +108,8 @@ clean: doc_clean fixdep-clean
96108
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
97109
$(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-*
98110
$(Q)rm -rf feature
99-
$(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h
100-
check: $(RTLA)
101-
RTLA=$(RTLA) prove -o -f tests/
111+
$(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h example/timerlat_bpf_action.o
112+
check: $(RTLA) tests/bpf/bpf_action_map.o
113+
RTLA=$(RTLA) BPFTOOL=$(SYSTEM_BPFTOOL) prove -o -f -v tests/
114+
examples: example/timerlat_bpf_action.o
102115
.PHONY: FORCE clean check
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_tracing.h>
4+
5+
char LICENSE[] SEC("license") = "GPL";
6+
7+
struct trace_event_raw_timerlat_sample {
8+
unsigned long long timer_latency;
9+
} __attribute__((preserve_access_index));
10+
11+
SEC("tp/timerlat_action")
12+
int action_handler(struct trace_event_raw_timerlat_sample *tp_args)
13+
{
14+
bpf_printk("Latency: %lld\n", tp_args->timer_latency);
15+
return 0;
16+
}
File renamed without changes.

tools/tracing/rtla/src/actions.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ actions_init(struct actions *self)
1919
self->len = 0;
2020
self->continue_flag = false;
2121

22-
memset(&self->present, 0, sizeof(self->present));
23-
2422
/* This has to be set by the user */
2523
self->trace_output_inst = NULL;
2624
}
@@ -32,7 +30,9 @@ void
3230
actions_destroy(struct actions *self)
3331
{
3432
/* Free any action-specific data */
35-
for (struct action *action = self->list; action < self->list + self->len; action++) {
33+
struct action *action;
34+
35+
for_each_action(self, action) {
3636
if (action->type == ACTION_SHELL)
3737
free(action->command);
3838
if (action->type == ACTION_TRACE_OUTPUT)
@@ -141,6 +141,8 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
141141

142142
strcpy(trigger_c, trigger);
143143
token = strtok(trigger_c, ",");
144+
if (!token)
145+
return -1;
144146

145147
if (strcmp(token, "trace") == 0)
146148
type = ACTION_TRACE_OUTPUT;
@@ -179,12 +181,13 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
179181
/* Takes two arguments, num (signal) and pid */
180182
while (token != NULL) {
181183
if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
182-
signal = atoi(token + 4);
184+
if (strtoi(token + 4, &signal))
185+
return -1;
183186
} else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
184187
if (strncmp(token + 4, "parent", 7) == 0)
185188
pid = -1;
186-
else
187-
pid = atoi(token + 4);
189+
else if (strtoi(token + 4, &pid))
190+
return -1;
188191
} else {
189192
/* Invalid argument */
190193
return -1;
@@ -223,7 +226,7 @@ actions_perform(struct actions *self)
223226
int pid, retval;
224227
const struct action *action;
225228

226-
for (action = self->list; action < self->list + self->len; action++) {
229+
for_each_action(self, action) {
227230
switch (action->type) {
228231
case ACTION_TRACE_OUTPUT:
229232
retval = save_trace_to_file(self->trace_output_inst, action->trace_output);

tools/tracing/rtla/src/actions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ struct actions {
4242
struct tracefs_instance *trace_output_inst;
4343
};
4444

45+
#define for_each_action(actions, action) \
46+
for ((action) = (actions)->list; \
47+
(action) < (actions)->list + (actions)->len; \
48+
(action)++)
49+
4550
void actions_init(struct actions *self);
4651
void actions_destroy(struct actions *self);
4752
int actions_add_trace_output(struct actions *self, const char *trace_output);

tools/tracing/rtla/src/common.c

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
#include <pthread.h>
55
#include <signal.h>
66
#include <stdlib.h>
7+
#include <string.h>
78
#include <unistd.h>
9+
#include <getopt.h>
810
#include "common.h"
911

1012
struct trace_instance *trace_inst;
11-
int stop_tracing;
13+
volatile int stop_tracing;
1214

1315
static void stop_trace(int sig)
1416
{
@@ -37,6 +39,84 @@ static void set_signals(struct common_params *params)
3739
}
3840
}
3941

42+
/*
43+
* common_parse_options - parse common command line options
44+
*
45+
* @argc: argument count
46+
* @argv: argument vector
47+
* @common: common parameters structure
48+
*
49+
* Parse command line options that are common to all rtla tools.
50+
*
51+
* Returns: non zero if a common option was parsed, or 0
52+
* if the option should be handled by tool-specific parsing.
53+
*/
54+
int common_parse_options(int argc, char **argv, struct common_params *common)
55+
{
56+
struct trace_events *tevent;
57+
int saved_state = optind;
58+
int c;
59+
60+
static struct option long_options[] = {
61+
{"cpus", required_argument, 0, 'c'},
62+
{"cgroup", optional_argument, 0, 'C'},
63+
{"debug", no_argument, 0, 'D'},
64+
{"duration", required_argument, 0, 'd'},
65+
{"event", required_argument, 0, 'e'},
66+
{"house-keeping", required_argument, 0, 'H'},
67+
{"priority", required_argument, 0, 'P'},
68+
{0, 0, 0, 0}
69+
};
70+
71+
opterr = 0;
72+
c = getopt_long(argc, argv, "c:C::Dd:e:H:P:", long_options, NULL);
73+
opterr = 1;
74+
75+
switch (c) {
76+
case 'c':
77+
if (parse_cpu_set(optarg, &common->monitored_cpus))
78+
fatal("Invalid -c cpu list");
79+
common->cpus = optarg;
80+
break;
81+
case 'C':
82+
common->cgroup = 1;
83+
common->cgroup_name = parse_optional_arg(argc, argv);
84+
break;
85+
case 'D':
86+
config_debug = 1;
87+
break;
88+
case 'd':
89+
common->duration = parse_seconds_duration(optarg);
90+
if (!common->duration)
91+
fatal("Invalid -d duration");
92+
break;
93+
case 'e':
94+
tevent = trace_event_alloc(optarg);
95+
if (!tevent)
96+
fatal("Error alloc trace event");
97+
98+
if (common->events)
99+
tevent->next = common->events;
100+
common->events = tevent;
101+
break;
102+
case 'H':
103+
common->hk_cpus = 1;
104+
if (parse_cpu_set(optarg, &common->hk_cpu_set))
105+
fatal("Error parsing house keeping CPUs");
106+
break;
107+
case 'P':
108+
if (parse_prio(optarg, &common->sched_param) == -1)
109+
fatal("Invalid -P priority");
110+
common->set_sched = 1;
111+
break;
112+
default:
113+
optind = saved_state;
114+
return 0;
115+
}
116+
117+
return c;
118+
}
119+
40120
/*
41121
* common_apply_config - apply common configs to the initialized tool
42122
*/
@@ -348,3 +428,61 @@ int hist_main_loop(struct osnoise_tool *tool)
348428

349429
return retval;
350430
}
431+
432+
int osn_set_stop(struct osnoise_tool *tool)
433+
{
434+
struct common_params *params = tool->params;
435+
int retval;
436+
437+
retval = osnoise_set_stop_us(tool->context, params->stop_us);
438+
if (retval) {
439+
err_msg("Failed to set stop us\n");
440+
return retval;
441+
}
442+
443+
retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us);
444+
if (retval) {
445+
err_msg("Failed to set stop total us\n");
446+
return retval;
447+
}
448+
449+
return 0;
450+
}
451+
452+
static void print_msg_array(const char * const *msgs)
453+
{
454+
if (!msgs)
455+
return;
456+
457+
for (int i = 0; msgs[i]; i++)
458+
fprintf(stderr, "%s\n", msgs[i]);
459+
}
460+
461+
/*
462+
* common_usage - print complete usage information
463+
*/
464+
void common_usage(const char *tool, const char *mode,
465+
const char *desc, const char * const *start_msgs, const char * const *opt_msgs)
466+
{
467+
static const char * const common_options[] = {
468+
" -h/--help: print this menu",
469+
NULL
470+
};
471+
fprintf(stderr, "rtla %s", tool);
472+
if (strcmp(mode, ""))
473+
fprintf(stderr, " %s", mode);
474+
fprintf(stderr, ": %s (version %s)\n\n", desc, VERSION);
475+
fprintf(stderr, " usage: [rtla] %s ", tool);
476+
477+
if (strcmp(mode, "top") == 0)
478+
fprintf(stderr, "[top] [-h] ");
479+
else
480+
fprintf(stderr, "%s [-h] ", mode);
481+
482+
print_msg_array(start_msgs);
483+
fprintf(stderr, "\n");
484+
print_msg_array(common_options);
485+
print_msg_array(opt_msgs);
486+
487+
exit(EXIT_SUCCESS);
488+
}

tools/tracing/rtla/src/common.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct osnoise_context {
5454
};
5555

5656
extern struct trace_instance *trace_inst;
57-
extern int stop_tracing;
57+
extern volatile int stop_tracing;
5858

5959
struct hist_params {
6060
char no_irq;
@@ -152,7 +152,15 @@ void osnoise_destroy_tool(struct osnoise_tool *top);
152152
struct osnoise_tool *osnoise_init_tool(char *tool_name);
153153
struct osnoise_tool *osnoise_init_trace_tool(const char *tracer);
154154
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record);
155+
int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
156+
int osnoise_set_stop_total_us(struct osnoise_context *context,
157+
long long stop_total_us);
155158

159+
int common_parse_options(int argc, char **argv, struct common_params *common);
156160
int common_apply_config(struct osnoise_tool *tool, struct common_params *params);
157161
int top_main_loop(struct osnoise_tool *tool);
158162
int hist_main_loop(struct osnoise_tool *tool);
163+
int osn_set_stop(struct osnoise_tool *tool);
164+
165+
void common_usage(const char *tool, const char *mode,
166+
const char *desc, const char * const *start_msgs, const char * const *opt_msgs);

tools/tracing/rtla/src/osnoise.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,18 +1128,6 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params)
11281128
goto out_err;
11291129
}
11301130

1131-
retval = osnoise_set_stop_us(tool->context, params->common.stop_us);
1132-
if (retval) {
1133-
err_msg("Failed to set stop us\n");
1134-
goto out_err;
1135-
}
1136-
1137-
retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us);
1138-
if (retval) {
1139-
err_msg("Failed to set stop total us\n");
1140-
goto out_err;
1141-
}
1142-
11431131
retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
11441132
if (retval) {
11451133
err_msg("Failed to set tracing_thresh\n");
@@ -1184,9 +1172,12 @@ int osnoise_enable(struct osnoise_tool *tool)
11841172
debug_msg("Error cleaning up the buffer");
11851173
return retval;
11861174
}
1187-
11881175
}
11891176

1177+
retval = osn_set_stop(tool);
1178+
if (retval)
1179+
return retval;
1180+
11901181
return 0;
11911182
}
11921183

0 commit comments

Comments
 (0)