Last active
August 29, 2015 14:14
-
-
Save filipevarjao/91bcf6860c5b7b3c54c2 to your computer and use it in GitHub Desktop.
rapl_read
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Read the RAPL registers on a sandybridge-ep machine */ | |
| /* Code based on Intel RAPL driver by Zhang Rui <rui.zhang@intel.com> */ | |
| /* */ | |
| /* The /dev/cpu/??/msr driver must be enabled and permissions set */ | |
| /* to allow read access for this to work. */ | |
| /* */ | |
| /* Code to properly get this info from Linux through a real device */ | |
| /* driver and the perf tool should be available as of Linux 3.14 */ | |
| /* Compile with: gcc -O2 -Wall -o rapl-read rapl-read.c -lm */ | |
| /* */ | |
| /* Vince Weaver -- vincent.weaver @ maine.edu -- 29 November 2013 */ | |
| /* */ | |
| /* Additional contributions by: */ | |
| /* Romain Dolbeau -- romain @ dolbeau.org */ | |
| /* http://web.eece.maine.edu/~vweaver/projects/rapl/rapl-read.c */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #include <errno.h> | |
| #include <inttypes.h> | |
| #include <unistd.h> | |
| #include <math.h> | |
| #include <string.h> | |
| #define MSR_RAPL_POWER_UNIT 0x606 | |
| /* | |
| * Platform specific RAPL Domains. | |
| * Note that PP1 RAPL Domain is supported on 062A only | |
| * And DRAM RAPL Domain is supported on 062D only | |
| */ | |
| /* Package RAPL Domain */ | |
| #define MSR_PKG_RAPL_POWER_LIMIT 0x610 | |
| #define MSR_PKG_ENERGY_STATUS 0x611 | |
| #define MSR_PKG_PERF_STATUS 0x613 | |
| #define MSR_PKG_POWER_INFO 0x614 | |
| /* PP0 RAPL Domain */ | |
| #define MSR_PP0_POWER_LIMIT 0x638 | |
| #define MSR_PP0_ENERGY_STATUS 0x639 | |
| #define MSR_PP0_POLICY 0x63A | |
| #define MSR_PP0_PERF_STATUS 0x63B | |
| /* PP1 RAPL Domain, may reflect to uncore devices */ | |
| #define MSR_PP1_POWER_LIMIT 0x640 | |
| #define MSR_PP1_ENERGY_STATUS 0x641 | |
| #define MSR_PP1_POLICY 0x642 | |
| /* DRAM RAPL Domain */ | |
| #define MSR_DRAM_POWER_LIMIT 0x618 | |
| #define MSR_DRAM_ENERGY_STATUS 0x619 | |
| #define MSR_DRAM_PERF_STATUS 0x61B | |
| #define MSR_DRAM_POWER_INFO 0x61C | |
| /* RAPL UNIT BITMASK */ | |
| #define POWER_UNIT_OFFSET 0 | |
| #define POWER_UNIT_MASK 0x0F | |
| #define ENERGY_UNIT_OFFSET 0x08 | |
| #define ENERGY_UNIT_MASK 0x1F00 | |
| #define TIME_UNIT_OFFSET 0x10 | |
| #define TIME_UNIT_MASK 0xF000 | |
| int open_msr(int core) { | |
| char msr_filename[BUFSIZ]; | |
| int fd; | |
| sprintf(msr_filename, "/dev/cpu/%d/msr", core); | |
| fd = open(msr_filename, O_RDONLY); | |
| if ( fd < 0 ) { | |
| if ( errno == ENXIO ) { | |
| fprintf(stderr, "rdmsr: No CPU %d\n", core); | |
| exit(2); | |
| } else if ( errno == EIO ) { | |
| fprintf(stderr, "rdmsr: CPU %d doesn't support MSRs\n", core); | |
| exit(3); | |
| } else { | |
| perror("rdmsr:open"); | |
| fprintf(stderr,"Trying to open %s\n",msr_filename); | |
| exit(127); | |
| } | |
| } | |
| return fd; | |
| } | |
| long long read_msr(int fd, int which) { | |
| uint64_t data; | |
| if ( pread(fd, &data, sizeof data, which) != sizeof data ) { | |
| perror("rdmsr:pread"); | |
| exit(127); | |
| } | |
| return (long long)data; | |
| } | |
| #define CPU_SANDYBRIDGE 42 | |
| #define CPU_SANDYBRIDGE_EP 45 | |
| #define CPU_IVYBRIDGE 58 | |
| #define CPU_IVYBRIDGE_EP 62 | |
| #define CPU_HASWELL 60 | |
| int detect_cpu(void) { | |
| FILE *fff; | |
| int family,model=-1; | |
| char buffer[BUFSIZ],*result; | |
| char vendor[BUFSIZ]; | |
| fff=fopen("/proc/cpuinfo","r"); | |
| if (fff==NULL) return -1; | |
| while(1) { | |
| result=fgets(buffer,BUFSIZ,fff); | |
| if (result==NULL) break; | |
| if (!strncmp(result,"vendor_id",8)) { | |
| sscanf(result,"%*s%*s%s",vendor); | |
| if (strncmp(vendor,"GenuineIntel",12)) { | |
| printf("%s not an Intel chip\n",vendor); | |
| return -1; | |
| } | |
| } | |
| if (!strncmp(result,"cpu family",10)) { | |
| sscanf(result,"%*s%*s%*s%d",&family); | |
| if (family!=6) { | |
| printf("Wrong CPU family %d\n",family); | |
| return -1; | |
| } | |
| } | |
| if (!strncmp(result,"model",5)) { | |
| sscanf(result,"%*s%*s%d",&model); | |
| } | |
| } | |
| fclose(fff); | |
| switch(model) { | |
| case CPU_SANDYBRIDGE: | |
| printf("Found Sandybridge CPU\n"); | |
| break; | |
| case CPU_SANDYBRIDGE_EP: | |
| printf("Found Sandybridge-EP CPU\n"); | |
| break; | |
| case CPU_IVYBRIDGE: | |
| printf("Found Ivybridge CPU\n"); | |
| break; | |
| case CPU_IVYBRIDGE_EP: | |
| printf("Found Ivybridge-EP CPU\n"); | |
| break; | |
| case CPU_HASWELL: | |
| printf("Found Haswell CPU\n"); | |
| break; | |
| default: printf("Unsupported model %d\n",model); | |
| model=-1; | |
| break; | |
| } | |
| return model; | |
| } | |
| int main(int argc, char **argv) { | |
| int fd; | |
| int core=0; | |
| long long result; | |
| double power_units,energy_units,time_units; | |
| double package_before,package_after; | |
| double pp0_before,pp0_after; | |
| double pp1_before=0.0,pp1_after; | |
| double dram_before=0.0,dram_after; | |
| double thermal_spec_power,minimum_power,maximum_power,time_window; | |
| int cpu_model; | |
| int c; | |
| printf("\n"); | |
| opterr=0; | |
| while ((c = getopt (argc, argv, "c:")) != -1) { | |
| switch (c) | |
| { | |
| case 'c': | |
| core = atoi(optarg); | |
| break; | |
| default: | |
| exit(-1); | |
| } | |
| } | |
| cpu_model=detect_cpu(); | |
| if (cpu_model<0) { | |
| printf("Unsupported CPU type\n"); | |
| return -1; | |
| } | |
| printf("Checking core #%d\n",core); | |
| fd=open_msr(core); | |
| /* Calculate the units used */ | |
| result=read_msr(fd,MSR_RAPL_POWER_UNIT); | |
| power_units=pow(0.5,(double)(result&0xf)); | |
| energy_units=pow(0.5,(double)((result>>8)&0x1f)); | |
| time_units=pow(0.5,(double)((result>>16)&0xf)); | |
| printf("Power units = %.3fW\n",power_units); | |
| printf("Energy units = %.8fJ\n",energy_units); | |
| printf("Time units = %.8fs\n",time_units); | |
| printf("\n"); | |
| /* Show package power info */ | |
| result=read_msr(fd,MSR_PKG_POWER_INFO); | |
| thermal_spec_power=power_units*(double)(result&0x7fff); | |
| printf("Package thermal spec: %.3fW\n",thermal_spec_power); | |
| minimum_power=power_units*(double)((result>>16)&0x7fff); | |
| printf("Package minimum power: %.3fW\n",minimum_power); | |
| maximum_power=power_units*(double)((result>>32)&0x7fff); | |
| printf("Package maximum power: %.3fW\n",maximum_power); | |
| time_window=time_units*(double)((result>>48)&0x7fff); | |
| printf("Package maximum time window: %.6fs\n",time_window); | |
| /* Show package power limit */ | |
| result=read_msr(fd,MSR_PKG_RAPL_POWER_LIMIT); | |
| printf("Package power limits are %s\n", (result >> 63) ? "locked" : "unlocked"); | |
| double pkg_power_limit_1 = power_units*(double)((result>>0)&0x7FFF); | |
| double pkg_time_window_1 = time_units*(double)((result>>17)&0x007F); | |
| printf("Package power limit #1: %.3fW for %.6fs (%s, %s)\n", pkg_power_limit_1, pkg_time_window_1, | |
| (result & (1LL<<15)) ? "enabled" : "disabled", | |
| (result & (1LL<<16)) ? "clamped" : "not_clamped"); | |
| double pkg_power_limit_2 = power_units*(double)((result>>32)&0x7FFF); | |
| double pkg_time_window_2 = time_units*(double)((result>>49)&0x007F); | |
| printf("Package power limit #2: %.3fW for %.6fs (%s, %s)\n", pkg_power_limit_2, pkg_time_window_2, | |
| (result & (1LL<<47)) ? "enabled" : "disabled", | |
| (result & (1LL<<48)) ? "clamped" : "not_clamped"); | |
| printf("\n"); | |
| /* result=read_msr(fd,MSR_RAPL_POWER_UNIT); */ | |
| result=read_msr(fd,MSR_PKG_ENERGY_STATUS); | |
| package_before=(double)result*energy_units; | |
| printf("Package energy before: %.6fJ\n",package_before); | |
| /* only available on *Bridge-EP */ | |
| if ((cpu_model==CPU_SANDYBRIDGE_EP) || (cpu_model==CPU_IVYBRIDGE_EP)) | |
| { | |
| result=read_msr(fd,MSR_PKG_PERF_STATUS); | |
| double acc_pkg_throttled_time=(double)result*time_units; | |
| printf("Accumulated Package Throttled Time : %.6fs\n",acc_pkg_throttled_time); | |
| } | |
| result=read_msr(fd,MSR_PP0_ENERGY_STATUS); | |
| pp0_before=(double)result*energy_units; | |
| printf("PowerPlane0 (core) for core %d energy before: %.6fJ\n",core,pp0_before); | |
| result=read_msr(fd,MSR_PP0_POLICY); | |
| int pp0_policy=(int)result&0x001f; | |
| printf("PowerPlane0 (core) for core %d policy: %d\n",core,pp0_policy); | |
| /* only available on *Bridge-EP */ | |
| if ((cpu_model==CPU_SANDYBRIDGE_EP) || (cpu_model==CPU_IVYBRIDGE_EP)) | |
| { | |
| result=read_msr(fd,MSR_PP0_PERF_STATUS); | |
| double acc_pp0_throttled_time=(double)result*time_units; | |
| printf("PowerPlane0 (core) Accumulated Throttled Time : %.6fs\n",acc_pp0_throttled_time); | |
| } | |
| /* not available on *Bridge-EP */ | |
| if ((cpu_model==CPU_SANDYBRIDGE) || (cpu_model==CPU_IVYBRIDGE) || | |
| (cpu_model==CPU_HASWELL)) { | |
| result=read_msr(fd,MSR_PP1_ENERGY_STATUS); | |
| pp1_before=(double)result*energy_units; | |
| printf("PowerPlane1 (on-core GPU if avail) before: %.6fJ\n",pp1_before); | |
| result=read_msr(fd,MSR_PP1_POLICY); | |
| int pp1_policy=(int)result&0x001f; | |
| printf("PowerPlane1 (on-core GPU if avail) %d policy: %d\n",core,pp1_policy); | |
| } | |
| /* Despite documentation saying otherwise, it looks like */ | |
| /* You can get DRAM readings on regular Haswell */ | |
| if ((cpu_model==CPU_SANDYBRIDGE_EP) || (cpu_model==CPU_IVYBRIDGE_EP) || | |
| (cpu_model==CPU_HASWELL)) { | |
| result=read_msr(fd,MSR_DRAM_ENERGY_STATUS); | |
| dram_before=(double)result*energy_units; | |
| printf("DRAM energy before: %.6fJ\n",dram_before); | |
| } | |
| printf("\nSleeping 1 second\n\n"); | |
| sleep(1); | |
| result=read_msr(fd,MSR_PKG_ENERGY_STATUS); | |
| package_after=(double)result*energy_units; | |
| printf("Package energy after: %.6f (%.6fJ consumed)\n", | |
| package_after,package_after-package_before); | |
| result=read_msr(fd,MSR_PP0_ENERGY_STATUS); | |
| pp0_after=(double)result*energy_units; | |
| printf("PowerPlane0 (core) for core %d energy after: %.6f (%.6fJ consumed)\n", | |
| core,pp0_after,pp0_after-pp0_before); | |
| /* not available on SandyBridge-EP */ | |
| if ((cpu_model==CPU_SANDYBRIDGE) || (cpu_model==CPU_IVYBRIDGE) || | |
| (cpu_model==CPU_HASWELL)) { | |
| result=read_msr(fd,MSR_PP1_ENERGY_STATUS); | |
| pp1_after=(double)result*energy_units; | |
| printf("PowerPlane1 (on-core GPU if avail) after: %.6f (%.6fJ consumed)\n", | |
| pp1_after,pp1_after-pp1_before); | |
| } | |
| if ((cpu_model==CPU_SANDYBRIDGE_EP) || (cpu_model==CPU_IVYBRIDGE_EP) || | |
| (cpu_model==CPU_HASWELL)) { | |
| result=read_msr(fd,MSR_DRAM_ENERGY_STATUS); | |
| dram_after=(double)result*energy_units; | |
| printf("DRAM energy after: %.6f (%.6fJ consumed)\n", | |
| dram_after,dram_after-dram_before); | |
| } | |
| printf("\n"); | |
| printf("Note: the energy measurements can overflow in 60s or so\n"); | |
| printf(" so try to sample the counters more often than that.\n\n"); | |
| close(fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment