diff options
Diffstat (limited to 'tools/power/cpupower/utils')
-rw-r--r-- | tools/power/cpupower/utils/builtin.h | 7 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpufreq-info.c | 42 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpufreq-set.c | 29 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpuidle-info.c | 24 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpupower-info.c | 20 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpupower-set.c | 25 | ||||
-rw-r--r-- | tools/power/cpupower/utils/cpupower.c | 91 | ||||
-rw-r--r-- | tools/power/cpupower/utils/helpers/helpers.h | 12 | ||||
-rw-r--r-- | tools/power/cpupower/utils/helpers/sysfs.c | 50 | ||||
-rw-r--r-- | tools/power/cpupower/utils/helpers/sysfs.h | 2 | ||||
-rw-r--r-- | tools/power/cpupower/utils/helpers/topology.c | 5 | ||||
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | 2 | ||||
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c | 66 | ||||
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | 177 |
14 files changed, 286 insertions, 266 deletions
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h index c870ffba5219..c10496fbe3c6 100644 --- a/tools/power/cpupower/utils/builtin.h +++ b/tools/power/cpupower/utils/builtin.h | |||
@@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv); | |||
8 | extern int cmd_idle_info(int argc, const char **argv); | 8 | extern int cmd_idle_info(int argc, const char **argv); |
9 | extern int cmd_monitor(int argc, const char **argv); | 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 | #endif | 11 | #endif |
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 5a1d25f056b3..28953c9a7bd5 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c | |||
@@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human) | |||
510 | return 0; | 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 | static struct option info_opts[] = { | 513 | static struct option info_opts[] = { |
545 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, | 514 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, |
546 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, | 515 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, |
@@ -556,7 +525,6 @@ static struct option info_opts[] = { | |||
556 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, | 525 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, |
557 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | 526 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, |
558 | { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, | 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 | ||
@@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv) | |||
570 | int output_param = 0; | 538 | int output_param = 0; |
571 | 539 | ||
572 | do { | 540 | do { |
573 | ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL); | 541 | ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); |
574 | switch (ret) { | 542 | switch (ret) { |
575 | case '?': | 543 | case '?': |
576 | output_param = '?'; | 544 | output_param = '?'; |
577 | cont = 0; | 545 | cont = 0; |
578 | break; | 546 | break; |
579 | case 'h': | ||
580 | output_param = 'h'; | ||
581 | cont = 0; | ||
582 | break; | ||
583 | case -1: | 547 | case -1: |
584 | cont = 0; | 548 | cont = 0; |
585 | break; | 549 | break; |
@@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv) | |||
642 | return -EINVAL; | 606 | return -EINVAL; |
643 | case '?': | 607 | case '?': |
644 | printf(_("invalid or unknown argument\n")); | 608 | printf(_("invalid or unknown argument\n")); |
645 | freq_info_help(); | ||
646 | return -EINVAL; | 609 | return -EINVAL; |
647 | case 'h': | ||
648 | freq_info_help(); | ||
649 | return EXIT_SUCCESS; | ||
650 | case 'o': | 610 | case 'o': |
651 | proc_cpufreq_output(); | 611 | proc_cpufreq_output(); |
652 | return EXIT_SUCCESS; | 612 | return EXIT_SUCCESS; |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 5f783622bf31..dd1539eb8c63 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -20,34 +20,11 @@ | |||
20 | 20 | ||
21 | #define NORM_FREQ_LEN 32 | 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 | static struct option set_opts[] = { | 23 | static struct option set_opts[] = { |
46 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, | 24 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, |
47 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, | 25 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, |
48 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, | 26 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, |
49 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, | 27 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, |
50 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
51 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, | 28 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, |
52 | { }, | 29 | { }, |
53 | }; | 30 | }; |
@@ -80,7 +57,6 @@ const struct freq_units def_units[] = { | |||
80 | static void print_unknown_arg(void) | 57 | static void print_unknown_arg(void) |
81 | { | 58 | { |
82 | printf(_("invalid or unknown argument\n")); | 59 | printf(_("invalid or unknown argument\n")); |
83 | freq_set_help(); | ||
84 | } | 60 | } |
85 | 61 | ||
86 | static unsigned long string_to_frequency(const char *str) | 62 | static unsigned long string_to_frequency(const char *str) |
@@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv) | |||
231 | 207 | ||
232 | /* parameter parsing */ | 208 | /* parameter parsing */ |
233 | do { | 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 | switch (ret) { | 211 | switch (ret) { |
236 | case '?': | 212 | case '?': |
237 | print_unknown_arg(); | 213 | print_unknown_arg(); |
238 | return -EINVAL; | 214 | return -EINVAL; |
239 | case 'h': | ||
240 | freq_set_help(); | ||
241 | return 0; | ||
242 | case -1: | 215 | case -1: |
243 | cont = 0; | 216 | cont = 0; |
244 | break; | 217 | break; |
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 70da3574f1e9..b028267c1376 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
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 | static struct option info_opts[] = { | 142 | static struct option info_opts[] = { |
157 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, | 143 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, |
158 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | 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 | static inline void cpuidle_exit(int fail) | 148 | static inline void cpuidle_exit(int fail) |
164 | { | 149 | { |
165 | idle_info_help(); | ||
166 | exit(EXIT_FAILURE); | 150 | exit(EXIT_FAILURE); |
167 | } | 151 | } |
168 | 152 | ||
@@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv) | |||
174 | unsigned int cpu = 0; | 158 | unsigned int cpu = 0; |
175 | 159 | ||
176 | do { | 160 | do { |
177 | ret = getopt_long(argc, argv, "hos", info_opts, NULL); | 161 | ret = getopt_long(argc, argv, "os", info_opts, NULL); |
178 | if (ret == -1) | 162 | if (ret == -1) |
179 | break; | 163 | break; |
180 | switch (ret) { | 164 | switch (ret) { |
@@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv) | |||
182 | output_param = '?'; | 166 | output_param = '?'; |
183 | cont = 0; | 167 | cont = 0; |
184 | break; | 168 | break; |
185 | case 'h': | ||
186 | output_param = 'h'; | ||
187 | cont = 0; | ||
188 | break; | ||
189 | case 's': | 169 | case 's': |
190 | verbose = 0; | 170 | verbose = 0; |
191 | break; | 171 | break; |
@@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv) | |||
211 | case '?': | 191 | case '?': |
212 | printf(_("invalid or unknown argument\n")); | 192 | printf(_("invalid or unknown argument\n")); |
213 | cpuidle_exit(EXIT_FAILURE); | 193 | cpuidle_exit(EXIT_FAILURE); |
214 | case 'h': | ||
215 | cpuidle_exit(EXIT_SUCCESS); | ||
216 | } | 194 | } |
217 | 195 | ||
218 | /* Default is: show output of CPU 0 only */ | 196 | /* Default is: show output of CPU 0 only */ |
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 85253cb7600e..3f68632c28c7 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c | |||
@@ -16,31 +16,16 @@ | |||
16 | #include "helpers/helpers.h" | 16 | #include "helpers/helpers.h" |
17 | #include "helpers/sysfs.h" | 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 | static struct option set_opts[] = { | 19 | static struct option set_opts[] = { |
33 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | 20 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | 21 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | 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 | static void print_wrong_arg_exit(void) | 26 | static void print_wrong_arg_exit(void) |
41 | { | 27 | { |
42 | printf(_("invalid or unknown argument\n")); | 28 | printf(_("invalid or unknown argument\n")); |
43 | info_help(); | ||
44 | exit(EXIT_FAILURE); | 29 | exit(EXIT_FAILURE); |
45 | } | 30 | } |
46 | 31 | ||
@@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv) | |||
64 | textdomain(PACKAGE); | 49 | textdomain(PACKAGE); |
65 | 50 | ||
66 | /* parameter parsing */ | 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 | switch (ret) { | 53 | switch (ret) { |
69 | case 'h': | ||
70 | info_help(); | ||
71 | return 0; | ||
72 | case 'b': | 54 | case 'b': |
73 | if (params.perf_bias) | 55 | if (params.perf_bias) |
74 | print_wrong_arg_exit(); | 56 | print_wrong_arg_exit(); |
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index bc1b391e46f0..dc4de3762111 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c | |||
@@ -17,30 +17,16 @@ | |||
17 | #include "helpers/sysfs.h" | 17 | #include "helpers/sysfs.h" |
18 | #include "helpers/bitmask.h" | 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 | static struct option set_opts[] = { | 20 | static struct option set_opts[] = { |
33 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | 21 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | 22 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | 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 | static void print_wrong_arg_exit(void) | 27 | static void print_wrong_arg_exit(void) |
41 | { | 28 | { |
42 | printf(_("invalid or unknown argument\n")); | 29 | printf(_("invalid or unknown argument\n")); |
43 | set_help(); | ||
44 | exit(EXIT_FAILURE); | 30 | exit(EXIT_FAILURE); |
45 | } | 31 | } |
46 | 32 | ||
@@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv) | |||
66 | 52 | ||
67 | params.params = 0; | 53 | params.params = 0; |
68 | /* parameter parsing */ | 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 | set_opts, NULL)) != -1) { | 56 | set_opts, NULL)) != -1) { |
71 | switch (ret) { | 57 | switch (ret) { |
72 | case 'h': | ||
73 | set_help(); | ||
74 | return 0; | ||
75 | case 'b': | 58 | case 'b': |
76 | if (params.perf_bias) | 59 | if (params.perf_bias) |
77 | print_wrong_arg_exit(); | 60 | print_wrong_arg_exit(); |
@@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv) | |||
110 | } | 93 | } |
111 | }; | 94 | }; |
112 | 95 | ||
113 | if (!params.params) { | 96 | if (!params.params) |
114 | set_help(); | 97 | print_wrong_arg_exit(); |
115 | return -EINVAL; | ||
116 | } | ||
117 | 98 | ||
118 | if (params.sched_mc) { | 99 | if (params.sched_mc) { |
119 | ret = sysfs_set_sched("mc", sched_mc); | 100 | ret = sysfs_set_sched("mc", sched_mc); |
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 5844ae0f786f..52bee591c1c5 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | #include <string.h> | 12 | #include <string.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <errno.h> | ||
14 | 15 | ||
15 | #include "builtin.h" | 16 | #include "builtin.h" |
16 | #include "helpers/helpers.h" | 17 | #include "helpers/helpers.h" |
@@ -19,13 +20,12 @@ | |||
19 | struct cmd_struct { | 20 | struct cmd_struct { |
20 | const char *cmd; | 21 | const char *cmd; |
21 | int (*main)(int, const char **); | 22 | int (*main)(int, const char **); |
22 | void (*usage)(void); | ||
23 | int needs_root; | 23 | int needs_root; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | 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 | /* Global cpu_info object available for all binaries | 30 | /* Global cpu_info object available for all binaries |
31 | * Info only retrieved from CPU 0 | 31 | * Info only retrieved from CPU 0 |
@@ -44,55 +44,66 @@ int be_verbose; | |||
44 | static void print_help(void); | 44 | static void print_help(void); |
45 | 45 | ||
46 | static struct cmd_struct commands[] = { | 46 | static struct cmd_struct commands[] = { |
47 | { "frequency-info", cmd_freq_info, freq_info_help, 0 }, | 47 | { "frequency-info", cmd_freq_info, 0 }, |
48 | { "frequency-set", cmd_freq_set, freq_set_help, 1 }, | 48 | { "frequency-set", cmd_freq_set, 1 }, |
49 | { "idle-info", cmd_idle_info, idle_info_help, 0 }, | 49 | { "idle-info", cmd_idle_info, 0 }, |
50 | { "set", cmd_set, set_help, 1 }, | 50 | { "set", cmd_set, 1 }, |
51 | { "info", cmd_info, info_help, 0 }, | 51 | { "info", cmd_info, 0 }, |
52 | { "monitor", cmd_monitor, monitor_help, 0 }, | 52 | { "monitor", cmd_monitor, 0 }, |
53 | { "help", cmd_help, print_help, 0 }, | 53 | { "help", cmd_help, 0 }, |
54 | /* { "bench", cmd_bench, NULL, 1 }, */ | 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 | static void print_help(void) | 57 | static void print_help(void) |
79 | { | 58 | { |
80 | unsigned int i; | 59 | unsigned int i; |
81 | 60 | ||
82 | #ifdef DEBUG | 61 | #ifdef DEBUG |
83 | printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n")); | 62 | printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); |
84 | printf(_(" -d, --debug May increase output (stderr) on some subcommands\n")); | ||
85 | #else | 63 | #else |
86 | printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n")); | 64 | printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); |
87 | #endif | 65 | #endif |
88 | printf(_("cpupower --version\n")); | 66 | printf(_("Supported commands are:\n")); |
89 | printf(_("Supported subcommands are:\n")); | ||
90 | for (i = 0; i < ARRAY_SIZE(commands); i++) | 67 | for (i = 0; i < ARRAY_SIZE(commands); i++) |
91 | printf("\t%s\n", commands[i].cmd); | 68 | printf("\t%s\n", commands[i].cmd); |
92 | printf(_("\nSome subcommands can make use of the -c cpulist option.\n")); | 69 | printf(_("\nNot all commands can make use of the -c cpulist option.\n")); |
93 | printf(_("Look at the general cpupower manpage how to use it\n")); | 70 | printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); |
94 | printf(_("and read up the subcommand's manpage whether it is supported.\n")); | 71 | } |
95 | printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n")); | 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 | static void print_version(void) | 109 | static void print_version(void) |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 592ee362b877..2747e738efb0 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -16,11 +16,20 @@ | |||
16 | #include "helpers/bitmask.h" | 16 | #include "helpers/bitmask.h" |
17 | 17 | ||
18 | /* Internationalization ****************************/ | 18 | /* Internationalization ****************************/ |
19 | #ifdef NLS | ||
20 | |||
19 | #define _(String) gettext(String) | 21 | #define _(String) gettext(String) |
20 | #ifndef gettext_noop | 22 | #ifndef gettext_noop |
21 | #define gettext_noop(String) String | 23 | #define gettext_noop(String) String |
22 | #endif | 24 | #endif |
23 | #define N_(String) gettext_noop(String) | 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 | /* Internationalization ****************************/ | 33 | /* Internationalization ****************************/ |
25 | 34 | ||
26 | extern int run_as_root; | 35 | extern int run_as_root; |
@@ -96,6 +105,9 @@ struct cpupower_topology { | |||
96 | int pkg; | 105 | int pkg; |
97 | int core; | 106 | int core; |
98 | int cpu; | 107 | int cpu; |
108 | |||
109 | /* flags */ | ||
110 | unsigned int is_online:1; | ||
99 | } *core_info; | 111 | } *core_info; |
100 | }; | 112 | }; |
101 | 113 | ||
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 55e2466674c6..c6343024a611 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c | |||
@@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path, | |||
56 | return (unsigned int) numwrite; | 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 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | 109 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ |
60 | 110 | ||
61 | /* | 111 | /* |
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h index f9373e090637..8cb797bbceb0 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.h +++ b/tools/power/cpupower/utils/helpers/sysfs.h | |||
@@ -7,6 +7,8 @@ | |||
7 | 7 | ||
8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | 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 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | 12 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, |
11 | unsigned int idlestate); | 13 | unsigned int idlestate); |
12 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, | 14 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, |
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 385ee5c7570c..4eae2c47ba48 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -41,6 +41,8 @@ struct cpuid_core_info { | |||
41 | unsigned int pkg; | 41 | unsigned int pkg; |
42 | unsigned int thread; | 42 | unsigned int thread; |
43 | unsigned int cpu; | 43 | unsigned int cpu; |
44 | /* flags */ | ||
45 | unsigned int is_online:1; | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | static int __compare(const void *t1, const void *t2) | 48 | static int __compare(const void *t1, const void *t2) |
@@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) | |||
78 | return -ENOMEM; | 80 | return -ENOMEM; |
79 | cpu_top->pkgs = cpu_top->cores = 0; | 81 | cpu_top->pkgs = cpu_top->cores = 0; |
80 | for (cpu = 0; cpu < cpus; cpu++) { | 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 | cpu_top->core_info[cpu].pkg = | 85 | cpu_top->core_info[cpu].pkg = |
82 | sysfs_topology_read_file(cpu, "physical_package_id"); | 86 | sysfs_topology_read_file(cpu, "physical_package_id"); |
83 | if ((int)cpu_top->core_info[cpu].pkg != -1 && | 87 | if ((int)cpu_top->core_info[cpu].pkg != -1 && |
@@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) | |||
85 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; | 89 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; |
86 | cpu_top->core_info[cpu].core = | 90 | cpu_top->core_info[cpu].core = |
87 | sysfs_topology_read_file(cpu, "core_id"); | 91 | sysfs_topology_read_file(cpu, "core_id"); |
88 | cpu_top->core_info[cpu].cpu = cpu; | ||
89 | } | 92 | } |
90 | cpu_top->pkgs++; | 93 | cpu_top->pkgs++; |
91 | 94 | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index d048b96a6155..bcd22a1a3970 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
134 | /* Assume idle state count is the same for all CPUs */ | 134 | /* Assume idle state count is the same for all CPUs */ |
135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); | 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 | return NULL; | 138 | return NULL; |
139 | 139 | ||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | 140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index ba4bf068380d..0d6571e418db 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c | |||
@@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top; | |||
43 | /* ToDo: Document this in the manpage */ | 43 | /* ToDo: Document this in the manpage */ |
44 | static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; | 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 | long long timespec_diff_us(struct timespec start, struct timespec end) | 52 | long long timespec_diff_us(struct timespec start, struct timespec end) |
47 | { | 53 | { |
48 | struct timespec temp; | 54 | struct timespec temp; |
@@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end) | |||
56 | return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); | 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 | void print_n_spaces(int n) | 65 | void print_n_spaces(int n) |
75 | { | 66 | { |
76 | int x; | 67 | int x; |
@@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu) | |||
149 | unsigned long long result; | 140 | unsigned long long result; |
150 | cstate_t s; | 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 | if (topology_depth > 2) | 147 | if (topology_depth > 2) |
153 | printf("%4d|", cpu_top.core_info[cpu].pkg); | 148 | printf("%4d|", cpu_top.core_info[cpu].pkg); |
154 | if (topology_depth > 1) | 149 | if (topology_depth > 1) |
@@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu) | |||
190 | } | 185 | } |
191 | } | 186 | } |
192 | } | 187 | } |
193 | /* cpu offline */ | 188 | /* |
194 | if (cpu_top.core_info[cpu].pkg == -1 || | 189 | * The monitor could still provide useful data, for example |
195 | cpu_top.core_info[cpu].core == -1) { | 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 | printf(_(" *is offline\n")); | 195 | printf(_(" *is offline\n")); |
197 | return; | 196 | return; |
198 | } else | 197 | } else |
@@ -238,7 +237,6 @@ static void parse_monitor_param(char *param) | |||
238 | if (hits == 0) { | 237 | if (hits == 0) { |
239 | printf(_("No matching monitor found in %s, " | 238 | printf(_("No matching monitor found in %s, " |
240 | "try -l option\n"), param); | 239 | "try -l option\n"), param); |
241 | monitor_help(); | ||
242 | exit(EXIT_FAILURE); | 240 | exit(EXIT_FAILURE); |
243 | } | 241 | } |
244 | /* Override detected/registerd monitors array with requested one */ | 242 | /* Override detected/registerd monitors array with requested one */ |
@@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[]) | |||
335 | int opt; | 333 | int opt; |
336 | progname = basename(argv[0]); | 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 | switch (opt) { | 337 | switch (opt) { |
340 | case 'h': | ||
341 | monitor_help(); | ||
342 | exit(EXIT_SUCCESS); | ||
343 | case 'l': | 338 | case 'l': |
344 | if (mode) { | 339 | if (mode) |
345 | monitor_help(); | 340 | print_wrong_arg_exit(); |
346 | exit(EXIT_FAILURE); | ||
347 | } | ||
348 | mode = list; | 341 | mode = list; |
349 | break; | 342 | break; |
350 | case 'i': | 343 | case 'i': |
351 | /* only allow -i with -m or no option */ | 344 | /* only allow -i with -m or no option */ |
352 | if (mode && mode != show) { | 345 | if (mode && mode != show) |
353 | monitor_help(); | 346 | print_wrong_arg_exit(); |
354 | exit(EXIT_FAILURE); | ||
355 | } | ||
356 | interval = atoi(optarg); | 347 | interval = atoi(optarg); |
357 | break; | 348 | break; |
358 | case 'm': | 349 | case 'm': |
359 | if (mode) { | 350 | if (mode) |
360 | monitor_help(); | 351 | print_wrong_arg_exit(); |
361 | exit(EXIT_FAILURE); | ||
362 | } | ||
363 | mode = show; | 352 | mode = show; |
364 | show_monitors_param = optarg; | 353 | show_monitors_param = optarg; |
365 | break; | 354 | break; |
366 | default: | 355 | default: |
367 | monitor_help(); | 356 | print_wrong_arg_exit(); |
368 | exit(EXIT_FAILURE); | ||
369 | } | 357 | } |
370 | } | 358 | } |
371 | if (!mode) | 359 | if (!mode) |
@@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv) | |||
385 | return EXIT_FAILURE; | 373 | return EXIT_FAILURE; |
386 | } | 374 | } |
387 | 375 | ||
376 | /* Default is: monitor all CPUs */ | ||
377 | if (bitmask_isallclear(cpus_chosen)) | ||
378 | bitmask_setall(cpus_chosen); | ||
379 | |||
388 | dprint("System has up to %d CPU cores\n", cpu_count); | 380 | dprint("System has up to %d CPU cores\n", cpu_count); |
389 | 381 | ||
390 | for (num = 0; all_monitors[num]; num++) { | 382 | for (num = 0; all_monitors[num]; num++) { |
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c index 63ca87a05e5f..5650ab5a2c20 100644 --- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | |||
@@ -22,12 +22,15 @@ | |||
22 | 22 | ||
23 | #define MSR_TSC 0x10 | 23 | #define MSR_TSC 0x10 |
24 | 24 | ||
25 | #define MSR_AMD_HWCR 0xc0010015 | ||
26 | |||
25 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; | 27 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; |
26 | 28 | ||
27 | static int mperf_get_count_percent(unsigned int self_id, double *percent, | 29 | static int mperf_get_count_percent(unsigned int self_id, double *percent, |
28 | unsigned int cpu); | 30 | unsigned int cpu); |
29 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 31 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
30 | unsigned int cpu); | 32 | unsigned int cpu); |
33 | static struct timespec time_start, time_end; | ||
31 | 34 | ||
32 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | 35 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { |
33 | { | 36 | { |
@@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | |||
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 | static unsigned long long tsc_at_measure_start; | 70 | static unsigned long long tsc_at_measure_start; |
58 | static unsigned long long tsc_at_measure_end; | 71 | static unsigned long long tsc_at_measure_end; |
59 | static unsigned long max_frequency; | ||
60 | static unsigned long long *mperf_previous_count; | 72 | static unsigned long long *mperf_previous_count; |
61 | static unsigned long long *aperf_previous_count; | 73 | static unsigned long long *aperf_previous_count; |
62 | static unsigned long long *mperf_current_count; | 74 | static unsigned long long *mperf_current_count; |
63 | static unsigned long long *aperf_current_count; | 75 | static unsigned long long *aperf_current_count; |
76 | |||
64 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | 77 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ |
65 | static int *is_valid; | 78 | static int *is_valid; |
66 | 79 | ||
67 | static int mperf_get_tsc(unsigned long long *tsc) | 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 | static int mperf_init_stats(unsigned int cpu) | 89 | static int mperf_init_stats(unsigned int cpu) |
@@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu) | |||
97 | return 0; | 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 | static int mperf_get_count_percent(unsigned int id, double *percent, | 117 | static int mperf_get_count_percent(unsigned int id, double *percent, |
127 | unsigned int cpu) | 118 | unsigned int cpu) |
128 | { | 119 | { |
129 | unsigned long long aperf_diff, mperf_diff, tsc_diff; | 120 | unsigned long long aperf_diff, mperf_diff, tsc_diff; |
121 | unsigned long long timediff; | ||
130 | 122 | ||
131 | if (!is_valid[cpu]) | 123 | if (!is_valid[cpu]) |
132 | return -1; | 124 | return -1; |
@@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent, | |||
136 | 128 | ||
137 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 129 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
138 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 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; | 132 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
142 | dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", | 133 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
143 | mperf_cstates[id].name, mperf_diff, tsc_diff); | 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 | if (id == Cx) | 145 | if (id == Cx) |
146 | *percent = 100.0 - *percent; | 146 | *percent = 100.0 - *percent; |
@@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent, | |||
154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
155 | unsigned int cpu) | 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 | if (id != AVG_FREQ) | 159 | if (id != AVG_FREQ) |
160 | return 1; | 160 | return 1; |
@@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | |||
165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 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 | 168 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
169 | generic */ | 169 | /* Calculate max_freq from TSC count */ |
170 | *count = get_average_perf(aperf_diff, mperf_diff) / 1000; | 170 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
171 | dprint("%s: %llu\n", mperf_cstates[id].name, *count); | 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 | return 0; | 183 | return 0; |
174 | } | 184 | } |
175 | 185 | ||
@@ -178,6 +188,7 @@ static int mperf_start(void) | |||
178 | int cpu; | 188 | int cpu; |
179 | unsigned long long dbg; | 189 | unsigned long long dbg; |
180 | 190 | ||
191 | clock_gettime(CLOCK_REALTIME, &time_start); | ||
181 | mperf_get_tsc(&tsc_at_measure_start); | 192 | mperf_get_tsc(&tsc_at_measure_start); |
182 | 193 | ||
183 | for (cpu = 0; cpu < cpu_count; cpu++) | 194 | for (cpu = 0; cpu < cpu_count; cpu++) |
@@ -193,32 +204,104 @@ static int mperf_stop(void) | |||
193 | unsigned long long dbg; | 204 | unsigned long long dbg; |
194 | int cpu; | 205 | int cpu; |
195 | 206 | ||
196 | mperf_get_tsc(&tsc_at_measure_end); | ||
197 | |||
198 | for (cpu = 0; cpu < cpu_count; cpu++) | 207 | for (cpu = 0; cpu < cpu_count; cpu++) |
199 | mperf_measure_stats(cpu); | 208 | mperf_measure_stats(cpu); |
200 | 209 | ||
210 | mperf_get_tsc(&tsc_at_measure_end); | ||
211 | clock_gettime(CLOCK_REALTIME, &time_end); | ||
212 | |||
201 | mperf_get_tsc(&dbg); | 213 | mperf_get_tsc(&dbg); |
202 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | 214 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); |
203 | 215 | ||
204 | return 0; | 216 | return 0; |
205 | } | 217 | } |
206 | 218 | ||
207 | struct cpuidle_monitor mperf_monitor; | 219 | /* |
208 | 220 | * Mperf register is defined to tick at P0 (maximum) frequency | |
209 | struct cpuidle_monitor *mperf_register(void) | 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 | unsigned long min; | 238 | unsigned long min; |
212 | 239 | ||
213 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | 240 | if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) |
214 | return NULL; | 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 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { | 276 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { |
218 | dprint("Cannot retrieve max freq from cpufreq kernel " | 277 | dprint("Cannot retrieve max freq from cpufreq kernel " |
219 | "subsystem\n"); | 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 | /* Free this at program termination */ | 306 | /* Free this at program termination */ |
224 | is_valid = calloc(cpu_count, sizeof(int)); | 307 | is_valid = calloc(cpu_count, sizeof(int)); |