Commit be5378f3baabb5667508c42c56b4281f967d6861
Exists in
master
and in
4 other branches
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils: cpupower: use man(1) when calling "cpupower help subcommand" cpupower: make NLS truly optional cpupower: fix Makefile typo cpupower: Make monitor command -c/--cpu aware cpupower: Better detect offlined CPUs cpupower: Do not show an empty Idle_Stats monitor if no idle driver is available cpupower: mperf monitor - Use TSC to calculate max frequency if possible cpupower: avoid using symlinks
Showing 21 changed files Side-by-side Diff
- tools/power/cpupower/Makefile
- tools/power/cpupower/debug/x86_64/Makefile
- tools/power/cpupower/debug/x86_64/centrino-decode.c
- tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
- tools/power/cpupower/man/cpupower-frequency-info.1
- tools/power/cpupower/man/cpupower-frequency-set.1
- tools/power/cpupower/man/cpupower.1
- tools/power/cpupower/utils/builtin.h
- tools/power/cpupower/utils/cpufreq-info.c
- tools/power/cpupower/utils/cpufreq-set.c
- tools/power/cpupower/utils/cpuidle-info.c
- tools/power/cpupower/utils/cpupower-info.c
- tools/power/cpupower/utils/cpupower-set.c
- tools/power/cpupower/utils/cpupower.c
- tools/power/cpupower/utils/helpers/helpers.h
- tools/power/cpupower/utils/helpers/sysfs.c
- tools/power/cpupower/utils/helpers/sysfs.h
- tools/power/cpupower/utils/helpers/topology.c
- tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
- tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
- tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
tools/power/cpupower/Makefile
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | |
25 | 25 | # Set the following to `true' to make a unstripped, unoptimized |
26 | 26 | # binary. Leave this set to `false' for production use. |
27 | -DEBUG ?= false | |
27 | +DEBUG ?= true | |
28 | 28 | |
29 | 29 | # make the build silent. Set this to something else to make it noisy again. |
30 | 30 | V ?= false |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | |
36 | 36 | # Set the following to 'true' to build/install the |
37 | 37 | # cpufreq-bench benchmarking tool |
38 | -CPUFRQ_BENCH ?= true | |
38 | +CPUFREQ_BENCH ?= true | |
39 | 39 | |
40 | 40 | # Prefix to the directories we're installing to |
41 | 41 | DESTDIR ?= |
42 | 42 | |
... | ... | @@ -137,9 +137,10 @@ |
137 | 137 | ifeq ($(strip $(NLS)),true) |
138 | 138 | INSTALL_NLS += install-gmo |
139 | 139 | COMPILE_NLS += create-gmo |
140 | + CFLAGS += -DNLS | |
140 | 141 | endif |
141 | 142 | |
142 | -ifeq ($(strip $(CPUFRQ_BENCH)),true) | |
143 | +ifeq ($(strip $(CPUFREQ_BENCH)),true) | |
143 | 144 | INSTALL_BENCH += install-bench |
144 | 145 | COMPILE_BENCH += compile-bench |
145 | 146 | endif |
tools/power/cpupower/debug/x86_64/Makefile
1 | 1 | default: all |
2 | 2 | |
3 | -centrino-decode: centrino-decode.c | |
4 | - $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c | |
3 | +centrino-decode: ../i386/centrino-decode.c | |
4 | + $(CC) $(CFLAGS) -o $@ $< | |
5 | 5 | |
6 | -powernow-k8-decode: powernow-k8-decode.c | |
7 | - $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c | |
6 | +powernow-k8-decode: ../i386/powernow-k8-decode.c | |
7 | + $(CC) $(CFLAGS) -o $@ $< | |
8 | 8 | |
9 | 9 | all: centrino-decode powernow-k8-decode |
10 | 10 |
tools/power/cpupower/debug/x86_64/centrino-decode.c
1 | -../i386/centrino-decode.c |
tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
1 | -../i386/powernow-k8-decode.c |
tools/power/cpupower/man/cpupower-frequency-info.1
1 | -.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" "" | |
1 | +.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" "" | |
2 | 2 | .SH "NAME" |
3 | 3 | .LP |
4 | -cpufreq\-info \- Utility to retrieve cpufreq kernel information | |
4 | +cpupower frequency\-info \- Utility to retrieve cpufreq kernel information | |
5 | 5 | .SH "SYNTAX" |
6 | 6 | .LP |
7 | -cpufreq\-info [\fIoptions\fP] | |
7 | +cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] | |
8 | 8 | .SH "DESCRIPTION" |
9 | 9 | .LP |
10 | 10 | A small tool which prints out cpufreq information helpful to developers and interested users. |
tools/power/cpupower/man/cpupower-frequency-set.1
1 | -.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" "" | |
1 | +.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" "" | |
2 | 2 | .SH "NAME" |
3 | 3 | .LP |
4 | -cpufreq\-set \- A small tool which allows to modify cpufreq settings. | |
4 | +cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. | |
5 | 5 | .SH "SYNTAX" |
6 | 6 | .LP |
7 | -cpufreq\-set [\fIoptions\fP] | |
7 | +cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] | |
8 | 8 | .SH "DESCRIPTION" |
9 | 9 | .LP |
10 | -cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. | |
10 | +cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. | |
11 | 11 | .SH "OPTIONS" |
12 | 12 | .LP |
13 | 13 | .TP |
tools/power/cpupower/man/cpupower.1
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | cpupower \- Shows and sets processor power related values |
4 | 4 | .SH SYNOPSIS |
5 | 5 | .ft B |
6 | -.B cpupower [ \-c cpulist ] subcommand [ARGS] | |
6 | +.B cpupower [ \-c cpulist ] <command> [ARGS] | |
7 | 7 | |
8 | 8 | .B cpupower \-v|\-\-version |
9 | 9 | |
10 | 10 | |
11 | 11 | |
12 | 12 | |
13 | 13 | |
... | ... | @@ -13,24 +13,24 @@ |
13 | 13 | \fBcpupower \fP is a collection of tools to examine and tune power saving |
14 | 14 | related features of your processor. |
15 | 15 | |
16 | -The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed | |
16 | +The manpages of the commands (cpupower\-<command>(1)) provide detailed | |
17 | 17 | descriptions of supported features. Run \fBcpupower help\fP to get an overview |
18 | -of supported subcommands. | |
18 | +of supported commands. | |
19 | 19 | |
20 | 20 | .SH Options |
21 | 21 | .PP |
22 | 22 | \-\-help, \-h |
23 | 23 | .RS 4 |
24 | -Shows supported subcommands and general usage. | |
24 | +Shows supported commands and general usage. | |
25 | 25 | .RE |
26 | 26 | .PP |
27 | 27 | \-\-cpu cpulist, \-c cpulist |
28 | 28 | .RS 4 |
29 | 29 | Only show or set values for specific cores. |
30 | -This option is not supported by all subcommands, details can be found in the | |
31 | -manpages of the subcommands. | |
30 | +This option is not supported by all commands, details can be found in the | |
31 | +manpages of the commands. | |
32 | 32 | |
33 | -Some subcommands access all cores (typically the *\-set commands), some only | |
33 | +Some commands access all cores (typically the *\-set commands), some only | |
34 | 34 | the first core (typically the *\-info commands) by default. |
35 | 35 | |
36 | 36 | The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via |
tools/power/cpupower/utils/builtin.h
... | ... | @@ -8,12 +8,5 @@ |
8 | 8 | extern int cmd_idle_info(int argc, const char **argv); |
9 | 9 | extern int cmd_monitor(int argc, const char **argv); |
10 | 10 | |
11 | -extern void set_help(void); | |
12 | -extern void info_help(void); | |
13 | -extern void freq_set_help(void); | |
14 | -extern void freq_info_help(void); | |
15 | -extern void idle_info_help(void); | |
16 | -extern void monitor_help(void); | |
17 | - | |
18 | 11 | #endif |
tools/power/cpupower/utils/cpufreq-info.c
... | ... | @@ -510,37 +510,6 @@ |
510 | 510 | return 0; |
511 | 511 | } |
512 | 512 | |
513 | -void freq_info_help(void) | |
514 | -{ | |
515 | - printf(_("Usage: cpupower freqinfo [options]\n")); | |
516 | - printf(_("Options:\n")); | |
517 | - printf(_(" -e, --debug Prints out debug information [default]\n")); | |
518 | - printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n" | |
519 | - " to the cpufreq core *\n")); | |
520 | - printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | |
521 | - " it from hardware (only available to root) *\n")); | |
522 | - printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n")); | |
523 | - printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n")); | |
524 | - printf(_(" -p, --policy Gets the currently used cpufreq policy *\n")); | |
525 | - printf(_(" -g, --governors Determines available cpufreq governors *\n")); | |
526 | - printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n")); | |
527 | - printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n" | |
528 | - " coordinated by software *\n")); | |
529 | - printf(_(" -s, --stats Shows cpufreq statistics if available\n")); | |
530 | - printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n")); | |
531 | - printf(_(" -b, --boost Checks for turbo or boost modes *\n")); | |
532 | - printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n" | |
533 | - " interface in 2.4. and early 2.6. kernels\n")); | |
534 | - printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n")); | |
535 | - printf(_(" -h, --help Prints out this screen\n")); | |
536 | - | |
537 | - printf("\n"); | |
538 | - printf(_("If no argument is given, full output about\n" | |
539 | - "cpufreq is printed which is useful e.g. for reporting bugs.\n\n")); | |
540 | - printf(_("By default info of CPU 0 is shown which can be overridden\n" | |
541 | - "with the cpupower --cpu main command option.\n")); | |
542 | -} | |
543 | - | |
544 | 513 | static struct option info_opts[] = { |
545 | 514 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, |
546 | 515 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, |
... | ... | @@ -556,7 +525,6 @@ |
556 | 525 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, |
557 | 526 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, |
558 | 527 | { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, |
559 | - { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | |
560 | 528 | { }, |
561 | 529 | }; |
562 | 530 | |
563 | 531 | |
... | ... | @@ -570,16 +538,12 @@ |
570 | 538 | int output_param = 0; |
571 | 539 | |
572 | 540 | do { |
573 | - ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL); | |
541 | + ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); | |
574 | 542 | switch (ret) { |
575 | 543 | case '?': |
576 | 544 | output_param = '?'; |
577 | 545 | cont = 0; |
578 | 546 | break; |
579 | - case 'h': | |
580 | - output_param = 'h'; | |
581 | - cont = 0; | |
582 | - break; | |
583 | 547 | case -1: |
584 | 548 | cont = 0; |
585 | 549 | break; |
586 | 550 | |
... | ... | @@ -642,11 +606,7 @@ |
642 | 606 | return -EINVAL; |
643 | 607 | case '?': |
644 | 608 | printf(_("invalid or unknown argument\n")); |
645 | - freq_info_help(); | |
646 | 609 | return -EINVAL; |
647 | - case 'h': | |
648 | - freq_info_help(); | |
649 | - return EXIT_SUCCESS; | |
650 | 610 | case 'o': |
651 | 611 | proc_cpufreq_output(); |
652 | 612 | return EXIT_SUCCESS; |
tools/power/cpupower/utils/cpufreq-set.c
... | ... | @@ -20,34 +20,11 @@ |
20 | 20 | |
21 | 21 | #define NORM_FREQ_LEN 32 |
22 | 22 | |
23 | -void freq_set_help(void) | |
24 | -{ | |
25 | - printf(_("Usage: cpupower frequency-set [options]\n")); | |
26 | - printf(_("Options:\n")); | |
27 | - printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n")); | |
28 | - printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n")); | |
29 | - printf(_(" -g GOV, --governor GOV new cpufreq governor\n")); | |
30 | - printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | |
31 | - " governor to be available and loaded\n")); | |
32 | - printf(_(" -r, --related Switches all hardware-related CPUs\n")); | |
33 | - printf(_(" -h, --help Prints out this screen\n")); | |
34 | - printf("\n"); | |
35 | - printf(_("Notes:\n" | |
36 | - "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n")); | |
37 | - printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n" | |
38 | - " except the -c CPU, --cpu CPU parameter\n" | |
39 | - "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | |
40 | - " by postfixing the value with the wanted unit name, without any space\n" | |
41 | - " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n")); | |
42 | - | |
43 | -} | |
44 | - | |
45 | 23 | static struct option set_opts[] = { |
46 | 24 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, |
47 | 25 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, |
48 | 26 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, |
49 | 27 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, |
50 | - { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | |
51 | 28 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, |
52 | 29 | { }, |
53 | 30 | }; |
... | ... | @@ -80,7 +57,6 @@ |
80 | 57 | static void print_unknown_arg(void) |
81 | 58 | { |
82 | 59 | printf(_("invalid or unknown argument\n")); |
83 | - freq_set_help(); | |
84 | 60 | } |
85 | 61 | |
86 | 62 | static unsigned long string_to_frequency(const char *str) |
87 | 63 | |
... | ... | @@ -231,14 +207,11 @@ |
231 | 207 | |
232 | 208 | /* parameter parsing */ |
233 | 209 | do { |
234 | - ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL); | |
210 | + ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL); | |
235 | 211 | switch (ret) { |
236 | 212 | case '?': |
237 | 213 | print_unknown_arg(); |
238 | 214 | return -EINVAL; |
239 | - case 'h': | |
240 | - freq_set_help(); | |
241 | - return 0; | |
242 | 215 | case -1: |
243 | 216 | cont = 0; |
244 | 217 | break; |
tools/power/cpupower/utils/cpuidle-info.c
... | ... | @@ -139,30 +139,14 @@ |
139 | 139 | } |
140 | 140 | } |
141 | 141 | |
142 | -/* --freq / -f */ | |
143 | - | |
144 | -void idle_info_help(void) | |
145 | -{ | |
146 | - printf(_ ("Usage: cpupower idleinfo [options]\n")); | |
147 | - printf(_ ("Options:\n")); | |
148 | - printf(_ (" -s, --silent Only show general C-state information\n")); | |
149 | - printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n" | |
150 | - " interface in older kernels\n")); | |
151 | - printf(_ (" -h, --help Prints out this screen\n")); | |
152 | - | |
153 | - printf("\n"); | |
154 | -} | |
155 | - | |
156 | 142 | static struct option info_opts[] = { |
157 | 143 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, |
158 | 144 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, |
159 | - { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | |
160 | 145 | { }, |
161 | 146 | }; |
162 | 147 | |
163 | 148 | static inline void cpuidle_exit(int fail) |
164 | 149 | { |
165 | - idle_info_help(); | |
166 | 150 | exit(EXIT_FAILURE); |
167 | 151 | } |
168 | 152 | |
... | ... | @@ -174,7 +158,7 @@ |
174 | 158 | unsigned int cpu = 0; |
175 | 159 | |
176 | 160 | do { |
177 | - ret = getopt_long(argc, argv, "hos", info_opts, NULL); | |
161 | + ret = getopt_long(argc, argv, "os", info_opts, NULL); | |
178 | 162 | if (ret == -1) |
179 | 163 | break; |
180 | 164 | switch (ret) { |
... | ... | @@ -182,10 +166,6 @@ |
182 | 166 | output_param = '?'; |
183 | 167 | cont = 0; |
184 | 168 | break; |
185 | - case 'h': | |
186 | - output_param = 'h'; | |
187 | - cont = 0; | |
188 | - break; | |
189 | 169 | case 's': |
190 | 170 | verbose = 0; |
191 | 171 | break; |
... | ... | @@ -211,8 +191,6 @@ |
211 | 191 | case '?': |
212 | 192 | printf(_("invalid or unknown argument\n")); |
213 | 193 | cpuidle_exit(EXIT_FAILURE); |
214 | - case 'h': | |
215 | - cpuidle_exit(EXIT_SUCCESS); | |
216 | 194 | } |
217 | 195 | |
218 | 196 | /* Default is: show output of CPU 0 only */ |
tools/power/cpupower/utils/cpupower-info.c
... | ... | @@ -16,31 +16,16 @@ |
16 | 16 | #include "helpers/helpers.h" |
17 | 17 | #include "helpers/sysfs.h" |
18 | 18 | |
19 | -void info_help(void) | |
20 | -{ | |
21 | - printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n")); | |
22 | - printf(_("Options:\n")); | |
23 | - printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n" | |
24 | - " Intel models [0-15], see manpage for details\n")); | |
25 | - printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n")); | |
26 | - printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n")); | |
27 | - printf(_(" -h, --help Prints out this screen\n")); | |
28 | - printf(_("\nPassing no option will show all info, by default only on core 0\n")); | |
29 | - printf("\n"); | |
30 | -} | |
31 | - | |
32 | 19 | static struct option set_opts[] = { |
33 | 20 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | 21 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | 22 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, |
36 | - { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | |
37 | 23 | { }, |
38 | 24 | }; |
39 | 25 | |
40 | 26 | static void print_wrong_arg_exit(void) |
41 | 27 | { |
42 | 28 | printf(_("invalid or unknown argument\n")); |
43 | - info_help(); | |
44 | 29 | exit(EXIT_FAILURE); |
45 | 30 | } |
46 | 31 | |
47 | 32 | |
... | ... | @@ -64,11 +49,8 @@ |
64 | 49 | textdomain(PACKAGE); |
65 | 50 | |
66 | 51 | /* parameter parsing */ |
67 | - while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) { | |
52 | + while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) { | |
68 | 53 | switch (ret) { |
69 | - case 'h': | |
70 | - info_help(); | |
71 | - return 0; | |
72 | 54 | case 'b': |
73 | 55 | if (params.perf_bias) |
74 | 56 | print_wrong_arg_exit(); |
tools/power/cpupower/utils/cpupower-set.c
... | ... | @@ -17,30 +17,16 @@ |
17 | 17 | #include "helpers/sysfs.h" |
18 | 18 | #include "helpers/bitmask.h" |
19 | 19 | |
20 | -void set_help(void) | |
21 | -{ | |
22 | - printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n")); | |
23 | - printf(_("Options:\n")); | |
24 | - printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | |
25 | - " Intel models [0-15], see manpage for details\n")); | |
26 | - printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n")); | |
27 | - printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n")); | |
28 | - printf(_(" -h, --help Prints out this screen\n")); | |
29 | - printf("\n"); | |
30 | -} | |
31 | - | |
32 | 20 | static struct option set_opts[] = { |
33 | 21 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | 22 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | 23 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, |
36 | - { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | |
37 | 24 | { }, |
38 | 25 | }; |
39 | 26 | |
40 | 27 | static void print_wrong_arg_exit(void) |
41 | 28 | { |
42 | 29 | printf(_("invalid or unknown argument\n")); |
43 | - set_help(); | |
44 | 30 | exit(EXIT_FAILURE); |
45 | 31 | } |
46 | 32 | |
47 | 33 | |
... | ... | @@ -66,12 +52,9 @@ |
66 | 52 | |
67 | 53 | params.params = 0; |
68 | 54 | /* parameter parsing */ |
69 | - while ((ret = getopt_long(argc, argv, "m:s:b:h", | |
55 | + while ((ret = getopt_long(argc, argv, "m:s:b:", | |
70 | 56 | set_opts, NULL)) != -1) { |
71 | 57 | switch (ret) { |
72 | - case 'h': | |
73 | - set_help(); | |
74 | - return 0; | |
75 | 58 | case 'b': |
76 | 59 | if (params.perf_bias) |
77 | 60 | print_wrong_arg_exit(); |
... | ... | @@ -110,10 +93,8 @@ |
110 | 93 | } |
111 | 94 | }; |
112 | 95 | |
113 | - if (!params.params) { | |
114 | - set_help(); | |
115 | - return -EINVAL; | |
116 | - } | |
96 | + if (!params.params) | |
97 | + print_wrong_arg_exit(); | |
117 | 98 | |
118 | 99 | if (params.sched_mc) { |
119 | 100 | ret = sysfs_set_sched("mc", sched_mc); |
tools/power/cpupower/utils/cpupower.c
... | ... | @@ -11,6 +11,7 @@ |
11 | 11 | #include <stdlib.h> |
12 | 12 | #include <string.h> |
13 | 13 | #include <unistd.h> |
14 | +#include <errno.h> | |
14 | 15 | |
15 | 16 | #include "builtin.h" |
16 | 17 | #include "helpers/helpers.h" |
17 | 18 | |
... | ... | @@ -19,13 +20,12 @@ |
19 | 20 | struct cmd_struct { |
20 | 21 | const char *cmd; |
21 | 22 | int (*main)(int, const char **); |
22 | - void (*usage)(void); | |
23 | 23 | int needs_root; |
24 | 24 | }; |
25 | 25 | |
26 | 26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
27 | 27 | |
28 | -int cmd_help(int argc, const char **argv); | |
28 | +static int cmd_help(int argc, const char **argv); | |
29 | 29 | |
30 | 30 | /* Global cpu_info object available for all binaries |
31 | 31 | * Info only retrieved from CPU 0 |
32 | 32 | |
33 | 33 | |
34 | 34 | |
35 | 35 | |
36 | 36 | |
... | ... | @@ -44,55 +44,66 @@ |
44 | 44 | static void print_help(void); |
45 | 45 | |
46 | 46 | static struct cmd_struct commands[] = { |
47 | - { "frequency-info", cmd_freq_info, freq_info_help, 0 }, | |
48 | - { "frequency-set", cmd_freq_set, freq_set_help, 1 }, | |
49 | - { "idle-info", cmd_idle_info, idle_info_help, 0 }, | |
50 | - { "set", cmd_set, set_help, 1 }, | |
51 | - { "info", cmd_info, info_help, 0 }, | |
52 | - { "monitor", cmd_monitor, monitor_help, 0 }, | |
53 | - { "help", cmd_help, print_help, 0 }, | |
54 | - /* { "bench", cmd_bench, NULL, 1 }, */ | |
47 | + { "frequency-info", cmd_freq_info, 0 }, | |
48 | + { "frequency-set", cmd_freq_set, 1 }, | |
49 | + { "idle-info", cmd_idle_info, 0 }, | |
50 | + { "set", cmd_set, 1 }, | |
51 | + { "info", cmd_info, 0 }, | |
52 | + { "monitor", cmd_monitor, 0 }, | |
53 | + { "help", cmd_help, 0 }, | |
54 | + /* { "bench", cmd_bench, 1 }, */ | |
55 | 55 | }; |
56 | 56 | |
57 | -int cmd_help(int argc, const char **argv) | |
58 | -{ | |
59 | - unsigned int i; | |
60 | - | |
61 | - if (argc > 1) { | |
62 | - for (i = 0; i < ARRAY_SIZE(commands); i++) { | |
63 | - struct cmd_struct *p = commands + i; | |
64 | - if (strcmp(p->cmd, argv[1])) | |
65 | - continue; | |
66 | - if (p->usage) { | |
67 | - p->usage(); | |
68 | - return EXIT_SUCCESS; | |
69 | - } | |
70 | - } | |
71 | - } | |
72 | - print_help(); | |
73 | - if (argc == 1) | |
74 | - return EXIT_SUCCESS; /* cpupower help */ | |
75 | - return EXIT_FAILURE; | |
76 | -} | |
77 | - | |
78 | 57 | static void print_help(void) |
79 | 58 | { |
80 | 59 | unsigned int i; |
81 | 60 | |
82 | 61 | #ifdef DEBUG |
83 | - printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n")); | |
84 | - printf(_(" -d, --debug May increase output (stderr) on some subcommands\n")); | |
62 | + printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); | |
85 | 63 | #else |
86 | - printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n")); | |
64 | + printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); | |
87 | 65 | #endif |
88 | - printf(_("cpupower --version\n")); | |
89 | - printf(_("Supported subcommands are:\n")); | |
66 | + printf(_("Supported commands are:\n")); | |
90 | 67 | for (i = 0; i < ARRAY_SIZE(commands); i++) |
91 | 68 | printf("\t%s\n", commands[i].cmd); |
92 | - printf(_("\nSome subcommands can make use of the -c cpulist option.\n")); | |
93 | - printf(_("Look at the general cpupower manpage how to use it\n")); | |
94 | - printf(_("and read up the subcommand's manpage whether it is supported.\n")); | |
95 | - printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n")); | |
69 | + printf(_("\nNot all commands can make use of the -c cpulist option.\n")); | |
70 | + printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); | |
71 | +} | |
72 | + | |
73 | +static int print_man_page(const char *subpage) | |
74 | +{ | |
75 | + int len; | |
76 | + char *page; | |
77 | + | |
78 | + len = 10; /* enough for "cpupower-" */ | |
79 | + if (subpage != NULL) | |
80 | + len += strlen(subpage); | |
81 | + | |
82 | + page = malloc(len); | |
83 | + if (!page) | |
84 | + return -ENOMEM; | |
85 | + | |
86 | + sprintf(page, "cpupower"); | |
87 | + if ((subpage != NULL) && strcmp(subpage, "help")) { | |
88 | + strcat(page, "-"); | |
89 | + strcat(page, subpage); | |
90 | + } | |
91 | + | |
92 | + execlp("man", "man", page, NULL); | |
93 | + | |
94 | + /* should not be reached */ | |
95 | + return -EINVAL; | |
96 | +} | |
97 | + | |
98 | +static int cmd_help(int argc, const char **argv) | |
99 | +{ | |
100 | + if (argc > 1) { | |
101 | + print_man_page(argv[1]); /* exits within execlp() */ | |
102 | + return EXIT_FAILURE; | |
103 | + } | |
104 | + | |
105 | + print_help(); | |
106 | + return EXIT_SUCCESS; | |
96 | 107 | } |
97 | 108 | |
98 | 109 | static void print_version(void) |
tools/power/cpupower/utils/helpers/helpers.h
... | ... | @@ -16,11 +16,20 @@ |
16 | 16 | #include "helpers/bitmask.h" |
17 | 17 | |
18 | 18 | /* Internationalization ****************************/ |
19 | +#ifdef NLS | |
20 | + | |
19 | 21 | #define _(String) gettext(String) |
20 | 22 | #ifndef gettext_noop |
21 | 23 | #define gettext_noop(String) String |
22 | 24 | #endif |
23 | 25 | #define N_(String) gettext_noop(String) |
26 | + | |
27 | +#else /* !NLS */ | |
28 | + | |
29 | +#define _(String) String | |
30 | +#define N_(String) String | |
31 | + | |
32 | +#endif | |
24 | 33 | /* Internationalization ****************************/ |
25 | 34 | |
26 | 35 | extern int run_as_root; |
... | ... | @@ -96,6 +105,9 @@ |
96 | 105 | int pkg; |
97 | 106 | int core; |
98 | 107 | int cpu; |
108 | + | |
109 | + /* flags */ | |
110 | + unsigned int is_online:1; | |
99 | 111 | } *core_info; |
100 | 112 | }; |
101 | 113 |
tools/power/cpupower/utils/helpers/sysfs.c
... | ... | @@ -56,6 +56,56 @@ |
56 | 56 | return (unsigned int) numwrite; |
57 | 57 | } |
58 | 58 | |
59 | +/* | |
60 | + * Detect whether a CPU is online | |
61 | + * | |
62 | + * Returns: | |
63 | + * 1 -> if CPU is online | |
64 | + * 0 -> if CPU is offline | |
65 | + * negative errno values in error case | |
66 | + */ | |
67 | +int sysfs_is_cpu_online(unsigned int cpu) | |
68 | +{ | |
69 | + char path[SYSFS_PATH_MAX]; | |
70 | + int fd; | |
71 | + ssize_t numread; | |
72 | + unsigned long long value; | |
73 | + char linebuf[MAX_LINE_LEN]; | |
74 | + char *endp; | |
75 | + struct stat statbuf; | |
76 | + | |
77 | + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); | |
78 | + | |
79 | + if (stat(path, &statbuf) != 0) | |
80 | + return 0; | |
81 | + | |
82 | + /* | |
83 | + * kernel without CONFIG_HOTPLUG_CPU | |
84 | + * -> cpuX directory exists, but not cpuX/online file | |
85 | + */ | |
86 | + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); | |
87 | + if (stat(path, &statbuf) != 0) | |
88 | + return 1; | |
89 | + | |
90 | + fd = open(path, O_RDONLY); | |
91 | + if (fd == -1) | |
92 | + return -errno; | |
93 | + | |
94 | + numread = read(fd, linebuf, MAX_LINE_LEN - 1); | |
95 | + if (numread < 1) { | |
96 | + close(fd); | |
97 | + return -EIO; | |
98 | + } | |
99 | + linebuf[numread] = '\0'; | |
100 | + close(fd); | |
101 | + | |
102 | + value = strtoull(linebuf, &endp, 0); | |
103 | + if (value > 1 || value < 0) | |
104 | + return -EINVAL; | |
105 | + | |
106 | + return value; | |
107 | +} | |
108 | + | |
59 | 109 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ |
60 | 110 | |
61 | 111 | /* |
tools/power/cpupower/utils/helpers/sysfs.h
... | ... | @@ -7,6 +7,8 @@ |
7 | 7 | |
8 | 8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); |
9 | 9 | |
10 | +extern int sysfs_is_cpu_online(unsigned int cpu); | |
11 | + | |
10 | 12 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, |
11 | 13 | unsigned int idlestate); |
12 | 14 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, |
tools/power/cpupower/utils/helpers/topology.c
... | ... | @@ -41,6 +41,8 @@ |
41 | 41 | unsigned int pkg; |
42 | 42 | unsigned int thread; |
43 | 43 | unsigned int cpu; |
44 | + /* flags */ | |
45 | + unsigned int is_online:1; | |
44 | 46 | }; |
45 | 47 | |
46 | 48 | static int __compare(const void *t1, const void *t2) |
... | ... | @@ -78,6 +80,8 @@ |
78 | 80 | return -ENOMEM; |
79 | 81 | cpu_top->pkgs = cpu_top->cores = 0; |
80 | 82 | for (cpu = 0; cpu < cpus; cpu++) { |
83 | + cpu_top->core_info[cpu].cpu = cpu; | |
84 | + cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); | |
81 | 85 | cpu_top->core_info[cpu].pkg = |
82 | 86 | sysfs_topology_read_file(cpu, "physical_package_id"); |
83 | 87 | if ((int)cpu_top->core_info[cpu].pkg != -1 && |
... | ... | @@ -85,7 +89,6 @@ |
85 | 89 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; |
86 | 90 | cpu_top->core_info[cpu].core = |
87 | 91 | sysfs_topology_read_file(cpu, "core_id"); |
88 | - cpu_top->core_info[cpu].cpu = cpu; | |
89 | 92 | } |
90 | 93 | cpu_top->pkgs++; |
91 | 94 |
tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
... | ... | @@ -134,7 +134,7 @@ |
134 | 134 | /* Assume idle state count is the same for all CPUs */ |
135 | 135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); |
136 | 136 | |
137 | - if (cpuidle_sysfs_monitor.hw_states_num == 0) | |
137 | + if (cpuidle_sysfs_monitor.hw_states_num <= 0) | |
138 | 138 | return NULL; |
139 | 139 | |
140 | 140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
... | ... | @@ -43,6 +43,12 @@ |
43 | 43 | /* ToDo: Document this in the manpage */ |
44 | 44 | static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; |
45 | 45 | |
46 | +static void print_wrong_arg_exit(void) | |
47 | +{ | |
48 | + printf(_("invalid or unknown argument\n")); | |
49 | + exit(EXIT_FAILURE); | |
50 | +} | |
51 | + | |
46 | 52 | long long timespec_diff_us(struct timespec start, struct timespec end) |
47 | 53 | { |
48 | 54 | struct timespec temp; |
... | ... | @@ -56,21 +62,6 @@ |
56 | 62 | return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); |
57 | 63 | } |
58 | 64 | |
59 | -void monitor_help(void) | |
60 | -{ | |
61 | - printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n")); | |
62 | - printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n")); | |
63 | - printf(_("cpupower monitor: -l\n")); | |
64 | - printf(_("\t command: pass an arbitrary command to measure specific workload\n")); | |
65 | - printf(_("\t -i: time intervall to measure for in seconds (default 1)\n")); | |
66 | - printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n")); | |
67 | - printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n")); | |
68 | - printf(_("\t -h: print this help\n")); | |
69 | - printf("\n"); | |
70 | - printf(_("only one of: -l, -m are allowed\nIf none of them is passed,")); | |
71 | - printf(_(" all supported monitors are shown\n")); | |
72 | -} | |
73 | - | |
74 | 65 | void print_n_spaces(int n) |
75 | 66 | { |
76 | 67 | int x; |
... | ... | @@ -149,6 +140,10 @@ |
149 | 140 | unsigned long long result; |
150 | 141 | cstate_t s; |
151 | 142 | |
143 | + /* Be careful CPUs may got resorted for pkg value do not just use cpu */ | |
144 | + if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) | |
145 | + return; | |
146 | + | |
152 | 147 | if (topology_depth > 2) |
153 | 148 | printf("%4d|", cpu_top.core_info[cpu].pkg); |
154 | 149 | if (topology_depth > 1) |
... | ... | @@ -190,9 +185,13 @@ |
190 | 185 | } |
191 | 186 | } |
192 | 187 | } |
193 | - /* cpu offline */ | |
194 | - if (cpu_top.core_info[cpu].pkg == -1 || | |
195 | - cpu_top.core_info[cpu].core == -1) { | |
188 | + /* | |
189 | + * The monitor could still provide useful data, for example | |
190 | + * AMD HW counters partly sit in PCI config space. | |
191 | + * It's up to the monitor plug-in to check .is_online, this one | |
192 | + * is just for additional info. | |
193 | + */ | |
194 | + if (!cpu_top.core_info[cpu].is_online) { | |
196 | 195 | printf(_(" *is offline\n")); |
197 | 196 | return; |
198 | 197 | } else |
... | ... | @@ -238,7 +237,6 @@ |
238 | 237 | if (hits == 0) { |
239 | 238 | printf(_("No matching monitor found in %s, " |
240 | 239 | "try -l option\n"), param); |
241 | - monitor_help(); | |
242 | 240 | exit(EXIT_FAILURE); |
243 | 241 | } |
244 | 242 | /* Override detected/registerd monitors array with requested one */ |
245 | 243 | |
246 | 244 | |
247 | 245 | |
248 | 246 | |
249 | 247 | |
... | ... | @@ -335,37 +333,27 @@ |
335 | 333 | int opt; |
336 | 334 | progname = basename(argv[0]); |
337 | 335 | |
338 | - while ((opt = getopt(argc, argv, "+hli:m:")) != -1) { | |
336 | + while ((opt = getopt(argc, argv, "+li:m:")) != -1) { | |
339 | 337 | switch (opt) { |
340 | - case 'h': | |
341 | - monitor_help(); | |
342 | - exit(EXIT_SUCCESS); | |
343 | 338 | case 'l': |
344 | - if (mode) { | |
345 | - monitor_help(); | |
346 | - exit(EXIT_FAILURE); | |
347 | - } | |
339 | + if (mode) | |
340 | + print_wrong_arg_exit(); | |
348 | 341 | mode = list; |
349 | 342 | break; |
350 | 343 | case 'i': |
351 | 344 | /* only allow -i with -m or no option */ |
352 | - if (mode && mode != show) { | |
353 | - monitor_help(); | |
354 | - exit(EXIT_FAILURE); | |
355 | - } | |
345 | + if (mode && mode != show) | |
346 | + print_wrong_arg_exit(); | |
356 | 347 | interval = atoi(optarg); |
357 | 348 | break; |
358 | 349 | case 'm': |
359 | - if (mode) { | |
360 | - monitor_help(); | |
361 | - exit(EXIT_FAILURE); | |
362 | - } | |
350 | + if (mode) | |
351 | + print_wrong_arg_exit(); | |
363 | 352 | mode = show; |
364 | 353 | show_monitors_param = optarg; |
365 | 354 | break; |
366 | 355 | default: |
367 | - monitor_help(); | |
368 | - exit(EXIT_FAILURE); | |
356 | + print_wrong_arg_exit(); | |
369 | 357 | } |
370 | 358 | } |
371 | 359 | if (!mode) |
... | ... | @@ -384,6 +372,10 @@ |
384 | 372 | printf(_("Cannot read number of available processors\n")); |
385 | 373 | return EXIT_FAILURE; |
386 | 374 | } |
375 | + | |
376 | + /* Default is: monitor all CPUs */ | |
377 | + if (bitmask_isallclear(cpus_chosen)) | |
378 | + bitmask_setall(cpus_chosen); | |
387 | 379 | |
388 | 380 | dprint("System has up to %d CPU cores\n", cpu_count); |
389 | 381 |
tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
... | ... | @@ -22,12 +22,15 @@ |
22 | 22 | |
23 | 23 | #define MSR_TSC 0x10 |
24 | 24 | |
25 | +#define MSR_AMD_HWCR 0xc0010015 | |
26 | + | |
25 | 27 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; |
26 | 28 | |
27 | 29 | static int mperf_get_count_percent(unsigned int self_id, double *percent, |
28 | 30 | unsigned int cpu); |
29 | 31 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
30 | 32 | unsigned int cpu); |
33 | +static struct timespec time_start, time_end; | |
31 | 34 | |
32 | 35 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { |
33 | 36 | { |
34 | 37 | |
35 | 38 | |
36 | 39 | |
... | ... | @@ -54,19 +57,33 @@ |
54 | 57 | }, |
55 | 58 | }; |
56 | 59 | |
60 | +enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; | |
61 | +static int max_freq_mode; | |
62 | +/* | |
63 | + * The max frequency mperf is ticking at (in C0), either retrieved via: | |
64 | + * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency | |
65 | + * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time | |
66 | + * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) | |
67 | + */ | |
68 | +static unsigned long max_frequency; | |
69 | + | |
57 | 70 | static unsigned long long tsc_at_measure_start; |
58 | 71 | static unsigned long long tsc_at_measure_end; |
59 | -static unsigned long max_frequency; | |
60 | 72 | static unsigned long long *mperf_previous_count; |
61 | 73 | static unsigned long long *aperf_previous_count; |
62 | 74 | static unsigned long long *mperf_current_count; |
63 | 75 | static unsigned long long *aperf_current_count; |
76 | + | |
64 | 77 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ |
65 | 78 | static int *is_valid; |
66 | 79 | |
67 | 80 | static int mperf_get_tsc(unsigned long long *tsc) |
68 | 81 | { |
69 | - return read_msr(0, MSR_TSC, tsc); | |
82 | + int ret; | |
83 | + ret = read_msr(0, MSR_TSC, tsc); | |
84 | + if (ret) | |
85 | + dprint("Reading TSC MSR failed, returning %llu\n", *tsc); | |
86 | + return ret; | |
70 | 87 | } |
71 | 88 | |
72 | 89 | static int mperf_init_stats(unsigned int cpu) |
73 | 90 | |
... | ... | @@ -97,36 +114,11 @@ |
97 | 114 | return 0; |
98 | 115 | } |
99 | 116 | |
100 | -/* | |
101 | - * get_average_perf() | |
102 | - * | |
103 | - * Returns the average performance (also considers boosted frequencies) | |
104 | - * | |
105 | - * Input: | |
106 | - * aperf_diff: Difference of the aperf register over a time period | |
107 | - * mperf_diff: Difference of the mperf register over the same time period | |
108 | - * max_freq: Maximum frequency (P0) | |
109 | - * | |
110 | - * Returns: | |
111 | - * Average performance over the time period | |
112 | - */ | |
113 | -static unsigned long get_average_perf(unsigned long long aperf_diff, | |
114 | - unsigned long long mperf_diff) | |
115 | -{ | |
116 | - unsigned int perf_percent = 0; | |
117 | - if (((unsigned long)(-1) / 100) < aperf_diff) { | |
118 | - int shift_count = 7; | |
119 | - aperf_diff >>= shift_count; | |
120 | - mperf_diff >>= shift_count; | |
121 | - } | |
122 | - perf_percent = (aperf_diff * 100) / mperf_diff; | |
123 | - return (max_frequency * perf_percent) / 100; | |
124 | -} | |
125 | - | |
126 | 117 | static int mperf_get_count_percent(unsigned int id, double *percent, |
127 | 118 | unsigned int cpu) |
128 | 119 | { |
129 | 120 | unsigned long long aperf_diff, mperf_diff, tsc_diff; |
121 | + unsigned long long timediff; | |
130 | 122 | |
131 | 123 | if (!is_valid[cpu]) |
132 | 124 | return -1; |
133 | 125 | |
... | ... | @@ -136,11 +128,19 @@ |
136 | 128 | |
137 | 129 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
138 | 130 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
139 | - tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | |
140 | 131 | |
141 | - *percent = 100.0 * mperf_diff / tsc_diff; | |
142 | - dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", | |
143 | - mperf_cstates[id].name, mperf_diff, tsc_diff); | |
132 | + if (max_freq_mode == MAX_FREQ_TSC_REF) { | |
133 | + tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | |
134 | + *percent = 100.0 * mperf_diff / tsc_diff; | |
135 | + dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", | |
136 | + mperf_cstates[id].name, mperf_diff, tsc_diff); | |
137 | + } else if (max_freq_mode == MAX_FREQ_SYSFS) { | |
138 | + timediff = timespec_diff_us(time_start, time_end); | |
139 | + *percent = 100.0 * mperf_diff / timediff; | |
140 | + dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", | |
141 | + mperf_cstates[id].name, mperf_diff, timediff); | |
142 | + } else | |
143 | + return -1; | |
144 | 144 | |
145 | 145 | if (id == Cx) |
146 | 146 | *percent = 100.0 - *percent; |
... | ... | @@ -154,7 +154,7 @@ |
154 | 154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
155 | 155 | unsigned int cpu) |
156 | 156 | { |
157 | - unsigned long long aperf_diff, mperf_diff; | |
157 | + unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff; | |
158 | 158 | |
159 | 159 | if (id != AVG_FREQ) |
160 | 160 | return 1; |
161 | 161 | |
... | ... | @@ -165,11 +165,21 @@ |
165 | 165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
166 | 166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
167 | 167 | |
168 | - /* Return MHz for now, might want to return KHz if column width is more | |
169 | - generic */ | |
170 | - *count = get_average_perf(aperf_diff, mperf_diff) / 1000; | |
171 | - dprint("%s: %llu\n", mperf_cstates[id].name, *count); | |
168 | + if (max_freq_mode == MAX_FREQ_TSC_REF) { | |
169 | + /* Calculate max_freq from TSC count */ | |
170 | + tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | |
171 | + time_diff = timespec_diff_us(time_start, time_end); | |
172 | + max_frequency = tsc_diff / time_diff; | |
173 | + } | |
172 | 174 | |
175 | + *count = max_frequency * ((double)aperf_diff / mperf_diff); | |
176 | + dprint("%s: Average freq based on %s maximum frequency:\n", | |
177 | + mperf_cstates[id].name, | |
178 | + (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); | |
179 | + dprint("%max_frequency: %lu", max_frequency); | |
180 | + dprint("aperf_diff: %llu\n", aperf_diff); | |
181 | + dprint("mperf_diff: %llu\n", mperf_diff); | |
182 | + dprint("avg freq: %llu\n", *count); | |
173 | 183 | return 0; |
174 | 184 | } |
175 | 185 | |
... | ... | @@ -178,6 +188,7 @@ |
178 | 188 | int cpu; |
179 | 189 | unsigned long long dbg; |
180 | 190 | |
191 | + clock_gettime(CLOCK_REALTIME, &time_start); | |
181 | 192 | mperf_get_tsc(&tsc_at_measure_start); |
182 | 193 | |
183 | 194 | for (cpu = 0; cpu < cpu_count; cpu++) |
184 | 195 | |
185 | 196 | |
186 | 197 | |
187 | 198 | |
188 | 199 | |
189 | 200 | |
190 | 201 | |
... | ... | @@ -193,32 +204,104 @@ |
193 | 204 | unsigned long long dbg; |
194 | 205 | int cpu; |
195 | 206 | |
196 | - mperf_get_tsc(&tsc_at_measure_end); | |
197 | - | |
198 | 207 | for (cpu = 0; cpu < cpu_count; cpu++) |
199 | 208 | mperf_measure_stats(cpu); |
200 | 209 | |
210 | + mperf_get_tsc(&tsc_at_measure_end); | |
211 | + clock_gettime(CLOCK_REALTIME, &time_end); | |
212 | + | |
201 | 213 | mperf_get_tsc(&dbg); |
202 | 214 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); |
203 | 215 | |
204 | 216 | return 0; |
205 | 217 | } |
206 | 218 | |
207 | -struct cpuidle_monitor mperf_monitor; | |
208 | - | |
209 | -struct cpuidle_monitor *mperf_register(void) | |
219 | +/* | |
220 | + * Mperf register is defined to tick at P0 (maximum) frequency | |
221 | + * | |
222 | + * Instead of reading out P0 which can be tricky to read out from HW, | |
223 | + * we use TSC counter if it reliably ticks at P0/mperf frequency. | |
224 | + * | |
225 | + * Still try to fall back to: | |
226 | + * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq | |
227 | + * on older Intel HW without invariant TSC feature. | |
228 | + * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but | |
229 | + * it's still double checked (MSR_AMD_HWCR)). | |
230 | + * | |
231 | + * On these machines the user would still get useful mperf | |
232 | + * stats when acpi-cpufreq driver is loaded. | |
233 | + */ | |
234 | +static int init_maxfreq_mode(void) | |
210 | 235 | { |
236 | + int ret; | |
237 | + unsigned long long hwcr; | |
211 | 238 | unsigned long min; |
212 | 239 | |
213 | - if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | |
214 | - return NULL; | |
240 | + if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) | |
241 | + goto use_sysfs; | |
215 | 242 | |
216 | - /* Assume min/max all the same on all cores */ | |
243 | + if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { | |
244 | + /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf | |
245 | + * freq. | |
246 | + * A test whether hwcr is accessable/available would be: | |
247 | + * (cpupower_cpu_info.family > 0x10 || | |
248 | + * cpupower_cpu_info.family == 0x10 && | |
249 | + * cpupower_cpu_info.model >= 0x2)) | |
250 | + * This should be the case for all aperf/mperf | |
251 | + * capable AMD machines and is therefore safe to test here. | |
252 | + * Compare with Linus kernel git commit: acf01734b1747b1ec4 | |
253 | + */ | |
254 | + ret = read_msr(0, MSR_AMD_HWCR, &hwcr); | |
255 | + /* | |
256 | + * If the MSR read failed, assume a Xen system that did | |
257 | + * not explicitly provide access to it and assume TSC works | |
258 | + */ | |
259 | + if (ret != 0) { | |
260 | + dprint("TSC read 0x%x failed - assume TSC working\n", | |
261 | + MSR_AMD_HWCR); | |
262 | + return 0; | |
263 | + } else if (1 & (hwcr >> 24)) { | |
264 | + max_freq_mode = MAX_FREQ_TSC_REF; | |
265 | + return 0; | |
266 | + } else { /* Use sysfs max frequency if available */ } | |
267 | + } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { | |
268 | + /* | |
269 | + * On Intel we assume mperf (in C0) is ticking at same | |
270 | + * rate than TSC | |
271 | + */ | |
272 | + max_freq_mode = MAX_FREQ_TSC_REF; | |
273 | + return 0; | |
274 | + } | |
275 | +use_sysfs: | |
217 | 276 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { |
218 | 277 | dprint("Cannot retrieve max freq from cpufreq kernel " |
219 | 278 | "subsystem\n"); |
220 | - return NULL; | |
279 | + return -1; | |
221 | 280 | } |
281 | + max_freq_mode = MAX_FREQ_SYSFS; | |
282 | + return 0; | |
283 | +} | |
284 | + | |
285 | +/* | |
286 | + * This monitor provides: | |
287 | + * | |
288 | + * 1) Average frequency a CPU resided in | |
289 | + * This always works if the CPU has aperf/mperf capabilities | |
290 | + * | |
291 | + * 2) C0 and Cx (any sleep state) time a CPU resided in | |
292 | + * Works if mperf timer stops ticking in sleep states which | |
293 | + * seem to be the case on all current HW. | |
294 | + * Both is directly retrieved from HW registers and is independent | |
295 | + * from kernel statistics. | |
296 | + */ | |
297 | +struct cpuidle_monitor mperf_monitor; | |
298 | +struct cpuidle_monitor *mperf_register(void) | |
299 | +{ | |
300 | + if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | |
301 | + return NULL; | |
302 | + | |
303 | + if (init_maxfreq_mode()) | |
304 | + return NULL; | |
222 | 305 | |
223 | 306 | /* Free this at program termination */ |
224 | 307 | is_valid = calloc(cpu_count, sizeof(int)); |