Skip to content

Commit 5172a77

Browse files
committed
Merge tag 'trace-tools-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull tracing tools updates from Steven Rostedt: - Introduce enum timerlat_tracing_mode Now that BPF based sampling has been added to timerlat, add an enum to represent which mode timerlat is running in - Add action on timelat threshold feature A new option, --on-threshold, is added, taking an argument that further specifies the action. Actions added in this patch are: - trace[,file=<filename>]: Saves tracefs buffer, optionally taking a filename - signal,num=<sig>,pid=<pid>: Sends signal to process. "parent" might be specified instead of number to send signal to parent process - shell,command=<command>: Execute shell command - Allow resuming tracing in timerlat bpf rtla-timerlat BPF program uses a global variable stored in a .bss section to store whether tracing has been stopped. Map it to allow it to resume tracing after it has been stopped - Add continue action to timerlat Introduce option to resume tracing after a latency threshold overflow. The option is implemented as an action named "continue" - Add action on end feature to timerlat Implement actions on end next to actions on threshold. A new option, --on-end is added, parallel to --on-threshold. Instead of being executed whenever a latency threshold is reached, it is executed at the end of the measurement - Have rtla tests check output with grep Add argument to the check command in the test suite that takes a regular expression that the output of rtla command is checked against. This allows testing for specific information in rtla output in addition to checking the return value - Add tests for timerlat actions - Update the documentation for the new features * tag 'trace-tools-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rtla/tests: Test timerlat -P option using actions rtla/tests: Add grep checks for base test cases Documentation/rtla: Add actions feature rtla/tests: Limit duration to maximum of 10s rtla/tests: Add tests for actions rtla/tests: Check rtla output with grep rtla/timerlat: Add action on end feature rtla/timerlat: Add continue action rtla/timerlat_bpf: Allow resuming tracing rtla/timerlat: Add action on threshold feature rtla/timerlat: Introduce enum timerlat_tracing_mode
2 parents c6439bf + a80db1f commit 5172a77

File tree

16 files changed

+732
-124
lines changed

16 files changed

+732
-124
lines changed

Documentation/tools/rtla/common_timerlat_options.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,67 @@
5555
Set timerlat to run without workload, waiting for the user to dispatch a per-cpu
5656
task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd.
5757
See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code.
58+
59+
**--on-threshold** *action*
60+
61+
Defines an action to be executed when tracing is stopped on a latency threshold
62+
specified by **-i/--irq** or **-T/--thread**.
63+
64+
Multiple --on-threshold actions may be specified, and they will be executed in
65+
the order they are provided. If any action fails, subsequent actions in the list
66+
will not be executed.
67+
68+
Supported actions are:
69+
70+
- *trace[,file=<filename>]*
71+
72+
Saves trace output, optionally taking a filename. Alternative to -t/--trace.
73+
Note that nlike -t/--trace, specifying this multiple times will result in
74+
the trace being saved multiple times.
75+
76+
- *signal,num=<sig>,pid=<pid>*
77+
78+
Sends signal to process. "parent" might be specified in place of pid to target
79+
the parent process of rtla.
80+
81+
- *shell,command=<command>*
82+
83+
Execute shell command.
84+
85+
- *continue*
86+
87+
Continue tracing after actions are executed instead of stopping.
88+
89+
Example:
90+
91+
$ rtla timerlat -T 20 --on-threshold trace
92+
--on-threshold shell,command="grep ipi_send timerlat_trace.txt"
93+
--on-threshold signal,num=2,pid=parent
94+
95+
This will save a trace with the default filename "timerlat_trace.txt", print its
96+
lines that contain the text "ipi_send" on standard output, and send signal 2
97+
(SIGINT) to the parent process.
98+
99+
Performance Considerations:
100+
101+
For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF
102+
support and RT priority. Note that due to implementational limitations, actions
103+
might be delayed up to one second after tracing is stopped if BPF mode is not
104+
available or disabled.
105+
106+
**--on-end** *action*
107+
108+
Defines an action to be executed at the end of **rtla timerlat** tracing.
109+
110+
Multiple --on-end actions can be specified, and they will be executed in the order
111+
they are provided. If any action fails, subsequent actions in the list will not be
112+
executed.
113+
114+
See the documentation for **--on-threshold** for the list of supported actions, with
115+
the exception that *continue* has no effect.
116+
117+
Example:
118+
119+
$ rtla timerlat -d 5s --on-end trace
120+
121+
This runs rtla timerlat with default options and save trace output at the end.

tools/tracing/rtla/src/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
rtla-y += trace.o
22
rtla-y += utils.o
3+
rtla-y += actions.o
34
rtla-y += osnoise.o
45
rtla-y += osnoise_top.o
56
rtla-y += osnoise_hist.o

