mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 14:19:16 +00:00
Specific for timerlat:
- Improves the output of timerlat top by adding a missing \n, and by avoiding printing color-formatting characters where they are translated to regular characters. - Improves timerlat auto-analysis output by replacing '\t' with spaces to avoid copy-and-paste issues when reporting problems. - For timerlat, make the user-space (-u) option the default, as it is the most complete test. Add a -k option to use the in-kernel workload. - On timerlat top and hist, add a summary with the overall results. For instance, the minimum value for all CPUs, the overall average and the maximum value from all CPUs. - timerlat hist was printing initial values (i.e., 0 as max, and ~0 as min) if the trace stopped before the first Ret-User event. This problem was fixed by printing the " - " no value string to the output if that was the case. For all RTLA tools: - Add a --warm-up <seconds> option, allowing the workload to run for <seconds> before starting to collect results. - Add a --trace-buffer-size option, allowing the user to set the tracing buffer size for -t option. This option is mainly useful for reducing the trace file. Now rtla depends on libtracefs >= 1.6. - Fix the -t [trace_file] parsing, now it does not require the '=' before the option parameter, and better handles the multiple ways a user can pass the trace_file.txt -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZkeciRQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qs71AQC48M82m9LPGVt1gg8f3NoChIuo4908 fr+SXq2+Va+18gEAoYJ5G0JuAb7FkHtvpPGB5yQYArTSYJ5LiHrjSXNG1w8= =ZrJJ -----END PGP SIGNATURE----- Merge tag 'trace-tools-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing tool updates from Steven Rostedt: "Specific for timerlat: - Improve the output of timerlat top by adding a missing \n, and by avoiding printing color-formatting characters where they are translated to regular characters. - Improve timerlat auto-analysis output by replacing '\t' with spaces to avoid copy-and-paste issues when reporting problems. - Make the user-space (-u) option the default, as it is the most complete test. Add a -k option to use the in-kernel workload. - On timerlat top and hist, add a summary with the overall results. For instance, the minimum value for all CPUs, the overall average and the maximum value from all CPUs. - timerlat hist was printing initial values (i.e., 0 as max, and ~0 as min) if the trace stopped before the first Ret-User event. This problem was fixed by printing the " - " no value string to the output if that was the case. For all RTLA tools: - Add a --warm-up <seconds> option, allowing the workload to run for <seconds> before starting to collect results. - Add a --trace-buffer-size option, allowing the user to set the tracing buffer size for -t option. This option is mainly useful for reducing the trace file. Now rtla depends on libtracefs >= 1.6. - Fix the -t [trace_file] parsing, now it does not require the '=' before the option parameter, and better handles the multiple ways a user can pass the trace_file.txt" * tag 'trace-tools-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rtla: Documentation: Fix -t, --trace rtla: Fix -t\--trace[=file] rtla/timerlat: Fix histogram report when a cpu count is 0 rtla: Add --trace-buffer-size option rtla/timerlat: Make user-space threads the default rtla: Add the --warm-up option rtla/timerlat: Add a summary for hist mode rtla/timerlat: Add a summary for top mode rtla/timerlat: Use pretty formatting only on interactive tty rtla/auto-analysis: Replace \t with spaces rtla/timerlat: Simplify "no value" printing on top
This commit is contained in:
commit
26aa834ff2
11 changed files with 653 additions and 153 deletions
|
@ -14,10 +14,6 @@
|
||||||
|
|
||||||
Print debug info.
|
Print debug info.
|
||||||
|
|
||||||
**-t**, **--trace**\[*=file*]
|
|
||||||
|
|
||||||
Save the stopped trace to [*file|osnoise_trace.txt*].
|
|
||||||
|
|
||||||
**-e**, **--event** *sys:event*
|
**-e**, **--event** *sys:event*
|
||||||
|
|
||||||
Enable an event in the trace (**-t**) session. The argument can be a specific event, e.g., **-e** *sched:sched_switch*, or all events of a system group, e.g., **-e** *sched*. Multiple **-e** are allowed. It is only active when **-t** or **-a** are set.
|
Enable an event in the trace (**-t**) session. The argument can be a specific event, e.g., **-e** *sched:sched_switch*, or all events of a system group, e.g., **-e** *sched*. Multiple **-e** are allowed. It is only active when **-t** or **-a** are set.
|
||||||
|
@ -50,6 +46,13 @@
|
||||||
|
|
||||||
Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option.
|
Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option.
|
||||||
|
|
||||||
|
**--warm-up** *s*
|
||||||
|
|
||||||
|
After starting the workload, let it run for *s* seconds before starting collecting the data, allowing the system to warm-up. Statistical data generated during warm-up is discarded.
|
||||||
|
|
||||||
|
**--trace-buffer-size** *kB*
|
||||||
|
Set the per-cpu trace buffer size in kB for the tracing output.
|
||||||
|
|
||||||
**-h**, **--help**
|
**-h**, **--help**
|
||||||
|
|
||||||
Print help menu.
|
Print help menu.
|
||||||
|
|
|
@ -25,3 +25,7 @@
|
||||||
|
|
||||||
Specify the minimum delta between two time reads to be considered noise.
|
Specify the minimum delta between two time reads to be considered noise.
|
||||||
The default threshold is *5 us*.
|
The default threshold is *5 us*.
|
||||||
|
|
||||||
|
**-t**, **--trace** \[*file*]
|
||||||
|
|
||||||
|
Save the stopped trace to [*file|osnoise_trace.txt*].
|
||||||
|
|
|
@ -22,17 +22,25 @@
|
||||||
Save the stack trace at the *IRQ* if a *Thread* latency is higher than the
|
Save the stack trace at the *IRQ* if a *Thread* latency is higher than the
|
||||||
argument in us.
|
argument in us.
|
||||||
|
|
||||||
|
**-t**, **--trace** \[*file*]
|
||||||
|
|
||||||
|
Save the stopped trace to [*file|timerlat_trace.txt*].
|
||||||
|
|
||||||
**--dma-latency** *us*
|
**--dma-latency** *us*
|
||||||
Set the /dev/cpu_dma_latency to *us*, aiming to bound exit from idle latencies.
|
Set the /dev/cpu_dma_latency to *us*, aiming to bound exit from idle latencies.
|
||||||
*cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have
|
*cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have
|
||||||
similar results.
|
similar results.
|
||||||
|
|
||||||
|
**-k**, **--kernel-threads**
|
||||||
|
|
||||||
|
Use timerlat kernel-space threads, in contrast of **-u**.
|
||||||
|
|
||||||
**-u**, **--user-threads**
|
**-u**, **--user-threads**
|
||||||
|
|
||||||
Set timerlat to run without a workload, and then dispatches user-space workloads
|
Set timerlat to run without a workload, and then dispatches user-space workloads
|
||||||
to wait on the timerlat_fd. Once the workload is awakes, it goes to sleep again
|
to wait on the timerlat_fd. Once the workload is awakes, it goes to sleep again
|
||||||
adding so the measurement for the kernel-to-user and user-to-kernel to the tracer
|
adding so the measurement for the kernel-to-user and user-to-kernel to the tracer
|
||||||
output.
|
output. **--user-threads** will be used unless the user specify **-k**.
|
||||||
|
|
||||||
**-U**, **--user-load**
|
**-U**, **--user-load**
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
STOP_ERROR :=
|
STOP_ERROR :=
|
||||||
|
|
||||||
LIBTRACEEVENT_MIN_VERSION = 1.5
|
LIBTRACEEVENT_MIN_VERSION = 1.5
|
||||||
LIBTRACEFS_MIN_VERSION = 1.3
|
LIBTRACEFS_MIN_VERSION = 1.6
|
||||||
|
|
||||||
define lib_setup
|
define lib_setup
|
||||||
$(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
|
$(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
|
||||||
|
|
|
@ -36,13 +36,14 @@ struct osnoise_hist_params {
|
||||||
cpu_set_t hk_cpu_set;
|
cpu_set_t hk_cpu_set;
|
||||||
struct sched_attr sched_param;
|
struct sched_attr sched_param;
|
||||||
struct trace_events *events;
|
struct trace_events *events;
|
||||||
|
|
||||||
char no_header;
|
char no_header;
|
||||||
char no_summary;
|
char no_summary;
|
||||||
char no_index;
|
char no_index;
|
||||||
char with_zeros;
|
char with_zeros;
|
||||||
int bucket_size;
|
int bucket_size;
|
||||||
int entries;
|
int entries;
|
||||||
|
int warmup;
|
||||||
|
int buffer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osnoise_hist_cpu {
|
struct osnoise_hist_cpu {
|
||||||
|
@ -436,9 +437,9 @@ static void osnoise_hist_usage(char *usage)
|
||||||
static const char * const msg[] = {
|
static const char * const msg[] = {
|
||||||
"",
|
"",
|
||||||
" usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
|
" usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
|
||||||
" [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
|
" [-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] \\",
|
" [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
|
||||||
" [--no-index] [--with-zeros] [-C[=cgroup_name]]",
|
" [--no-index] [--with-zeros] [-C[=cgroup_name]] [--warm-up]",
|
||||||
"",
|
"",
|
||||||
" -h/--help: print this menu",
|
" -h/--help: print this menu",
|
||||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
||||||
|
@ -452,7 +453,7 @@ static void osnoise_hist_usage(char *usage)
|
||||||
" -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
" -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||||
" -d/--duration time[s|m|h|d]: duration of the session",
|
" -d/--duration time[s|m|h|d]: duration of the session",
|
||||||
" -D/--debug: print debug info",
|
" -D/--debug: print debug info",
|
||||||
" -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
|
" -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]",
|
||||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||||
|
@ -468,6 +469,8 @@ static void osnoise_hist_usage(char *usage)
|
||||||
" f:prio - use SCHED_FIFO with prio",
|
" f:prio - use SCHED_FIFO with prio",
|
||||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||||
" in nanoseconds",
|
" in nanoseconds",
|
||||||
|
" --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",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -531,13 +534,15 @@ static struct osnoise_hist_params
|
||||||
{"with-zeros", no_argument, 0, '3'},
|
{"with-zeros", no_argument, 0, '3'},
|
||||||
{"trigger", required_argument, 0, '4'},
|
{"trigger", required_argument, 0, '4'},
|
||||||
{"filter", required_argument, 0, '5'},
|
{"filter", required_argument, 0, '5'},
|
||||||
|
{"warm-up", required_argument, 0, '6'},
|
||||||
|
{"trace-buffer-size", required_argument, 0, '7'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* getopt_long stores the option index here. */
|
/* getopt_long stores the option index here. */
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:",
|
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
|
|
||||||
/* detect the end of the options. */
|
/* detect the end of the options. */
|
||||||
|
@ -640,9 +645,13 @@ static struct osnoise_hist_params
|
||||||
params->threshold = get_llong_from_str(optarg);
|
params->threshold = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (optarg)
|
if (optarg) {
|
||||||
/* skip = */
|
if (optarg[0] == '=')
|
||||||
params->trace_output = &optarg[1];
|
params->trace_output = &optarg[1];
|
||||||
|
else
|
||||||
|
params->trace_output = &optarg[0];
|
||||||
|
} else if (optind < argc && argv[optind][0] != '0')
|
||||||
|
params->trace_output = argv[optind];
|
||||||
else
|
else
|
||||||
params->trace_output = "osnoise_trace.txt";
|
params->trace_output = "osnoise_trace.txt";
|
||||||
break;
|
break;
|
||||||
|
@ -680,6 +689,12 @@ static struct osnoise_hist_params
|
||||||
osnoise_hist_usage("--filter requires a previous -e\n");
|
osnoise_hist_usage("--filter requires a previous -e\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '6':
|
||||||
|
params->warmup = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
params->buffer_size = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
osnoise_hist_usage("Invalid option");
|
osnoise_hist_usage("Invalid option");
|
||||||
}
|
}
|
||||||
|
@ -886,6 +901,11 @@ int osnoise_hist_main(int argc, char *argv[])
|
||||||
goto out_hist;
|
goto out_hist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->buffer_size > 0) {
|
||||||
|
retval = trace_set_buffer_size(&record->trace, params->buffer_size);
|
||||||
|
if (retval)
|
||||||
|
goto out_hist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -899,6 +919,25 @@ int osnoise_hist_main(int argc, char *argv[])
|
||||||
trace_instance_start(&record->trace);
|
trace_instance_start(&record->trace);
|
||||||
trace_instance_start(trace);
|
trace_instance_start(trace);
|
||||||
|
|
||||||
|
if (params->warmup > 0) {
|
||||||
|
debug_msg("Warming up for %d seconds\n", params->warmup);
|
||||||
|
sleep(params->warmup);
|
||||||
|
if (stop_tracing)
|
||||||
|
goto out_hist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up the buffer. The osnoise workload do not run
|
||||||
|
* with tracing off to avoid creating a performance penalty
|
||||||
|
* when not needed.
|
||||||
|
*/
|
||||||
|
retval = tracefs_instance_file_write(trace->inst, "trace", "");
|
||||||
|
if (retval < 0) {
|
||||||
|
debug_msg("Error cleaning up the buffer");
|
||||||
|
goto out_hist;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
tool->start_time = time(NULL);
|
tool->start_time = time(NULL);
|
||||||
osnoise_hist_set_signals(params);
|
osnoise_hist_set_signals(params);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ struct osnoise_top_params {
|
||||||
int set_sched;
|
int set_sched;
|
||||||
int cgroup;
|
int cgroup;
|
||||||
int hk_cpus;
|
int hk_cpus;
|
||||||
|
int warmup;
|
||||||
|
int buffer_size;
|
||||||
cpu_set_t hk_cpu_set;
|
cpu_set_t hk_cpu_set;
|
||||||
struct sched_attr sched_param;
|
struct sched_attr sched_param;
|
||||||
struct trace_events *events;
|
struct trace_events *events;
|
||||||
|
@ -281,8 +283,8 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
|
||||||
|
|
||||||
static const char * const msg[] = {
|
static const char * const msg[] = {
|
||||||
" [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
|
" [-h] [-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>] \\",
|
" [-T us] [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
|
||||||
" [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]]",
|
" [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]] [--warm-up s]",
|
||||||
"",
|
"",
|
||||||
" -h/--help: print this menu",
|
" -h/--help: print this menu",
|
||||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
||||||
|
@ -296,7 +298,7 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
|
||||||
" -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
" -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||||
" -d/--duration time[s|m|h|d]: duration of the session",
|
" -d/--duration time[s|m|h|d]: duration of the session",
|
||||||
" -D/--debug: print debug info",
|
" -D/--debug: print debug info",
|
||||||
" -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
|
" -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]",
|
||||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||||
|
@ -307,6 +309,8 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
|
||||||
" f:prio - use SCHED_FIFO with prio",
|
" f:prio - use SCHED_FIFO with prio",
|
||||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||||
" in nanoseconds",
|
" in nanoseconds",
|
||||||
|
" --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",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -381,13 +385,15 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
|
||||||
{"trace", optional_argument, 0, 't'},
|
{"trace", optional_argument, 0, 't'},
|
||||||
{"trigger", required_argument, 0, '0'},
|
{"trigger", required_argument, 0, '0'},
|
||||||
{"filter", required_argument, 0, '1'},
|
{"filter", required_argument, 0, '1'},
|
||||||
|
{"warm-up", required_argument, 0, '2'},
|
||||||
|
{"trace-buffer-size", required_argument, 0, '3'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* getopt_long stores the option index here. */
|
/* getopt_long stores the option index here. */
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:",
|
c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
|
|
||||||
/* Detect the end of the options. */
|
/* Detect the end of the options. */
|
||||||
|
@ -480,9 +486,13 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
|
||||||
params->stop_total_us = get_llong_from_str(optarg);
|
params->stop_total_us = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (optarg)
|
if (optarg) {
|
||||||
/* skip = */
|
if (optarg[0] == '=')
|
||||||
params->trace_output = &optarg[1];
|
params->trace_output = &optarg[1];
|
||||||
|
else
|
||||||
|
params->trace_output = &optarg[0];
|
||||||
|
} else if (optind < argc && argv[optind][0] != '-')
|
||||||
|
params->trace_output = argv[optind];
|
||||||
else
|
else
|
||||||
params->trace_output = "osnoise_trace.txt";
|
params->trace_output = "osnoise_trace.txt";
|
||||||
break;
|
break;
|
||||||
|
@ -511,6 +521,12 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
|
||||||
osnoise_top_usage(params, "--filter requires a previous -e\n");
|
osnoise_top_usage(params, "--filter requires a previous -e\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '2':
|
||||||
|
params->warmup = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
params->buffer_size = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
osnoise_top_usage(params, "Invalid option");
|
osnoise_top_usage(params, "Invalid option");
|
||||||
}
|
}
|
||||||
|
@ -719,6 +735,12 @@ int osnoise_top_main(int argc, char **argv)
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_top;
|
goto out_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->buffer_size > 0) {
|
||||||
|
retval = trace_set_buffer_size(&record->trace, params->buffer_size);
|
||||||
|
if (retval)
|
||||||
|
goto out_top;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -732,6 +754,25 @@ int osnoise_top_main(int argc, char **argv)
|
||||||
trace_instance_start(&record->trace);
|
trace_instance_start(&record->trace);
|
||||||
trace_instance_start(trace);
|
trace_instance_start(trace);
|
||||||
|
|
||||||
|
if (params->warmup > 0) {
|
||||||
|
debug_msg("Warming up for %d seconds\n", params->warmup);
|
||||||
|
sleep(params->warmup);
|
||||||
|
if (stop_tracing)
|
||||||
|
goto out_top;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up the buffer. The osnoise workload do not run
|
||||||
|
* with tracing off to avoid creating a performance penalty
|
||||||
|
* when not needed.
|
||||||
|
*/
|
||||||
|
retval = tracefs_instance_file_write(trace->inst, "trace", "");
|
||||||
|
if (retval < 0) {
|
||||||
|
debug_msg("Error cleaning up the buffer");
|
||||||
|
goto out_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
tool->start_time = time(NULL);
|
tool->start_time = time(NULL);
|
||||||
osnoise_top_set_signals(params);
|
osnoise_top_set_signals(params);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ enum timelat_state {
|
||||||
TIMERLAT_WAITING_THREAD,
|
TIMERLAT_WAITING_THREAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Used to fill spaces in the output */
|
||||||
|
static const char *spaces = " ";
|
||||||
|
|
||||||
#define MAX_COMM 24
|
#define MAX_COMM 24
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -274,14 +277,17 @@ static int timerlat_aa_nmi_handler(struct trace_seq *s, struct tep_record *recor
|
||||||
taa_data->prev_irq_timstamp = start;
|
taa_data->prev_irq_timstamp = start;
|
||||||
|
|
||||||
trace_seq_reset(taa_data->prev_irqs_seq);
|
trace_seq_reset(taa_data->prev_irqs_seq);
|
||||||
trace_seq_printf(taa_data->prev_irqs_seq, "\t%24s \t\t\t%9.2f us\n",
|
trace_seq_printf(taa_data->prev_irqs_seq, " %24s %.*s %9.2f us\n",
|
||||||
"nmi", ns_to_usf(duration));
|
"nmi",
|
||||||
|
24, spaces,
|
||||||
|
ns_to_usf(duration));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
taa_data->thread_nmi_sum += duration;
|
taa_data->thread_nmi_sum += duration;
|
||||||
trace_seq_printf(taa_data->nmi_seq, " %24s \t\t\t%9.2f us\n",
|
trace_seq_printf(taa_data->nmi_seq, " %24s %.*s %9.2f us\n",
|
||||||
"nmi", ns_to_usf(duration));
|
"nmi",
|
||||||
|
24, spaces, ns_to_usf(duration));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -323,8 +329,10 @@ static int timerlat_aa_irq_handler(struct trace_seq *s, struct tep_record *recor
|
||||||
taa_data->prev_irq_timstamp = start;
|
taa_data->prev_irq_timstamp = start;
|
||||||
|
|
||||||
trace_seq_reset(taa_data->prev_irqs_seq);
|
trace_seq_reset(taa_data->prev_irqs_seq);
|
||||||
trace_seq_printf(taa_data->prev_irqs_seq, "\t%24s:%-3llu \t\t%9.2f us\n",
|
trace_seq_printf(taa_data->prev_irqs_seq, " %24s:%-3llu %.*s %9.2f us\n",
|
||||||
desc, vector, ns_to_usf(duration));
|
desc, vector,
|
||||||
|
15, spaces,
|
||||||
|
ns_to_usf(duration));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,8 +380,10 @@ static int timerlat_aa_irq_handler(struct trace_seq *s, struct tep_record *recor
|
||||||
* IRQ interference.
|
* IRQ interference.
|
||||||
*/
|
*/
|
||||||
taa_data->thread_irq_sum += duration;
|
taa_data->thread_irq_sum += duration;
|
||||||
trace_seq_printf(taa_data->irqs_seq, " %24s:%-3llu \t %9.2f us\n",
|
trace_seq_printf(taa_data->irqs_seq, " %24s:%-3llu %.*s %9.2f us\n",
|
||||||
desc, vector, ns_to_usf(duration));
|
desc, vector,
|
||||||
|
24, spaces,
|
||||||
|
ns_to_usf(duration));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -408,8 +418,10 @@ static int timerlat_aa_softirq_handler(struct trace_seq *s, struct tep_record *r
|
||||||
|
|
||||||
taa_data->thread_softirq_sum += duration;
|
taa_data->thread_softirq_sum += duration;
|
||||||
|
|
||||||
trace_seq_printf(taa_data->softirqs_seq, "\t%24s:%-3llu \t %9.2f us\n",
|
trace_seq_printf(taa_data->softirqs_seq, " %24s:%-3llu %.*s %9.2f us\n",
|
||||||
softirq_name[vector], vector, ns_to_usf(duration));
|
softirq_name[vector], vector,
|
||||||
|
24, spaces,
|
||||||
|
ns_to_usf(duration));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,8 +464,10 @@ static int timerlat_aa_thread_handler(struct trace_seq *s, struct tep_record *re
|
||||||
} else {
|
} else {
|
||||||
taa_data->thread_thread_sum += duration;
|
taa_data->thread_thread_sum += duration;
|
||||||
|
|
||||||
trace_seq_printf(taa_data->threads_seq, "\t%24s:%-3llu \t\t%9.2f us\n",
|
trace_seq_printf(taa_data->threads_seq, " %24s:%-12llu %.*s %9.2f us\n",
|
||||||
comm, pid, ns_to_usf(duration));
|
comm, pid,
|
||||||
|
15, spaces,
|
||||||
|
ns_to_usf(duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -482,7 +496,8 @@ static int timerlat_aa_stack_handler(struct trace_seq *s, struct tep_record *rec
|
||||||
function = tep_find_function(taa_ctx->tool->trace.tep, caller[i]);
|
function = tep_find_function(taa_ctx->tool->trace.tep, caller[i]);
|
||||||
if (!function)
|
if (!function)
|
||||||
break;
|
break;
|
||||||
trace_seq_printf(taa_data->stack_seq, "\t\t-> %s\n", function);
|
trace_seq_printf(taa_data->stack_seq, " %.*s -> %s\n",
|
||||||
|
14, spaces, function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -568,23 +583,24 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
exp_irq_ts = taa_data->timer_irq_start_time - taa_data->timer_irq_start_delay;
|
exp_irq_ts = taa_data->timer_irq_start_time - taa_data->timer_irq_start_delay;
|
||||||
if (exp_irq_ts < taa_data->prev_irq_timstamp + taa_data->prev_irq_duration) {
|
if (exp_irq_ts < taa_data->prev_irq_timstamp + taa_data->prev_irq_duration) {
|
||||||
if (taa_data->prev_irq_timstamp < taa_data->timer_irq_start_time)
|
if (taa_data->prev_irq_timstamp < taa_data->timer_irq_start_time)
|
||||||
printf(" Previous IRQ interference: \t\t up to %9.2f us\n",
|
printf(" Previous IRQ interference: %.*s up to %9.2f us\n",
|
||||||
ns_to_usf(taa_data->prev_irq_duration));
|
16, spaces,
|
||||||
|
ns_to_usf(taa_data->prev_irq_duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The delay that the IRQ suffered before starting.
|
* The delay that the IRQ suffered before starting.
|
||||||
*/
|
*/
|
||||||
printf(" IRQ handler delay: %16s %9.2f us (%.2f %%)\n",
|
printf(" IRQ handler delay: %.*s %16s %9.2f us (%.2f %%)\n", 16, spaces,
|
||||||
(ns_to_usf(taa_data->timer_exit_from_idle) > 10) ? "(exit from idle)" : "",
|
(ns_to_usf(taa_data->timer_exit_from_idle) > 10) ? "(exit from idle)" : "",
|
||||||
ns_to_usf(taa_data->timer_irq_start_delay),
|
ns_to_usf(taa_data->timer_irq_start_delay),
|
||||||
ns_to_per(total, taa_data->timer_irq_start_delay));
|
ns_to_per(total, taa_data->timer_irq_start_delay));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timerlat IRQ.
|
* Timerlat IRQ.
|
||||||
*/
|
*/
|
||||||
printf(" IRQ latency: \t\t\t\t %9.2f us\n",
|
printf(" IRQ latency: %.*s %9.2f us\n", 40, spaces,
|
||||||
ns_to_usf(taa_data->tlat_irq_latency));
|
ns_to_usf(taa_data->tlat_irq_latency));
|
||||||
|
|
||||||
if (irq) {
|
if (irq) {
|
||||||
/*
|
/*
|
||||||
|
@ -595,15 +611,16 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* so it will be displayed, it is the key.
|
* so it will be displayed, it is the key.
|
||||||
*/
|
*/
|
||||||
printf(" Blocking thread:\n");
|
printf(" Blocking thread:\n");
|
||||||
printf(" %24s:%-9llu\n",
|
printf(" %.*s %24s:%-9llu\n", 6, spaces, taa_data->run_thread_comm,
|
||||||
taa_data->run_thread_comm, taa_data->run_thread_pid);
|
taa_data->run_thread_pid);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* The duration of the IRQ handler that handled the timerlat IRQ.
|
* The duration of the IRQ handler that handled the timerlat IRQ.
|
||||||
*/
|
*/
|
||||||
printf(" Timerlat IRQ duration: \t\t %9.2f us (%.2f %%)\n",
|
printf(" Timerlat IRQ duration: %.*s %9.2f us (%.2f %%)\n",
|
||||||
ns_to_usf(taa_data->timer_irq_duration),
|
30, spaces,
|
||||||
ns_to_per(total, taa_data->timer_irq_duration));
|
ns_to_usf(taa_data->timer_irq_duration),
|
||||||
|
ns_to_per(total, taa_data->timer_irq_duration));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The amount of time that the current thread postponed the scheduler.
|
* The amount of time that the current thread postponed the scheduler.
|
||||||
|
@ -611,13 +628,13 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* Recalling that it is net from NMI/IRQ/Softirq interference, so there
|
* Recalling that it is net from NMI/IRQ/Softirq interference, so there
|
||||||
* is no need to compute values here.
|
* is no need to compute values here.
|
||||||
*/
|
*/
|
||||||
printf(" Blocking thread: \t\t\t %9.2f us (%.2f %%)\n",
|
printf(" Blocking thread: %.*s %9.2f us (%.2f %%)\n", 36, spaces,
|
||||||
ns_to_usf(taa_data->thread_blocking_duration),
|
ns_to_usf(taa_data->thread_blocking_duration),
|
||||||
ns_to_per(total, taa_data->thread_blocking_duration));
|
ns_to_per(total, taa_data->thread_blocking_duration));
|
||||||
|
|
||||||
printf(" %24s:%-9llu %9.2f us\n",
|
printf(" %.*s %24s:%-9llu %.*s %9.2f us\n", 6, spaces,
|
||||||
taa_data->run_thread_comm, taa_data->run_thread_pid,
|
taa_data->run_thread_comm, taa_data->run_thread_pid,
|
||||||
ns_to_usf(taa_data->thread_blocking_duration));
|
12, spaces, ns_to_usf(taa_data->thread_blocking_duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -629,9 +646,9 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* NMIs can happen during the IRQ, so they are always possible.
|
* NMIs can happen during the IRQ, so they are always possible.
|
||||||
*/
|
*/
|
||||||
if (taa_data->thread_nmi_sum)
|
if (taa_data->thread_nmi_sum)
|
||||||
printf(" NMI interference \t\t\t %9.2f us (%.2f %%)\n",
|
printf(" NMI interference %.*s %9.2f us (%.2f %%)\n", 36, spaces,
|
||||||
ns_to_usf(taa_data->thread_nmi_sum),
|
ns_to_usf(taa_data->thread_nmi_sum),
|
||||||
ns_to_per(total, taa_data->thread_nmi_sum));
|
ns_to_per(total, taa_data->thread_nmi_sum));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it is an IRQ latency, the other factors can be skipped.
|
* If it is an IRQ latency, the other factors can be skipped.
|
||||||
|
@ -643,9 +660,9 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* Prints the interference caused by IRQs to the thread latency.
|
* Prints the interference caused by IRQs to the thread latency.
|
||||||
*/
|
*/
|
||||||
if (taa_data->thread_irq_sum) {
|
if (taa_data->thread_irq_sum) {
|
||||||
printf(" IRQ interference \t\t\t %9.2f us (%.2f %%)\n",
|
printf(" IRQ interference %.*s %9.2f us (%.2f %%)\n", 36, spaces,
|
||||||
ns_to_usf(taa_data->thread_irq_sum),
|
ns_to_usf(taa_data->thread_irq_sum),
|
||||||
ns_to_per(total, taa_data->thread_irq_sum));
|
ns_to_per(total, taa_data->thread_irq_sum));
|
||||||
|
|
||||||
trace_seq_do_printf(taa_data->irqs_seq);
|
trace_seq_do_printf(taa_data->irqs_seq);
|
||||||
}
|
}
|
||||||
|
@ -654,9 +671,9 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* Prints the interference caused by Softirqs to the thread latency.
|
* Prints the interference caused by Softirqs to the thread latency.
|
||||||
*/
|
*/
|
||||||
if (taa_data->thread_softirq_sum) {
|
if (taa_data->thread_softirq_sum) {
|
||||||
printf(" Softirq interference \t\t\t %9.2f us (%.2f %%)\n",
|
printf(" Softirq interference %.*s %9.2f us (%.2f %%)\n", 32, spaces,
|
||||||
ns_to_usf(taa_data->thread_softirq_sum),
|
ns_to_usf(taa_data->thread_softirq_sum),
|
||||||
ns_to_per(total, taa_data->thread_softirq_sum));
|
ns_to_per(total, taa_data->thread_softirq_sum));
|
||||||
|
|
||||||
trace_seq_do_printf(taa_data->softirqs_seq);
|
trace_seq_do_printf(taa_data->softirqs_seq);
|
||||||
}
|
}
|
||||||
|
@ -670,9 +687,9 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
* timer handling latency.
|
* timer handling latency.
|
||||||
*/
|
*/
|
||||||
if (taa_data->thread_thread_sum) {
|
if (taa_data->thread_thread_sum) {
|
||||||
printf(" Thread interference \t\t\t %9.2f us (%.2f %%)\n",
|
printf(" Thread interference %.*s %9.2f us (%.2f %%)\n", 33, spaces,
|
||||||
ns_to_usf(taa_data->thread_thread_sum),
|
ns_to_usf(taa_data->thread_thread_sum),
|
||||||
ns_to_per(total, taa_data->thread_thread_sum));
|
ns_to_per(total, taa_data->thread_thread_sum));
|
||||||
|
|
||||||
trace_seq_do_printf(taa_data->threads_seq);
|
trace_seq_do_printf(taa_data->threads_seq);
|
||||||
}
|
}
|
||||||
|
@ -682,8 +699,8 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
|
||||||
*/
|
*/
|
||||||
print_total:
|
print_total:
|
||||||
printf("------------------------------------------------------------------------\n");
|
printf("------------------------------------------------------------------------\n");
|
||||||
printf(" %s latency: \t\t\t %9.2f us (100%%)\n", irq ? "IRQ" : "Thread",
|
printf(" %s latency: %.*s %9.2f us (100%%)\n", irq ? " IRQ" : "Thread",
|
||||||
ns_to_usf(total));
|
37, spaces, ns_to_usf(total));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int timerlat_auto_analysis_collect_trace(struct timerlat_aa_context *taa_ctx)
|
static int timerlat_auto_analysis_collect_trace(struct timerlat_aa_context *taa_ctx)
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct timerlat_hist_params {
|
||||||
int no_aa;
|
int no_aa;
|
||||||
int dump_tasks;
|
int dump_tasks;
|
||||||
int user_workload;
|
int user_workload;
|
||||||
|
int kernel_workload;
|
||||||
int user_hist;
|
int user_hist;
|
||||||
cpu_set_t hk_cpu_set;
|
cpu_set_t hk_cpu_set;
|
||||||
struct sched_attr sched_param;
|
struct sched_attr sched_param;
|
||||||
|
@ -52,6 +53,8 @@ struct timerlat_hist_params {
|
||||||
char with_zeros;
|
char with_zeros;
|
||||||
int bucket_size;
|
int bucket_size;
|
||||||
int entries;
|
int entries;
|
||||||
|
int warmup;
|
||||||
|
int buffer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct timerlat_hist_cpu {
|
struct timerlat_hist_cpu {
|
||||||
|
@ -324,17 +327,29 @@ timerlat_print_summary(struct timerlat_hist_params *params,
|
||||||
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
|
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!params->no_irq)
|
if (!params->no_irq) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].irq_count)
|
||||||
data->hist[cpu].min_irq);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].min_irq);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
|
|
||||||
if (!params->no_thread)
|
if (!params->no_thread) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].thread_count)
|
||||||
data->hist[cpu].min_thread);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].min_thread);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
|
|
||||||
if (params->user_hist)
|
if (params->user_hist) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].user_count)
|
||||||
data->hist[cpu].min_user);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].min_user);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
trace_seq_printf(trace->seq, "\n");
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
|
||||||
|
@ -384,25 +399,164 @@ timerlat_print_summary(struct timerlat_hist_params *params,
|
||||||
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
|
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!params->no_irq)
|
if (!params->no_irq) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].irq_count)
|
||||||
data->hist[cpu].max_irq);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].max_irq);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
|
|
||||||
if (!params->no_thread)
|
if (!params->no_thread) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].thread_count)
|
||||||
data->hist[cpu].max_thread);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].max_thread);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
|
|
||||||
if (params->user_hist)
|
if (params->user_hist) {
|
||||||
trace_seq_printf(trace->seq, "%9llu ",
|
if (data->hist[cpu].user_count)
|
||||||
data->hist[cpu].max_user);
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
data->hist[cpu].max_user);
|
||||||
|
else
|
||||||
|
trace_seq_printf(trace->seq, " - ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
trace_seq_printf(trace->seq, "\n");
|
trace_seq_printf(trace->seq, "\n");
|
||||||
trace_seq_do_printf(trace->seq);
|
trace_seq_do_printf(trace->seq);
|
||||||
trace_seq_reset(trace->seq);
|
trace_seq_reset(trace->seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timerlat_print_stats_all(struct timerlat_hist_params *params,
|
||||||
|
struct trace_instance *trace,
|
||||||
|
struct timerlat_hist_data *data)
|
||||||
|
{
|
||||||
|
struct timerlat_hist_cpu *cpu_data;
|
||||||
|
struct timerlat_hist_cpu sum;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
if (params->no_summary)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&sum, 0, sizeof(sum));
|
||||||
|
sum.min_irq = ~0;
|
||||||
|
sum.min_thread = ~0;
|
||||||
|
sum.min_user = ~0;
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
|
||||||
|
if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpu_data = &data->hist[cpu];
|
||||||
|
|
||||||
|
sum.irq_count += cpu_data->irq_count;
|
||||||
|
update_min(&sum.min_irq, &cpu_data->min_irq);
|
||||||
|
update_sum(&sum.sum_irq, &cpu_data->sum_irq);
|
||||||
|
update_max(&sum.max_irq, &cpu_data->max_irq);
|
||||||
|
|
||||||
|
sum.thread_count += cpu_data->thread_count;
|
||||||
|
update_min(&sum.min_thread, &cpu_data->min_thread);
|
||||||
|
update_sum(&sum.sum_thread, &cpu_data->sum_thread);
|
||||||
|
update_max(&sum.max_thread, &cpu_data->max_thread);
|
||||||
|
|
||||||
|
sum.user_count += cpu_data->user_count;
|
||||||
|
update_min(&sum.min_user, &cpu_data->min_user);
|
||||||
|
update_sum(&sum.sum_user, &cpu_data->sum_user);
|
||||||
|
update_max(&sum.max_user, &cpu_data->max_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params->no_index)
|
||||||
|
trace_seq_printf(trace->seq, "ALL: ");
|
||||||
|
|
||||||
|
if (!params->no_irq)
|
||||||
|
trace_seq_printf(trace->seq, " IRQ");
|
||||||
|
|
||||||
|
if (!params->no_thread)
|
||||||
|
trace_seq_printf(trace->seq, " Thr");
|
||||||
|
|
||||||
|
if (params->user_hist)
|
||||||
|
trace_seq_printf(trace->seq, " Usr");
|
||||||
|
|
||||||
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
|
||||||
|
if (!params->no_index)
|
||||||
|
trace_seq_printf(trace->seq, "count:");
|
||||||
|
|
||||||
|
if (!params->no_irq)
|
||||||
|
trace_seq_printf(trace->seq, "%9d ",
|
||||||
|
sum.irq_count);
|
||||||
|
|
||||||
|
if (!params->no_thread)
|
||||||
|
trace_seq_printf(trace->seq, "%9d ",
|
||||||
|
sum.thread_count);
|
||||||
|
|
||||||
|
if (params->user_hist)
|
||||||
|
trace_seq_printf(trace->seq, "%9d ",
|
||||||
|
sum.user_count);
|
||||||
|
|
||||||
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
|
||||||
|
if (!params->no_index)
|
||||||
|
trace_seq_printf(trace->seq, "min: ");
|
||||||
|
|
||||||
|
if (!params->no_irq)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.min_irq);
|
||||||
|
|
||||||
|
if (!params->no_thread)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.min_thread);
|
||||||
|
|
||||||
|
if (params->user_hist)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.min_user);
|
||||||
|
|
||||||
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
|
||||||
|
if (!params->no_index)
|
||||||
|
trace_seq_printf(trace->seq, "avg: ");
|
||||||
|
|
||||||
|
if (!params->no_irq)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.sum_irq / sum.irq_count);
|
||||||
|
|
||||||
|
if (!params->no_thread)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.sum_thread / sum.thread_count);
|
||||||
|
|
||||||
|
if (params->user_hist)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.sum_user / sum.user_count);
|
||||||
|
|
||||||
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
|
||||||
|
if (!params->no_index)
|
||||||
|
trace_seq_printf(trace->seq, "max: ");
|
||||||
|
|
||||||
|
if (!params->no_irq)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.max_irq);
|
||||||
|
|
||||||
|
if (!params->no_thread)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.max_thread);
|
||||||
|
|
||||||
|
if (params->user_hist)
|
||||||
|
trace_seq_printf(trace->seq, "%9llu ",
|
||||||
|
sum.max_user);
|
||||||
|
|
||||||
|
trace_seq_printf(trace->seq, "\n");
|
||||||
|
trace_seq_do_printf(trace->seq);
|
||||||
|
trace_seq_reset(trace->seq);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timerlat_print_stats - print data for all CPUs
|
* timerlat_print_stats - print data for each CPUs
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *tool)
|
timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *tool)
|
||||||
|
@ -485,6 +639,7 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
|
||||||
trace_seq_reset(trace->seq);
|
trace_seq_reset(trace->seq);
|
||||||
|
|
||||||
timerlat_print_summary(params, trace, data);
|
timerlat_print_summary(params, trace, data);
|
||||||
|
timerlat_print_stats_all(params, trace, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -497,9 +652,10 @@ static void timerlat_hist_usage(char *usage)
|
||||||
char *msg[] = {
|
char *msg[] = {
|
||||||
"",
|
"",
|
||||||
" usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\",
|
" usage: [rtla] timerlat hist [-h] [-q] [-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]\\",
|
" [-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] \\",
|
" [-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]",
|
" [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u|-k]",
|
||||||
|
" [--warm-up s]",
|
||||||
"",
|
"",
|
||||||
" -h/--help: print this menu",
|
" -h/--help: print this menu",
|
||||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||||
|
@ -513,7 +669,7 @@ static void timerlat_hist_usage(char *usage)
|
||||||
" -d/--duration time[m|h|d]: duration of the session in seconds",
|
" -d/--duration time[m|h|d]: duration of the session in seconds",
|
||||||
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
||||||
" -D/--debug: print debug info",
|
" -D/--debug: print debug info",
|
||||||
" -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
|
" -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]",
|
||||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||||
|
@ -534,8 +690,11 @@ static void timerlat_hist_usage(char *usage)
|
||||||
" f:prio - use SCHED_FIFO with prio",
|
" f:prio - use SCHED_FIFO with prio",
|
||||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||||
" in nanoseconds",
|
" in nanoseconds",
|
||||||
" -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
|
" -u/--user-threads: use rtla user-space threads instead of kernel-space timerlat threads",
|
||||||
|
" -k/--kernel-threads: use timerlat kernel-space threads instead of rtla user-space threads",
|
||||||
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
||||||
|
" --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",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -597,6 +756,7 @@ static struct timerlat_hist_params
|
||||||
{"thread", required_argument, 0, 'T'},
|
{"thread", required_argument, 0, 'T'},
|
||||||
{"trace", optional_argument, 0, 't'},
|
{"trace", optional_argument, 0, 't'},
|
||||||
{"user-threads", no_argument, 0, 'u'},
|
{"user-threads", no_argument, 0, 'u'},
|
||||||
|
{"kernel-threads", no_argument, 0, 'k'},
|
||||||
{"user-load", no_argument, 0, 'U'},
|
{"user-load", no_argument, 0, 'U'},
|
||||||
{"event", required_argument, 0, 'e'},
|
{"event", required_argument, 0, 'e'},
|
||||||
{"no-irq", no_argument, 0, '0'},
|
{"no-irq", no_argument, 0, '0'},
|
||||||
|
@ -610,13 +770,15 @@ static struct timerlat_hist_params
|
||||||
{"dma-latency", required_argument, 0, '8'},
|
{"dma-latency", required_argument, 0, '8'},
|
||||||
{"no-aa", no_argument, 0, '9'},
|
{"no-aa", no_argument, 0, '9'},
|
||||||
{"dump-task", no_argument, 0, '\1'},
|
{"dump-task", no_argument, 0, '\1'},
|
||||||
|
{"warm-up", required_argument, 0, '\2'},
|
||||||
|
{"trace-buffer-size", required_argument, 0, '\3'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* getopt_long stores the option index here. */
|
/* getopt_long stores the option index here. */
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:uU0123456:7:8:9\1",
|
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",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
|
|
||||||
/* detect the end of the options. */
|
/* detect the end of the options. */
|
||||||
|
@ -699,6 +861,9 @@ static struct timerlat_hist_params
|
||||||
case 'i':
|
case 'i':
|
||||||
params->stop_us = get_llong_from_str(optarg);
|
params->stop_us = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
params->kernel_workload = 1;
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
params->output_divisor = 1;
|
params->output_divisor = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -720,9 +885,13 @@ static struct timerlat_hist_params
|
||||||
params->stop_total_us = get_llong_from_str(optarg);
|
params->stop_total_us = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (optarg)
|
if (optarg) {
|
||||||
/* skip = */
|
if (optarg[0] == '=')
|
||||||
params->trace_output = &optarg[1];
|
params->trace_output = &optarg[1];
|
||||||
|
else
|
||||||
|
params->trace_output = &optarg[0];
|
||||||
|
} else if (optind < argc && argv[optind][0] != '-')
|
||||||
|
params->trace_output = argv[optind];
|
||||||
else
|
else
|
||||||
params->trace_output = "timerlat_trace.txt";
|
params->trace_output = "timerlat_trace.txt";
|
||||||
break;
|
break;
|
||||||
|
@ -785,6 +954,12 @@ static struct timerlat_hist_params
|
||||||
case '\1':
|
case '\1':
|
||||||
params->dump_tasks = 1;
|
params->dump_tasks = 1;
|
||||||
break;
|
break;
|
||||||
|
case '\2':
|
||||||
|
params->warmup = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
|
case '\3':
|
||||||
|
params->buffer_size = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
timerlat_hist_usage("Invalid option");
|
timerlat_hist_usage("Invalid option");
|
||||||
}
|
}
|
||||||
|
@ -807,6 +982,9 @@ static struct timerlat_hist_params
|
||||||
if (!params->stop_us && !params->stop_total_us)
|
if (!params->stop_us && !params->stop_total_us)
|
||||||
params->no_aa = 1;
|
params->no_aa = 1;
|
||||||
|
|
||||||
|
if (params->kernel_workload && params->user_workload)
|
||||||
|
timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!");
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,6 +1060,22 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
|
||||||
auto_house_keeping(¶ms->monitored_cpus);
|
auto_house_keeping(¶ms->monitored_cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user did not specify a type of thread, try user-threads first.
|
||||||
|
* Fall back to kernel threads otherwise.
|
||||||
|
*/
|
||||||
|
if (!params->kernel_workload && !params->user_workload) {
|
||||||
|
retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd");
|
||||||
|
if (retval) {
|
||||||
|
debug_msg("User-space interface detected, setting user-threads\n");
|
||||||
|
params->user_workload = 1;
|
||||||
|
params->user_hist = 1;
|
||||||
|
} else {
|
||||||
|
debug_msg("User-space interface not detected, setting kernel-threads\n");
|
||||||
|
params->kernel_workload = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (params->user_hist) {
|
if (params->user_hist) {
|
||||||
retval = osnoise_set_workload(tool->context, 0);
|
retval = osnoise_set_workload(tool->context, 0);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -1019,6 +1213,12 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_hist;
|
goto out_hist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->buffer_size > 0) {
|
||||||
|
retval = trace_set_buffer_size(&record->trace, params->buffer_size);
|
||||||
|
if (retval)
|
||||||
|
goto out_hist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params->no_aa) {
|
if (!params->no_aa) {
|
||||||
|
@ -1039,22 +1239,6 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Start the tracers here, after having set all instances.
|
|
||||||
*
|
|
||||||
* Let the trace instance start first for the case of hitting a stop
|
|
||||||
* tracing while enabling other instances. The trace instance is the
|
|
||||||
* one with most valuable information.
|
|
||||||
*/
|
|
||||||
if (params->trace_output)
|
|
||||||
trace_instance_start(&record->trace);
|
|
||||||
if (!params->no_aa)
|
|
||||||
trace_instance_start(&aa->trace);
|
|
||||||
trace_instance_start(trace);
|
|
||||||
|
|
||||||
tool->start_time = time(NULL);
|
|
||||||
timerlat_hist_set_signals(params);
|
|
||||||
|
|
||||||
if (params->user_workload) {
|
if (params->user_workload) {
|
||||||
/* rtla asked to stop */
|
/* rtla asked to stop */
|
||||||
params_u.should_run = 1;
|
params_u.should_run = 1;
|
||||||
|
@ -1074,6 +1258,29 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||||
err_msg("Error creating timerlat user-space threads\n");
|
err_msg("Error creating timerlat user-space threads\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->warmup > 0) {
|
||||||
|
debug_msg("Warming up for %d seconds\n", params->warmup);
|
||||||
|
sleep(params->warmup);
|
||||||
|
if (stop_tracing)
|
||||||
|
goto out_hist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the tracers here, after having set all instances.
|
||||||
|
*
|
||||||
|
* Let the trace instance start first for the case of hitting a stop
|
||||||
|
* tracing while enabling other instances. The trace instance is the
|
||||||
|
* one with most valuable information.
|
||||||
|
*/
|
||||||
|
if (params->trace_output)
|
||||||
|
trace_instance_start(&record->trace);
|
||||||
|
if (!params->no_aa)
|
||||||
|
trace_instance_start(&aa->trace);
|
||||||
|
trace_instance_start(trace);
|
||||||
|
|
||||||
|
tool->start_time = time(NULL);
|
||||||
|
timerlat_hist_set_signals(params);
|
||||||
|
|
||||||
while (!stop_tracing) {
|
while (!stop_tracing) {
|
||||||
sleep(params->sleep_time);
|
sleep(params->sleep_time);
|
||||||
|
|
||||||
|
@ -1099,6 +1306,7 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->user_workload && !params_u.stopped_running) {
|
if (params->user_workload && !params_u.stopped_running) {
|
||||||
params_u.should_run = 0;
|
params_u.should_run = 0;
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
|
@ -44,6 +44,10 @@ struct timerlat_top_params {
|
||||||
int hk_cpus;
|
int hk_cpus;
|
||||||
int user_top;
|
int user_top;
|
||||||
int user_workload;
|
int user_workload;
|
||||||
|
int kernel_workload;
|
||||||
|
int pretty_output;
|
||||||
|
int warmup;
|
||||||
|
int buffer_size;
|
||||||
cpu_set_t hk_cpu_set;
|
cpu_set_t hk_cpu_set;
|
||||||
struct sched_attr sched_param;
|
struct sched_attr sched_param;
|
||||||
struct trace_events *events;
|
struct trace_events *events;
|
||||||
|
@ -118,6 +122,37 @@ static struct timerlat_top_data *timerlat_alloc_top(int nr_cpus)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timerlat_top_reset_sum(struct timerlat_top_cpu *summary)
|
||||||
|
{
|
||||||
|
memset(summary, 0, sizeof(*summary));
|
||||||
|
summary->min_irq = ~0;
|
||||||
|
summary->min_thread = ~0;
|
||||||
|
summary->min_user = ~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timerlat_top_update_sum(struct osnoise_tool *tool, int cpu, struct timerlat_top_cpu *sum)
|
||||||
|
{
|
||||||
|
struct timerlat_top_data *data = tool->data;
|
||||||
|
struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu];
|
||||||
|
|
||||||
|
sum->irq_count += cpu_data->irq_count;
|
||||||
|
update_min(&sum->min_irq, &cpu_data->min_irq);
|
||||||
|
update_sum(&sum->sum_irq, &cpu_data->sum_irq);
|
||||||
|
update_max(&sum->max_irq, &cpu_data->max_irq);
|
||||||
|
|
||||||
|
sum->thread_count += cpu_data->thread_count;
|
||||||
|
update_min(&sum->min_thread, &cpu_data->min_thread);
|
||||||
|
update_sum(&sum->sum_thread, &cpu_data->sum_thread);
|
||||||
|
update_max(&sum->max_thread, &cpu_data->max_thread);
|
||||||
|
|
||||||
|
sum->user_count += cpu_data->user_count;
|
||||||
|
update_min(&sum->min_user, &cpu_data->min_user);
|
||||||
|
update_sum(&sum->sum_user, &cpu_data->sum_user);
|
||||||
|
update_max(&sum->max_user, &cpu_data->max_user);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timerlat_hist_update - record a new timerlat occurent on cpu, updating data
|
* timerlat_hist_update - record a new timerlat occurent on cpu, updating data
|
||||||
*/
|
*/
|
||||||
|
@ -179,19 +214,22 @@ timerlat_top_handler(struct trace_seq *s, struct tep_record *record,
|
||||||
/*
|
/*
|
||||||
* timerlat_top_header - print the header of the tool output
|
* timerlat_top_header - print the header of the tool output
|
||||||
*/
|
*/
|
||||||
static void timerlat_top_header(struct osnoise_tool *top)
|
static void timerlat_top_header(struct timerlat_top_params *params, struct osnoise_tool *top)
|
||||||
{
|
{
|
||||||
struct timerlat_top_params *params = top->params;
|
|
||||||
struct trace_seq *s = top->trace.seq;
|
struct trace_seq *s = top->trace.seq;
|
||||||
char duration[26];
|
char duration[26];
|
||||||
|
|
||||||
get_duration(top->start_time, duration, sizeof(duration));
|
get_duration(top->start_time, duration, sizeof(duration));
|
||||||
|
|
||||||
trace_seq_printf(s, "\033[2;37;40m");
|
if (params->pretty_output)
|
||||||
|
trace_seq_printf(s, "\033[2;37;40m");
|
||||||
|
|
||||||
trace_seq_printf(s, " Timer Latency ");
|
trace_seq_printf(s, " Timer Latency ");
|
||||||
if (params->user_top)
|
if (params->user_top)
|
||||||
trace_seq_printf(s, " ");
|
trace_seq_printf(s, " ");
|
||||||
trace_seq_printf(s, "\033[0;0;0m");
|
|
||||||
|
if (params->pretty_output)
|
||||||
|
trace_seq_printf(s, "\033[0;0;0m");
|
||||||
trace_seq_printf(s, "\n");
|
trace_seq_printf(s, "\n");
|
||||||
|
|
||||||
trace_seq_printf(s, "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)", duration,
|
trace_seq_printf(s, "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)", duration,
|
||||||
|
@ -204,14 +242,20 @@ static void timerlat_top_header(struct osnoise_tool *top)
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_seq_printf(s, "\n");
|
trace_seq_printf(s, "\n");
|
||||||
trace_seq_printf(s, "\033[2;30;47m");
|
if (params->pretty_output)
|
||||||
|
trace_seq_printf(s, "\033[2;30;47m");
|
||||||
|
|
||||||
trace_seq_printf(s, "CPU COUNT | cur min avg max | cur min avg max");
|
trace_seq_printf(s, "CPU COUNT | cur min avg max | cur min avg max");
|
||||||
if (params->user_top)
|
if (params->user_top)
|
||||||
trace_seq_printf(s, " | cur min avg max");
|
trace_seq_printf(s, " | cur min avg max");
|
||||||
trace_seq_printf(s, "\033[0;0;0m");
|
|
||||||
|
if (params->pretty_output)
|
||||||
|
trace_seq_printf(s, "\033[0;0;0m");
|
||||||
trace_seq_printf(s, "\n");
|
trace_seq_printf(s, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *no_value = " -";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timerlat_top_print - prints the output of a given CPU
|
* timerlat_top_print - prints the output of a given CPU
|
||||||
*/
|
*/
|
||||||
|
@ -239,10 +283,7 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
|
||||||
trace_seq_printf(s, "%3d #%-9d |", cpu, cpu_data->irq_count);
|
trace_seq_printf(s, "%3d #%-9d |", cpu, cpu_data->irq_count);
|
||||||
|
|
||||||
if (!cpu_data->irq_count) {
|
if (!cpu_data->irq_count) {
|
||||||
trace_seq_printf(s, " - ");
|
trace_seq_printf(s, "%s %s %s %s |", no_value, no_value, no_value, no_value);
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " - |");
|
|
||||||
} else {
|
} else {
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->cur_irq / params->output_divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->cur_irq / params->output_divisor);
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->min_irq / params->output_divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->min_irq / params->output_divisor);
|
||||||
|
@ -251,10 +292,7 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpu_data->thread_count) {
|
if (!cpu_data->thread_count) {
|
||||||
trace_seq_printf(s, " - ");
|
trace_seq_printf(s, "%s %s %s %s", no_value, no_value, no_value, no_value);
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " -\n");
|
|
||||||
} else {
|
} else {
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->cur_thread / divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->cur_thread / divisor);
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->min_thread / divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->min_thread / divisor);
|
||||||
|
@ -271,10 +309,7 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
|
||||||
trace_seq_printf(s, " |");
|
trace_seq_printf(s, " |");
|
||||||
|
|
||||||
if (!cpu_data->user_count) {
|
if (!cpu_data->user_count) {
|
||||||
trace_seq_printf(s, " - ");
|
trace_seq_printf(s, "%s %s %s %s\n", no_value, no_value, no_value, no_value);
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " - ");
|
|
||||||
trace_seq_printf(s, " -\n");
|
|
||||||
} else {
|
} else {
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->cur_user / divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->cur_user / divisor);
|
||||||
trace_seq_printf(s, "%9llu ", cpu_data->min_user / divisor);
|
trace_seq_printf(s, "%9llu ", cpu_data->min_user / divisor);
|
||||||
|
@ -284,6 +319,77 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* timerlat_top_print_sum - prints the summary output
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
timerlat_top_print_sum(struct osnoise_tool *top, struct timerlat_top_cpu *summary)
|
||||||
|
{
|
||||||
|
const char *split = "----------------------------------------";
|
||||||
|
struct timerlat_top_params *params = top->params;
|
||||||
|
unsigned long long count = summary->irq_count;
|
||||||
|
int divisor = params->output_divisor;
|
||||||
|
struct trace_seq *s = top->trace.seq;
|
||||||
|
int e = 0;
|
||||||
|
|
||||||
|
if (divisor == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip if no data is available: is this cpu offline?
|
||||||
|
*/
|
||||||
|
if (!summary->irq_count && !summary->thread_count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (count > 999999) {
|
||||||
|
e++;
|
||||||
|
count /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_seq_printf(s, "%.*s|%.*s|%.*s", 15, split, 40, split, 39, split);
|
||||||
|
if (params->user_top)
|
||||||
|
trace_seq_printf(s, "-|%.*s", 39, split);
|
||||||
|
trace_seq_printf(s, "\n");
|
||||||
|
|
||||||
|
trace_seq_printf(s, "ALL #%-6llu e%d |", count, e);
|
||||||
|
|
||||||
|
if (!summary->irq_count) {
|
||||||
|
trace_seq_printf(s, " %s %s %s |", no_value, no_value, no_value);
|
||||||
|
} else {
|
||||||
|
trace_seq_printf(s, " ");
|
||||||
|
trace_seq_printf(s, "%9llu ", summary->min_irq / params->output_divisor);
|
||||||
|
trace_seq_printf(s, "%9llu ", (summary->sum_irq / summary->irq_count) / divisor);
|
||||||
|
trace_seq_printf(s, "%9llu |", summary->max_irq / divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!summary->thread_count) {
|
||||||
|
trace_seq_printf(s, "%s %s %s %s", no_value, no_value, no_value, no_value);
|
||||||
|
} else {
|
||||||
|
trace_seq_printf(s, " ");
|
||||||
|
trace_seq_printf(s, "%9llu ", summary->min_thread / divisor);
|
||||||
|
trace_seq_printf(s, "%9llu ",
|
||||||
|
(summary->sum_thread / summary->thread_count) / divisor);
|
||||||
|
trace_seq_printf(s, "%9llu", summary->max_thread / divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params->user_top) {
|
||||||
|
trace_seq_printf(s, "\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_seq_printf(s, " |");
|
||||||
|
|
||||||
|
if (!summary->user_count) {
|
||||||
|
trace_seq_printf(s, " %s %s %s |", no_value, no_value, no_value);
|
||||||
|
} else {
|
||||||
|
trace_seq_printf(s, " ");
|
||||||
|
trace_seq_printf(s, "%9llu ", summary->min_user / divisor);
|
||||||
|
trace_seq_printf(s, "%9llu ",
|
||||||
|
(summary->sum_user / summary->user_count) / divisor);
|
||||||
|
trace_seq_printf(s, "%9llu\n", summary->max_user / divisor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear_terminal - clears the output terminal
|
* clear_terminal - clears the output terminal
|
||||||
*/
|
*/
|
||||||
|
@ -300,6 +406,7 @@ static void
|
||||||
timerlat_print_stats(struct timerlat_top_params *params, struct osnoise_tool *top)
|
timerlat_print_stats(struct timerlat_top_params *params, struct osnoise_tool *top)
|
||||||
{
|
{
|
||||||
struct trace_instance *trace = &top->trace;
|
struct trace_instance *trace = &top->trace;
|
||||||
|
struct timerlat_top_cpu summary;
|
||||||
static int nr_cpus = -1;
|
static int nr_cpus = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -312,14 +419,19 @@ timerlat_print_stats(struct timerlat_top_params *params, struct osnoise_tool *to
|
||||||
if (!params->quiet)
|
if (!params->quiet)
|
||||||
clear_terminal(trace->seq);
|
clear_terminal(trace->seq);
|
||||||
|
|
||||||
timerlat_top_header(top);
|
timerlat_top_reset_sum(&summary);
|
||||||
|
|
||||||
|
timerlat_top_header(params, top);
|
||||||
|
|
||||||
for (i = 0; i < nr_cpus; i++) {
|
for (i = 0; i < nr_cpus; i++) {
|
||||||
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
||||||
continue;
|
continue;
|
||||||
timerlat_top_print(top, i);
|
timerlat_top_print(top, i);
|
||||||
|
timerlat_top_update_sum(top, i, &summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timerlat_top_print_sum(top, &summary);
|
||||||
|
|
||||||
trace_seq_do_printf(trace->seq);
|
trace_seq_do_printf(trace->seq);
|
||||||
trace_seq_reset(trace->seq);
|
trace_seq_reset(trace->seq);
|
||||||
}
|
}
|
||||||
|
@ -334,8 +446,8 @@ static void timerlat_top_usage(char *usage)
|
||||||
static const char *const msg[] = {
|
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] \\",
|
" usage: rtla timerlat [top] [-h] [-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]\\",
|
" [[-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]",
|
" [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s]",
|
||||||
"",
|
"",
|
||||||
" -h/--help: print this menu",
|
" -h/--help: print this menu",
|
||||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||||
|
@ -350,7 +462,7 @@ static void timerlat_top_usage(char *usage)
|
||||||
" -d/--duration time[m|h|d]: duration of the session in seconds",
|
" -d/--duration time[m|h|d]: duration of the session in seconds",
|
||||||
" -D/--debug: print debug info",
|
" -D/--debug: print debug info",
|
||||||
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
||||||
" -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
|
" -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]",
|
||||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||||
" --filter <command>: enable a trace event filter to the previous -e event",
|
" --filter <command>: enable a trace event filter to the previous -e event",
|
||||||
" --trigger <command>: enable a trace event trigger to the previous -e event",
|
" --trigger <command>: enable a trace event trigger to the previous -e event",
|
||||||
|
@ -364,8 +476,11 @@ static void timerlat_top_usage(char *usage)
|
||||||
" f:prio - use SCHED_FIFO with prio",
|
" f:prio - use SCHED_FIFO with prio",
|
||||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||||
" in nanoseconds",
|
" in nanoseconds",
|
||||||
" -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
|
" -u/--user-threads: use rtla user-space threads instead of kernel-space timerlat threads",
|
||||||
|
" -k/--kernel-threads: use timerlat kernel-space threads instead of rtla user-space threads",
|
||||||
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
||||||
|
" --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",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -425,6 +540,7 @@ static struct timerlat_top_params
|
||||||
{"thread", required_argument, 0, 'T'},
|
{"thread", required_argument, 0, 'T'},
|
||||||
{"trace", optional_argument, 0, 't'},
|
{"trace", optional_argument, 0, 't'},
|
||||||
{"user-threads", no_argument, 0, 'u'},
|
{"user-threads", no_argument, 0, 'u'},
|
||||||
|
{"kernel-threads", no_argument, 0, 'k'},
|
||||||
{"user-load", no_argument, 0, 'U'},
|
{"user-load", no_argument, 0, 'U'},
|
||||||
{"trigger", required_argument, 0, '0'},
|
{"trigger", required_argument, 0, '0'},
|
||||||
{"filter", required_argument, 0, '1'},
|
{"filter", required_argument, 0, '1'},
|
||||||
|
@ -432,13 +548,15 @@ static struct timerlat_top_params
|
||||||
{"no-aa", no_argument, 0, '3'},
|
{"no-aa", no_argument, 0, '3'},
|
||||||
{"dump-tasks", no_argument, 0, '4'},
|
{"dump-tasks", no_argument, 0, '4'},
|
||||||
{"aa-only", required_argument, 0, '5'},
|
{"aa-only", required_argument, 0, '5'},
|
||||||
|
{"warm-up", required_argument, 0, '6'},
|
||||||
|
{"trace-buffer-size", required_argument, 0, '7'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* getopt_long stores the option index here. */
|
/* getopt_long stores the option index here. */
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:np:P:qs:t::T:uU0:1:2:345:",
|
c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
|
|
||||||
/* detect the end of the options. */
|
/* detect the end of the options. */
|
||||||
|
@ -523,6 +641,9 @@ static struct timerlat_top_params
|
||||||
case 'i':
|
case 'i':
|
||||||
params->stop_us = get_llong_from_str(optarg);
|
params->stop_us = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
params->kernel_workload = true;
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
params->output_divisor = 1;
|
params->output_divisor = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -547,9 +668,13 @@ static struct timerlat_top_params
|
||||||
params->stop_total_us = get_llong_from_str(optarg);
|
params->stop_total_us = get_llong_from_str(optarg);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (optarg)
|
if (optarg) {
|
||||||
/* skip = */
|
if (optarg[0] == '=')
|
||||||
params->trace_output = &optarg[1];
|
params->trace_output = &optarg[1];
|
||||||
|
else
|
||||||
|
params->trace_output = &optarg[0];
|
||||||
|
} else if (optind < argc && argv[optind][0] != '-')
|
||||||
|
params->trace_output = argv[optind];
|
||||||
else
|
else
|
||||||
params->trace_output = "timerlat_trace.txt";
|
params->trace_output = "timerlat_trace.txt";
|
||||||
|
|
||||||
|
@ -595,6 +720,12 @@ static struct timerlat_top_params
|
||||||
case '4':
|
case '4':
|
||||||
params->dump_tasks = 1;
|
params->dump_tasks = 1;
|
||||||
break;
|
break;
|
||||||
|
case '6':
|
||||||
|
params->warmup = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
params->buffer_size = get_llong_from_str(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
timerlat_top_usage("Invalid option");
|
timerlat_top_usage("Invalid option");
|
||||||
}
|
}
|
||||||
|
@ -614,6 +745,9 @@ static struct timerlat_top_params
|
||||||
if (params->no_aa && params->aa_only)
|
if (params->no_aa && params->aa_only)
|
||||||
timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!");
|
timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!");
|
||||||
|
|
||||||
|
if (params->kernel_workload && params->user_workload)
|
||||||
|
timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!");
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,6 +826,22 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
|
||||||
auto_house_keeping(¶ms->monitored_cpus);
|
auto_house_keeping(¶ms->monitored_cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user did not specify a type of thread, try user-threads first.
|
||||||
|
* Fall back to kernel threads otherwise.
|
||||||
|
*/
|
||||||
|
if (!params->kernel_workload && !params->user_workload) {
|
||||||
|
retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd");
|
||||||
|
if (retval) {
|
||||||
|
debug_msg("User-space interface detected, setting user-threads\n");
|
||||||
|
params->user_workload = 1;
|
||||||
|
params->user_top = 1;
|
||||||
|
} else {
|
||||||
|
debug_msg("User-space interface not detected, setting kernel-threads\n");
|
||||||
|
params->kernel_workload = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (params->user_top) {
|
if (params->user_top) {
|
||||||
retval = osnoise_set_workload(top->context, 0);
|
retval = osnoise_set_workload(top->context, 0);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -700,6 +850,9 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isatty(1) && !params->quiet)
|
||||||
|
params->pretty_output = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
|
@ -830,6 +983,12 @@ int timerlat_top_main(int argc, char *argv[])
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_top;
|
goto out_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->buffer_size > 0) {
|
||||||
|
retval = trace_set_buffer_size(&record->trace, params->buffer_size);
|
||||||
|
if (retval)
|
||||||
|
goto out_top;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params->no_aa) {
|
if (!params->no_aa) {
|
||||||
|
@ -859,22 +1018,6 @@ int timerlat_top_main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Start the tracers here, after having set all instances.
|
|
||||||
*
|
|
||||||
* Let the trace instance start first for the case of hitting a stop
|
|
||||||
* tracing while enabling other instances. The trace instance is the
|
|
||||||
* one with most valuable information.
|
|
||||||
*/
|
|
||||||
if (params->trace_output)
|
|
||||||
trace_instance_start(&record->trace);
|
|
||||||
if (!params->no_aa && aa != top)
|
|
||||||
trace_instance_start(&aa->trace);
|
|
||||||
trace_instance_start(trace);
|
|
||||||
|
|
||||||
top->start_time = time(NULL);
|
|
||||||
timerlat_top_set_signals(params);
|
|
||||||
|
|
||||||
if (params->user_workload) {
|
if (params->user_workload) {
|
||||||
/* rtla asked to stop */
|
/* rtla asked to stop */
|
||||||
params_u.should_run = 1;
|
params_u.should_run = 1;
|
||||||
|
@ -894,6 +1037,27 @@ int timerlat_top_main(int argc, char *argv[])
|
||||||
err_msg("Error creating timerlat user-space threads\n");
|
err_msg("Error creating timerlat user-space threads\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->warmup > 0) {
|
||||||
|
debug_msg("Warming up for %d seconds\n", params->warmup);
|
||||||
|
sleep(params->warmup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the tracers here, after having set all instances.
|
||||||
|
*
|
||||||
|
* Let the trace instance start first for the case of hitting a stop
|
||||||
|
* tracing while enabling other instances. The trace instance is the
|
||||||
|
* one with most valuable information.
|
||||||
|
*/
|
||||||
|
if (params->trace_output)
|
||||||
|
trace_instance_start(&record->trace);
|
||||||
|
if (!params->no_aa && aa != top)
|
||||||
|
trace_instance_start(&aa->trace);
|
||||||
|
trace_instance_start(trace);
|
||||||
|
|
||||||
|
top->start_time = time(NULL);
|
||||||
|
timerlat_top_set_signals(params);
|
||||||
|
|
||||||
while (!stop_tracing) {
|
while (!stop_tracing) {
|
||||||
sleep(params->sleep_time);
|
sleep(params->sleep_time);
|
||||||
|
|
||||||
|
|
|
@ -540,3 +540,18 @@ int trace_is_off(struct trace_instance *tool, struct trace_instance *trace)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* trace_set_buffer_size - set the per-cpu tracing buffer size.
|
||||||
|
*/
|
||||||
|
int trace_set_buffer_size(struct trace_instance *trace, int size)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
debug_msg("Setting trace buffer size to %d Kb\n", size);
|
||||||
|
retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
|
||||||
|
if (retval)
|
||||||
|
err_msg("Error setting trace buffer size\n");
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
|
@ -48,3 +48,4 @@ int trace_events_enable(struct trace_instance *instance,
|
||||||
int trace_event_add_filter(struct trace_events *event, char *filter);
|
int trace_event_add_filter(struct trace_events *event, char *filter);
|
||||||
int trace_event_add_trigger(struct trace_events *event, char *trigger);
|
int trace_event_add_trigger(struct trace_events *event, char *trigger);
|
||||||
int trace_is_off(struct trace_instance *tool, struct trace_instance *trace);
|
int trace_is_off(struct trace_instance *tool, struct trace_instance *trace);
|
||||||
|
int trace_set_buffer_size(struct trace_instance *trace, int size);
|
||||||
|
|
Loading…
Reference in a new issue