Add a monitor debug function for rendez waiters
[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; just 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; just 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; just 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; just 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; just 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.  Changing
140          * 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", enable ? "Enabled" : "Disabled");
152         free(buf);
153         close(fd);
154         return 0;
155 }
156
157 static int print_turbo_status(void)
158 {
159         size_t buf_sz;
160         ssize_t ret;
161         int fd;
162         uint64_t *buf;
163         uint64_t msr_val;
164
165         fd = get_msr_fd();
166         buf_sz = num_cores * sizeof(uint64_t);
167         buf = malloc(buf_sz);
168         assert(buf);
169
170         ret = pread(fd, buf, buf_sz, MSR_IA32_PERF_CTL);
171         if (ret < 0) {
172                 perror("pread MSR_PERF_CTL");
173                 exit(-1);
174         }
175         /* The assumption here is that all cores have the same MSR value.  Changing
176          * this would require changing the wrmsr kernel interface. */
177         msr_val = buf[0];
178         printf("Turbo mode is %s for all cores\n", msr_val & (1ULL << 32) ?
179                                                    "disabled" : "enabled");
180         free(buf);
181         close(fd);
182         return 0;
183 }
184
185 static void check_for_ratio_msrs(void)
186 {
187         uint32_t ecx;
188
189         parlib_cpuid(0x6, 0, NULL, NULL, &ecx, NULL);
190         if (!(ecx & (1 << 0))) {
191                 fprintf(stderr, "cpuid says no MPERF and APERF\n");
192                 exit(-1);
193         }
194 }
195
196 static int print_turbo_ratio(void)
197 {
198         size_t buf_sz;
199         ssize_t ret;
200         int fd;
201         uint64_t *mperf_buf, *aperf_buf;
202
203         check_for_ratio_msrs();
204
205         fd = get_msr_fd();
206         buf_sz = num_cores * sizeof(uint64_t);
207         mperf_buf = malloc(buf_sz);
208         aperf_buf = malloc(buf_sz);
209         assert(mperf_buf && aperf_buf);
210         /* ideally these reads happen with no interference/interrupts in between */
211         ret = pread(fd, mperf_buf, buf_sz, MSR_IA32_MPERF);
212         if (ret < 0) {
213                 perror("pread MSR_MPERF");
214                 exit(-1);
215         }
216         ret = pread(fd, aperf_buf, buf_sz, MSR_IA32_APERF);
217         if (ret < 0) {
218                 perror("pread MSR_APERF");
219                 exit(-1);
220         }
221         for (int i = 0; i < num_cores; i++)
222                 printf("Core %3d: %4f%\n", i, 100.0 * aperf_buf[i] / mperf_buf[i]);
223         free(mperf_buf);
224         free(aperf_buf);
225         close(fd);
226         return 0;
227 }
228
229 static int zero_turbo_ratio(void)
230 {
231         uint64_t reset_val = 0;
232         ssize_t ret;
233         int fd;
234
235         check_for_ratio_msrs();
236
237         fd = get_msr_fd();
238         ret = pwrite(fd, &reset_val, sizeof(reset_val), MSR_IA32_MPERF);
239         if (ret < 0) {
240                 perror("pwrite MSR_MPERF");
241                 exit(-1);
242         }
243         ret = pwrite(fd, &reset_val, sizeof(reset_val), MSR_IA32_APERF);
244         if (ret < 0) {
245                 perror("pwrite MSR_APERF");
246                 exit(-1);
247         }
248         close(fd);
249         return 0;
250 }
251
252 int main(int argc, char **argv)
253 {
254         struct prog_opts popts = {0};
255
256         argp_parse(&argp, argc, argv, 0, 0, &popts);
257         /* TODO: could use a core list or something in the future (like perf) */
258         num_cores = get_num_pcores();
259
260         switch (popts.cmd) {
261         case PROG_CMD_ENABLE:
262                 return set_turbo_mode(TRUE);
263         case PROG_CMD_DISABLE:
264                 return set_turbo_mode(FALSE);
265         case PROG_CMD_STATUS:
266                 return print_turbo_status();
267         case PROG_CMD_PRINT_RATIO:
268                 return print_turbo_ratio();
269         case PROG_CMD_ZERO_RATIO:
270                 return zero_turbo_ratio();
271         default:
272                 fprintf(stderr, "Unhandled options (argp should catch this)!\n");
273                 return -1;
274         };
275 }