kconfig: use pkg-config for ncurses detection
[akaros.git] / tests / turbo.c
1 /* Copyright (c) 2016-7 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Usage: turbo [reset]
6  *
7  * This will print the turbo ratio since the last reset for each core.
8  *
9  * x86 only (TODO) */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <assert.h>
18 #include <unistd.h>
19 #include <parlib/sysinfo.h>
20 #include <parlib/arch/arch.h>
21 #include <ros/arch/msr-index.h>
22 #include <argp.h>
23
24 static const char doc[] = "turbo -- control for turbo mode";
25 static const char args_doc[] = "";
26
27 static struct argp_option options[] = {
28         {"enable",              'e', 0, 0, "Enable turbo mode"},
29         {"disable",             'd', 0, 0, "Disable turbo mode"},
30         {"status",              's', 0, 0, "Print status of turbo mode"},
31         {0, 0, 0, 0, ""},
32         {"ratio",               'r', 0, 0, "Print the experienced turbo ratio"},
33         {"zero",                'z', 0, 0, "Zero the turbo ratio"},
34         {NULL,                  'h', 0, OPTION_HIDDEN, NULL},
35         { 0 }
36 };
37
38 #define PROG_CMD_ENABLE         1
39 #define PROG_CMD_DISABLE        2
40 #define PROG_CMD_STATUS         3
41 #define PROG_CMD_PRINT_RATIO    4
42 #define PROG_CMD_ZERO_RATIO     5
43
44 struct prog_opts {
45         int                     cmd;
46 };
47
48 static int num_cores;
49
50 static error_t parse_opt(int key, char *arg, struct argp_state *state)
51 {
52         struct prog_opts *p_opts = state->input;
53
54         switch (key) {
55         case 'e':
56                 if (p_opts->cmd) {
57                         fprintf(stderr, "Too many commands; one allowed.\n\n");
58                         argp_usage(state);
59                 }
60                 p_opts->cmd = PROG_CMD_ENABLE;
61                 break;
62         case 'd':
63                 if (p_opts->cmd) {
64                         fprintf(stderr, "Too many commands; one allowed.\n\n");
65                         argp_usage(state);
66                 }
67                 p_opts->cmd = PROG_CMD_DISABLE;
68                 break;
69         case 's':
70                 if (p_opts->cmd) {
71                         fprintf(stderr, "Too many commands; one allowed.\n\n");
72                         argp_usage(state);
73                 }
74                 p_opts->cmd = PROG_CMD_STATUS;
75                 break;
76         case 'r':
77                 if (p_opts->cmd) {
78                         fprintf(stderr, "Too many commands; one allowed.\n\n");
79                         argp_usage(state);
80                 }
81                 p_opts->cmd = PROG_CMD_PRINT_RATIO;
82                 break;
83         case 'z':
84                 if (p_opts->cmd) {
85                         fprintf(stderr, "Too many commands; one allowed.\n\n");
86                         argp_usage(state);
87                 }
88                 p_opts->cmd = PROG_CMD_ZERO_RATIO;
89                 break;
90         case ARGP_KEY_ARG:
91                 fprintf(stderr, "Extra arguments\n");
92                 argp_usage(state);
93                 break;
94         case ARGP_KEY_END:
95                 if (!p_opts->cmd)
96                         argp_usage(state);
97                 break;
98         case 'h':
99                 argp_state_help(state, stderr, ARGP_HELP_LONG);
100                 break;
101         default:
102                 return ARGP_ERR_UNKNOWN;
103         };
104         return 0;
105 }
106
107 static struct argp argp = {options, parse_opt, args_doc, doc};
108
109 static int get_msr_fd(void)
110 {
111         int fd;
112
113         fd = open("#arch/msr", O_RDWR);
114         if (fd < 0) {
115                 perror("open");
116                 exit(-1);
117         }
118         return fd;
119 }
120
121 static int set_turbo_mode(bool enable)
122 {
123         size_t buf_sz;
124         ssize_t ret;
125         int fd;
126         uint64_t *buf;
127         uint64_t msr_val;
128
129         fd = get_msr_fd();
130         buf_sz = num_cores * sizeof(uint64_t);
131         buf = malloc(buf_sz);
132         assert(buf);
133
134         ret = pread(fd, buf, buf_sz, MSR_IA32_PERF_CTL);
135         if (ret < 0) {
136                 perror("pread MSR_PERF_CTL");
137                 exit(-1);
138         }
139         /* The assumption here is that all cores have the same MSR value.
140          * Changing this would require changing the wrmsr kernel interface. */
141         msr_val = buf[0];
142         if (enable)
143                 msr_val &= ~(1ULL << 32);
144         else
145                 msr_val |= 1ULL << 32;
146         ret = pwrite(fd, &msr_val, sizeof(msr_val), MSR_IA32_PERF_CTL);
147         if (ret < 0) {
148                 perror("pwrite MSR_PERF_CTL");
149                 exit(-1);
150         }
151         printf("%s turbo mode for all cores\n",
152                enable ? "Enabled" : "Disabled");
153         free(buf);
154         close(fd);
155         return 0;
156 }
157
158 static int print_turbo_status(void)
159 {
160         size_t buf_sz;
161         ssize_t ret;
162         int fd;
163         uint64_t *buf;
164         uint64_t msr_val;
165
166         fd = get_msr_fd();
167         buf_sz = num_cores * sizeof(uint64_t);
168         buf = malloc(buf_sz);
169         assert(buf);
170
171         ret = pread(fd, buf, buf_sz, MSR_IA32_PERF_CTL);
172         if (ret < 0) {
173                 perror("pread MSR_PERF_CTL");
174                 exit(-1);
175         }
176         /* The assumption here is that all cores have the same MSR value.
177          * Changing this would require changing the wrmsr kernel interface. */
178         msr_val = buf[0];
179         printf("Turbo mode is %s for all cores\n", msr_val & (1ULL << 32) ?
180                                                    "disabled" : "enabled");
181         free(buf);
182         close(fd);
183         return 0;
184 }
185
186 static void check_for_ratio_msrs(void)
187 {
188         uint32_t ecx;
189
190         parlib_cpuid(0x6, 0, NULL, NULL, &ecx, NULL);
191         if (!(ecx & (1 << 0))) {
192                 fprintf(stderr, "cpuid says no MPERF and APERF\n");
193                 exit(-1);
194         }
195 }
196
197 static int print_turbo_ratio(void)
198 {
199         size_t buf_sz;
200         ssize_t ret;
201         int fd;
202         uint64_t *mperf_buf, *aperf_buf;
203
204         check_for_ratio_msrs();
205
206         fd = get_msr_fd();
207         buf_sz = num_cores * sizeof(uint64_t);
208         mperf_buf = malloc(buf_sz);
209         aperf_buf = malloc(buf_sz);
210         assert(mperf_buf && aperf_buf);
211         /* ideally these reads happen with no interference/interrupts in between
212          */
213         ret = pread(fd, mperf_buf, buf_sz, MSR_IA32_MPERF);
214         if (ret < 0) {
215                 perror("pread MSR_MPERF");
216                 exit(-1);
217         }
218         ret = pread(fd, aperf_buf, buf_sz, MSR_IA32_APERF);
219         if (ret < 0) {
220                 perror("pread MSR_APERF");
221                 exit(-1);
222         }
223         for (int i = 0; i < num_cores; i++)
224                 printf("Core %3d: %4f%\n", i,
225                        100.0 * aperf_buf[i] / mperf_buf[i]);
226         free(mperf_buf);
227         free(aperf_buf);
228         close(fd);
229         return 0;
230 }
231
232 static int zero_turbo_ratio(void)
233 {
234         uint64_t reset_val = 0;
235         ssize_t ret;
236         int fd;
237
238         check_for_ratio_msrs();
239
240         fd = get_msr_fd();
241         ret = pwrite(fd, &reset_val, sizeof(reset_val), MSR_IA32_MPERF);
242         if (ret < 0) {
243                 perror("pwrite MSR_MPERF");
244                 exit(-1);
245         }
246         ret = pwrite(fd, &reset_val, sizeof(reset_val), MSR_IA32_APERF);
247         if (ret < 0) {
248                 perror("pwrite MSR_APERF");
249                 exit(-1);
250         }
251         close(fd);
252         return 0;
253 }
254
255 int main(int argc, char **argv)
256 {
257         struct prog_opts popts = {0};
258
259         argp_parse(&argp, argc, argv, 0, 0, &popts);
260         /* TODO: could use a core list or something in the future (like perf) */
261         num_cores = get_num_pcores();
262
263         switch (popts.cmd) {
264         case PROG_CMD_ENABLE:
265                 return set_turbo_mode(TRUE);
266         case PROG_CMD_DISABLE:
267                 return set_turbo_mode(FALSE);
268         case PROG_CMD_STATUS:
269                 return print_turbo_status();
270         case PROG_CMD_PRINT_RATIO:
271                 return print_turbo_ratio();
272         case PROG_CMD_ZERO_RATIO:
273                 return zero_turbo_ratio();
274         default:
275                 fprintf(stderr, "Unhandled cmd (argp should catch this)!\n");
276                 return -1;
277         };
278 }