Skip to content

Commit 97caeae

Browse files
committed
Merge: tools/rtla: Add idle state disabling via libcpupower
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/53 JIRA: https://issues.redhat.com/browse/RHEL-40744 In addition to disabling all idle states via cpu_dma_latency, use libcpupower to set idle states only for CPUs timerlat is running on. The parameter --deepest-idle-state is added, taking the deepest allowed idle state as an argument. -1 means disable all idle states. Signed-off-by: Tomas Glozar <tglozar@redhat.com> Approved-by: Herton R. Krzesinski <herton@redhat.com> Approved-by: John B. Wyatt IV <jwyatt@redhat.com> Approved-by: Wander Lairson Costa <wander@redhat.com> Approved-by: Luis Claudio R. Goncalves <lgoncalv@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Jan Stancek <jstancek@redhat.com>
2 parents 9620771 + 631aa87 commit 97caeae

File tree

12 files changed

+290
-3
lines changed

12 files changed

+290
-3
lines changed

Documentation/tools/rtla/common_timerlat_options.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@
3131
*cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have
3232
similar results.
3333

34+
**--deepest-idle-state** *n*
35+
Disable idle states higher than *n* for cpus that are running timerlat threads to
36+
reduce exit from idle latencies. If *n* is -1, all idle states are disabled.
37+
On exit from timerlat, the idle state setting is restored to its original state
38+
before running timerlat.
39+
40+
Requires rtla to be built with libcpupower.
41+
3442
**-k**, **--kernel-threads**
3543

3644
Use timerlat kernel-space threads, in contrast of **-u**.

redhat/kernel.spec.template

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3106,6 +3106,13 @@ chmod +x tools/perf/check-headers.sh
31063106
%global tools_make \
31073107
CFLAGS="${RPM_OPT_FLAGS}" LDFLAGS="%{__global_ldflags}" EXTRA_CFLAGS="${RPM_OPT_FLAGS}" %{make} %{?make_opts}
31083108

3109+
%ifarch %{cpupowerarchs}
3110+
# link against in-tree libcpupower for idle state support
3111+
%global rtla_make %{tools_make} LDFLAGS="%{__global_ldflags} -L../../power/cpupower" INCLUDES="-I../../power/cpupower/lib"
3112+
%else
3113+
%global rtla_make %{tools_make}
3114+
%endif
3115+
31093116
%if %{with_tools}
31103117
%ifarch %{cpupowerarchs}
31113118
# cpupower
@@ -3165,7 +3172,7 @@ pushd tools/verification/rv/
31653172
popd
31663173
pushd tools/tracing/rtla
31673174
%{log_msg "build rtla"}
3168-
%{tools_make}
3175+
%{rtla_make}
31693176
popd
31703177
%endif
31713178

tools/build/Makefile.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ FEATURE_TESTS_BASIC := \
5353
libslang-include-subdir \
5454
libtraceevent \
5555
libtracefs \
56+
libcpupower \
5657
libcrypto \
5758
libunwind \
5859
pthread-attr-setaffinity-np \

tools/build/feature/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ FILES= \
3838
test-libslang.bin \
3939
test-libslang-include-subdir.bin \
4040
test-libtraceevent.bin \
41+
test-libcpupower.bin \
4142
test-libtracefs.bin \
4243
test-libcrypto.bin \
4344
test-libunwind.bin \
@@ -248,6 +249,9 @@ $(OUTPUT)test-libslang-include-subdir.bin:
248249
$(OUTPUT)test-libtraceevent.bin:
249250
$(BUILD) -ltraceevent
250251

