aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils')
-rw-r--r--tools/power/cpupower/utils/builtin.h7
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c42
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c29
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c20
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c25
-rw-r--r--tools/power/cpupower/utils/cpupower.c91
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h12
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c50
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h2
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c5
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c66
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c177
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);
8extern int cmd_idle_info(int argc, const char **argv); 8extern int cmd_idle_info(int argc, const char **argv);
9extern int cmd_monitor(int argc, const char **argv); 9extern int cmd_monitor(int argc, const char **argv);
10 10
11extern void set_help(void);
12extern void info_help(void);
13extern void freq_set_help(void);
14extern void freq_info_help(void);
15extern void idle_info_help(void);
16extern 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
513void 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
544static struct option info_opts[] = { 513static 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
23void 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
45static struct option set_opts[] = { 23static 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[] = {
80static void print_unknown_arg(void) 57static 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
86static unsigned long string_to_frequency(const char *str) 62static 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
144void 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
156static struct option info_opts[] = { 142static 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
163static inline void cpuidle_exit(int fail) 148static 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
19void 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
32static struct option set_opts[] = { 19static 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
40static void print_wrong_arg_exit(void) 26static 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
20void 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
32static struct option set_opts[] = { 20static 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
40static void print_wrong_arg_exit(void) 27static 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 @@
19struct cmd_struct { 20struct 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
28int cmd_help(int argc, const char **argv); 28static 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;
44static void print_help(void); 44static void print_help(void);
45 45
46static struct cmd_struct commands[] = { 46static 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
57int 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
78static void print_help(void) 57static 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
73static 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
98static 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
98static void print_version(void) 109static 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
26extern int run_as_root; 35extern 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 */
67int 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
8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); 8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
9 9
10extern int sysfs_is_cpu_online(unsigned int cpu);
11
10extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 12extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
11 unsigned int idlestate); 13 unsigned int idlestate);
12extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, 14extern 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
46static int __compare(const void *t1, const void *t2) 48static 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 */
44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; 44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
45 45
46static void print_wrong_arg_exit(void)
47{
48 printf(_("invalid or unknown argument\n"));
49 exit(EXIT_FAILURE);
50}
51
46long long timespec_diff_us(struct timespec start, struct timespec end) 52long 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
59void 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
74void print_n_spaces(int n) 65void 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
25enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; 27enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
26 28
27static int mperf_get_count_percent(unsigned int self_id, double *percent, 29static int mperf_get_count_percent(unsigned int self_id, double *percent,
28 unsigned int cpu); 30 unsigned int cpu);
29static int mperf_get_count_freq(unsigned int id, unsigned long long *count, 31static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
30 unsigned int cpu); 32 unsigned int cpu);
33static struct timespec time_start, time_end;
31 34
32static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { 35static 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
60enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF };
61static 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 */
68static unsigned long max_frequency;
69
57static unsigned long long tsc_at_measure_start; 70static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end; 71static unsigned long long tsc_at_measure_end;
59static unsigned long max_frequency;
60static unsigned long long *mperf_previous_count; 72static unsigned long long *mperf_previous_count;
61static unsigned long long *aperf_previous_count; 73static unsigned long long *aperf_previous_count;
62static unsigned long long *mperf_current_count; 74static unsigned long long *mperf_current_count;
63static unsigned long long *aperf_current_count; 75static 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 */
65static int *is_valid; 78static int *is_valid;
66 79
67static int mperf_get_tsc(unsigned long long *tsc) 80static 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
72static int mperf_init_stats(unsigned int cpu) 89static 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 */
113static 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
126static int mperf_get_count_percent(unsigned int id, double *percent, 117static 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,
154static int mperf_get_count_freq(unsigned int id, unsigned long long *count, 154static 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
207struct cpuidle_monitor mperf_monitor; 219/*
208 220 * Mperf register is defined to tick at P0 (maximum) frequency
209struct 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 */
234static 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 }
275use_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 */
297struct cpuidle_monitor mperf_monitor;
298struct 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));