mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 00:35:01 +00:00
tracing/tools: Updates for 6.13
- Add ':' to getopt option 'trace-buffer-size' in timerlat_hist for consistency - Remove unused sched_getattr define - Rename sched_setattr() helper to syscall_sched_setattr() to avoid conflicts - Update counters to long from int to avoid overflow - Add libcpupower dependency detection - Add --deepest-idle-state to timerlat to limit deep idle sleeps - Other minor clean ups and documentation changes -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZz5O/hQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qkLlAQDAJ0MASrdbJRDrLrfmKX6sja582MLe 3MvevdSkOeXRdQEA0tzm46KOb5/aYNotzpntQVkTjuZiPBHSgn1JzASiaAI= =OZ1w -----END PGP SIGNATURE----- Merge tag 'trace-tools-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing tools updates from Steven Rostedt: - Add ':' to getopt option 'trace-buffer-size' in timerlat_hist for consistency - Remove unused sched_getattr define - Rename sched_setattr() helper to syscall_sched_setattr() to avoid conflicts - Update counters to long from int to avoid overflow - Add libcpupower dependency detection - Add --deepest-idle-state to timerlat to limit deep idle sleeps - Other minor clean ups and documentation changes * tag 'trace-tools-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: verification/dot2: Improve dot parser robustness tools/rtla: Improve exception handling in timerlat_load.py tools/rtla: Enhance argument parsing in timerlat_load.py tools/rtla: Improve code readability in timerlat_load.py rtla/timerlat: Do not set params->user_workload with -U rtla: Documentation: Mention --deepest-idle-state rtla/timerlat: Add --deepest-idle-state for hist rtla/timerlat: Add --deepest-idle-state for top rtla/utils: Add idle state disabling via libcpupower rtla: Add optional dependency on libcpupower tools/build: Add libcpupower dependency detection rtla/timerlat: Make timerlat_hist_cpu->*_count unsigned long long rtla/timerlat: Make timerlat_top_cpu->*_count unsigned long long tools/rtla: fix collision with glibc sched_attr/sched_set_attr tools/rtla: drop __NR_sched_getattr rtla: Fix consistency in getopt_long for timerlat_hist rv: Fix a typo tools/rv: Correct the grammatical errors in the comments tools/rv: Correct the grammatical errors in the comments rtla: use the definition for stdout fd when calling isatty()
This commit is contained in:
commit
4b01712311
@ -31,6 +31,14 @@
|
||||
*cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have
|
||||
similar results.
|
||||
|
||||
**--deepest-idle-state** *n*
|
||||
Disable idle states higher than *n* for cpus that are running timerlat threads to
|
||||
reduce exit from idle latencies. If *n* is -1, all idle states are disabled.
|
||||
On exit from timerlat, the idle state setting is restored to its original state
|
||||
before running timerlat.
|
||||
|
||||
Requires rtla to be built with libcpupower.
|
||||
|
||||
**-k**, **--kernel-threads**
|
||||
|
||||
Use timerlat kernel-space threads, in contrast of **-u**.
|
||||
|
@ -41,7 +41,7 @@
|
||||
* per-task monitor, and so on), and the helper functions that glue the
|
||||
* monitor to the system via trace. Generally, a monitor includes some form
|
||||
* of trace output as a reaction for event parsing and exceptions,
|
||||
* as depicted bellow:
|
||||
* as depicted below:
|
||||
*
|
||||
* Linux +----- RV Monitor ----------------------------------+ Formal
|
||||
* Realm | | Realm
|
||||
|
@ -53,6 +53,7 @@ FEATURE_TESTS_BASIC := \
|
||||
libslang-include-subdir \
|
||||
libtraceevent \
|
||||
libtracefs \
|
||||
libcpupower \
|
||||
libcrypto \
|
||||
libunwind \
|
||||
pthread-attr-setaffinity-np \
|
||||
|
@ -38,6 +38,7 @@ FILES= \
|
||||
test-libslang.bin \
|
||||
test-libslang-include-subdir.bin \
|
||||
test-libtraceevent.bin \
|
||||
test-libcpupower.bin \
|
||||
test-libtracefs.bin \
|
||||
test-libcrypto.bin \
|
||||
test-libunwind.bin \
|
||||
@ -248,6 +249,9 @@ $(OUTPUT)test-libslang-include-subdir.bin:
|
||||
$(OUTPUT)test-libtraceevent.bin:
|
||||
$(BUILD) -ltraceevent
|
||||
|
||||
$(OUTPUT)test-libcpupower.bin:
|
||||
$(BUILD) -lcpupower
|
||||
|
||||
$(OUTPUT)test-libtracefs.bin:
|
||||
$(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs
|
||||
|
||||
|
8
tools/build/feature/test-libcpupower.c
Normal file
8
tools/build/feature/test-libcpupower.c
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <cpuidle.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rv = cpuidle_state_count(0);
|
||||
return rv;
|
||||
}
|
@ -32,8 +32,10 @@ DOCSRC := ../../../Documentation/tools/rtla/
|
||||
|
||||
FEATURE_TESTS := libtraceevent
|
||||
FEATURE_TESTS += libtracefs
|
||||
FEATURE_TESTS += libcpupower
|
||||
FEATURE_DISPLAY := libtraceevent
|
||||
FEATURE_DISPLAY += libtracefs
|
||||
FEATURE_DISPLAY += libcpupower
|
||||
|
||||
ifeq ($(V),1)
|
||||
Q =
|
||||
|
@ -43,6 +43,16 @@ else
|
||||
$(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
|
||||
endif
|
||||
|
||||
$(call feature_check,libcpupower)
|
||||
ifeq ($(feature-libcpupower), 1)
|
||||
$(call detected,CONFIG_LIBCPUPOWER)
|
||||
CFLAGS += -DHAVE_LIBCPUPOWER_SUPPORT
|
||||
EXTLIBS += -lcpupower
|
||||
else
|
||||
$(info libcpupower is missing, building without --deepest-idle-state support.)
|
||||
$(info Please install libcpupower-dev/kernel-tools-libs-devel)
|
||||
endif
|
||||
|
||||
ifeq ($(STOP_ERROR),1)
|
||||
$(error Please, check the errors above.)
|
||||
endif
|
||||
|
@ -11,6 +11,7 @@ RTLA depends on the following libraries and tools:
|
||||
|
||||
- libtracefs
|
||||
- libtraceevent
|
||||
- libcpupower (optional, for --deepest-idle-state)
|
||||
|
||||
It also depends on python3-docutils to compile man pages.
|
||||
|
||||
@ -26,6 +27,9 @@ For development, we suggest the following steps for compiling rtla:
|
||||
$ make
|
||||
$ sudo make install
|
||||
$ cd ..
|
||||
$ cd $libcpupower_src
|
||||
$ make
|
||||
$ sudo make install
|
||||
$ cd $rtla_src
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
@ -25,50 +25,54 @@ import sys
|
||||
import os
|
||||
|
||||
parser = argparse.ArgumentParser(description='user-space timerlat thread in Python')
|
||||
parser.add_argument("cpu", help='CPU to run timerlat thread')
|
||||
parser.add_argument("-p", "--prio", help='FIFO priority')
|
||||
|
||||
parser.add_argument("cpu", type=int, help='CPU to run timerlat thread')
|
||||
parser.add_argument("-p", "--prio", type=int, help='FIFO priority')
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
affinity_mask = { int(args.cpu) }
|
||||
except:
|
||||
print("Invalid cpu: " + args.cpu)
|
||||
exit(1)
|
||||
affinity_mask = {args.cpu}
|
||||
os.sched_setaffinity(0, affinity_mask)
|
||||
except Exception as e:
|
||||
print(f"Error setting affinity: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
os.sched_setaffinity(0, affinity_mask);
|
||||
except:
|
||||
print("Error setting affinity")
|
||||
exit(1)
|
||||
|
||||
if (args.prio):
|
||||
if args.prio:
|
||||
try:
|
||||
param = os.sched_param(int(args.prio))
|
||||
param = os.sched_param(args.prio)
|
||||
os.sched_setscheduler(0, os.SCHED_FIFO, param)
|
||||
except:
|
||||
print("Error setting priority")
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error setting priority: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
timerlat_path = "/sys/kernel/tracing/osnoise/per_cpu/cpu" + args.cpu + "/timerlat_fd"
|
||||
timerlat_path = f"/sys/kernel/tracing/osnoise/per_cpu/cpu{args.cpu}/timerlat_fd"
|
||||
timerlat_fd = open(timerlat_path, 'r')
|
||||
except:
|
||||
except PermissionError:
|
||||
print("Permission denied. Please check your access rights.")
|
||||
sys.exit(1)
|
||||
except OSError:
|
||||
print("Error opening timerlat fd, did you run timerlat -U?")
|
||||
exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
data_fd = open("/dev/full", 'r');
|
||||
except:
|
||||
print("Error opening data fd")
|
||||
data_fd = open("/dev/full", 'r')
|
||||
except Exception as e:
|
||||
print(f"Error opening data fd: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
while True:
|
||||
try:
|
||||
timerlat_fd.read(1)
|
||||
data_fd.read(20*1024*1024)
|
||||
except:
|
||||
data_fd.read(20 * 1024 * 1024)
|
||||
except KeyboardInterrupt:
|
||||
print("Leaving")
|
||||
break
|
||||
except IOError as e:
|
||||
print(f"I/O error occurred: {e}")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
break
|
||||
|
||||
timerlat_fd.close()
|
||||
data_fd.close()
|
||||
|
@ -627,7 +627,7 @@ osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_top_params *p
|
||||
auto_house_keeping(¶ms->monitored_cpus);
|
||||
}
|
||||
|
||||
if (isatty(1) && !params->quiet)
|
||||
if (isatty(STDOUT_FILENO) && !params->quiet)
|
||||
params->pretty_output = 1;
|
||||
|
||||
return 0;
|
||||
|
@ -55,6 +55,7 @@ struct timerlat_hist_params {
|
||||
int entries;
|
||||
int warmup;
|
||||
int buffer_size;
|
||||
int deepest_idle_state;
|
||||
};
|
||||
|
||||
struct timerlat_hist_cpu {
|
||||
@ -62,9 +63,9 @@ struct timerlat_hist_cpu {
|
||||
int *thread;
|
||||
int *user;
|
||||
|
||||
int irq_count;
|
||||
int thread_count;
|
||||
int user_count;
|
||||
unsigned long long irq_count;
|
||||
unsigned long long thread_count;
|
||||
unsigned long long user_count;
|
||||
|
||||
unsigned long long min_irq;
|
||||
unsigned long long sum_irq;
|
||||
@ -304,15 +305,15 @@ timerlat_print_summary(struct timerlat_hist_params *params,
|
||||
continue;
|
||||
|
||||
if (!params->no_irq)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
data->hist[cpu].irq_count);
|
||||
|
||||
if (!params->no_thread)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
data->hist[cpu].thread_count);
|
||||
|
||||
if (params->user_hist)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
data->hist[cpu].user_count);
|
||||
}
|
||||
trace_seq_printf(trace->seq, "\n");
|
||||
@ -488,15 +489,15 @@ timerlat_print_stats_all(struct timerlat_hist_params *params,
|
||||
trace_seq_printf(trace->seq, "count:");
|
||||
|
||||
if (!params->no_irq)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
sum.irq_count);
|
||||
|
||||
if (!params->no_thread)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
sum.thread_count);
|
||||
|
||||
if (params->user_hist)
|
||||
trace_seq_printf(trace->seq, "%9d ",
|
||||
trace_seq_printf(trace->seq, "%9llu ",
|
||||
sum.user_count);
|
||||
|
||||
trace_seq_printf(trace->seq, "\n");
|
||||
@ -655,7 +656,7 @@ static void timerlat_hist_usage(char *usage)
|
||||
" [-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]",
|
||||
" [--warm-up s] [--deepest-idle-state n]",
|
||||
"",
|
||||
" -h/--help: print this menu",
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||
@ -695,6 +696,7 @@ static void timerlat_hist_usage(char *usage)
|
||||
" -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",
|
||||
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -732,6 +734,9 @@ static struct timerlat_hist_params
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
|
||||
/* disabled by default */
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->output_divisor = 1000;
|
||||
params->bucket_size = 1;
|
||||
@ -772,13 +777,14 @@ static struct timerlat_hist_params
|
||||
{"dump-task", no_argument, 0, '\1'},
|
||||
{"warm-up", required_argument, 0, '\2'},
|
||||
{"trace-buffer-size", required_argument, 0, '\3'},
|
||||
{"deepest-idle-state", required_argument, 0, '\4'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 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",
|
||||
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);
|
||||
|
||||
/* detect the end of the options. */
|
||||
@ -960,6 +966,9 @@ static struct timerlat_hist_params
|
||||
case '\3':
|
||||
params->buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '\4':
|
||||
params->deepest_idle_state = get_llong_from_str(optarg);
|
||||
break;
|
||||
default:
|
||||
timerlat_hist_usage("Invalid option");
|
||||
}
|
||||
@ -1064,7 +1073,7 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
|
||||
* 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) {
|
||||
if (!params->kernel_workload && !params->user_hist) {
|
||||
retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd");
|
||||
if (retval) {
|
||||
debug_msg("User-space interface detected, setting user-threads\n");
|
||||
@ -1152,6 +1161,7 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||
int return_value = 1;
|
||||
pthread_t timerlat_u;
|
||||
int retval;
|
||||
int nr_cpus, i;
|
||||
|
||||
params = timerlat_hist_parse_args(argc, argv);
|
||||
if (!params)
|
||||
@ -1201,6 +1211,28 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (params->deepest_idle_state >= -1) {
|
||||
if (!have_libcpupower_support()) {
|
||||
err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
for (i = 0; i < nr_cpus; i++) {
|
||||
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
||||
continue;
|
||||
if (save_cpu_idle_disable_state(i) < 0) {
|
||||
err_msg("Could not save cpu idle state.\n");
|
||||
goto out_free;
|
||||
}
|
||||
if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) {
|
||||
err_msg("Could not set deepest cpu idle state.\n");
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params->trace_output) {
|
||||
record = osnoise_init_trace_tool("timerlat");
|
||||
if (!record) {
|
||||
@ -1332,6 +1364,13 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||
timerlat_aa_destroy();
|
||||
if (dma_latency_fd >= 0)
|
||||
close(dma_latency_fd);
|
||||
if (params->deepest_idle_state >= -1) {
|
||||
for (i = 0; i < nr_cpus; i++) {
|
||||
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
||||
continue;
|
||||
restore_cpu_idle_disable_state(i);
|
||||
}
|
||||
}
|
||||
trace_events_destroy(&record->trace, params->events);
|
||||
params->events = NULL;
|
||||
out_free:
|
||||
@ -1340,6 +1379,7 @@ int timerlat_hist_main(int argc, char *argv[])
|
||||
osnoise_destroy_tool(record);
|
||||
osnoise_destroy_tool(tool);
|
||||
free(params);
|
||||
free_cpu_idle_disable_states();
|
||||
out_exit:
|
||||
exit(return_value);
|
||||
}
|
||||
|
@ -48,15 +48,16 @@ struct timerlat_top_params {
|
||||
int pretty_output;
|
||||
int warmup;
|
||||
int buffer_size;
|
||||
int deepest_idle_state;
|
||||
cpu_set_t hk_cpu_set;
|
||||
struct sched_attr sched_param;
|
||||
struct trace_events *events;
|
||||
};
|
||||
|
||||
struct timerlat_top_cpu {
|
||||
int irq_count;
|
||||
int thread_count;
|
||||
int user_count;
|
||||
unsigned long long irq_count;
|
||||
unsigned long long thread_count;
|
||||
unsigned long long user_count;
|
||||
|
||||
unsigned long long cur_irq;
|
||||
unsigned long long min_irq;
|
||||
@ -280,7 +281,7 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu)
|
||||
/*
|
||||
* Unless trace is being lost, IRQ counter is always the max.
|
||||
*/
|
||||
trace_seq_printf(s, "%3d #%-9d |", cpu, cpu_data->irq_count);
|
||||
trace_seq_printf(s, "%3d #%-9llu |", cpu, cpu_data->irq_count);
|
||||
|
||||
if (!cpu_data->irq_count) {
|
||||
trace_seq_printf(s, "%s %s %s %s |", no_value, no_value, no_value, no_value);
|
||||
@ -447,7 +448,7 @@ static void timerlat_top_usage(char *usage)
|
||||
"",
|
||||
" 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]\\",
|
||||
" [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s]",
|
||||
" [-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",
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||
@ -481,6 +482,7 @@ static void timerlat_top_usage(char *usage)
|
||||
" -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",
|
||||
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -518,6 +520,9 @@ static struct timerlat_top_params
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
|
||||
/* disabled by default */
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->output_divisor = 1000;
|
||||
|
||||
@ -550,6 +555,7 @@ static struct timerlat_top_params
|
||||
{"aa-only", required_argument, 0, '5'},
|
||||
{"warm-up", required_argument, 0, '6'},
|
||||
{"trace-buffer-size", required_argument, 0, '7'},
|
||||
{"deepest-idle-state", required_argument, 0, '8'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@ -726,6 +732,9 @@ static struct timerlat_top_params
|
||||
case '7':
|
||||
params->buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '8':
|
||||
params->deepest_idle_state = get_llong_from_str(optarg);
|
||||
break;
|
||||
default:
|
||||
timerlat_top_usage("Invalid option");
|
||||
}
|
||||
@ -830,7 +839,7 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
|
||||
* 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) {
|
||||
if (!params->kernel_workload && !params->user_top) {
|
||||
retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd");
|
||||
if (retval) {
|
||||
debug_msg("User-space interface detected, setting user-threads\n");
|
||||
@ -850,7 +859,7 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
|
||||
}
|
||||
}
|
||||
|
||||
if (isatty(1) && !params->quiet)
|
||||
if (isatty(STDOUT_FILENO) && !params->quiet)
|
||||
params->pretty_output = 1;
|
||||
|
||||
return 0;
|
||||
@ -922,6 +931,7 @@ int timerlat_top_main(int argc, char *argv[])
|
||||
int return_value = 1;
|
||||
char *max_lat;
|
||||
int retval;
|
||||
int nr_cpus, i;
|
||||
|
||||
params = timerlat_top_parse_args(argc, argv);
|
||||
if (!params)
|
||||
@ -971,6 +981,28 @@ int timerlat_top_main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (params->deepest_idle_state >= -1) {
|
||||
if (!have_libcpupower_support()) {
|
||||
err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
for (i = 0; i < nr_cpus; i++) {
|
||||
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
||||
continue;
|
||||
if (save_cpu_idle_disable_state(i) < 0) {
|
||||
err_msg("Could not save cpu idle state.\n");
|
||||
goto out_free;
|
||||
}
|
||||
if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) {
|
||||
err_msg("Could not set deepest cpu idle state.\n");
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params->trace_output) {
|
||||
record = osnoise_init_trace_tool("timerlat");
|
||||
if (!record) {
|
||||
@ -1125,6 +1157,13 @@ int timerlat_top_main(int argc, char *argv[])
|
||||
timerlat_aa_destroy();
|
||||
if (dma_latency_fd >= 0)
|
||||
close(dma_latency_fd);
|
||||
if (params->deepest_idle_state >= -1) {
|
||||
for (i = 0; i < nr_cpus; i++) {
|
||||
if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus))
|
||||
continue;
|
||||
restore_cpu_idle_disable_state(i);
|
||||
}
|
||||
}
|
||||
trace_events_destroy(&record->trace, params->events);
|
||||
params->events = NULL;
|
||||
out_free:
|
||||
@ -1134,6 +1173,7 @@ int timerlat_top_main(int argc, char *argv[])
|
||||
osnoise_destroy_tool(record);
|
||||
osnoise_destroy_tool(top);
|
||||
free(params);
|
||||
free_cpu_idle_disable_states();
|
||||
out_exit:
|
||||
exit(return_value);
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#ifdef HAVE_LIBCPUPOWER_SUPPORT
|
||||
#include <cpuidle.h>
|
||||
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
|
||||
#include <dirent.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
@ -211,29 +214,25 @@ long parse_ns_duration(char *val)
|
||||
/*
|
||||
* This is a set of helper functions to use SCHED_DEADLINE.
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
# define __NR_sched_setattr 314
|
||||
# define __NR_sched_getattr 315
|
||||
#elif __i386__
|
||||
# define __NR_sched_setattr 351
|
||||
# define __NR_sched_getattr 352
|
||||
#elif __arm__
|
||||
# define __NR_sched_setattr 380
|
||||
# define __NR_sched_getattr 381
|
||||
#elif __aarch64__ || __riscv
|
||||
# define __NR_sched_setattr 274
|
||||
# define __NR_sched_getattr 275
|
||||
#elif __powerpc__
|
||||
# define __NR_sched_setattr 355
|
||||
# define __NR_sched_getattr 356
|
||||
#elif __s390x__
|
||||
# define __NR_sched_setattr 345
|
||||
# define __NR_sched_getattr 346
|
||||
#ifndef __NR_sched_setattr
|
||||
# ifdef __x86_64__
|
||||
# define __NR_sched_setattr 314
|
||||
# elif __i386__
|
||||
# define __NR_sched_setattr 351
|
||||
# elif __arm__
|
||||
# define __NR_sched_setattr 380
|
||||
# elif __aarch64__ || __riscv
|
||||
# define __NR_sched_setattr 274
|
||||
# elif __powerpc__
|
||||
# define __NR_sched_setattr 355
|
||||
# elif __s390x__
|
||||
# define __NR_sched_setattr 345
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define SCHED_DEADLINE 6
|
||||
|
||||
static inline int sched_setattr(pid_t pid, const struct sched_attr *attr,
|
||||
static inline int syscall_sched_setattr(pid_t pid, const struct sched_attr *attr,
|
||||
unsigned int flags) {
|
||||
return syscall(__NR_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
@ -243,7 +242,7 @@ int __set_sched_attr(int pid, struct sched_attr *attr)
|
||||
int flags = 0;
|
||||
int retval;
|
||||
|
||||
retval = sched_setattr(pid, attr, flags);
|
||||
retval = syscall_sched_setattr(pid, attr, flags);
|
||||
if (retval < 0) {
|
||||
err_msg("Failed to set sched attributes to the pid %d: %s\n",
|
||||
pid, strerror(errno));
|
||||
@ -519,6 +518,153 @@ int set_cpu_dma_latency(int32_t latency)
|
||||
return fd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBCPUPOWER_SUPPORT
|
||||
static unsigned int **saved_cpu_idle_disable_state;
|
||||
static size_t saved_cpu_idle_disable_state_alloc_ctr;
|
||||
|
||||
/*
|
||||
* save_cpu_idle_state_disable - save disable for all idle states of a cpu
|
||||
*
|
||||
* Saves the current disable of all idle states of a cpu, to be subsequently
|
||||
* restored via restore_cpu_idle_disable_state.
|
||||
*
|
||||
* Return: idle state count on success, negative on error
|
||||
*/
|
||||
int save_cpu_idle_disable_state(unsigned int cpu)
|
||||
{
|
||||
unsigned int nr_states;
|
||||
unsigned int state;
|
||||
int disabled;
|
||||
int nr_cpus;
|
||||
|
||||
nr_states = cpuidle_state_count(cpu);
|
||||
|
||||
if (nr_states == 0)
|
||||
return 0;
|
||||
|
||||
if (saved_cpu_idle_disable_state == NULL) {
|
||||
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
saved_cpu_idle_disable_state = calloc(nr_cpus, sizeof(unsigned int *));
|
||||
if (!saved_cpu_idle_disable_state)
|
||||
return -1;
|
||||
}
|
||||
|
||||
saved_cpu_idle_disable_state[cpu] = calloc(nr_states, sizeof(unsigned int));
|
||||
if (!saved_cpu_idle_disable_state[cpu])
|
||||
return -1;
|
||||
saved_cpu_idle_disable_state_alloc_ctr++;
|
||||
|
||||
for (state = 0; state < nr_states; state++) {
|
||||
disabled = cpuidle_is_state_disabled(cpu, state);
|
||||
if (disabled < 0)
|
||||
return disabled;
|
||||
saved_cpu_idle_disable_state[cpu][state] = disabled;
|
||||
}
|
||||
|
||||
return nr_states;
|
||||
}
|
||||
|
||||
/*
|
||||
* restore_cpu_idle_disable_state - restore disable for all idle states of a cpu
|
||||
*
|
||||
* Restores the current disable state of all idle states of a cpu that was
|
||||
* previously saved by save_cpu_idle_disable_state.
|
||||
*
|
||||
* Return: idle state count on success, negative on error
|
||||
*/
|
||||
int restore_cpu_idle_disable_state(unsigned int cpu)
|
||||
{
|
||||
unsigned int nr_states;
|
||||
unsigned int state;
|
||||
int disabled;
|
||||
int result;
|
||||
|
||||
nr_states = cpuidle_state_count(cpu);
|
||||
|
||||
if (nr_states == 0)
|
||||
return 0;
|
||||
|
||||
if (!saved_cpu_idle_disable_state)
|
||||
return -1;
|
||||
|
||||
for (state = 0; state < nr_states; state++) {
|
||||
if (!saved_cpu_idle_disable_state[cpu])
|
||||
return -1;
|
||||
disabled = saved_cpu_idle_disable_state[cpu][state];
|
||||
result = cpuidle_state_disable(cpu, state, disabled);
|
||||
if (result < 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
free(saved_cpu_idle_disable_state[cpu]);
|
||||
saved_cpu_idle_disable_state[cpu] = NULL;
|
||||
saved_cpu_idle_disable_state_alloc_ctr--;
|
||||
if (saved_cpu_idle_disable_state_alloc_ctr == 0) {
|
||||
free(saved_cpu_idle_disable_state);
|
||||
saved_cpu_idle_disable_state = NULL;
|
||||
}
|
||||
|
||||
return nr_states;
|
||||
}
|
||||
|
||||
/*
|
||||
* free_cpu_idle_disable_states - free saved idle state disable for all cpus
|
||||
*
|
||||
* Frees the memory used for storing cpu idle state disable for all cpus
|
||||
* and states.
|
||||
*
|
||||
* Normally, the memory is freed automatically in
|
||||
* restore_cpu_idle_disable_state; this is mostly for cleaning up after an
|
||||
* error.
|
||||
*/
|
||||
void free_cpu_idle_disable_states(void)
|
||||
{
|
||||
int cpu;
|
||||
int nr_cpus;
|
||||
|
||||
if (!saved_cpu_idle_disable_state)
|
||||
return;
|
||||
|
||||
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
||||
free(saved_cpu_idle_disable_state[cpu]);
|
||||
saved_cpu_idle_disable_state[cpu] = NULL;
|
||||
}
|
||||
|
||||
free(saved_cpu_idle_disable_state);
|
||||
saved_cpu_idle_disable_state = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set_deepest_cpu_idle_state - limit idle state of cpu
|
||||
*
|
||||
* Disables all idle states deeper than the one given in
|
||||
* deepest_state (assuming states with higher number are deeper).
|
||||
*
|
||||
* This is used to reduce the exit from idle latency. Unlike
|
||||
* set_cpu_dma_latency, it can disable idle states per cpu.
|
||||
*
|
||||
* Return: idle state count on success, negative on error
|
||||
*/
|
||||
int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int deepest_state)
|
||||
{
|
||||
unsigned int nr_states;
|
||||
unsigned int state;
|
||||
int result;
|
||||
|
||||
nr_states = cpuidle_state_count(cpu);
|
||||
|
||||
for (state = deepest_state + 1; state < nr_states; state++) {
|
||||
result = cpuidle_state_disable(cpu, state, 1);
|
||||
if (result < 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
return nr_states;
|
||||
}
|
||||
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
|
||||
|
||||
#define _STR(x) #x
|
||||
#define STR(x) _STR(x)
|
||||
|
||||
|
@ -46,6 +46,7 @@ update_sum(unsigned long long *a, unsigned long long *b)
|
||||
*a += *b;
|
||||
}
|
||||
|
||||
#ifndef SCHED_ATTR_SIZE_VER0
|
||||
struct sched_attr {
|
||||
uint32_t size;
|
||||
uint32_t sched_policy;
|
||||
@ -56,6 +57,7 @@ struct sched_attr {
|
||||
uint64_t sched_deadline;
|
||||
uint64_t sched_period;
|
||||
};
|
||||
#endif /* SCHED_ATTR_SIZE_VER0 */
|
||||
|
||||
int parse_prio(char *arg, struct sched_attr *sched_param);
|
||||
int parse_cpu_set(char *cpu_list, cpu_set_t *set);
|
||||
@ -64,6 +66,19 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
|
||||
int set_comm_cgroup(const char *comm_prefix, const char *cgroup);
|
||||
int set_pid_cgroup(pid_t pid, const char *cgroup);
|
||||
int set_cpu_dma_latency(int32_t latency);
|
||||
#ifdef HAVE_LIBCPUPOWER_SUPPORT
|
||||
int save_cpu_idle_disable_state(unsigned int cpu);
|
||||
int restore_cpu_idle_disable_state(unsigned int cpu);
|
||||
void free_cpu_idle_disable_states(void);
|
||||
int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int state);
|
||||
static inline int have_libcpupower_support(void) { return 1; }
|
||||
#else
|
||||
static inline int save_cpu_idle_disable_state(unsigned int cpu) { return -1; }
|
||||
static inline int restore_cpu_idle_disable_state(unsigned int cpu) { return -1; }
|
||||
static inline void free_cpu_idle_disable_states(void) { }
|
||||
static inline int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int state) { return -1; }
|
||||
static inline int have_libcpupower_support(void) { return 0; }
|
||||
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
|
||||
int auto_house_keeping(cpu_set_t *monitored_cpus);
|
||||
|
||||
#define ns_to_usf(x) (((double)x/1000))
|
||||
|
@ -29,11 +29,11 @@ class Automata:
|
||||
|
||||
def __get_model_name(self):
|
||||
basename = ntpath.basename(self.__dot_path)
|
||||
if basename.endswith(".dot") == False:
|
||||
if not basename.endswith(".dot") and not basename.endswith(".gv"):
|
||||
print("not a dot file")
|
||||
raise Exception("not a dot file: %s" % self.__dot_path)
|
||||
|
||||
model_name = basename[0:-4]
|
||||
model_name = ntpath.splitext(basename)[0]
|
||||
if model_name.__len__() == 0:
|
||||
raise Exception("not a dot file: %s" % self.__dot_path)
|
||||
|
||||
@ -68,9 +68,9 @@ class Automata:
|
||||
def __get_cursor_begin_events(self):
|
||||
cursor = 0
|
||||
while self.__dot_lines[cursor].split()[0] != "{node":
|
||||
cursor += 1
|
||||
cursor += 1
|
||||
while self.__dot_lines[cursor].split()[0] == "{node":
|
||||
cursor += 1
|
||||
cursor += 1
|
||||
# skip initial state transition
|
||||
cursor += 1
|
||||
return cursor
|
||||
@ -94,11 +94,11 @@ class Automata:
|
||||
initial_state = state[7:]
|
||||
else:
|
||||
states.append(state)
|
||||
if self.__dot_lines[cursor].__contains__("doublecircle") == True:
|
||||
if "doublecircle" in self.__dot_lines[cursor]:
|
||||
final_states.append(state)
|
||||
has_final_states = True
|
||||
|
||||
if self.__dot_lines[cursor].__contains__("ellipse") == True:
|
||||
if "ellipse" in self.__dot_lines[cursor]:
|
||||
final_states.append(state)
|
||||
has_final_states = True
|
||||
|
||||
@ -110,7 +110,7 @@ class Automata:
|
||||
# Insert the initial state at the bein og the states
|
||||
states.insert(0, initial_state)
|
||||
|
||||
if has_final_states == False:
|
||||
if not has_final_states:
|
||||
final_states.append(initial_state)
|
||||
|
||||
return states, initial_state, final_states
|
||||
@ -120,7 +120,7 @@ class Automata:
|
||||
cursor = self.__get_cursor_begin_events()
|
||||
|
||||
events = []
|
||||
while self.__dot_lines[cursor][1] == '"':
|
||||
while self.__dot_lines[cursor].lstrip()[0] == '"':
|
||||
# transitions have the format:
|
||||
# "all_fired" -> "both_fired" [ label = "disable_irq" ];
|
||||
# ------------ event is here ------------^^^^^
|
||||
@ -161,7 +161,7 @@ class Automata:
|
||||
# and we are back! Let's fill the matrix
|
||||
cursor = self.__get_cursor_begin_events()
|
||||
|
||||
while self.__dot_lines[cursor][1] == '"':
|
||||
while self.__dot_lines[cursor].lstrip()[0] == '"':
|
||||
if self.__dot_lines[cursor].split()[1] == "->":
|
||||
line = self.__dot_lines[cursor].split()
|
||||
origin_state = line[0].replace('"','').replace(',','_')
|
||||
|
@ -332,7 +332,7 @@ static void ikm_print_header(struct trace_seq *s)
|
||||
* ikm_event_handler - callback to handle event events
|
||||
*
|
||||
* Called any time a rv:"monitor"_event events is generated.
|
||||
* It parses and print event.
|
||||
* It parses and prints event.
|
||||
*/
|
||||
static int
|
||||
ikm_event_handler(struct trace_seq *s, struct tep_record *record,
|
||||
@ -384,7 +384,7 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
|
||||
* ikm_error_handler - callback to handle error events
|
||||
*
|
||||
* Called any time a rv:"monitor"_errors events is generated.
|
||||
* It parses and print event.
|
||||
* It parses and prints event.
|
||||
*/
|
||||
static int
|
||||
ikm_error_handler(struct trace_seq *s, struct tep_record *record,
|
||||
|
@ -81,7 +81,7 @@ void trace_instance_destroy(struct trace_instance *trace)
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_instance_init - create an trace instance
|
||||
* trace_instance_init - create a trace instance
|
||||
*
|
||||
* It is more than the tracefs instance, as it contains other
|
||||
* things required for the tracing, such as the local events and
|
||||
|
Loading…
Reference in New Issue
Block a user