tools/tracing/rtla/src/actions.c

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <signal.h>
5+
#include <unistd.h>
6+
7+
#include "actions.h"
8+
#include "trace.h"
9+
#include "utils.h"
10+
11+
/*
12+
* actions_init - initialize struct actions
13+
*/
14+
void
15+
actions_init(struct actions *self)
16+
{
17+
self->size = action_default_size;
18+
self->list = calloc(self->size, sizeof(struct action));
19+
self->len = 0;
20+
self->continue_flag = false;
21+
22+
memset(&self->present, 0, sizeof(self->present));
23+
24+
/* This has to be set by the user */
25+
self->trace_output_inst = NULL;
26+
}
27+
28+
/*
29+
* actions_destroy - destroy struct actions
30+
*/
31+
void
32+
actions_destroy(struct actions *self)
33+
{
34+
/* Free any action-specific data */
35+
for (struct action *action = self->list; action < self->list + self->len; action++) {
36+
if (action->type == ACTION_SHELL)
37+
free(action->command);
38+
if (action->type == ACTION_TRACE_OUTPUT)
39+
free(action->trace_output);
40+
}
41+
42+
/* Free action list */
43+
free(self->list);
44+
}
45+
46+
/*
47+
* actions_new - Get pointer to new action
48+
*/
49+
static struct action *
50+
actions_new(struct actions *self)
51+
{
52+
if (self->size >= self->len) {
53+
self->size *= 2;
54+
self->list = realloc(self->list, self->size * sizeof(struct action));
55+
}
56+
57+
return &self->list[self->len++];
58+
}
59+
60+
/*
61+
* actions_add_trace_output - add an action to output trace
62+
*/
63+
int
64+
actions_add_trace_output(struct actions *self, const char *trace_output)
65+
{
66+
struct action *action = actions_new(self);
67+
68+
self->present[ACTION_TRACE_OUTPUT] = true;
69+
action->type = ACTION_TRACE_OUTPUT;
70+
action->trace_output = calloc(strlen(trace_output) + 1, sizeof(char));
71+
if (!action->trace_output)
72+
return -1;
73+
strcpy(action->trace_output, trace_output);
74+
75+
return 0;
76+
}
77+
78+
/*
79+
* actions_add_trace_output - add an action to send signal to a process
80+
*/
81+
int
82+
actions_add_signal(struct actions *self, int signal, int pid)
83+
{
84+
struct action *action = actions_new(self);
85+
86+
self->present[ACTION_SIGNAL] = true;
87+
action->type = ACTION_SIGNAL;
88+
action->signal = signal;
89+
action->pid = pid;
90+
91+
return 0;
92+
}
93+
94+
/*
95+
* actions_add_shell - add an action to execute a shell command
96+
*/
97+
int
98+
actions_add_shell(struct actions *self, const char *command)
99+
{
100+
struct action *action = actions_new(self);
101+
102+
self->present[ACTION_SHELL] = true;
103+
action->type = ACTION_SHELL;
104+
action->command = calloc(strlen(command) + 1, sizeof(char));
105+
if (!action->command)
106+
return -1;
107+
strcpy(action->command, command);
108+
109+
return 0;
110+
}
111+
112+
/*
113+
* actions_add_continue - add an action to resume measurement
114+
*/
115+
int
116+
actions_add_continue(struct actions *self)
117+
{
118+
struct action *action = actions_new(self);
119+
120+
self->present[ACTION_CONTINUE] = true;
121+
action->type = ACTION_CONTINUE;
122+
123+
return 0;
124+
}
125+
126+
/*
127+
* actions_parse - add an action based on text specification
128+
*/
129+
int
130+
actions_parse(struct actions *self, const char *trigger)
131+
{
132+
enum action_type type = ACTION_NONE;
133+
char *token;
134+
char trigger_c[strlen(trigger)];
135+
136+
/* For ACTION_SIGNAL */
137+
int signal = 0, pid = 0;
138+
139+
/* For ACTION_TRACE_OUTPUT */
140+
char *trace_output;
141+
142+
strcpy(trigger_c, trigger);
143+
token = strtok(trigger_c, ",");
144+
145+
if (strcmp(token, "trace") == 0)
146+
type = ACTION_TRACE_OUTPUT;
147+
else if (strcmp(token, "signal") == 0)
148+
type = ACTION_SIGNAL;
149+
else if (strcmp(token, "shell") == 0)
150+
type = ACTION_SHELL;
151+
else if (strcmp(token, "continue") == 0)
152+
type = ACTION_CONTINUE;
153+
else
154+
/* Invalid trigger type */
155+
return -1;
156+
157+
token = strtok(NULL, ",");
158+
159+
switch (type) {
160+
case ACTION_TRACE_OUTPUT:
161+
/* Takes no argument */
162+
if (token == NULL)
163+
trace_output = "timerlat_trace.txt";
164+
else {
165+
if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
166+
trace_output = token + 5;
167+
} else {
168+
/* Invalid argument */
169+
return -1;
170+
}
171+
172+
token = strtok(NULL, ",");
173+
if (token != NULL)
174+
/* Only one argument allowed */
175+
return -1;
176+
}
177+
return actions_add_trace_output(self, trace_output);
178+
case ACTION_SIGNAL:
179+
/* Takes two arguments, num (signal) and pid */
180+
while (token != NULL) {
181+
if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
182+
signal = atoi(token + 4);
183+
} else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
184+
if (strncmp(token + 4, "parent", 7) == 0)
185+
pid = -1;
186+
else
187+
pid = atoi(token + 4);
188+
} else {
189+
/* Invalid argument */
190+
return -1;
191+
}
192+
193+
token = strtok(NULL, ",");
194+
}
195+
196+
if (!signal || !pid)
197+
/* Missing argument */
198+
return -1;
199+
200+
return actions_add_signal(self, signal, pid);
201+
case ACTION_SHELL:
202+
if (token == NULL)
203+
return -1;
204+
if (strlen(token) > 8 && strncmp(token, "command=", 8) == 0)
205+
return actions_add_shell(self, token + 8);
206+
return -1;
207+
case ACTION_CONTINUE:
208+
/* Takes no argument */
209+
if (token != NULL)
210+
return -1;
211+
return actions_add_continue(self);
212+
default:
213+
return -1;
214+
}
215+
}
216+
217+
/*
218+
* actions_perform - perform all actions
219+
*/
220+
int
221+
actions_perform(struct actions *self)
222+
{
223+
int pid, retval;
224+
const struct action *action;
225+
226+
for (action = self->list; action < self->list + self->len; action++) {
227+
switch (action->type) {
228+
case ACTION_TRACE_OUTPUT:
229+
retval = save_trace_to_file(self->trace_output_inst, action->trace_output);
230+
if (retval) {
231+
err_msg("Error saving trace\n");
232+
return retval;
233+
}
234+
break;
235+
case ACTION_SIGNAL:
236+
if (action->pid == -1)
237+
pid = getppid();
238+
else
239+
pid = action->pid;
240+
retval = kill(pid, action->signal);
241+
if (retval) {
242+
err_msg("Error sending signal\n");
243+
return retval;
244+
}
245+
break;
246+
case ACTION_SHELL:
247+
retval = system(action->command);
248+
if (retval)
249+
return retval;
250+
break;
251+
case ACTION_CONTINUE:
252+
self->continue_flag = true;
253+
return 0;
254+
default:
255+
break;
256+
}
257+
}
258+
259+
return 0;
260+
}

tools/tracing/rtla/src/actions.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <tracefs.h>
3+
#include <stdbool.h>
4+
5+
enum action_type {
6+
ACTION_NONE = 0,
7+
ACTION_TRACE_OUTPUT,
8+
ACTION_SIGNAL,
9+
ACTION_SHELL,
10+
ACTION_CONTINUE,
11+
ACTION_FIELD_N
12+
};
13+
14+
struct action {
15+
enum action_type type;
16+
union {
17+
struct {
18+
/* For ACTION_TRACE_OUTPUT */
19+
char *trace_output;
20+
};
21+
struct {
22+
/* For ACTION_SIGNAL */
23+
int signal;
24+
int pid;
25+
};
26+
struct {
27+
/* For ACTION_SHELL */
28+
char *command;
29+
};
30+
};
31+
};
32+
33+
static const int action_default_size = 8;
34+
35+
struct actions {
36+
struct action *list;
37+
int len, size;
38+
bool present[ACTION_FIELD_N];
39+
bool continue_flag;
40+
41+
/* External dependencies */
42+
struct tracefs_instance *trace_output_inst;
43+
};
44+
45+
void actions_init(struct actions *self);
46+
void actions_destroy(struct actions *self);
47+
int actions_add_trace_output(struct actions *self, const char *trace_output);
48+
int actions_add_signal(struct actions *self, int signal, int pid);
49+
int actions_add_shell(struct actions *self, const char *command);
50+
int actions_add_continue(struct actions *self);
51+
int actions_parse(struct actions *self, const char *trigger);
52+
int actions_perform(struct actions *self);

0 commit comments

Comments
 (0)