/// @brief Allocate space for batch arrays. /// /// @param [out] batchsel Storage for batch operations. /// /// @param [in] batchnum libmsr_data_type_e data type of batch operation. /// /// @param [out] opssize Size of specific set of batch operations. /// /// @return 0 if successful, else NULL pointer as a result of libmsr_calloc(), /// libmsr_malloc(), or libmsr_realloc(). static int batch_storage(struct msr_batch_array **batchsel, const int batchnum, unsigned **opssize) { static struct msr_batch_array *batch = NULL; static unsigned arrsize = 1; static unsigned *size = NULL; int i; if (batch == NULL) { #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: initializing batch ops\n"); #endif arrsize = (batchnum + 1 > arrsize ? batchnum + 1 : arrsize); size = (unsigned *) libmsr_calloc(arrsize, sizeof(unsigned)); batch = (struct msr_batch_array *) libmsr_calloc(arrsize, sizeof(struct msr_batch_array)); for (i = 0; i < arrsize; i++) { size[i] = 0; batch[i].ops = NULL; batch[i].numops = 0; } } if (batchnum + 1 > arrsize) { #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: reallocating array of batches for batch %d\n", batchnum); #endif unsigned oldsize = arrsize; arrsize = batchnum + 1; batch = (struct msr_batch_array *) libmsr_realloc(batch, arrsize * sizeof(struct msr_batch_array)); size = (unsigned *) libmsr_realloc(size, arrsize * sizeof(unsigned)); for (; oldsize < arrsize; oldsize++) { batch[oldsize].ops = NULL; batch[oldsize].numops = 0; size[oldsize] = 0; } } if (batchsel == NULL) { libmsr_error_handler("batch_storage(): Loading uninitialized batch", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); } *batchsel = &batch[batchnum]; if (opssize != NULL) { *opssize = &size[batchnum]; } return 0; }
int allocate_batch(int batchnum, size_t bsize) { unsigned *size = NULL; struct msr_batch_array *batch = NULL; int i; #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: allocating batch %d\n", batchnum); #endif if (batch_storage(&batch, batchnum, &size)) { return -1; } #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: batch %d is at %p\n", batchnum, batch); #endif *size = bsize; if (batch->ops != NULL) { libmsr_error_handler("allocate_batch(): Conflicting batch pointers", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); } #ifdef MEMHDLR_DEBUG fprintf(stderr, "MEMHDLR: size of batch %d is %d\n", batchnum, *size); #endif batch->ops = (struct msr_batch_op *) libmsr_calloc(*size, sizeof(struct msr_batch_op)); for (i = batch->numops; i < *size; i++) { batch->ops[i].err = 0; } return 0; }
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); } }
/// @brief Allocate RAPL data for batch operations. /// /// @param [in] rapl_flags Platform-specific bit flags indicating availability /// of RAPL MSRs. /// /// @param [in] rapl Measurements of energy, time, and power data from a given /// RAPL power domain. static void create_rapl_data_batch(uint64_t *rapl_flags, struct rapl_data *rapl) { uint64_t sockets = num_sockets(); allocate_batch(RAPL_DATA, rapl_data_batch_size(rapl_flags) * sockets); if (*rapl_flags & PKG_ENERGY_STATUS) { rapl->pkg_bits = (uint64_t **) libmsr_calloc(sockets, sizeof(uint64_t *)); rapl->pkg_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->old_pkg_bits = (uint64_t *) libmsr_calloc(sockets, sizeof(uint64_t)); rapl->old_pkg_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->pkg_delta_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->pkg_watts = (double *) libmsr_calloc(sockets, sizeof(double)); load_socket_batch(MSR_PKG_ENERGY_STATUS, rapl->pkg_bits, RAPL_DATA); } if (*rapl_flags & PKG_PERF_STATUS) { rapl->pkg_perf_count = (uint64_t **) libmsr_calloc(sockets, sizeof(uint64_t)); load_socket_batch(MSR_PKG_PERF_STATUS, rapl->pkg_perf_count, RAPL_DATA); } if (*rapl_flags & DRAM_ENERGY_STATUS) { rapl->dram_bits = (uint64_t **) libmsr_calloc(sockets, sizeof(uint64_t *)); rapl->old_dram_bits = (uint64_t *) libmsr_calloc(sockets, sizeof(uint64_t)); rapl->dram_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->old_dram_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->dram_delta_joules = (double *) libmsr_calloc(sockets, sizeof(double)); rapl->dram_watts = (double *) libmsr_calloc(sockets, sizeof(double)); load_socket_batch(MSR_DRAM_ENERGY_STATUS, rapl->dram_bits, RAPL_DATA); } if (*rapl_flags & DRAM_PERF_STATUS) { rapl->dram_perf_count = (uint64_t **) libmsr_calloc(sockets, sizeof(uint64_t)); load_socket_batch(MSR_DRAM_PERF_STATUS, rapl->dram_perf_count, RAPL_DATA); } }
/// @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 get_rapl_power_unit(struct rapl_units *ru) { static int init = 0; static uint64_t sockets = 0; static uint64_t **val = NULL; int i; sockets = num_sockets(); if (!init) { init = 1; val = (uint64_t **) libmsr_calloc(sockets, sizeof(uint64_t *)); allocate_batch(RAPL_UNIT, sockets); load_socket_batch(MSR_RAPL_POWER_UNIT, val, RAPL_UNIT); } read_batch(RAPL_UNIT); /* Initialize the units used for each socket. */ for (i = 0; i < sockets; i++) { // See figure 14-16 for bit fields. // 1 1 1 1 1 // 9 6 5 2 1 8 7 4 3 0 // // 1010 0001 0000 0000 0011 // // A 1 0 0 3 //ru[i].msr_rapl_power_unit = 0xA1003; ru[i].msr_rapl_power_unit = *val[i]; /* Default is 1010b or 976 microseconds. */ /* Storing (1/(2^TU))^-1 for maximum precision. */ ru[i].seconds = (double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 19, 16))); /* Default is 10000b or 15.3 microjoules. */ /* Storing (1/(2^ESU))^-1 for maximum precision. */ ru[i].joules = (double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 12, 8))); #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: joules unit is %f register has %lx\n", ru[i].joules, ru[i].msr_rapl_power_unit); #endif /* Default is 0011b or 1/8 Watts. */ ru[i].watts = ((1.0)/((double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 3, 0))))); #ifdef LIBMSR_DEBUG fprintf(stdout, "Pkg %d MSR_RAPL_POWER_UNIT\n", i); fprintf(stdout, "Raw: %f sec, %f J, %f watts\n", ru[i].seconds, ru[i].joules, ru[i].watts); fprintf(stdout, "Adjusted: %f sec, %f J, %f watts\n", 1/ru[i].seconds, 1/ru[i].joules, ru[i].watts); #endif } /* Check consistency between packages. */ uint64_t *tmp = (uint64_t *) libmsr_calloc(sockets, sizeof(uint64_t)); for (i = 0; i < sockets; i++) { read_msr_by_coord(i, 0, 0, MSR_RAPL_POWER_UNIT, tmp); double energy = (double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 12, 8))); double seconds = (double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 19, 16))); double power = ((1.0)/((double)(1 << (MASK_VAL(ru[i].msr_rapl_power_unit, 3, 0))))); if (energy != ru[i].joules || power != ru[i].watts || seconds != ru[i].seconds) { libmsr_error_handler("get_rapl_power_unit(): Inconsistent rapl power units across packages", LIBMSR_ERROR_RUNTIME, getenv("HOSTNAME"), __FILE__, __LINE__); } } }