252+
$(OUTPUT)test-libcpupower.bin:
253+
$(BUILD) -lcpupower
254+
251255
$(OUTPUT)test-libtracefs.bin:
252256
$(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs
253257

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <cpuidle.h>
3+
4+
int main(void)
5+
{
6+
int rv = cpuidle_state_count(0);
7+
return rv;
8+
}

tools/tracing/rtla/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ DOCSRC := ../../../Documentation/tools/rtla/
3232

3333
FEATURE_TESTS := libtraceevent
3434
FEATURE_TESTS += libtracefs
35+
FEATURE_TESTS += libcpupower
3536
FEATURE_DISPLAY := libtraceevent
3637
FEATURE_DISPLAY += libtracefs
38+
FEATURE_DISPLAY += libcpupower
3739

3840
ifeq ($(V),1)
3941
Q =

tools/tracing/rtla/Makefile.config

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ else
4343
$(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
4444
endif
4545

46+
$(call feature_check,libcpupower)
47+
ifeq ($(feature-libcpupower), 1)
48+
$(call detected,CONFIG_LIBCPUPOWER)
49+
CFLAGS += -DHAVE_LIBCPUPOWER_SUPPORT
50+
EXTLIBS += -lcpupower
51+
else
52+
$(info libcpupower is missing, building without --deepest-idle-state support.)
53+
$(info Please install libcpupower-dev/kernel-tools-libs-devel)
54+
endif
55+
4656
ifeq ($(STOP_ERROR),1)
4757
$(error Please, check the errors above.)
4858
endif

tools/tracing/rtla/README.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ RTLA depends on the following libraries and tools:
1111

1212
- libtracefs
1313
- libtraceevent
14+
- libcpupower (optional, for --deepest-idle-state)
1415

1516
It also depends on python3-docutils to compile man pages.
1617

@@ -26,6 +27,9 @@ For development, we suggest the following steps for compiling rtla:
2627
$ make
2728
$ sudo make install
2829
$ cd ..
30+
$ cd $libcpupower_src
31+
$ make
32+
$ sudo make install
2933
$ cd $rtla_src
3034
$ make
3135
$ sudo make install

tools/tracing/rtla/src/timerlat_hist.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct timerlat_hist_params {
5555
int entries;
5656
int warmup;
5757
int buffer_size;
58+
int deepest_idle_state;
5859
};
5960

6061
struct timerlat_hist_cpu {
@@ -655,7 +656,7 @@ static void timerlat_hist_usage(char *usage)
655656
" [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
656657
" [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
657658
" [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u|-k]",
658-
" [--warm-up s]",
659+
" [--warm-up s] [--deepest-idle-state n]",
659660
"",
660661
" -h/--help: print this menu",
661662
" -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)
695696
" -U/--user-load: enable timerlat for user-defined user-space workload",
696697
" --warm-up s: let the workload run for s seconds before collecting data",
697698
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
699+
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
698700
NULL,
699701
};
700702

@@ -732,6 +734,9 @@ static struct timerlat_hist_params
732734
/* disabled by default */
733735
params->dma_latency = -1;
734736

737+
/* disabled by default */
738+
params->deepest_idle_state = -2;
739+
735740
/* display data in microseconds */
736741
params->output_divisor = 1000;
737742
params->bucket_size = 1;
@@ -772,6 +777,7 @@ static struct timerlat_hist_params
772777
{"dump-task", no_argument, 0, '\1'},
773778
{"warm-up", required_argument, 0, '\2'},
774779
{"trace-buffer-size", required_argument, 0, '\3'},
780+
{"deepest-idle-state", required_argument, 0, '\4'},
775781
{0, 0, 0, 0}
776782
};
777783

@@ -960,6 +966,9 @@ static struct timerlat_hist_params
960966
case '\3':
961967
params->buffer_size = get_llong_from_str(optarg);
962968
break;
969+
case '\4':
970+
params->deepest_idle_state = get_llong_from_str(optarg);
971+
break;
963972
default:
964973
timerlat_hist_usage("Invalid option");
965974
}
@@ -1152,6 +1161,7 @@ int timerlat_hist_main(int argc, char *argv[])
11521161
int return_value = 1;
11531162
pthread_t timerlat_u;
11541163
int retval;
1164+
int nr_cpus, i;
11551165

11561166
params = timerlat_hist_parse_args(argc, argv);
11571167
if (!params)
@@ -1201,6 +1211,28 @@ int timerlat_hist_main(int argc, char *argv[])
12011211
}
12021212
}
12031213

1214+
if (params->deepest_idle_state >= -1) {
1215+
if (!have_libcpupower_support()) {
1216+
err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n");
1217+
goto out_free;
1218+
}
1219+
1220+
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
1221+
1222+
for (i = 0; i < nr_cpus; i++) {
1223+
if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus))
1224+
continue;
1225+
if (save_cpu_idle_disable_state(i) < 0) {
1226+
err_msg("Could not save cpu idle state.\n");
1227+
goto out_free;
1228+
}
1229+
if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) {
1230+
err_msg("Could not set deepest cpu idle state.\n");
1231+
goto out_free;
1232+
}
1233+
}
1234+
}
1235+
12041236
if (params->trace_output) {
12051237
record = osnoise_init_trace_tool("timerlat");
12061238
if (!record) {
@@ -1332,6 +1364,13 @@ int timerlat_hist_main(int argc, char *argv[])
13321364
timerlat_aa_destroy();
13331365
if (dma_latency_fd >= 0)
13341366
close(dma_latency_fd);
1367+
if (params->deepest_idle_state >= -1) {
1368+
for (i = 0; i < nr_cpus; i++) {
1369+
if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus))
1370+
continue;
1371+
restore_cpu_idle_disable_state(i);
1372+
}
1373+
}
13351374
trace_events_destroy(&record->trace, params->events);
13361375
params->events = NULL;
13371376
out_free:
@@ -1340,6 +1379,7 @@ int timerlat_hist_main(int argc, char *argv[])
13401379
osnoise_destroy_tool(record);
13411380
osnoise_destroy_tool(tool);
13421381
free(params);
1382+
free_cpu_idle_disable_states();
13431383
out_exit:
13441384
exit(return_value);
13451385
}

