akaros/tests/turbo.c
<<
>>
Prefs
   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
  24static const char doc[] = "turbo -- control for turbo mode";
  25static const char args_doc[] = "";
  26
  27static 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
  44struct prog_opts {
  45        int                     cmd;
  46};
  47
  48static int num_cores;
  49
  50static 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
 107static struct argp argp = {options, parse_opt, args_doc, doc};
 108
 109static 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
 121static 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
 158static 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
 186static 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
 197static 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
 232static 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
 255int 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}
 279