summaryrefslogtreecommitdiff
path: root/tools/tracing/rtla/src
diff options
context:
space:
mode:
Diffstat (limited to 'tools/tracing/rtla/src')
-rw-r--r--tools/tracing/rtla/src/actions.c17
-rw-r--r--tools/tracing/rtla/src/actions.h5
-rw-r--r--tools/tracing/rtla/src/common.c140
-rw-r--r--tools/tracing/rtla/src/common.h10
-rw-r--r--tools/tracing/rtla/src/osnoise.c17
-rw-r--r--tools/tracing/rtla/src/osnoise.h8
-rw-r--r--tools/tracing/rtla/src/osnoise_hist.c76
-rw-r--r--tools/tracing/rtla/src/osnoise_top.c90
-rw-r--r--tools/tracing/rtla/src/timerlat.bpf.c25
-rw-r--r--tools/tracing/rtla/src/timerlat.c29
-rw-r--r--tools/tracing/rtla/src/timerlat.h2
-rw-r--r--tools/tracing/rtla/src/timerlat_bpf.c66
-rw-r--r--tools/tracing/rtla/src/timerlat_bpf.h7
-rw-r--r--tools/tracing/rtla/src/timerlat_hist.c80
-rw-r--r--tools/tracing/rtla/src/timerlat_top.c80
-rw-r--r--tools/tracing/rtla/src/trace.c1
-rw-r--r--tools/tracing/rtla/src/utils.c100
-rw-r--r--tools/tracing/rtla/src/utils.h10
18 files changed, 412 insertions, 351 deletions
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index 8945aee58d51..a42615011962 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -19,8 +19,6 @@ actions_init(struct actions *self)
self->len = 0;
self->continue_flag = false;
- memset(&self->present, 0, sizeof(self->present));
-
/* This has to be set by the user */
self->trace_output_inst = NULL;
}
@@ -32,7 +30,9 @@ void
actions_destroy(struct actions *self)
{
/* Free any action-specific data */
- for (struct action *action = self->list; action < self->list + self->len; action++) {
+ struct action *action;
+
+ for_each_action(self, action) {
if (action->type == ACTION_SHELL)
free(action->command);
if (action->type == ACTION_TRACE_OUTPUT)
@@ -141,6 +141,8 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
strcpy(trigger_c, trigger);
token = strtok(trigger_c, ",");
+ if (!token)
+ return -1;
if (strcmp(token, "trace") == 0)
type = ACTION_TRACE_OUTPUT;
@@ -179,12 +181,13 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
/* Takes two arguments, num (signal) and pid */
while (token != NULL) {
if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
- signal = atoi(token + 4);
+ if (strtoi(token + 4, &signal))
+ return -1;
} else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
if (strncmp(token + 4, "parent", 7) == 0)
pid = -1;
- else
- pid = atoi(token + 4);
+ else if (strtoi(token + 4, &pid))
+ return -1;
} else {
/* Invalid argument */
return -1;
@@ -223,7 +226,7 @@ actions_perform(struct actions *self)
int pid, retval;
const struct action *action;
- for (action = self->list; action < self->list + self->len; action++) {
+ for_each_action(self, action) {
switch (action->type) {
case ACTION_TRACE_OUTPUT:
retval = save_trace_to_file(self->trace_output_inst, action->trace_output);
diff --git a/tools/tracing/rtla/src/actions.h b/tools/tracing/rtla/src/actions.h
index a4f9b570775b..fb77069c972b 100644
--- a/tools/tracing/rtla/src/actions.h
+++ b/tools/tracing/rtla/src/actions.h
@@ -42,6 +42,11 @@ struct actions {
struct tracefs_instance *trace_output_inst;
};
+#define for_each_action(actions, action) \
+ for ((action) = (actions)->list; \
+ (action) < (actions)->list + (actions)->len; \
+ (action)++)
+
void actions_init(struct actions *self);
void actions_destroy(struct actions *self);
int actions_add_trace_output(struct actions *self, const char *trace_output);
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index b197037fc58b..ceff76a62a30 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -4,11 +4,13 @@
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+#include <getopt.h>
#include "common.h"
struct trace_instance *trace_inst;
-int stop_tracing;
+volatile int stop_tracing;
static void stop_trace(int sig)
{
@@ -38,6 +40,84 @@ static void set_signals(struct common_params *params)
}
/*
+ * common_parse_options - parse common command line options
+ *
+ * @argc: argument count
+ * @argv: argument vector
+ * @common: common parameters structure
+ *
+ * Parse command line options that are common to all rtla tools.
+ *
+ * Returns: non zero if a common option was parsed, or 0
+ * if the option should be handled by tool-specific parsing.
+ */
+int common_parse_options(int argc, char **argv, struct common_params *common)
+{
+ struct trace_events *tevent;
+ int saved_state = optind;
+ int c;
+
+ static struct option long_options[] = {
+ {"cpus", required_argument, 0, 'c'},
+ {"cgroup", optional_argument, 0, 'C'},
+ {"debug", no_argument, 0, 'D'},
+ {"duration", required_argument, 0, 'd'},
+ {"event", required_argument, 0, 'e'},
+ {"house-keeping", required_argument, 0, 'H'},
+ {"priority", required_argument, 0, 'P'},
+ {0, 0, 0, 0}
+ };
+
+ opterr = 0;
+ c = getopt_long(argc, argv, "c:C::Dd:e:H:P:", long_options, NULL);
+ opterr = 1;
+
+ switch (c) {
+ case 'c':
+ if (parse_cpu_set(optarg, &common->monitored_cpus))
+ fatal("Invalid -c cpu list");
+ common->cpus = optarg;
+ break;
+ case 'C':
+ common->cgroup = 1;
+ common->cgroup_name = parse_optional_arg(argc, argv);
+ break;
+ case 'D':
+ config_debug = 1;
+ break;
+ case 'd':
+ common->duration = parse_seconds_duration(optarg);
+ if (!common->duration)
+ fatal("Invalid -d duration");
+ break;
+ case 'e':
+ tevent = trace_event_alloc(optarg);
+ if (!tevent)
+ fatal("Error alloc trace event");
+
+ if (common->events)
+ tevent->next = common->events;
+ common->events = tevent;
+ break;
+ case 'H':
+ common->hk_cpus = 1;
+ if (parse_cpu_set(optarg, &common->hk_cpu_set))
+ fatal("Error parsing house keeping CPUs");
+ break;
+ case 'P':
+ if (parse_prio(optarg, &common->sched_param) == -1)
+ fatal("Invalid -P priority");
+ common->set_sched = 1;
+ break;
+ default:
+ optind = saved_state;
+ return 0;
+ }
+
+ return c;
+}
+
+/*
* common_apply_config - apply common configs to the initialized tool
*/
int
@@ -348,3 +428,61 @@ int hist_main_loop(struct osnoise_tool *tool)
return retval;
}
+
+int osn_set_stop(struct osnoise_tool *tool)
+{
+ struct common_params *params = tool->params;
+ int retval;
+
+ retval = osnoise_set_stop_us(tool->context, params->stop_us);
+ if (retval) {
+ err_msg("Failed to set stop us\n");
+ return retval;
+ }
+
+ retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us);
+ if (retval) {
+ err_msg("Failed to set stop total us\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void print_msg_array(const char * const *msgs)
+{
+ if (!msgs)
+ return;
+
+ for (int i = 0; msgs[i]; i++)
+ fprintf(stderr, "%s\n", msgs[i]);
+}
+
+/*
+ * common_usage - print complete usage information
+ */
+void common_usage(const char *tool, const char *mode,
+ const char *desc, const char * const *start_msgs, const char * const *opt_msgs)
+{
+ static const char * const common_options[] = {
+ " -h/--help: print this menu",
+ NULL
+ };
+ fprintf(stderr, "rtla %s", tool);
+ if (strcmp(mode, ""))
+ fprintf(stderr, " %s", mode);
+ fprintf(stderr, ": %s (version %s)\n\n", desc, VERSION);
+ fprintf(stderr, " usage: [rtla] %s ", tool);
+
+ if (strcmp(mode, "top") == 0)
+ fprintf(stderr, "[top] [-h] ");
+ else
+ fprintf(stderr, "%s [-h] ", mode);
+
+ print_msg_array(start_msgs);
+ fprintf(stderr, "\n");
+ print_msg_array(common_options);
+ print_msg_array(opt_msgs);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 9ec2b7632c37..7602c5593ef5 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -54,7 +54,7 @@ struct osnoise_context {
};
extern struct trace_instance *trace_inst;
-extern int stop_tracing;
+extern volatile int stop_tracing;
struct hist_params {
char no_irq;
@@ -152,7 +152,15 @@ void osnoise_destroy_tool(struct osnoise_tool *top);
struct osnoise_tool *osnoise_init_tool(char *tool_name);
struct osnoise_tool *osnoise_init_trace_tool(const char *tracer);
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record);
+int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
+int osnoise_set_stop_total_us(struct osnoise_context *context,
+ long long stop_total_us);
+int common_parse_options(int argc, char **argv, struct common_params *common);
int common_apply_config(struct osnoise_tool *tool, struct common_params *params);
int top_main_loop(struct osnoise_tool *tool);
int hist_main_loop(struct osnoise_tool *tool);
+int osn_set_stop(struct osnoise_tool *tool);
+
+void common_usage(const char *tool, const char *mode,
+ const char *desc, const char * const *start_msgs, const char * const *opt_msgs);
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 312c511fa004..945eb61efc46 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -1128,18 +1128,6 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params)
goto out_err;
}
- retval = osnoise_set_stop_us(tool->context, params->common.stop_us);
- if (retval) {
- err_msg("Failed to set stop us\n");
- goto out_err;
- }
-
- retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us);
- if (retval) {
- err_msg("Failed to set stop total us\n");
- goto out_err;
- }
-
retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
if (retval) {
err_msg("Failed to set tracing_thresh\n");
@@ -1184,9 +1172,12 @@ int osnoise_enable(struct osnoise_tool *tool)
debug_msg("Error cleaning up the buffer");
return retval;
}
-
}
+ retval = osn_set_stop(tool);
+ if (retval)
+ return retval;
+
return 0;
}
diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h
index 895687030c0b..168669aa7e0d 100644
--- a/tools/tracing/rtla/src/osnoise.h
+++ b/tools/tracing/rtla/src/osnoise.h
@@ -34,12 +34,7 @@ int osnoise_set_runtime_period(struct osnoise_context *context,
unsigned long long period);
void osnoise_restore_runtime_period(struct osnoise_context *context);
-int osnoise_set_stop_us(struct osnoise_context *context,
- long long stop_us);
void osnoise_restore_stop_us(struct osnoise_context *context);
-
-int osnoise_set_stop_total_us(struct osnoise_context *context,
- long long stop_total_us);
void osnoise_restore_stop_total_us(struct osnoise_context *context);
int osnoise_set_timerlat_period_us(struct osnoise_context *context,
@@ -58,8 +53,6 @@ int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff);
void osnoise_report_missed_events(struct osnoise_tool *tool);
int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params);
-int osnoise_hist_main(int argc, char *argv[]);
-int osnoise_top_main(int argc, char **argv);
int osnoise_enable(struct osnoise_tool *tool);
int osnoise_main(int argc, char **argv);
int hwnoise_main(int argc, char **argv);
@@ -68,4 +61,3 @@ extern struct tool_ops timerlat_top_ops, timerlat_hist_ops;
extern struct tool_ops osnoise_top_ops, osnoise_hist_ops;
int run_tool(struct tool_ops *ops, int argc, char *argv[]);
-int hist_main_loop(struct osnoise_tool *tool);
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index ff8c231e47c4..9d70ea34807f 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -9,7 +9,6 @@
#include <string.h>
#include <signal.h>
#include <unistd.h>
-#include <errno.h>
#include <stdio.h>
#include <time.h>
@@ -409,16 +408,15 @@ osnoise_print_stats(struct osnoise_tool *tool)
*/
static void osnoise_hist_usage(void)
{
- int i;
-
- static const char * const msg[] = {
- "",
- " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
+ static const char * const msg_start[] = {
+ "[-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
" [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
" [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
" [--no-index] [--with-zeros] [-C [cgroup_name]] [--warm-up]",
- "",
- " -h/--help: print this menu",
+ NULL,
+ };
+
+ static const char * const msg_opts[] = {
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
" -p/--period us: osnoise period in us",
" -r/--runtime us: osnoise runtime in us",
@@ -453,13 +451,8 @@ static void osnoise_hist_usage(void)
NULL,
};
- fprintf(stderr, "rtla osnoise hist: a per-cpu histogram of the OS noise (version %s)\n",
- VERSION);
-
- for (i = 0; msg[i]; i++)
- fprintf(stderr, "%s\n", msg[i]);
-
- exit(EXIT_SUCCESS);
+ common_usage("osnoise", "hist", "a per-cpu histogram of the OS noise",
+ msg_start, msg_opts);
}
/*
@@ -469,7 +462,6 @@ static struct common_params
*osnoise_hist_parse_args(int argc, char *argv[])
{
struct osnoise_params *params;
- struct trace_events *tevent;
int retval;
int c;
char *trace_output = NULL;
@@ -491,19 +483,12 @@ static struct common_params
{"auto", required_argument, 0, 'a'},
{"bucket-size", required_argument, 0, 'b'},
{"entries", required_argument, 0, 'E'},
- {"cpus", required_argument, 0, 'c'},
- {"cgroup", optional_argument, 0, 'C'},
- {"debug", no_argument, 0, 'D'},
- {"duration", required_argument, 0, 'd'},
- {"house-keeping", required_argument, 0, 'H'},
{"help", no_argument, 0, 'h'},
{"period", required_argument, 0, 'p'},
- {"priority", required_argument, 0, 'P'},
{"runtime", required_argument, 0, 'r'},
{"stop", required_argument, 0, 's'},
{"stop-total", required_argument, 0, 'S'},
{"trace", optional_argument, 0, 't'},
- {"event", required_argument, 0, 'e'},
{"threshold", required_argument, 0, 'T'},
{"no-header", no_argument, 0, '0'},
{"no-summary", no_argument, 0, '1'},
@@ -518,7 +503,10 @@ static struct common_params
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:",
+ if (common_parse_options(argc, argv, &params->common))
+ continue;
+
+ c = getopt_long(argc, argv, "a:b:E:hp:r:s:S:t::T:01234:5:6:7:",
long_options, NULL);
/* detect the end of the options. */
@@ -544,34 +532,6 @@ static struct common_params
params->common.hist.bucket_size >= 1000000)
fatal("Bucket size needs to be > 0 and <= 1000000");
break;
- case 'c':
- retval = parse_cpu_set(optarg, &params->common.monitored_cpus);
- if (retval)
- fatal("Invalid -c cpu list");
- params->common.cpus = optarg;
- break;
- case 'C':
- params->common.cgroup = 1;
- params->common.cgroup_name = parse_optional_arg(argc, argv);
- break;
- case 'D':
- config_debug = 1;
- break;
- case 'd':
- params->common.duration = parse_seconds_duration(optarg);
- if (!params->common.duration)
- fatal("Invalid -D duration");
- break;
- case 'e':
- tevent = trace_event_alloc(optarg);
- if (!tevent)
- fatal("Error alloc trace event");
-
- if (params->common.events)
- tevent->next = params->common.events;
-
- params->common.events = tevent;
- break;
case 'E':
params->common.hist.entries = get_llong_from_str(optarg);
if (params->common.hist.entries < 10 ||
@@ -582,23 +542,11 @@ static struct common_params
case '?':
osnoise_hist_usage();
break;
- case 'H':
- params->common.hk_cpus = 1;
- retval = parse_cpu_set(optarg, &params->common.hk_cpu_set);
- if (retval)
- fatal("Error parsing house keeping CPUs");
- break;
case 'p':
params->period = get_llong_from_str(optarg);
if (params->period > 10000000)
fatal("Period longer than 10 s");
break;
- case 'P':
- retval = parse_prio(optarg, &params->common.sched_param);
- if (retval == -1)
- fatal("Invalid -P priority");
- params->common.set_sched = 1;
- break;
case 'r':
params->runtime = get_llong_from_str(optarg);
if (params->runtime < 100)
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 04c699bdd736..d54d47947fb4 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -257,14 +257,16 @@ osnoise_print_stats(struct osnoise_tool *top)
*/
static void osnoise_top_usage(struct osnoise_params *params)
{
- int i;
+ const char *tool, *mode, *desc;
- static const char * const msg[] = {
- " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
+ static const char * const msg_start[] = {
+ "[-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
" [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
" [-c cpu-list] [-H cpu-list] [-P priority] [-C [cgroup_name]] [--warm-up s]",
- "",
- " -h/--help: print this menu",
+ NULL,
+ };
+
+ static const char * const msg_opts[] = {
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
" -p/--period us: osnoise period in us",
" -r/--runtime us: osnoise runtime in us",
@@ -295,25 +297,16 @@ static void osnoise_top_usage(struct osnoise_params *params)
};
if (params->mode == MODE_OSNOISE) {
- fprintf(stderr,
- "rtla osnoise top: a per-cpu summary of the OS noise (version %s)\n",
- VERSION);
-
- fprintf(stderr, " usage: rtla osnoise [top]");
+ tool = "osnoise";
+ mode = "top";
+ desc = "a per-cpu summary of the OS noise";
+ } else {
+ tool = "hwnoise";
+ mode = "";
+ desc = "a summary of hardware-related noise";
}
- if (params->mode == MODE_HWNOISE) {
- fprintf(stderr,
- "rtla hwnoise: a summary of hardware-related noise (version %s)\n",
- VERSION);
-
- fprintf(stderr, " usage: rtla hwnoise");
- }
-
- for (i = 0; msg[i]; i++)
- fprintf(stderr, "%s\n", msg[i]);
-
- exit(EXIT_SUCCESS);
+ common_usage(tool, mode, desc, msg_start, msg_opts);
}
/*
@@ -322,7 +315,6 @@ static void osnoise_top_usage(struct osnoise_params *params)
struct common_params *osnoise_top_parse_args(int argc, char **argv)
{
struct osnoise_params *params;
- struct trace_events *tevent;
int retval;
int c;
char *trace_output = NULL;
@@ -346,15 +338,8 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
- {"cpus", required_argument, 0, 'c'},
- {"cgroup", optional_argument, 0, 'C'},
- {"debug", no_argument, 0, 'D'},
- {"duration", required_argument, 0, 'd'},
- {"event", required_argument, 0, 'e'},
- {"house-keeping", required_argument, 0, 'H'},
{"help", no_argument, 0, 'h'},
{"period", required_argument, 0, 'p'},
- {"priority", required_argument, 0, 'P'},
{"quiet", no_argument, 0, 'q'},
{"runtime", required_argument, 0, 'r'},
{"stop", required_argument, 0, 's'},
@@ -370,7 +355,10 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:",
+ if (common_parse_options(argc, argv, &params->common))
+ continue;
+
+ c = getopt_long(argc, argv, "a:hp:qr:s:S:t::T:0:1:2:3:",
long_options, NULL);
/* Detect the end of the options. */
@@ -390,55 +378,15 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
trace_output = "osnoise_trace.txt";
break;
- case 'c':
- retval = parse_cpu_set(optarg, &params->common.monitored_cpus);
- if (retval)
- fatal("Invalid -c cpu list");
- params->common.cpus = optarg;
- break;
- case 'C':
- params->common.cgroup = 1;
- params->common.cgroup_name = parse_optional_arg(argc, argv);
- break;
- case 'D':
- config_debug = 1;
- break;
- case 'd':
- params->common.duration = parse_seconds_duration(optarg);
- if (!params->common.duration)
- fatal("Invalid -d duration");
- break;
- case 'e':
- tevent = trace_event_alloc(optarg);
- if (!tevent)
- fatal("Error alloc trace event");
-
- if (params->common.events)
- tevent->next = params->common.events;
- params->common.events = tevent;
-
- break;
case 'h':
case '?':
osnoise_top_usage(params);
break;
- case 'H':
- params->common.hk_cpus = 1;
- retval = parse_cpu_set(optarg, &params->common.hk_cpu_set);
- if (retval)
- fatal("Error parsing house keeping CPUs");
- break;
case 'p':
params->period = get_llong_from_str(optarg);
if (params->period > 10000000)
fatal("Period longer than 10 s");
break;
- case 'P':
- retval = parse_prio(optarg, &params->common.sched_param);
- if (retval == -1)
- fatal("Invalid -P priority");
- params->common.set_sched = 1;
- break;
case 'q':
params->common.quiet = 1;
break;
diff --git a/tools/tracing/rtla/src/timerlat.bpf.c b/tools/tracing/rtla/src/timerlat.bpf.c
index e2265b5d6491..549d2d2191d2 100644
--- a/tools/tracing/rtla/src/timerlat.bpf.c
+++ b/tools/tracing/rtla/src/timerlat.bpf.c
@@ -40,6 +40,17 @@ struct {
__uint(max_entries, 1);
} signal_stop_tracing SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+ __uint(key_size, sizeof(unsigned int));
+ __uint(max_entries, 1);
+ __array(values, unsigned int (void *));
+} bpf_action SEC(".maps") = {
+ .values = {
+ [0] = 0
+ },
+};
+
/* Params to be set by rtla */
const volatile int bucket_size = 1;
const volatile int output_divisor = 1000;
@@ -109,7 +120,7 @@ nosubprog void update_summary(void *map,
map_set(map, SUMMARY_SUM, map_get(map, SUMMARY_SUM) + latency);
}
-nosubprog void set_stop_tracing(void)
+nosubprog void set_stop_tracing(struct trace_event_raw_timerlat_sample *tp_args)
{
int value = 0;
@@ -118,6 +129,12 @@ nosubprog void set_stop_tracing(void)
/* Signal to userspace */
bpf_ringbuf_output(&signal_stop_tracing, &value, sizeof(value), 0);
+
+ /*
+ * Call into BPF action program, if attached.
+ * Otherwise, just silently fail.
+ */
+ bpf_tail_call(tp_args, &bpf_action, 0);
}
SEC("tp/osnoise/timerlat_sample")
@@ -138,19 +155,19 @@ int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args)
update_summary(&summary_irq, latency, bucket);
if (irq_threshold != 0 && latency_us >= irq_threshold)
- set_stop_tracing();
+ set_stop_tracing(tp_args);
} else if (tp_args->context == 1) {
update_main_hist(&hist_thread, bucket);
update_summary(&summary_thread, latency, bucket);
if (thread_threshold != 0 && latency_us >= thread_threshold)
- set_stop_tracing();
+ set_stop_tracing(tp_args);
} else {
update_main_hist(&hist_user, bucket);
update_summary(&summary_user, latency, bucket);
if (thread_threshold != 0 && latency_us >= thread_threshold)
- set_stop_tracing();
+ set_stop_tracing(tp_args);
}
return 0;
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index df4f9bfe3433..8f8811f7a13b 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -9,7 +9,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sched.h>
@@ -48,25 +47,17 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
}
}
- if (params->mode != TRACING_MODE_BPF) {
- /*
- * In tracefs and mixed mode, timerlat tracer handles stopping
- * on threshold
- */
- retval = osnoise_set_stop_us(tool->context, params->common.stop_us);
- if (retval) {
- err_msg("Failed to set stop us\n");
+ /* Check if BPF action program is requested but BPF is not available */
+ if (params->bpf_action_program) {
+ if (params->mode == TRACING_MODE_TRACEFS) {
+ err_msg("BPF actions are not supported in tracefs-only mode\n");
goto out_err;
}
- retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us);
- if (retval) {
- err_msg("Failed to set stop total us\n");
+ if (timerlat_load_bpf_action_program(params->bpf_action_program))
goto out_err;
- }
}
-
retval = osnoise_set_timerlat_period_us(tool->context,
params->timerlat_period_us ?
params->timerlat_period_us :
@@ -184,6 +175,16 @@ int timerlat_enable(struct osnoise_tool *tool)
}
}
+ /*
+ * In tracefs and mixed mode, timerlat tracer handles stopping
+ * on threshold
+ */
+ if (params->mode != TRACING_MODE_BPF) {
+ retval = osn_set_stop(tool);
+ if (retval)
+ return retval;
+ }
+
return 0;
}
diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h
index fd6065f48bb7..8dd5d134ce08 100644
--- a/tools/tracing/rtla/src/timerlat.h
+++ b/tools/tracing/rtla/src/timerlat.h
@@ -27,6 +27,7 @@ struct timerlat_params {
int dump_tasks;
int deepest_idle_state;
enum timerlat_tracing_mode mode;
+ const char *bpf_action_program;
};
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
@@ -36,4 +37,3 @@ int timerlat_main(int argc, char *argv[]);
int timerlat_enable(struct osnoise_tool *tool);
void timerlat_analyze(struct osnoise_tool *tool, bool stopped);
void timerlat_free(struct osnoise_tool *tool);
-
diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c
index e97d16646bcd..05adf18303df 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.c
+++ b/tools/tracing/rtla/src/timerlat_bpf.c
@@ -7,6 +7,10 @@
static struct timerlat_bpf *bpf;
+/* BPF object and program for action program */
+static struct bpf_object *obj;
+static struct bpf_program *prog;
+
/*
* timerlat_bpf_init - load and initialize BPF program to collect timerlat data
*/
@@ -60,6 +64,19 @@ int timerlat_bpf_init(struct timerlat_params *params)
}
/*
+ * timerlat_bpf_set_action - set action on threshold executed on BPF side
+ */
+static int timerlat_bpf_set_action(struct bpf_program *prog)
+{
+ unsigned int key = 0, value = bpf_program__fd(prog);
+
+ return bpf_map__update_elem(bpf->maps.bpf_action,
+ &key, sizeof(key),
+ &value, sizeof(value),
+ BPF_ANY);
+}
+
+/*
* timerlat_bpf_attach - attach BPF program to collect timerlat data
*/
int timerlat_bpf_attach(void)
@@ -83,6 +100,11 @@ void timerlat_bpf_detach(void)
void timerlat_bpf_destroy(void)
{
timerlat_bpf__destroy(bpf);
+ bpf = NULL;
+ if (obj)
+ bpf_object__close(obj);
+ obj = NULL;
+ prog = NULL;
}
static int handle_rb_event(void *ctx, void *data, size_t data_sz)
@@ -177,4 +199,48 @@ int timerlat_bpf_get_summary_value(enum summary_field key,
bpf->maps.summary_user,
key, value_irq, value_thread, value_user, cpus);
}
+
+/*
+ * timerlat_load_bpf_action_program - load and register a BPF action program
+ */
+int timerlat_load_bpf_action_program(const char *program_path)
+{
+ int err;
+
+ obj = bpf_object__open_file(program_path, NULL);
+ if (!obj) {
+ err_msg("Failed to open BPF action program: %s\n", program_path);
+ goto out_err;
+ }
+
+ err = bpf_object__load(obj);
+ if (err) {
+ err_msg("Failed to load BPF action program: %s\n", program_path);
+ goto out_obj_err;
+ }
+
+ prog = bpf_object__find_program_by_name(obj, "action_handler");
+ if (!prog) {
+ err_msg("BPF action program must have 'action_handler' function: %s\n",
+ program_path);
+ goto out_obj_err;
+ }
+
+ err = timerlat_bpf_set_action(prog);
+ if (err) {
+ err_msg("Failed to register BPF action program: %s\n", program_path);
+ goto out_prog_err;
+ }
+
+ return 0;
+
+out_prog_err:
+ prog = NULL;
+out_obj_err:
+ bpf_object__close(obj);
+ obj = NULL;
+out_err:
+ return 1;
+}
+
#endif /* HAVE_BPF_SKEL */
diff --git a/tools/tracing/rtla/src/timerlat_bpf.h b/tools/tracing/rtla/src/timerlat_bpf.h
index 118487436d30..169abeaf4363 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.h
+++ b/tools/tracing/rtla/src/timerlat_bpf.h
@@ -12,6 +12,7 @@ enum summary_field {
};
#ifndef __bpf__
+#include <bpf/libbpf.h>
#ifdef HAVE_BPF_SKEL
int timerlat_bpf_init(struct timerlat_params *params);
int timerlat_bpf_attach(void);
@@ -29,7 +30,7 @@ int timerlat_bpf_get_summary_value(enum summary_field key,
long long *value_thread,
long long *value_user,
int cpus);
-
+int timerlat_load_bpf_action_program(const char *program_path);
static inline int have_libbpf_support(void) { return 1; }
#else
static inline int timerlat_bpf_init(struct timerlat_params *params)
@@ -57,6 +58,10 @@ static inline int timerlat_bpf_get_summary_value(enum summary_field key,
{
return -1;
}
+static inline int timerlat_load_bpf_action_program(const char *program_path)
+{
+ return -1;
+}
static inline int have_libbpf_support(void) { return 0; }
#endif /* HAVE_BPF_SKEL */
#endif /* __bpf__ */
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 1fb471a787b7..4e8c38a61197 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -696,17 +696,16 @@ timerlat_print_stats(struct osnoise_tool *tool)
*/
static void timerlat_hist_usage(void)
{
- int i;
-
- char *msg[] = {
- "",
- " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\",
+ static const char * const msg_start[] = {
+ "[-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\",
" [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
" [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
" [--no-index] [--with-zeros] [--dma-latency us] [-C [cgroup_name]] [--no-aa] [--dump-task] [-u|-k]",
" [--warm-up s] [--deepest-idle-state n]",
- "",
- " -h/--help: print this menu",
+ NULL,
+ };
+
+ static const char * const msg_opts[] = {
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
" -p/--period us: timerlat period in us",
" -i/--irq us: stop trace if the irq latency is higher than the argument in us",
@@ -747,16 +746,12 @@ static void timerlat_hist_usage(void)
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
+ " --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
NULL,
};
- fprintf(stderr, "rtla timerlat hist: a per-cpu histogram of the timer latency (version %s)\n",
- VERSION);
-
- for (i = 0; msg[i]; i++)
- fprintf(stderr, "%s\n", msg[i]);
-
- exit(EXIT_SUCCESS);
+ common_usage("timerlat", "hist", "a per-cpu histogram of the timer latency",
+ msg_start, msg_opts);
}
/*
@@ -766,7 +761,6 @@ static struct common_params
*timerlat_hist_parse_args(int argc, char *argv[])
{
struct timerlat_params *params;
- struct trace_events *tevent;
int auto_thresh;
int retval;
int c;
@@ -796,25 +790,18 @@ static struct common_params
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
- {"cpus", required_argument, 0, 'c'},
- {"cgroup", optional_argument, 0, 'C'},
{"bucket-size", required_argument, 0, 'b'},
- {"debug", no_argument, 0, 'D'},
{"entries", required_argument, 0, 'E'},
- {"duration", required_argument, 0, 'd'},
- {"house-keeping", required_argument, 0, 'H'},
{"help", no_argument, 0, 'h'},
{"irq", required_argument, 0, 'i'},
{"nano", no_argument, 0, 'n'},
{"period", required_argument, 0, 'p'},
- {"priority", required_argument, 0, 'P'},
{"stack", required_argument, 0, 's'},
{"thread", required_argument, 0, 'T'},
{"trace", optional_argument, 0, 't'},
{"user-threads", no_argument, 0, 'u'},
{"kernel-threads", no_argument, 0, 'k'},
{"user-load", no_argument, 0, 'U'},
- {"event", required_argument, 0, 'e'},
{"no-irq", no_argument, 0, '0'},
{"no-thread", no_argument, 0, '1'},
{"no-header", no_argument, 0, '2'},
@@ -831,10 +818,14 @@ static struct common_params
{"deepest-idle-state", required_argument, 0, '\4'},
{"on-threshold", required_argument, 0, '\5'},
{"on-end", required_argument, 0, '\6'},
+ {"bpf-action", required_argument, 0, '\7'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:",
+ if (common_parse_options(argc, argv, &params->common))
+ continue;
+
+ c = getopt_long(argc, argv, "a:b:E:hi:knp:s:t::T:uU0123456:7:8:9\1\2:\3:",
long_options, NULL);
/* detect the end of the options. */
@@ -857,40 +848,12 @@ static struct common_params
trace_output = "timerlat_trace.txt";
break;
- case 'c':
- retval = parse_cpu_set(optarg, &params->common.monitored_cpus);
- if (retval)
- fatal("Invalid -c cpu list");
- params->common.cpus = optarg;
- break;
- case 'C':
- params->common.cgroup = 1;
- params->common.cgroup_name = parse_optional_arg(argc, argv);
- break;
case 'b':
params->common.hist.bucket_size = get_llong_from_str(optarg);
if (params->common.hist.bucket_size == 0 ||
params->common.hist.bucket_size >= 1000000)
fatal("Bucket size needs to be > 0 and <= 1000000");
break;
- case 'D':
- config_debug = 1;
- break;
- case 'd':
- params->common.duration = parse_seconds_duration(optarg);
- if (!params->common.duration)
- fatal("Invalid -D duration");
- break;
- case 'e':
- tevent = trace_event_alloc(optarg);
- if (!tevent)
- fatal("Error alloc trace event");
-
- if (params->common.events)
- tevent->next = params->common.events;
-
- params->common.events = tevent;
- break;
case 'E':
params->common.hist.entries = get_llong_from_str(optarg);
if (params->common.hist.entries < 10 ||
@@ -901,12 +864,6 @@ static struct common_params
case '?':
timerlat_hist_usage();
break;
- case 'H':
- params->common.hk_cpus = 1;
- retval = parse_cpu_set(optarg, &params->common.hk_cpu_set);
- if (retval)
- fatal("Error parsing house keeping CPUs");
- break;
case 'i':
params->common.stop_us = get_llong_from_str(optarg);
break;
@@ -921,12 +878,6 @@ static struct common_params
if (params->timerlat_period_us > 1000000)
fatal("Period longer than 1 s");
break;
- case 'P':
- retval = parse_prio(optarg, &params->common.sched_param);
- if (retval == -1)
- fatal("Invalid -P priority");
- params->common.set_sched = 1;
- break;
case 's':
params->print_stack = get_llong_from_str(optarg);
break;
@@ -1012,6 +963,9 @@ static struct common_params
if (retval)
fatal("Invalid action %s", optarg);
break;
+ case '\7':
+ params->bpf_action_program = optarg;
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 29c2c1f717ed..284b74773c2b 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -11,7 +11,6 @@
#include <unistd.h>
#include <stdio.h>
#include <time.h>
-#include <errno.h>
#include <sched.h>
#include <pthread.h>
@@ -476,15 +475,14 @@ timerlat_print_stats(struct osnoise_tool *top)
*/
static void timerlat_top_usage(void)
{
- int i;
-
- static const char *const msg[] = {
- "",
- " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
+ static const char *const msg_start[] = {
+ "[-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
" [[-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
" [-P priority] [--dma-latency us] [--aa-only us] [-C [cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]",
- "",
- " -h/--help: print this menu",
+ NULL,
+ };
+
+ static const char *const msg_opts[] = {
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
" --aa-only us: stop if <us> latency is hit, only printing the auto analysis (reduces CPU usage)",
" -p/--period us: timerlat period in us",
@@ -519,16 +517,12 @@ static void timerlat_top_usage(void)
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end: define action to be executed at measurement end, multiple are allowed",
+ " --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
NULL,
};
- fprintf(stderr, "rtla timerlat top: a per-cpu summary of the timer latency (version %s)\n",
- VERSION);
-
- for (i = 0; msg[i]; i++)
- fprintf(stderr, "%s\n", msg[i]);
-
- exit(EXIT_SUCCESS);
+ common_usage("timerlat", "top", "a per-cpu summary of the timer latency",
+ msg_start, msg_opts);
}
/*
@@ -538,7 +532,6 @@ static struct common_params
*timerlat_top_parse_args(int argc, char **argv)
{
struct timerlat_params *params;
- struct trace_events *tevent;
long long auto_thresh;
int retval;
int c;
@@ -566,17 +559,10 @@ static struct common_params
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
- {"cpus", required_argument, 0, 'c'},
- {"cgroup", optional_argument, 0, 'C'},
- {"debug", no_argument, 0, 'D'},
- {"duration", required_argument, 0, 'd'},
- {"event", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
- {"house-keeping", required_argument, 0, 'H'},
{"irq", required_argument, 0, 'i'},
{"nano", no_argument, 0, 'n'},
{"period", required_argument, 0, 'p'},
- {"priority", required_argument, 0, 'P'},
{"quiet", no_argument, 0, 'q'},
{"stack", required_argument, 0, 's'},
{"thread", required_argument, 0, 'T'},
@@ -595,10 +581,14 @@ static struct common_params
{"deepest-idle-state", required_argument, 0, '8'},
{"on-threshold", required_argument, 0, '9'},
{"on-end", required_argument, 0, '\1'},
+ {"bpf-action", required_argument, 0, '\2'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:",
+ if (common_parse_options(argc, argv, &params->common))
+ continue;
+
+ c = getopt_long(argc, argv, "a:hi:knp:qs:t::T:uU0:1:2:345:6:7:",
long_options, NULL);
/* detect the end of the options. */
@@ -635,43 +625,10 @@ static struct common_params
/* set aa_only to avoid parsing the trace */
params->common.aa_only = 1;
break;
- case 'c':
- retval = parse_cpu_set(optarg, &params->common.monitored_cpus);
- if (retval)
- fatal("Invalid -c cpu list");
- params->common.cpus = optarg;
- break;
- case 'C':
- params->common.cgroup = 1;
- params->common.cgroup_name = optarg;
- break;
- case 'D':
- config_debug = 1;
- break;
- case 'd':
- params->common.duration = parse_seconds_duration(optarg);
- if (!params->common.duration)
- fatal("Invalid -d duration");
- break;
- case 'e':
- tevent = trace_event_alloc(optarg);
- if (!tevent)
- fatal("Error alloc trace event");
-
- if (params->common.events)
- tevent->next = params->common.events;
- params->common.events = tevent;
- break;
case 'h':
case '?':
timerlat_top_usage();
break;
- case 'H':
- params->common.hk_cpus = 1;
- retval = parse_cpu_set(optarg, &params->common.hk_cpu_set);
- if (retval)
- fatal("Error parsing house keeping CPUs");
- break;
case 'i':
params->common.stop_us = get_llong_from_str(optarg);
break;
@@ -686,12 +643,6 @@ static struct common_params
if (params->timerlat_period_us > 1000000)
fatal("Period longer than 1 s");
break;
- case 'P':
- retval = parse_prio(optarg, &params->common.sched_param);
- if (retval == -1)
- fatal("Invalid -P priority");
- params->common.set_sched = 1;
- break;
case 'q':
params->common.quiet = 1;
break;
@@ -762,6 +713,9 @@ static struct common_params
if (retval)
fatal("Invalid action %s", optarg);
break;
+ case '\2':
+ params->bpf_action_program = optarg;
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 69cbc48d53d3..b8be3e28680e 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -2,7 +2,6 @@
#define _GNU_SOURCE
#include <sys/sendfile.h>
#include <tracefs.h>
-#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 9cf5a0098e9a..0da3b2470c31 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
+#include <limits.h>
#include "utils.h"
@@ -112,7 +113,7 @@ void get_duration(time_t start_time, char *output, int output_size)
* Receives a cpu list, like 1-3,5 (cpus 1, 2, 3, 5), and then set
* filling cpu_set_t argument.
*
- * Returns 1 on success, 0 otherwise.
+ * Returns 0 on success, 1 otherwise.
*/
int parse_cpu_set(char *cpu_list, cpu_set_t *set)
{
@@ -314,6 +315,7 @@ static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_e
if (retval <= 0)
return 0;
+ buffer[MAX_PATH-1] = '\0';
retval = strncmp(comm_prefix, buffer, strlen(comm_prefix));
if (retval)
return 0;
@@ -337,6 +339,7 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
struct dirent *proc_entry;
DIR *procfs;
int retval;
+ int pid;
if (strlen(comm_prefix) >= MAX_PATH) {
err_msg("Command prefix is too long: %d < strlen(%s)\n",
@@ -356,8 +359,12 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
if (!retval)
continue;
+ if (strtoi(proc_entry->d_name, &pid)) {
+ err_msg("'%s' is not a valid pid", proc_entry->d_name);
+ goto out_err;
+ }
/* procfs_is_workload_pid confirmed it is a pid */
- retval = __set_sched_attr(atoi(proc_entry->d_name), attr);
+ retval = __set_sched_attr(pid, attr);
if (retval) {
err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name);
goto out_err;
@@ -742,6 +749,7 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg)
if (fd < 0)
return 0;
+ memset(path, 0, sizeof(path));
retval = read(fd, path, MAX_PATH);
close(fd);
@@ -749,6 +757,7 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg)
if (retval <= 0)
return 0;
+ path[MAX_PATH-1] = '\0';
start = path;
start = strstr(start, ":");
@@ -784,27 +793,27 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg)
}
/*
- * set_comm_cgroup - Set cgroup to pid_t pid
+ * open_cgroup_procs - Open the cgroup.procs file for the given cgroup
*
- * If cgroup argument is not NULL, the threads will move to the given cgroup.
- * Otherwise, the cgroup of the calling, i.e., rtla, thread will be used.
+ * If cgroup argument is not NULL, the cgroup.procs file for that cgroup
+ * will be opened. Otherwise, the cgroup of the calling, i.e., rtla, thread
+ * will be used.
*
* Supports cgroup v2.
*
- * Returns 1 on success, 0 otherwise.
+ * Returns the file descriptor on success, -1 otherwise.
*/
-int set_pid_cgroup(pid_t pid, const char *cgroup)
+static int open_cgroup_procs(const char *cgroup)
{
char cgroup_path[MAX_PATH - strlen("/cgroup.procs")];
char cgroup_procs[MAX_PATH];
- char pid_str[24];
int retval;
int cg_fd;
retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path));
if (!retval) {
err_msg("Did not find cgroupv2 mount point\n");
- return 0;
+ return -1;
}
if (!cgroup) {
@@ -812,7 +821,7 @@ int set_pid_cgroup(pid_t pid, const char *cgroup)
sizeof(cgroup_path) - strlen(cgroup_path));
if (!retval) {
err_msg("Did not find self cgroup\n");
- return 0;
+ return -1;
}
} else {
snprintf(&cgroup_path[strlen(cgroup_path)],
@@ -825,6 +834,29 @@ int set_pid_cgroup(pid_t pid, const char *cgroup)
cg_fd = open(cgroup_procs, O_RDWR);
if (cg_fd < 0)
+ return -1;
+
+ return cg_fd;
+}
+
+/*
+ * set_pid_cgroup - Set cgroup to pid_t pid
+ *
+ * If cgroup argument is not NULL, the threads will move to the given cgroup.
+ * Otherwise, the cgroup of the calling, i.e., rtla, thread will be used.
+ *
+ * Supports cgroup v2.
+ *
+ * Returns 1 on success, 0 otherwise.
+ */
+int set_pid_cgroup(pid_t pid, const char *cgroup)
+{
+ char pid_str[24];
+ int retval;
+ int cg_fd;
+
+ cg_fd = open_cgroup_procs(cgroup);
+ if (cg_fd < 0)
return 0;
snprintf(pid_str, sizeof(pid_str), "%d\n", pid);
@@ -853,8 +885,6 @@ int set_pid_cgroup(pid_t pid, const char *cgroup)
*/
int set_comm_cgroup(const char *comm_prefix, const char *cgroup)
{
- char cgroup_path[MAX_PATH - strlen("/cgroup.procs")];
- char cgroup_procs[MAX_PATH];
struct dirent *proc_entry;
DIR *procfs;
int retval;
@@ -866,29 +896,7 @@ int set_comm_cgroup(const char *comm_prefix, const char *cgroup)
return 0;
}
- retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path));
- if (!retval) {
- err_msg("Did not find cgroupv2 mount point\n");
- return 0;
- }
-
- if (!cgroup) {
- retval = get_self_cgroup(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path));
- if (!retval) {
- err_msg("Did not find self cgroup\n");
- return 0;
- }
- } else {
- snprintf(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path), "%s/", cgroup);
- }
-
- snprintf(cgroup_procs, MAX_PATH, "%s/cgroup.procs", cgroup_path);
-
- debug_msg("Using cgroup path at: %s\n", cgroup_procs);
-
- cg_fd = open(cgroup_procs, O_RDWR);
+ cg_fd = open_cgroup_procs(cgroup);
if (cg_fd < 0)
return 0;
@@ -1000,3 +1008,25 @@ char *parse_optional_arg(int argc, char **argv)
return NULL;
}
}
+
+/*
+ * strtoi - convert string to integer with error checking
+ *
+ * Returns 0 on success, -1 if conversion fails or result is out of int range.
+ */
+int strtoi(const char *s, int *res)
+{
+ char *end_ptr;
+ long lres;
+
+ if (!*s)
+ return -1;
+
+ errno = 0;
+ lres = strtol(s, &end_ptr, 0);
+ if (errno || *end_ptr || lres > INT_MAX || lres < INT_MIN)
+ return -1;
+
+ *res = (int) lres;
+ return 0;
+}
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index 091df4ba4587..f7c2a52a0ab5 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -3,6 +3,8 @@
#include <stdint.h>
#include <time.h>
#include <sched.h>
+#include <stdbool.h>
+#include <stdlib.h>
/*
* '18446744073709551615\0'
@@ -24,7 +26,6 @@ void fatal(const char *fmt, ...);
long parse_seconds_duration(char *val);
void get_duration(time_t start_time, char *output, int output_size);
-int parse_cpu_list(char *cpu_list, char **monitored_cpus);
char *parse_optional_arg(int argc, char **argv);
long long get_llong_from_str(char *start);
@@ -82,12 +83,13 @@ static inline int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int stat
static inline int have_libcpupower_support(void) { return 0; }
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
int auto_house_keeping(cpu_set_t *monitored_cpus);
+__attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res);
#define ns_to_usf(x) (((double)x/1000))
#define ns_to_per(total, part) ((part * 100) / (double)total)
enum result {
- PASSED = 0, /* same as EXIT_SUCCESS */
- ERROR = 1, /* same as EXIT_FAILURE, an error in arguments */
- FAILED = 2, /* test hit the stop tracing condition */
+ PASSED = EXIT_SUCCESS,
+ ERROR = EXIT_FAILURE,
+ FAILED, /* test hit the stop tracing condition */
};