tools/rtla: Add remaining support for osnoise actions

The basic functionality came with the consolidation; now hook up the
command line options, and add documentation and tests.

Cc: John Kacur <jkacur@redhat.com>
Cc: Costa Shulyupin <costa.shul@redhat.com>
Link: https://lore.kernel.org/20250907022325.243930-8-crwood@redhat.com
Reviewed-by: Tomas Glozar  <tglozar@redhat.com>
Signed-off-by: Crystal Wood <crwood@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
Crystal Wood 2025-09-06 21:23:25 -05:00 committed by Steven Rostedt (Google)
parent 3cd6b18d10
commit 05b7e10687
15 changed files with 168 additions and 74 deletions

View File

@ -53,6 +53,67 @@
**--trace-buffer-size** *kB* **--trace-buffer-size** *kB*
Set the per-cpu trace buffer size in kB for the tracing output. Set the per-cpu trace buffer size in kB for the tracing output.
**--on-threshold** *action*
Defines an action to be executed when tracing is stopped on a latency threshold
specified by |threshold|.
Multiple --on-threshold actions may be specified, and they will be executed in
the order they are provided. If any action fails, subsequent actions in the list
will not be executed.
Supported actions are:
- *trace[,file=<filename>]*
Saves trace output, optionally taking a filename. Alternative to -t/--trace.
Note that nlike -t/--trace, specifying this multiple times will result in
the trace being saved multiple times.
- *signal,num=<sig>,pid=<pid>*
Sends signal to process. "parent" might be specified in place of pid to target
the parent process of rtla.
- *shell,command=<command>*
Execute shell command.
- *continue*
Continue tracing after actions are executed instead of stopping.
Example:
$ rtla |tool| |thresharg| 20 --on-threshold trace
--on-threshold shell,command="grep ipi_send |tracer|\_trace.txt"
--on-threshold signal,num=2,pid=parent
This will save a trace with the default filename "|tracer|\_trace.txt", print its
lines that contain the text "ipi_send" on standard output, and send signal 2
(SIGINT) to the parent process.
Performance Considerations:
|actionsperf|
**--on-end** *action*
Defines an action to be executed at the end of tracing.
Multiple --on-end actions can be specified, and they will be executed in the order
they are provided. If any action fails, subsequent actions in the list will not be
executed.
See the documentation for **--on-threshold** for the list of supported actions, with
the exception that *continue* has no effect.
Example:
$ rtla |tool| -d 5s --on-end trace
This runs rtla with the default options, and saves trace output at the end.
**-h**, **--help** **-h**, **--help**
Print help menu. Print help menu.

View File

@ -1,3 +1,11 @@
.. |threshold| replace:: **-a/--auto**, **-s/--stop**, or **-S/--stop-total**
.. |thresharg| replace:: -s
.. |tracer| replace:: osnoise
.. |actionsperf| replace::
Due to implementational limitations, actions might be delayed
up to one second after tracing is stopped.
**-a**, **--auto** *us* **-a**, **--auto** *us*
Set the automatic trace mode. This mode sets some commonly used options Set the automatic trace mode. This mode sets some commonly used options

View File

@ -1,3 +1,13 @@
.. |threshold| replace:: **-a/--auto**, **-i/--irq**, or **-T/--thread**
.. |thresharg| replace:: -T
.. |tracer| replace:: timerlat
.. |actionsperf| replace::
For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF
support and RT priority. Note that due to implementational limitations, actions
might be delayed up to one second after tracing is stopped if BPF mode is not
available or disabled.
**-a**, **--auto** *us* **-a**, **--auto** *us*
Set the automatic trace mode. This mode sets some commonly used options Set the automatic trace mode. This mode sets some commonly used options
@ -55,67 +65,3 @@
Set timerlat to run without workload, waiting for the user to dispatch a per-cpu Set timerlat to run without workload, waiting for the user to dispatch a per-cpu
task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd. task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd.
See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code. See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code.
**--on-threshold** *action*
Defines an action to be executed when tracing is stopped on a latency threshold
specified by **-i/--irq** or **-T/--thread**.
Multiple --on-threshold actions may be specified, and they will be executed in
the order they are provided. If any action fails, subsequent actions in the list
will not be executed.
Supported actions are:
- *trace[,file=<filename>]*
Saves trace output, optionally taking a filename. Alternative to -t/--trace.
Note that nlike -t/--trace, specifying this multiple times will result in
the trace being saved multiple times.
- *signal,num=<sig>,pid=<pid>*
Sends signal to process. "parent" might be specified in place of pid to target
the parent process of rtla.
- *shell,command=<command>*
Execute shell command.
- *continue*
Continue tracing after actions are executed instead of stopping.
Example:
$ rtla timerlat -T 20 --on-threshold trace
--on-threshold shell,command="grep ipi_send timerlat_trace.txt"
--on-threshold signal,num=2,pid=parent
This will save a trace with the default filename "timerlat_trace.txt", print its
lines that contain the text "ipi_send" on standard output, and send signal 2
(SIGINT) to the parent process.
Performance Considerations:
For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF
support and RT priority. Note that due to implementational limitations, actions
might be delayed up to one second after tracing is stopped if BPF mode is not
available or disabled.
**--on-end** *action*
Defines an action to be executed at the end of **rtla timerlat** tracing.
Multiple --on-end actions can be specified, and they will be executed in the order
they are provided. If any action fails, subsequent actions in the list will not be
executed.
See the documentation for **--on-threshold** for the list of supported actions, with
the exception that *continue* has no effect.
Example:
$ rtla timerlat -d 5s --on-end trace
This runs rtla timerlat with default options and save trace output at the end.

