void get_all_info(int package, struct rapl_state_s *s){ if( s==NULL ){ s = &no_caller_rapl_state; } get_rapl_power_unit( package, &(s->power_unit[package]) ); get_power_info( package, PKG_DOMAIN, &(s->power_info[package][PKG_DOMAIN]), &(s->power_unit[package]) ); #ifdef ARCH_062D get_power_info( package, DRAM_DOMAIN, &(s->power_info[package][DRAM_DOMAIN]), &(s->power_unit[package]) ); #endif }
void dump_rapl_power_unit(FILE *writedest) { int socket; struct rapl_units *r; static uint64_t sockets = 0; sockets = num_sockets(); r = (struct rapl_units *) libmsr_calloc(sockets, sizeof(struct rapl_units)); get_rapl_power_unit(r); for (socket = 0; socket < sockets; socket++) { fprintf(writedest, "Socket: %d\n", socket); fprintf(writedest, " RAW power unit (W) = %8.4lf energy unit (J^-1) = %8.4lf time unit (s^-1) = %8.4lf\n", r[socket].watts, r[socket].joules, r[socket].seconds); fprintf(writedest, " ADJ power unit (W) = %f energy unit (J) = %f time unit (s) = %f\n", r[socket].watts, 1/r[socket].joules, 1/r[socket].seconds); } }
void rapl_init(struct rapl_state_s *s, FILE *f, int print_header){ int socket; init_msr(); //parse_opts( argc, argv ); //fprintf(stderr, "%s::%d returned from parse_opts\n", __FILE__, __LINE__); s->f = f; if(print_header) print_rapl_state_header(s); for(socket=0; socket<NUM_PACKAGES; socket++){ get_rapl_power_unit( socket, &(s->power_unit[socket]) ); get_power_info( socket, PKG_DOMAIN, &(s->power_info[socket][PKG_DOMAIN]), &(s->power_unit[socket]) ); #ifdef ARCH_062D get_power_info( socket, DRAM_DOMAIN, &(s->power_info[socket][DRAM_DOMAIN]), &(s->power_unit[socket]) ); #endif get_power_limit( socket, PKG_DOMAIN, &(s->power_limit[socket][PKG_DOMAIN]), &(s->power_unit[socket]) ); get_power_limit( socket, PP0_DOMAIN, &(s->power_limit[socket][PP0_DOMAIN]), &(s->power_unit[socket]) ); #ifdef ARCH_062D get_power_limit( socket, DRAM_DOMAIN, &(s->power_limit[socket][DRAM_DOMAIN]), &(s->power_unit[socket]) ); #endif get_energy_status( socket, PKG_DOMAIN, NULL, &(s->power_unit[socket]), &s->last_raw_joules[socket][PKG_DOMAIN]); get_energy_status( socket, PP0_DOMAIN, NULL, &(s->power_unit[socket]) , &s->last_raw_joules[socket][PP0_DOMAIN]); #ifdef ARCH_062D get_energy_status( socket, DRAM_DOMAIN, NULL, &(s->power_unit[socket]) , &s->last_raw_joules[socket][DRAM_DOMAIN]); #endif } gettimeofday( &(s->prev), NULL ); }
/// @brief Translate any user-desired values to the format expected in the MSRs /// and vice versa. /// /// @param [in] socket Unique socket/package identifier. /// /// @param [out] bits Raw bit field value. /// /// @param [out] units Human-readable value. /// /// @param [in] type libmsr_unit_conversions_e unit conversion identifier. /// /// @return 0 upon function completion or upon converting bits to Joules for /// DRAM RAPL power domain for 0x3F (Haswell) platform. static int translate(const unsigned socket, uint64_t *bits, double *units, int type) { static int init = 0; double logremainder = 0.0; static uint64_t sockets = 0; static uint64_t model = 0; static struct rapl_units *ru = NULL; uint64_t timeval_z = 0; uint64_t timeval_y = 0; #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: (translate) bits are at %p\n", bits); #endif if (sockets == 0) { sockets = num_sockets(); } if (model == 0) { cpuid_get_model(&model); } sockets_assert(&socket, __LINE__, __FILE__); if (!init) { init = 1; ru = (struct rapl_units *) libmsr_calloc(sockets, sizeof(struct rapl_units)); get_rapl_power_unit(ru); } switch(type) { case BITS_TO_WATTS: *units = (double)(*bits) * ru[socket].watts; break; case BITS_TO_JOULES_DRAM: if (model == 0x3F || model == 0x4F || model == 0x55) { *units = (double)(*bits) / STD_ENERGY_UNIT; #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: (translate_dram) %f is %f joules\n", (double)*bits, *units); #endif return 0; } /* No break statement, if not Haswell do standard stuff. */ case BITS_TO_JOULES: *units = (double)(*bits) / ru[socket].joules; break; case WATTS_TO_BITS: *bits = (uint64_t)((*units) / ru[socket].watts); break; case JOULES_TO_BITS: /// @todo Currently unused, but if it ever is used, we need a fix for Haswell. *bits = (uint64_t)((*units) * ru[socket].joules); break; case BITS_TO_SECONDS_STD: timeval_y = *bits & 0x1F; timeval_z = (*bits & 0x60) >> 5; /* Dividing by time unit because it's stored as (1/(2^TU))^-1. */ *units = ((1 + 0.25 * timeval_z) * pow(2.0,(double)timeval_y)) / ru[socket].seconds; // Temporary fix for haswell // if (model == 0x3F) // { // *units = *units * 2.5 + 15.0; // } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: timeval_z is %lx, timeval_y is %lx, units is %lf, bits is %lx\n", getenv("HOSTNAME"), __FILE__, __LINE__, timeval_z, timeval_y, *units, *bits); #endif break; case SECONDS_TO_BITS_STD: // Temporary fix for haswell // if (model == 0x3F) // { // *units = *units / 2.5 - 15; // } /* Store the whole number part of the log2. */ timeval_y = (uint64_t)log2(*units * ru[socket].seconds); /* Store the mantissa of the log2. */ logremainder = (double)log2(*units * ru[socket].seconds) - (double)timeval_y; timeval_z = 0; /* Based on the mantissa, choose the appropriate multiplier. */ if (logremainder > 0.15 && logremainder <= 0.45) { timeval_z = 1; } else if (logremainder > 0.45 && logremainder <= 0.7) { timeval_z = 2; } else if (logremainder > 0.7) { timeval_z = 3; } /* Store the bits in the Intel specified format. */ *bits = (uint64_t)(timeval_y | (timeval_z << 5)); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: timeval_z is %lx, timeval_y is %lx, units is %lf, bits is %lx, remainder is %lf\n", getenv("HOSTNAME"), __FILE__, __LINE__, timeval_z, timeval_y, *units, *bits, logremainder); #endif break; default: fprintf(stderr, "%s:%d Unknown value %d. This is bad.\n", __FILE__, __LINE__, type); *bits = -1; *units= -1.0; break; } return 0; }
void msSample(const char * const filename, int log){ struct power_unit_s units; struct power_info_s info[NUM_DOMAINS]; double joules[NUM_DOMAINS]; uint64_t last_raw_joules[NUM_DOMAINS], last_raw_joules_tmp[NUM_DOMAINS]; struct timeval now; uint64_t tsc; double time = 0; #ifdef ARCH_062D int i; #endif double tsc_rate; FILE *rateFile = fopen("/tmp/tsc_rate", "r"); //! @todo measure/read tsc rate if(!rateFile && errno == ENOENT){ tsc_rate = measure_tsc(); rateFile = fopen("/tmp/tsc_rate", "w"); fprintf(rateFile, "%lf\n", tsc_rate); }else if(rateFile){ // get rate from file fscanf(rateFile, "%lf", &tsc_rate); } else { perror("error opening /tmp/tsc_rate"); exit(1); } fclose(rateFile); fprintf(stderr, "tsc rate: %lf\n", tsc_rate); FILE *logFile = 0; if(log){ logFile = fopen(filename, "w"); assert(logFile); } if(log){ fprintf(logFile, "timestamp\tpkg_J\tpp0_J\t" #ifdef ARCH_062A "pp1_J" #endif #ifdef ARCH_062D "dram_J" #endif "\n"); fprintf(logFile, "%lf\t%15.10lf\t%15.10lf" "\t%15.10lf" "\n", 0.0, 0.0, 0.0 #ifdef ARCH_062A ,0.0 #endif #ifdef ARCH_062D ,0.0 #endif ); } sigset_t s; sigemptyset(&s); sigaddset(&s, SIGALRM); struct sigaction sa = {.sa_handler= &handler, .sa_mask = s, .sa_flags = 0, .sa_restorer = 0}; int status = sigaction(SIGALRM, &sa, 0); timer_t timerID; status = timer_create(CLOCK_MONOTONIC, 0, &timerID); struct itimerspec ts = {{0, 100000}, // .1ms {0, 100000}}; msr_debug=1; get_rapl_power_unit(0, &units); get_power_info(0, PKG_DOMAIN, &info[PKG_DOMAIN],&units); msr_debug = 0; get_energy_status(0, PKG_DOMAIN, &joules[PKG_DOMAIN], &units, &last_raw_joules[PKG_DOMAIN]); get_energy_status(0, PKG_DOMAIN, &joules[PKG_DOMAIN], &units, &last_raw_joules[PKG_DOMAIN]); // synchronize with an update while(!joules[PKG_DOMAIN]){ usleep(10); get_energy_status(0, PKG_DOMAIN, &joules[PKG_DOMAIN], &units, &last_raw_joules[PKG_DOMAIN]); } gettimeofday(&now, NULL); tsc = rdtsc(); status = timer_settime(timerID, 0, &ts, 0); get_energy_status(0, PKG_DOMAIN, &joules[PKG_DOMAIN], &units, &last_raw_joules[PKG_DOMAIN]); get_energy_status(0, PP0_DOMAIN, &joules[PP0_DOMAIN], &units, &last_raw_joules[PP0_DOMAIN]); #ifdef ARCH_062D get_power_info(0, DRAM_DOMAIN, &info[DRAM_DOMAIN], &units); #endif #ifdef ARCH_062A get_energy_status(0, PP1_DOMAIN, &joules[PP1_DOMAIN], &units, &last_raw_joules[PP1_DOMAIN]); #endif double PKG_max_watts = 0, PP0_max_watts = 0; double PKG_total_joules = 0, PP0_total_joules = 0, delta; uint64_t lastPrint = 0, lastNonzero = tsc; int glitch = 0; while(1){ sigwaitinfo(&s, 0); // timer will wake us up tsc = rdtsc(); get_raw_energy_status(0, PKG_DOMAIN, &last_raw_joules_tmp[PKG_DOMAIN]); get_raw_energy_status(0, PP0_DOMAIN, &last_raw_joules_tmp[PP0_DOMAIN]); #ifdef ARCH_062A get_raw_energy_status(0, PP1_DOMAIN, &last_raw_joules_tmp[PP1_DOMAIN]); #endif #ifdef ARCH_062D get_raw_energy_status(0, DRAM_DOMAIN, &last_raw_joules_tmp[DRAM_DOMAIN]); #endif //! @todo freq //read_aperf_mperf(0, &aperf, &mperf); // wait for an update //! @todo this needs fixing if(last_raw_joules_tmp[PKG_DOMAIN] == last_raw_joules[PKG_DOMAIN]){ continue; } double nzDelta = tsc_delta(&lastNonzero, &tsc, &tsc_rate); if(nzDelta < .001){ // wait at least 1ms /*! @todo flag these in the log. Updates seem to come in two time bases, ~1 KHz and ~100 Hz. I'm guessing they correspond to distinct segments of the chip. If I sample frequently enough, I can separate the updates by frequency. */ if(!glitch){ /* fprintf(logFile, "#%lf\t%lf\tglitch \n", time + nzDelta, nzDelta ); */ glitch = 1; } last_raw_joules_tmp[PKG_DOMAIN] = last_raw_joules[PKG_DOMAIN]; continue; } glitch = 0; lastNonzero = tsc; // convert raw joules joules[PKG_DOMAIN] = convert_raw_joules_delta(&last_raw_joules[PKG_DOMAIN], &last_raw_joules_tmp[PKG_DOMAIN], &units); joules[PP0_DOMAIN] = convert_raw_joules_delta(&last_raw_joules[PP0_DOMAIN], &last_raw_joules_tmp[PP0_DOMAIN], &units); #ifdef ARCH_062A joules[PP1_DOMAIN] = convert_raw_joules_delta(&last_raw_joules[PP1_DOMAIN], &last_raw_joules_tmp[PP1_DOMAIN], &units); #endif #ifdef ARCH_062D joules[DRAM_DOMAIN] = convert_raw_joules_delta(&last_raw_joules[DRAM_DOMAIN], &last_raw_joules_tmp[DRAM_DOMAIN], &units); #endif last_raw_joules[PKG_DOMAIN] = last_raw_joules_tmp[PKG_DOMAIN]; last_raw_joules[PP0_DOMAIN] = last_raw_joules_tmp[PP0_DOMAIN]; #ifdef ARCH_062A last_raw_joules[PP1_DOMAIN] = last_raw_joules_tmp[PP1_DOMAIN]; #endif #ifdef ARCH_062D last_raw_joules[DRAM_DOMAIN] = last_raw_joules_tmp[DRAM_DOMAIN]; #endif time += nzDelta; // don't log the suspect readings // && joules[PKG_DOMAIN] < info[PKG_DOMAIN].thermal_spec_power_watts if(log){ fprintf(logFile, "%lf\t%15.10lf\t%15.10lf" "\t%15.10lf" "\n", time, joules[PKG_DOMAIN], joules[PP0_DOMAIN] #ifdef ARCH_062A ,joules[PP1_DOMAIN] #endif #ifdef ARCH_062D ,joules[DRAM_DOMAIN] #endif ); } PKG_max_watts = max(PKG_max_watts, joules[PKG_DOMAIN]/nzDelta); PP0_max_watts = max(PP0_max_watts, joules[PP0_DOMAIN]/nzDelta); PKG_total_joules += joules[PKG_DOMAIN]; PP0_total_joules += joules[PP0_DOMAIN]; delta = tsc_delta(&lastPrint, &tsc, &tsc_rate); if(delta > 1){ fprintf(stderr, "max 1ms-power, average power in last second: " "PKG: %10lf, %10lf, PP0: %10lf, %10lf\n", PKG_max_watts, PKG_total_joules / delta, PP0_max_watts, PP0_total_joules / delta); lastPrint = tsc; PKG_max_watts = 0; PP0_max_watts = 0; PKG_total_joules = 0; PP0_total_joules = 0; } } // while(1) //! @todo calculate average power return; }