diff --git a/README.md b/README.md index 41b5cc2..a36a371 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ There are two variants of the tool: A user-space implementation and a kernel mod cd nanoBench make user +*nanoBench might not work if Secure Boot is enabled. [Click here](https://askubuntu.com/a/762255/925982) for instructions on how to disable Secure Boot.* + ### Kernel Module *Note: The following is not necessary if you would just like to use the user-space version.* diff --git a/common/nanoBench.c b/common/nanoBench.c index 7ccdcdc..7b6e089 100644 --- a/common/nanoBench.c +++ b/common/nanoBench.c @@ -1,5 +1,5 @@ // nanoBench -// +// // Copyright (C) 2019 Andreas Abel // // This program is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU Affero General Public License. @@ -58,7 +58,7 @@ void build_cpuid_string(char* buf, unsigned int r0, unsigned int r1, unsigned in int check_cpuid() { unsigned int eax, ebx, ecx, edx; __cpuid(0, eax, ebx, ecx, edx); - + char proc_vendor_string[17] = {0}; build_cpuid_string(proc_vendor_string, ebx, edx, ecx, 0); print_user_verbose("Vendor ID: %s\n", proc_vendor_string); @@ -71,7 +71,7 @@ int check_cpuid() { __cpuid(0x80000004, eax, ebx, ecx, edx); build_cpuid_string(proc_brand_string+32, eax, ebx, ecx, edx); print_user_verbose("Brand: %s\n", proc_brand_string); - + __cpuid(0x01, eax, ebx, ecx, edx); unsigned int displ_family = ((eax >> 8) & 0xF); if (displ_family == 0x0F) { @@ -85,9 +85,9 @@ int check_cpuid() { print_user_verbose("Stepping ID: %u\n", (eax & 0xF)); if (strcmp(proc_vendor_string, "GenuineIntel") == 0) { - is_Intel_CPU = 1; + is_Intel_CPU = 1; n_programmable_counters = 4; - + __cpuid(0x0A, eax, ebx, ecx, edx); unsigned int perf_mon_ver = (eax & 0xFF); print_user_verbose("Performance monitoring version: %u\n", perf_mon_ver); @@ -95,8 +95,8 @@ int check_cpuid() { print_error("Error: performance monitoring version >= 2 required\n"); return 1; } - - unsigned int n_available_counters = ((eax >> 8) & 0xFF); + + unsigned int n_available_counters = ((eax >> 8) & 0xFF); print_user_verbose("Number of general-purpose performance counters: %u\n", n_available_counters); print_user_verbose("Bit widths of general-purpose performance counters: %u\n", ((eax >> 16) & 0xFF)); @@ -110,14 +110,14 @@ int check_cpuid() { } else { print_error("Error: unsupported CPU found\n"); return 1; - } - + } + return 0; } void parse_counter_configs() { n_pfc_configs = 0; - + char* line; char* next_line = pfc_config_file_content; while ((line = strsep(&next_line, "\n")) != NULL) { @@ -137,19 +137,19 @@ void parse_counter_configs() { if (strlen(config_str) >= sizeof(buf)) { print_error("config string too long: %s\n", config_str); continue; - } + } strcpy(buf, config_str); - + char* tok = buf; - + char* evt_num = strsep(&tok, "."); nb_strtoul(evt_num, 16, &(pfc_configs[n_pfc_configs].evt_num)); - + if (!tok) { print_error("invalid configuration: %s\n", config_str); continue; } - + char* umask = strsep(&tok, "."); nb_strtoul(umask, 16, &(pfc_configs[n_pfc_configs].umask)); @@ -177,18 +177,18 @@ void parse_counter_configs() { pfc_configs[n_pfc_configs] = pfc_configs[prev_n_pfc_configs]; pfc_configs[n_pfc_configs].invalid = 0; } - } else if (!strncmp(ce, "CMSK=", 5)) { + } else if (!strncmp(ce, "CMSK=", 5)) { nb_strtoul(ce+5, 0, &(pfc_configs[n_pfc_configs].cmask)); - } else if (!strncmp(ce, "MSR_3F6H=", 9)) { + } else if (!strncmp(ce, "MSR_3F6H=", 9)) { nb_strtoul(ce+9, 0, &(pfc_configs[n_pfc_configs].msr_3f6h)); - } else if (!strncmp(ce, "MSR_PF=", 7)) { + } else if (!strncmp(ce, "MSR_PF=", 7)) { nb_strtoul(ce+7, 0, &(pfc_configs[n_pfc_configs].msr_pf)); - } else if (!strncmp(ce, "MSR_RSP0=", 9)) { + } else if (!strncmp(ce, "MSR_RSP0=", 9)) { nb_strtoul(ce+9, 0, &(pfc_configs[n_pfc_configs].msr_rsp0)); - } else if (!strncmp(ce, "MSR_RSP1=", 9)) { + } else if (!strncmp(ce, "MSR_RSP1=", 9)) { nb_strtoul(ce+9, 0, &(pfc_configs[n_pfc_configs].msr_rsp1)); - } - } + } + } n_pfc_configs++; } } @@ -197,14 +197,14 @@ void parse_counter_configs() { uint64_t read_value_from_cmd(char* cmd) { FILE* fp; if(!(fp = popen(cmd, "r"))){ - printf("Error reading from \"%s\"\n", cmd); + print_error("Error reading from \"%s\"", cmd); return 0; } - + char buf[20]; fgets(buf, sizeof(buf), fp); pclose(fp); - + uint64_t val; nb_strtoul(buf, 0, &val); return val; @@ -214,9 +214,9 @@ uint64_t read_value_from_cmd(char* cmd) { uint64_t read_msr(unsigned int msr) { #ifdef __KERNEL__ return native_read_msr(msr); - #else + #else char cmd[50]; - snprintf(cmd, sizeof(cmd), "rdmsr -c -p%d %#x", cpu, msr); + snprintf(cmd, sizeof(cmd), "rdmsr -c -p%d %#x", cpu, msr); return read_value_from_cmd(cmd); #endif } @@ -226,17 +226,20 @@ void write_msr(unsigned int msr, uint64_t value) { native_write_msr(msr, (uint32_t)value, (uint32_t)(value>>32)); #else char cmd[50]; - snprintf(cmd, sizeof(cmd), "wrmsr -a -p%d %#x %#lx", cpu, msr, value); - system(cmd); + snprintf(cmd, sizeof(cmd), "wrmsr -p%d %#x %#lx", cpu, msr, value); + if (system(cmd)) { + print_error("\"%s\" failed. You may need to disable Secure Boot (see README.md).", cmd); + exit(1); + } #endif } -void configure_perf_ctrs_FF(unsigned int usr, unsigned int os) { +void configure_perf_ctrs_FF(unsigned int usr, unsigned int os) { if (is_Intel_CPU) { - uint64_t global_ctrl = read_msr(MSR_IA32_PERF_GLOBAL_CTRL); + uint64_t global_ctrl = read_msr(MSR_IA32_PERF_GLOBAL_CTRL); global_ctrl |= ((uint64_t)7 << 32) | 15; write_msr(MSR_IA32_PERF_GLOBAL_CTRL, global_ctrl); - + uint64_t fixed_ctrl = read_msr(MSR_IA32_FIXED_CTR_CTRL); // disable fixed counters fixed_ctrl &= ~((1 << 12) - 1); @@ -252,12 +255,12 @@ void configure_perf_ctrs_FF(unsigned int usr, unsigned int os) { } } -void configure_perf_ctrs_programmable(int start, int end, unsigned int usr, unsigned int os) { +void configure_perf_ctrs_programmable(int start, int end, unsigned int usr, unsigned int os) { if (is_Intel_CPU) { - uint64_t global_ctrl = read_msr(MSR_IA32_PERF_GLOBAL_CTRL); + uint64_t global_ctrl = read_msr(MSR_IA32_PERF_GLOBAL_CTRL); global_ctrl |= ((uint64_t)7 << 32) | 15; write_msr(MSR_IA32_PERF_GLOBAL_CTRL, global_ctrl); - + for (int i=0; i= end) { write_msr(CORE_X86_MSR_PERF_CTL + (2*i), 0); continue; } - + struct pfc_config config = pfc_configs[start+i]; - - uint64_t perf_ctl = 0; + + uint64_t perf_ctl = 0; perf_ctl |= ((config.evt_num) & 0xF00) << 24; perf_ctl |= (config.evt_num) & 0xFF; perf_ctl |= ((config.umask) & 0xFF) << 8; @@ -324,8 +327,8 @@ void configure_perf_ctrs_programmable(int start, int end, unsigned int usr, unsi perf_ctl |= (1ULL << 22); perf_ctl |= (config.edge << 18); perf_ctl |= (os << 17); - perf_ctl |= (usr << 16); - + perf_ctl |= (usr << 16); + write_msr(CORE_X86_MSR_PERF_CTL + (2*i), perf_ctl); } } @@ -334,7 +337,7 @@ void configure_perf_ctrs_programmable(int start, int end, unsigned int usr, unsi void create_runtime_code(char* measurement_template, long local_unroll_count, long local_loop_count) { int templateI = 0; int rci = 0; - + while (!starts_with_magic_bytes(&measurement_template[templateI], MAGIC_BYTES_TEMPLATE_END)) { if (starts_with_magic_bytes(&measurement_template[templateI], MAGIC_BYTES_INIT)) { templateI += 8; @@ -342,7 +345,7 @@ void create_runtime_code(char* measurement_template, long local_unroll_count, lo rci += code_init_length; } else if (starts_with_magic_bytes(&measurement_template[templateI], MAGIC_BYTES_CODE)) { templateI += 8; - + if (local_loop_count == 0) { for (long i=0; i=0)?ri:0; - for (int c=0; c