View File

@ -1,5 +1,7 @@
.. SPDX-License-Identifier: GPL-2.0 .. SPDX-License-Identifier: GPL-2.0
.. |tool| replace:: hwnoise
============ ============
rtla-hwnoise rtla-hwnoise
============ ============

View File

@ -1,3 +1,5 @@
.. |tool| replace:: osnoise hist
=================== ===================
rtla-osnoise-hist rtla-osnoise-hist
=================== ===================

View File

@ -1,3 +1,5 @@
.. |tool| replace:: osnoise top
=================== ===================
rtla-osnoise-top rtla-osnoise-top
=================== ===================

View File

@ -1,3 +1,5 @@
.. |tool| replace:: timerlat hist
===================== =====================
rtla-timerlat-hist rtla-timerlat-hist
===================== =====================

View File

@ -1,3 +1,5 @@
.. |tool| replace:: timerlat top
==================== ====================
rtla-timerlat-top rtla-timerlat-top
==================== ====================

View File

@ -127,17 +127,17 @@ actions_add_continue(struct actions *self)
* actions_parse - add an action based on text specification * actions_parse - add an action based on text specification
*/ */
int int
actions_parse(struct actions *self, const char *trigger) actions_parse(struct actions *self, const char *trigger, const char *tracefn)
{ {
enum action_type type = ACTION_NONE; enum action_type type = ACTION_NONE;
char *token; const char *token;
char trigger_c[strlen(trigger)]; char trigger_c[strlen(trigger)];
/* For ACTION_SIGNAL */ /* For ACTION_SIGNAL */
int signal = 0, pid = 0; int signal = 0, pid = 0;
/* For ACTION_TRACE_OUTPUT */ /* For ACTION_TRACE_OUTPUT */
char *trace_output; const char *trace_output;
strcpy(trigger_c, trigger); strcpy(trigger_c, trigger);
token = strtok(trigger_c, ","); token = strtok(trigger_c, ",");
@ -160,7 +160,7 @@ actions_parse(struct actions *self, const char *trigger)
case ACTION_TRACE_OUTPUT: case ACTION_TRACE_OUTPUT:
/* Takes no argument */ /* Takes no argument */
if (token == NULL) if (token == NULL)
trace_output = "timerlat_trace.txt"; trace_output = tracefn;
else { else {
if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) { if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
trace_output = token + 5; trace_output = token + 5;

View File

@ -48,5 +48,5 @@ int actions_add_trace_output(struct actions *self, const char *trace_output);
int actions_add_signal(struct actions *self, int signal, int pid); int actions_add_signal(struct actions *self, int signal, int pid);
int actions_add_shell(struct actions *self, const char *command); int actions_add_shell(struct actions *self, const char *command);
int actions_add_continue(struct actions *self); int actions_add_continue(struct actions *self);
int actions_parse(struct actions *self, const char *trigger); int actions_parse(struct actions *self, const char *trigger, const char *tracefn);
int actions_perform(struct actions *self); int actions_perform(struct actions *self);

View File

@ -462,6 +462,8 @@ static void osnoise_hist_usage(char *usage)
" in nanoseconds", " in nanoseconds",
" --warm-up: let the workload run for s seconds before collecting data", " --warm-up: let the workload run for s seconds before collecting data",
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB", " --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
" --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed",
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
NULL, NULL,
}; };
@ -531,6 +533,8 @@ static struct common_params
{"filter", required_argument, 0, '5'}, {"filter", required_argument, 0, '5'},
{"warm-up", required_argument, 0, '6'}, {"warm-up", required_argument, 0, '6'},
{"trace-buffer-size", required_argument, 0, '7'}, {"trace-buffer-size", required_argument, 0, '7'},
{"on-threshold", required_argument, 0, '8'},
{"on-end", required_argument, 0, '9'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -692,6 +696,22 @@ static struct common_params
case '7': case '7':
params->common.buffer_size = get_llong_from_str(optarg); params->common.buffer_size = get_llong_from_str(optarg);
break; break;
case '8':
retval = actions_parse(&params->common.threshold_actions, optarg,
"osnoise_trace.txt");
if (retval) {
err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
case '9':
retval = actions_parse(&params->common.end_actions, optarg,
"osnoise_trace.txt");
if (retval) {
err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
default: default:
osnoise_hist_usage("Invalid option"); osnoise_hist_usage("Invalid option");
} }

View File

@ -291,6 +291,8 @@ static void osnoise_top_usage(struct osnoise_params *params, char *usage)
" in nanoseconds", " in nanoseconds",
" --warm-up s: let the workload run for s seconds before collecting data", " --warm-up s: let the workload run for s seconds before collecting data",
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB", " --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
" --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed",
" --on-end: define action to be executed at measurement end, multiple are allowed",
NULL, NULL,
}; };
@ -371,6 +373,8 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
{"filter", required_argument, 0, '1'}, {"filter", required_argument, 0, '1'},
{"warm-up", required_argument, 0, '2'}, {"warm-up", required_argument, 0, '2'},
{"trace-buffer-size", required_argument, 0, '3'}, {"trace-buffer-size", required_argument, 0, '3'},
{"on-threshold", required_argument, 0, '4'},
{"on-end", required_argument, 0, '5'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -511,6 +515,22 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
case '3': case '3':
params->common.buffer_size = get_llong_from_str(optarg); params->common.buffer_size = get_llong_from_str(optarg);
break; break;
case '4':
retval = actions_parse(&params->common.threshold_actions, optarg,
"osnoise_trace.txt");
if (retval) {
err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
case '5':
retval = actions_parse(&params->common.end_actions, optarg,
"osnoise_trace.txt");
if (retval) {
err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
default: default:
osnoise_top_usage(params, "Invalid option"); osnoise_top_usage(params, "Invalid option");
} }

View File

@ -1047,14 +1047,16 @@ static struct common_params
params->deepest_idle_state = get_llong_from_str(optarg); params->deepest_idle_state = get_llong_from_str(optarg);
break; break;
case '\5': case '\5':
retval = actions_parse(&params->common.threshold_actions, optarg); retval = actions_parse(&params->common.threshold_actions, optarg,
"timerlat_trace.txt");
if (retval) { if (retval) {
err_msg("Invalid action %s\n", optarg); err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
break; break;
case '\6': case '\6':
retval = actions_parse(&params->common.end_actions, optarg); retval = actions_parse(&params->common.end_actions, optarg,
"timerlat_trace.txt");
if (retval) { if (retval) {
err_msg("Invalid action %s\n", optarg); err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@ -783,14 +783,16 @@ static struct common_params
params->deepest_idle_state = get_llong_from_str(optarg); params->deepest_idle_state = get_llong_from_str(optarg);
break; break;
case '9': case '9':
retval = actions_parse(&params->common.threshold_actions, optarg); retval = actions_parse(&params->common.threshold_actions, optarg,
"timerlat_trace.txt");
if (retval) { if (retval) {
err_msg("Invalid action %s\n", optarg); err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
break; break;
case '\1': case '\1':
retval = actions_parse(&params->common.end_actions, optarg); retval = actions_parse(&params->common.end_actions, optarg,
"timerlat_trace.txt");
if (retval) { if (retval) {
err_msg("Invalid action %s\n", optarg); err_msg("Invalid action %s\n", optarg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@ -8,7 +8,8 @@ set_timeout 2m
check "verify help page" \ check "verify help page" \
"osnoise --help" 0 "osnoise version" "osnoise --help" 0 "osnoise version"
check "verify the --priority/-P param" \ check "verify the --priority/-P param" \
"osnoise top -P F:1 -c 0 -r 900000 -d 10s -q" "osnoise top -P F:1 -c 0 -r 900000 -d 10s -q -S 1 --on-threshold shell,command=\"tests/scripts/check-priority.sh osnoise/ SCHED_FIFO 1\"" \
2 "Priorities are set correctly"
check "verify the --stop/-s param" \ check "verify the --stop/-s param" \
"osnoise top -s 30 -T 1" 2 "osnoise hit stop tracing" "osnoise top -s 30 -T 1" 2 "osnoise hit stop tracing"
check "verify the --trace param" \ check "verify the --trace param" \
@ -22,4 +23,28 @@ check "verify the --entries/-E param" \
check_with_osnoise_options "apply default period" \ check_with_osnoise_options "apply default period" \
"osnoise hist -s 1" 2 period_us=600000000 "osnoise hist -s 1" 2 period_us=600000000
# Actions tests
check "trace output through -t with custom filename" \
"osnoise hist -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
check "trace output through --on-threshold trace" \
"osnoise hist -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$"
check "trace output through --on-threshold trace with custom filename" \
"osnoise hist -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
check "exec command" \
"osnoise hist -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"
check "multiple actions" \
"osnoise hist -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$"
check "hist stop at failed action" \
"osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$"
check "top stop at failed action" \
"timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh"
check "hist with continue" \
"osnoise hist -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
check "top with continue" \
"osnoise top -q -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
check "hist with trace output at end" \
"osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$"
check "top with trace output at end" \
"osnoise top -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$"
test_end test_end