tools/tracing/rtla/src/timerlat_top.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct timerlat_top_params {
4848
int pretty_output;
4949
int warmup;
5050
int buffer_size;
51+
int deepest_idle_state;
5152
cpu_set_t hk_cpu_set;
5253
struct sched_attr sched_param;
5354
struct trace_events *events;
@@ -447,7 +448,7 @@ static void timerlat_top_usage(char *usage)
447448
"",
448449
" usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
449450
" [[-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
450-
" [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s]",
451+
" [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]",
451452
"",
452453
" -h/--help: print this menu",
453454
" -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)
481482
" -U/--user-load: enable timerlat for user-defined user-space workload",
482483
" --warm-up s: let the workload run for s seconds before collecting data",
483484
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
485+
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
484486
NULL,
485487
};
486488

@@ -518,6 +520,9 @@ static struct timerlat_top_params
518520
/* disabled by default */
519521
params->dma_latency = -1;
520522

523+
/* disabled by default */
524+
params->deepest_idle_state = -2;
525+
521526
/* display data in microseconds */
522527
params->output_divisor = 1000;
523528

@@ -550,6 +555,7 @@ static struct timerlat_top_params
550555
{"aa-only", required_argument, 0, '5'},
551556
{"warm-up", required_argument, 0, '6'},
552557
{"trace-buffer-size", required_argument, 0, '7'},
558+
{"deepest-idle-state", required_argument, 0, '8'},
553559
{0, 0, 0, 0}
554560
};
555561

@@ -726,6 +732,9 @@ static struct timerlat_top_params
726732
case '7':
727733
params->buffer_size = get_llong_from_str(optarg);
728734
break;
735+
case '8':
736+
params->deepest_idle_state = get_llong_from_str(optarg);
737+
break;
729738
default:
730739
timerlat_top_usage("Invalid option");
731740
}
@@ -922,6 +931,7 @@ int timerlat_top_main(int argc, char *argv[])
922931
int return_value = 1;
923932
char *max_lat;
924933
int retval;
934+
int nr_cpus, i;
925935

926936
params = timerlat_top_parse_args(argc, argv);
927937
if (!params)
@@ -971,6 +981,28 @@ int timerlat_top_main(int argc, char *argv[])
971981
}
972982
}
973983

984+
if (params->deepest_idle_state >= -1) {
985+
if (!have_libcpupower_support()) {
986+
err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n");
987+
goto out_free;
988+
}
989+
990+
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
991+
992+
for (i = 0; i < nr_cpus; i++) {
993+
if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus))
994+
continue;
995+
if (save_cpu_idle_disable_state(i) < 0) {
996+
err_msg("Could not save cpu idle state.\n");
997+
goto out_free;
998+
}
999+
if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) {
1000+
err_msg("Could not set deepest cpu idle state.\n");
1001+
goto out_free;
1002+
}
1003+
}
1004+
}
1005+
9741006
if (params->trace_output) {
9751007
record = osnoise_init_trace_tool("timerlat");
9761008
if (!record) {
@@ -1125,6 +1157,13 @@ int timerlat_top_main(int argc, char *argv[])
11251157
timerlat_aa_destroy();
11261158
if (dma_latency_fd >= 0)
11271159
close(dma_latency_fd);
1160+
if (params->deepest_idle_state >= -1) {
1161+
for (i = 0; i < nr_cpus; i++) {
1162+
if (params->cpus && !CPU_ISSET(i, &params->monitored_cpus))
1163+
continue;
1164+
restore_cpu_idle_disable_state(i);
1165+
}
1166+
}
11281167
trace_events_destroy(&record->trace, params->events);
11291168
params->events = NULL;
11301169
out_free:
@@ -1134,6 +1173,7 @@ int timerlat_top_main(int argc, char *argv[])
11341173
osnoise_destroy_tool(record);
11351174
osnoise_destroy_tool(top);
11361175
free(params);
1176+
free_cpu_idle_disable_states();
11371177
out_exit:
11381178
exit(return_value);
11391179
}

0 commit comments

Comments
 (0)