int write_msr_by_idx_and_verify(int dev_idx, off_t msr, uint64_t val) { int rc; uint64_t test = 0; int *fileDescriptor = NULL; fileDescriptor = core_fd(dev_idx); if (fileDescriptor == NULL) { return -1; } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (write_msr_by_idx) msr=%lu (0x%lx)\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, msr, msr); #endif rc = pwrite(*fileDescriptor, &val, (size_t)sizeof(uint64_t), msr); if (rc != sizeof(uint64_t)) { libmsr_error_handler("write_msr_by_idx_and_verify(): Pwrite failed", LIBMSR_ERROR_MSR_WRITE, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } if (!pread(*fileDescriptor, (void *) &test, (size_t) sizeof(uint64_t), msr)) { libmsr_error_handler("write_msr_by_idx_and_verify(): Verification of write failed", LIBMSR_ERROR_MSR_WRITE, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } if (val != test) { libmsr_error_handler("write_msr_by_idx_and_verify(): Write unsuccessful", LIBMSR_ERROR_MSR_WRITE, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } return 0; }
/// @brief Translates human-readable power settings into raw 64-bit format. /// /// @param [in] socket Unique socket/package identifier. /// /// @param [out] limit Data for desired power limit. /// /// @param [in] offset Power limit 1 (lower) or power limit 2 (upper) /// identifier. Power limit 2 only applies to package domain. /// /// @return 0 if successful, else -1 if rapl_storage() fails or if the Watts /// value or seconds value overflow the bit field. static int calc_rapl_bits(const unsigned socket, struct rapl_limit *limit, const unsigned offset) { uint64_t watts_bits = 0; uint64_t seconds_bits = 0; sockets_assert(&socket, __LINE__, __FILE__); watts_bits = MASK_VAL(limit->bits, 14+offset, 0+offset); seconds_bits = MASK_VAL(limit->bits, 23+offset, 17+offset); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (calc_rapl_bits)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif /* * We have been given watts and seconds and need to translate these into * bit values. * If offset is >= 32 (we are setting the 2nd pkg limit), we don't need time * conversion. */ if (offset >= 32) { seconds_bits = (uint64_t)limit->seconds; // unit is milliseconds //translate(socket, &seconds_bits, &limit->seconds, SECONDS_TO_BITS_STD); } else { translate(socket, &seconds_bits, &limit->seconds, SECONDS_TO_BITS_STD); } /* There is only 1 translation for watts (so far). */ translate(socket, &watts_bits, &limit->watts, WATTS_TO_BITS); #ifdef LIBMSR_DEBUG fprintf(stderr, "Converted %lf watts into %lx bits.\n", limit->watts, watts_bits); fprintf(stderr, "Converted %lf seconds into %lx bits.\n", limit->seconds, seconds_bits); #endif /* Check to make sure the watts value does not overflow the bit field. */ if (watts_bits & 0xFFFFFFFFFFFF8000) { libmsr_error_handler("calc_rapl_bits(): Translation from bits to values failed", LIBMSR_ERROR_INVAL, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } watts_bits <<= 0 + offset; /* Check to make sure the seconds value does not overflow the bit field. */ if (seconds_bits & 0xFFFFFFFFFFFFFF80) { libmsr_error_handler("calc_rapl_bits(): Seconds value is too large", LIBMSR_ERROR_INVAL, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } seconds_bits <<= 17 + offset; limit->bits |= watts_bits; limit->bits |= seconds_bits; #ifdef LIBMSR_DEBUG fprintf(stderr, "calculated rapl bits\n"); #endif return 0; }
int stat_module(char *filename, int *kerneltype, int *dev_idx) { struct stat statbuf; if (*kerneltype == 3) { if (stat(filename, &statbuf)) { fprintf(stderr, "Warning: <libmsr> Could not stat %s: stat_module(): %s: %s:%s::%d\n", filename, strerror(errno), getenv("HOSTNAME"), __FILE__, __LINE__); *kerneltype = 1; return -1; } if (!(statbuf.st_mode & S_IRUSR) || !(statbuf.st_mode & S_IWUSR)) { fprintf(stderr, "Warning: <libmsr> Incorrect permissions on msr_whitelist: stat_module(): %s:%s::%d\n", getenv("HOSTNAME"), __FILE__, __LINE__); *kerneltype = 1; return -1; } *kerneltype = 0; return 0; } if (stat(filename, &statbuf)) { if (*kerneltype) { libmsr_error_handler("stat_module(): Could not stat file", LIBMSR_ERROR_MSR_MODULE, getenv("HOSTNAME"), __FILE__, __LINE__); /* Could not find any msr module so exit. */ return -1; } /* Could not find msr_safe module so try the msr module. */ libmsr_error_handler("stat_module(): Could not stat file", LIBMSR_ERROR_MSR_MODULE, getenv("HOSTNAME"), __FILE__, __LINE__); *kerneltype = 1; /* Restart loading file descriptors for each device. */ *dev_idx = -1; return 0; } if (!(statbuf.st_mode & S_IRUSR) || !(statbuf.st_mode & S_IWUSR)) { libmsr_error_handler("stat_module(): Read/write permissions denied for file", LIBMSR_ERROR_MSR_MODULE, getenv("HOSTNAME"), __FILE__, __LINE__); *kerneltype = 1; *dev_idx = -1; if (kerneltype != NULL) { libmsr_error_handler("stat_module(): Could not find any valid MSR module with correct permissions", LIBMSR_ERROR_MSR_MODULE, getenv("HOSTNAME"), __FILE__, __LINE__); /* Could not find any msr module with RW permissions, so exit. */ return -1; } } return 0; }
int poll_rapl_data(void) { static struct rapl_data *rapl = NULL; #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (poll_rapl_data) socket=%lu\n", getenv("HOSTNAME"), __FILE__, __LINE__, num_sockets()); #endif if (rapl == NULL) { if (rapl_storage(&rapl, NULL)) { return -1; } } if (rapl == NULL) { libmsr_error_handler("poll_rapl_data(): RAPL init failed or has not yet been called", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } read_rapl_data(); delta_rapl_data(); return 0; }
int finalize_msr(void) { int dev_idx; int rc; int *fileDescriptor = NULL; uint64_t numDevs = num_devs(); #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: finalize_msr\n"); #endif /* Close the file descriptors. */ for (dev_idx = 0; dev_idx < numDevs; dev_idx++) { fileDescriptor = core_fd(dev_idx); if (fileDescriptor != NULL) { rc = close(*fileDescriptor); if (rc != 0) { libmsr_error_handler("finalize_msr(): Could not close file", LIBMSR_ERROR_MSR_CLOSE, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } else { *fileDescriptor = 0; } } } memhdlr_finalize(); return 0; }
/// @brief Create the human-readable power settings if the user-supplied bits. /// /// @param [in] socket Unique socket/package identifier. /// /// @param [out] limit Data for desired power limit. /// /// @param [in] offset Power limit 1 (lower) or power limit 2 (upper) /// identifier. Power limit 2 only applies to package domain. /// /// @return 0 if successful, else -1 if translate() failed. static int calc_rapl_from_bits(const unsigned socket, struct rapl_limit *limit, const unsigned offset) { uint64_t watts_bits = 0; uint64_t seconds_bits = 0; int ret = 0; sockets_assert(&socket, __LINE__, __FILE__); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (calc_rapl_from_bits)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif watts_bits = MASK_VAL(limit->bits, 14+offset, 0+offset); seconds_bits = MASK_VAL(limit->bits, 23+offset, 17+offset); // We have been given the bits to be written to the msr. // For sake of completeness, translate these into watts and seconds. ret = translate(socket, &watts_bits, &limit->watts, BITS_TO_WATTS); // If the offset is > 31 (we are writing the upper PKG limit), then no // translation needed if (offset < 32) { ret += translate(socket, &seconds_bits, &limit->seconds, BITS_TO_SECONDS_STD); } else { limit->seconds = seconds_bits; } if (ret < 0) { libmsr_error_handler("calc_rapl_from_bits(): Translation from bits to values failed", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); return ret; } return 0; }
int create_batch_op(off_t msr, uint64_t cpu, uint64_t **dest, const int batchnum) { struct msr_batch_array *batch = NULL; unsigned *size = NULL; #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: creating new batch operation\n"); #endif if (batch_storage(&batch, batchnum, &size)) { return -1; } #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: batch %d is at %p\n", batchnum, batch); #endif if (batch->numops > *size) { libmsr_error_handler("create_batch_op(): Batch is full, you likely used the wrong size", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } batch->numops++; batch->ops[batch->numops-1].msr = msr; batch->ops[batch->numops-1].cpu = (__u16) cpu; batch->ops[batch->numops-1].isrdmsr = (__u8) 1; batch->ops[batch->numops-1].err = 0; *dest = (uint64_t *) &batch->ops[batch->numops - 1].msrdata; #ifdef BATCH_DEBUG fprintf(stderr, "BATCH: destination of msr %lx on core %lx (at %p) is %p\n", msr, cpu, dest, &batch->ops[batch->numops - 1].msrdata); fprintf(stderr, "\tbatch numops is %d\n", batch->numops); #endif 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; }
int get_dram_rapl_limit(const unsigned socket, struct rapl_limit *limit) { static uint64_t *rapl_flags = NULL; sockets_assert(&socket, __LINE__, __FILE__); if (rapl_flags == NULL) { if (rapl_storage(NULL, &rapl_flags)) { return -1; } } /* Make sure the dram power limit register exists. */ if ((limit != NULL) && (*rapl_flags & DRAM_POWER_LIMIT)) { read_msr_by_coord(socket, 0, 0, MSR_DRAM_POWER_LIMIT, &(limit->bits)); calc_std_rapl_limit(socket, limit); } else if (limit != NULL) { libmsr_error_handler("get_dram_rapl_limit(): DRAM domain RAPL power limit not supported on this architecture", LIBMSR_ERROR_PLATFORM_NOT_SUPPORTED, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } return 0; }
/// @brief Retrieve mapping of CPU hardware threads in a single socket. /// /// @return 0 if successful, else -1 if can't open core_sibling_list file. static int find_cpu_top(void) { FILE *cpu0top, *cpu1top; char filename[FILENAME_SIZE]; int siblings0 = 0; int siblings1 = 0; snprintf(filename, FILENAME_SIZE, "/sys/devices/system/cpu/cpu0/topology/core_siblings_list"); cpu0top = fopen(filename, "r"); if (cpu0top == NULL) { libmsr_error_handler("find_cpu_top(): Could not open file", LIBMSR_ERROR_PLATFORM_ENV, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } snprintf(filename, FILENAME_SIZE, "/sys/devices/system/cpu/cpu1/topology/core_siblings_list"); cpu1top = fopen(filename, "r"); if (cpu1top == NULL) { libmsr_error_handler("find_cpu_top(): Could not open file", LIBMSR_ERROR_PLATFORM_ENV, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } fscanf(cpu0top, "%d", &siblings0); //fprintf(stdout, "q1%d\n", siblings0); fscanf(cpu1top, "%d", &siblings1); //fprintf(stdout, "q1%d\n", siblings1); if (siblings0 == siblings1) { /* Uses default cpu ordering scheme. */ CPU_DEV_VER = 1; } else { /* Uses even-odd cpu ordering scheme. */ CPU_DEV_VER = 0; } if (cpu0top != NULL) { fclose(cpu0top); } if (cpu1top != NULL) { fclose(cpu1top); } return 0; }
int get_rapl_power_info(const unsigned socket, struct rapl_power_info *info) { uint64_t val = 0; static uint64_t *rapl_flags = NULL; sockets_assert(&socket, __LINE__, __FILE__); if (rapl_flags == NULL) { if (rapl_storage(NULL, &rapl_flags)) { libmsr_error_handler("get_rapl_power_info(): Cannot load rapl_flags", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (get_rapl_power_info)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif if (*rapl_flags & PKG_POWER_INFO) { read_msr_by_coord(socket, 0, 0, MSR_PKG_POWER_INFO, &(info->msr_pkg_power_info)); val = MASK_VAL(info->msr_pkg_power_info, 54, 48); translate(socket, &val, &(info->pkg_max_window), BITS_TO_SECONDS_STD); val = MASK_VAL(info->msr_pkg_power_info, 46, 32); translate(socket, &val, &(info->pkg_max_power), BITS_TO_WATTS); val = MASK_VAL(info->msr_pkg_power_info, 30, 16); translate(socket, &val, &(info->pkg_min_power), BITS_TO_WATTS); val = MASK_VAL(info->msr_pkg_power_info, 14, 0); translate(socket, &val, &(info->pkg_therm_power), BITS_TO_WATTS); } if (*rapl_flags & DRAM_POWER_INFO) { read_msr_by_coord(socket, 0, 0, MSR_DRAM_POWER_INFO, &(info->msr_dram_power_info)); val = MASK_VAL(info->msr_dram_power_info, 54, 48); translate(socket, &val, &(info->dram_max_window), BITS_TO_SECONDS_STD); val = MASK_VAL(info->msr_dram_power_info, 46, 32); translate(socket, &val, &(info->dram_max_power), BITS_TO_WATTS); val = MASK_VAL(info->msr_dram_power_info, 30, 16); translate(socket, &val, &(info->dram_min_power), BITS_TO_WATTS); val = MASK_VAL(info->msr_dram_power_info, 14, 0); translate(socket, &val, &(info->dram_therm_power), BITS_TO_WATTS); } return 0; }
int cores_assert(const unsigned *core, const int location, const char *file) { static uint64_t coresPerSocket = 0; if (coresPerSocket < 1) { core_config(&coresPerSocket, NULL, NULL, NULL); } if (*core > coresPerSocket) { libmsr_error_handler("cores_assert(): Requested invalid core", LIBMSR_ERROR_PLATFORM_ENV, getenv("HOSTNAME"), __FILE__, location); return -1; } return 0; }
/// @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 sockets_assert(const unsigned *socket, const int location, const char *file) { static uint64_t sockets = 0; if (!sockets) { sockets = num_sockets(); } if (*socket > sockets) { libmsr_error_handler("sockets_assert(): Requested invalid socket", LIBMSR_ERROR_PLATFORM_ENV, getenv("HOSTNAME"), __FILE__, location); return -1; } return 0; }
int threads_assert(const unsigned *thread, const int location, const char *file) { static uint64_t threadsPerCore = 0; if (threadsPerCore < 1) { core_config(NULL, &threadsPerCore, NULL, NULL); } if (*thread > threadsPerCore) { libmsr_error_handler("threads_assert(): Requested invalid thread", LIBMSR_ERROR_PLATFORM_ENV, getenv("HOSTNAME"), __FILE__, location); return -1; } return 0; }
int print_available_rapl(void) { uint64_t *rapl_flags = NULL; if (rapl_storage(NULL, &rapl_flags)) { libmsr_error_handler("print_available_rapl(): Could not load RAPL data", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } if (*rapl_flags & POWER_UNIT) { fprintf(stdout, "MSR_RAPL_POWER_UNIT, 606h\n"); } if (*rapl_flags & PKG_POWER_LIMIT) { fprintf(stdout, "MSR_PKG_POWER_LIMIT, 610h\n"); } if (*rapl_flags & PKG_ENERGY_STATUS) { fprintf(stdout, "MSR_PKG_ENERGY_STATUS, 611h\n"); } if (*rapl_flags & PKG_PERF_STATUS) { fprintf(stdout, "MSR_PKG_PERF_STATUS, 613h\n"); } if (*rapl_flags & PKG_POWER_INFO) { fprintf(stdout, "MSR_PKG_POWER_INFO, 614h\n"); } if (*rapl_flags & DRAM_POWER_LIMIT) { fprintf(stdout, "MSR_DRAM_POWER_LIMIT, 618h\n"); } if (*rapl_flags & DRAM_ENERGY_STATUS) { fprintf(stdout, "MSR_DRAM_ENERGY_STATUS, 619h\n"); } if (*rapl_flags & DRAM_PERF_STATUS) { fprintf(stdout, "MSR_DRAM_PERF_STATUS, 61Bh\n"); } if (*rapl_flags & DRAM_POWER_INFO) { fprintf(stdout, "MSR_DRAM_POWER_INFO, 61Ch\n"); } return 0; }
int load_core_batch(off_t msr, uint64_t **val, int batchnum) { int dev_idx, val_idx; static uint64_t coresPerSocket = 0; static uint64_t threadsPerCore = 0; static uint64_t sockets = 0; static uint64_t coretotal = 0; if (val == NULL) { libmsr_error_handler("load_core_batch(): Given uninitialized array", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } if (coresPerSocket == 0 || threadsPerCore == 0) { core_config(&coresPerSocket, &threadsPerCore, &sockets, NULL); coretotal = sockets * coresPerSocket; } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (read_all_cores) msr=%lu (0x%lx)\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, msr, msr); #endif if (CPU_DEV_VER == 1) { /// @todo dev_idx++? for (dev_idx = 0, val_idx = 0; dev_idx < coretotal; dev_idx++, val_idx++) { create_batch_op(msr, dev_idx, &val[val_idx], batchnum); } } else { /* Load socket 0. */ for (dev_idx = 0, val_idx = 0; dev_idx < coretotal; dev_idx += sockets, val_idx++) { create_batch_op(msr, dev_idx, &val[val_idx], batchnum); } /* Load socket 1. */ for (dev_idx = 1; dev_idx < coretotal; dev_idx += sockets) { create_batch_op(msr, dev_idx, &val[val_idx], batchnum); val_idx++; } } return 0; }
/// @brief Retrieve file descriptor per logical processor. /// /// @param [in] dev_idx Unique logical processor identifier. /// /// @return Unique file descriptor, else NULL. static int *core_fd(const int dev_idx) { static int init = 0; static int *file_descriptors = NULL; static uint64_t devices = 0; if (!init) { init = 1; uint64_t numDevs = num_devs();; devices = numDevs; file_descriptors = (int *) libmsr_malloc(devices * sizeof(int)); } if (dev_idx < devices) { return &(file_descriptors[dev_idx]); } libmsr_error_handler("core_fd(): Array reference out of bounds", LIBMSR_ERROR_ARRAY_BOUNDS, getenv("HOSTNAME"), __FILE__, __LINE__); return NULL; }
int write_msr_by_idx(int dev_idx, off_t msr, uint64_t val) { int rc; int *fileDescriptor = NULL; fileDescriptor = core_fd(dev_idx); if (fileDescriptor == NULL) { return -1; } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (write_msr_by_idx) msr=%lu (0x%lx)\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, msr, msr); #endif rc = pwrite(*fileDescriptor, &val, (size_t)sizeof(uint64_t), msr); if (rc != sizeof(uint64_t)) { libmsr_error_handler("write_msr_by_idx(): Pwrite failed", LIBMSR_ERROR_MSR_WRITE, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } return 0; }
int read_msr_by_coord(unsigned socket, unsigned core, unsigned thread, off_t msr, uint64_t *val) { static uint64_t coresPerSocket = 0; static uint64_t threadsPerCore = 0; #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (read_msr_by_coord) socket=%d core=%d thread=%d msr=%lu (0x%lx)\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, socket, core, thread, msr, msr); #endif sockets_assert(&socket, __LINE__, __FILE__); cores_assert(&core, __LINE__, __FILE__); threads_assert(&thread, __LINE__, __FILE__); if (val == NULL) { libmsr_error_handler("read_msr_by_coord(): Received NULL pointer", LIBMSR_ERROR_MSR_READ, getenv("HOSTNAME"), __FILE__, __LINE__); } if (coresPerSocket == 0 || threadsPerCore == 0) { core_config(&coresPerSocket, &threadsPerCore, NULL, NULL); } return read_msr_by_idx(devidx(socket, core, thread), msr, val); }
int load_socket_batch(off_t msr, uint64_t **val, int batchnum) { int dev_idx, val_idx; static uint64_t coresPerSocket = 0; static uint64_t threadsPerCore = 0; static uint64_t sockets = 0; if (val == NULL) { libmsr_error_handler("load_socket_batch(): Given uninitialized array", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } if (coresPerSocket == 0 || threadsPerCore == 0) { core_config(&coresPerSocket, &threadsPerCore, &sockets, NULL); } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (read_all_sockets) msr=%lu (0x%lx)\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, msr, msr); fprintf(stderr, "sockets %lu, cores %lu, threads %lu\n", sockets, coresPerSocket, threadsPerCore); #endif if (CPU_DEV_VER == 1) { for (dev_idx = 0, val_idx = 0; dev_idx < NUM_DEVS; dev_idx += coresPerSocket * threadsPerCore, val_idx++) { create_batch_op(msr, dev_idx, &val[val_idx], batchnum); } } else { for (dev_idx = 0, val_idx = 0; dev_idx < sockets; dev_idx++, val_idx++) { create_batch_op(msr, dev_idx, &val[val_idx], batchnum); } } return 0; }
int set_dram_rapl_limit(const unsigned socket, struct rapl_limit *limit) { uint64_t dram_limit = 0; static uint64_t *rapl_flags = NULL; sockets_assert(&socket, __LINE__, __FILE__); if (rapl_flags == NULL) { if (rapl_storage(NULL, &rapl_flags)) { return -1; } } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (set_dram_rapl_limit)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif /* Make sure the dram power limit register exists. */ if (*rapl_flags & DRAM_POWER_LIMIT) { if (limit != NULL) { if (calc_std_rapl_limit(socket, limit)) { return -1; } dram_limit |= limit->bits | (1LL << 15); write_msr_by_coord(socket, 0, 0, MSR_DRAM_POWER_LIMIT, dram_limit); } } else { libmsr_error_handler("set_dram_rapl_limit(): DRAM domain RAPL limit not supported on this architecture", LIBMSR_ERROR_PLATFORM_NOT_SUPPORTED, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } return 0; }
int set_pkg_rapl_limit(const unsigned socket, struct rapl_limit *limit1, struct rapl_limit *limit2) { uint64_t pkg_limit = 0; static uint64_t *rapl_flags = NULL; uint64_t currentval = 0; int ret = 0; sockets_assert(&socket, __LINE__, __FILE__); if (rapl_flags == NULL) { if (rapl_storage(NULL, &rapl_flags)) { return -1; } } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (set_pkg_rapl_limit) flags are at %p\n", getenv("HOSTNAME"), __FILE__, __LINE__, rapl_flags); #endif /* Make sure the pkg power limit register exists. */ if (*rapl_flags & PKG_POWER_LIMIT) { /* If there is only one limit, grab the other existing one. */ if (limit1 == NULL) { #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: only one rapl limit, retrieving any existing power limits\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif ret = read_msr_by_coord(socket, 0, 0, MSR_PKG_POWER_LIMIT, ¤tval); /* We want to keep the lower limit so mask off all other bits. */ pkg_limit |= currentval & 0x00000000FFFFFFFF; } else if (limit2 == NULL) { #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: only one rapl limit, retrieving any existing power limits\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif ret = read_msr_by_coord(socket, 0, 0, MSR_PKG_POWER_LIMIT, ¤tval); /* We want to keep the upper limit so mask off all other bits. */ pkg_limit |= currentval & 0xFFFFFFFF00000000; } if (calc_pkg_rapl_limit(socket, limit1, limit2)) { return -1; } /* Enable the rapl limit (15 && 47) and turn on clamping (16 && 48). */ if (limit1 != NULL) { pkg_limit |= limit1->bits | (1LL << 15) | (1LL << 16); } if (limit2 != NULL) { pkg_limit |= limit2->bits | (1LL << 47) | (1LL << 48); } if (limit1 != NULL || limit2 != NULL) { ret += write_msr_by_coord(socket, 0, 0, MSR_PKG_POWER_LIMIT, pkg_limit); } } else { libmsr_error_handler("set_pkg_rapl_limit(): PKG domain RAPL limit not supported on this architecture", LIBMSR_ERROR_PLATFORM_NOT_SUPPORTED, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } #ifdef LIBMSR_DEBUG fprintf(stderr, "pkg set\n"); #endif return ret; }
/// @brief Set the RAPL flags indicating available registers by looking up the /// model number of the CPU. /// /// @param [out] rapl_flags Platform-specific bit flags indicating availability /// of RAPL MSRs. /// /// @return 0 if successful, else -1 if platform does not have RAPL or if /// platform does not have MSR_RAPL_POWER_UNIT. static int setflags(uint64_t *rapl_flags) { uint64_t model = 0; cpuid_get_model(&model); switch(model) { case 0x37: *rapl_flags = MF_06_37; break; case 0x4A: *rapl_flags = MF_06_4A; break; case 0x5A: *rapl_flags = MF_06_5A; break; case 0x4D: *rapl_flags = MF_06_4D; break; case 0x4C: *rapl_flags = MF_06_4C; break; case 0x2A: *rapl_flags = MF_06_2A; break; case 0x2D: *rapl_flags = MF_06_2D; break; case 0x3A: *rapl_flags = MF_06_3A; break; case 0x3E: *rapl_flags = MF_06_3E; break; case 0x3C: *rapl_flags = MF_06_3C; break; case 0x45: *rapl_flags = MF_06_45; break; case 0x46: *rapl_flags = MF_06_46; break; case 0x3F: *rapl_flags = MF_06_3F; break; case 0x3D: *rapl_flags = MF_06_3D; break; case 0x47: *rapl_flags = MF_06_47; break; case 0x4F: *rapl_flags = MF_06_4F; break; case 0x56: *rapl_flags = MF_06_56; break; case 0x4E: *rapl_flags = MF_06_4E; break; case 0x5E: *rapl_flags = MF_06_5E; break; case 0x55: *rapl_flags = MF_06_55; break; case 0x57: *rapl_flags = MF_06_57; break; default: libmsr_error_handler("setflags(): This model number does not have RAPL", LIBMSR_ERROR_PLATFORM_NOT_SUPPORTED, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; break; } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: setflags() model is %lx, flags are %lx at %p\n", getenv("HOSTNAME"), __FILE__, __LINE__, model, *rapl_flags, rapl_flags); #endif /* Every RAPL-enabled CPU so far has this register. */ if (!(*rapl_flags & POWER_UNIT)) { libmsr_error_handler("setflags(): No RAPL power unit MSR found", LIBMSR_ERROR_PLATFORM_NOT_SUPPORTED, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } return 0; }
int init_msr(void) { int dev_idx; int ret; int *fileDescriptor = NULL; char filename[FILENAME_SIZE]; static int init = 0; int kerneltype = 3; // 0 is msr_safe, 1 is msr ret = find_cpu_top(); if (ret < 0) { return ret; } uint64_t numDevs = num_devs(); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s Initializing %lu device(s).\n", getenv("HOSTNAME"), (numDevs)); #endif if (init) { return 0; } snprintf(filename, FILENAME_SIZE, "/dev/cpu/msr_whitelist"); stat_module(filename, &kerneltype, 0); /* Open the file descriptor for each device's msr interface. */ for (dev_idx = 0; dev_idx < numDevs; dev_idx++) { /* Use the msr_safe module, or default to the msr module. */ if (kerneltype) { snprintf(filename, FILENAME_SIZE, "/dev/cpu/%d/msr", dev_idx); } else { snprintf(filename, FILENAME_SIZE, "/dev/cpu/%d/msr_safe", dev_idx); } if (stat_module(filename, &kerneltype, &dev_idx) < 0) { return -1; } if (dev_idx < 0) { continue; } /* Open the msr module, else return the appropriate error message. */ fileDescriptor = core_fd(dev_idx); *fileDescriptor = open(filename, O_RDWR); if (*fileDescriptor == -1) { libmsr_error_handler("init_msr(): Could not open file", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); if (kerneltype) { libmsr_error_handler("init_msr(): Could not open any valid MSR module", LIBMSR_ERROR_RAPL_INIT, getenv("HOSTNAME"), __FILE__, __LINE__); /* Could not open any msr module, so exit. */ return -1; } kerneltype = 1; dev_idx = -1; } } init = 1; return 0; }
int read_rapl_data(void) { static struct rapl_data *rapl = NULL; static uint64_t *rapl_flags = NULL; static short init = 0; static uint64_t sockets = 0; int s; if (!init) { sockets = num_sockets(); if (rapl_storage(&rapl, &rapl_flags)) { return -1; } create_rapl_data_batch(rapl_flags, rapl); rapl->now.tv_sec = 0; rapl->now.tv_usec = 0; rapl->old_now.tv_sec = 0; rapl->old_now.tv_usec = 0; rapl->elapsed = 0; for (s = 0; s < sockets; s++) { rapl->pkg_joules[s] = 0; rapl->old_pkg_joules[s] = 0; rapl->dram_joules[s] = 0; rapl->old_dram_joules[s] = 0; } } //p = &rapl[socket]; #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (read_rapl_data): socket=%lu at address %p\n", getenv("HOSTNAME"), __FILE__, __LINE__, num_sockets(), rapl); #endif /* Move current variables to "old" variables. */ rapl->old_now.tv_sec = rapl->now.tv_sec; rapl->old_now.tv_usec = rapl->now.tv_usec; /* Grab a timestamp. */ gettimeofday(&(rapl->now), NULL); if (init) { rapl->elapsed = (rapl->now.tv_sec - rapl->old_now.tv_sec) + (rapl->now.tv_usec - rapl->old_now.tv_usec)/1000000.0; for (s = 0; s < sockets; s++) { /* Make sure the pkg energy status register exists. */ if (*rapl_flags & PKG_ENERGY_STATUS) { #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: socket %lu msr 0x611 has destination %p\n", sockets, rapl->pkg_bits); #endif rapl->old_pkg_bits[s] = *rapl->pkg_bits[s]; rapl->old_pkg_joules[s] = rapl->pkg_joules[s]; } #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: (read_rapl_data): made it to 1st mark\n"); #endif /* Make sure the pkg perf status register exists. */ if (*rapl_flags & PKG_PERF_STATUS) { libmsr_error_handler("read_rapl_data(): MSR_PKG_PERF_STATUS not yet implemented", LIBMSR_ERROR_NOT_IMPLEMENTED_YET, getenv("HOSTNAME"), __FILE__, __LINE__); } /* Make sure the dram energy status register exists. */ if (*rapl_flags & DRAM_ENERGY_STATUS) { rapl->old_dram_bits[s] = *rapl->dram_bits[s]; rapl->old_dram_joules[s] = rapl->dram_joules[s]; } /* Make sure the dram perf status register exists. */ if (*rapl_flags & DRAM_PERF_STATUS) { libmsr_error_handler("read_rapl_data(): MSR_DRAM_PERF_STATUS not yet implemented", LIBMSR_ERROR_NOT_IMPLEMENTED_YET, getenv("HOSTNAME"), __FILE__, __LINE__); } } } read_batch(RAPL_DATA); for (s = 0; s < sockets; s++) { if (*rapl_flags & DRAM_ENERGY_STATUS) { #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: (read_rapl_data): translating dram\n"); #endif translate(s, rapl->dram_bits[s], &rapl->dram_joules[s], BITS_TO_JOULES_DRAM); } if (*rapl_flags & PKG_ENERGY_STATUS) { #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: (read_rapl_data): translating pkg\n"); #endif translate(s, rapl->pkg_bits[s], &rapl->pkg_joules[s], BITS_TO_JOULES); } #ifdef LIBMSR_DEBUG fprintf(stderr, "DEBUG: socket %d\n", s); fprintf(stderr, "DEBUG: elapsed %f\n", rapl->elapsed); fprintf(stderr, "DEBUG: pkg_bits %lx\n", *rapl->pkg_bits[s]); fprintf(stderr, "DEBUG: pkg_joules %lf\n", rapl->pkg_joules[s]); fprintf(stderr, "DEBUG: pkg_watts %lf\n", rapl->pkg_watts[s]); fprintf(stderr, "DEBUG: delta_joules %lf\n", rapl->pkg_delta_joules[s]); #endif } init = 1; 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__); } } }
/// @brief Execute read/write batch operation on a specific set of batch /// registers. /// /// @param [in] batchnum libmsr_data_type_e data type of batch operation. /// /// @param [in] type libmsr_batch_op_type_e type of batch operation. /// /// @return 0 if successful, else -1 if batch_storage() fails or if batch /// allocation is for 0 or less operations. static int do_batch_op(int batchnum, int type) { static int batchfd = 0; struct msr_batch_array *batch = NULL; int res, i, j; if (batchfd == 0) { if ((batchfd = open(MSR_BATCH_DIR, O_RDWR)) < 0) { perror(MSR_BATCH_DIR); batchfd = -1; } } #ifdef USE_NO_BATCH return compatibility_batch(batchnum, type); #endif if (batchfd < 0) { return compatibility_batch(batchnum, type); } if (batch_storage(&batch, batchnum, NULL)) { return -1; } #ifdef BATCH_DEBUG fprintf(stderr, "BATCH %d: %s MSRs, numops %u\n", batchnum, (type == BATCH_READ ? "reading" : "writing"), batch->numops); #endif if (batch->numops <= 0) { libmsr_error_handler("do_batch_op(): Using empty batch", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); return -1; } /* If current flag is the opposite type, switch the flags. */ if ((type == BATCH_WRITE && batch->ops[0].isrdmsr) || (type == BATCH_READ && !batch->ops[0].isrdmsr)) { __u8 readflag = (__u8) (type == BATCH_READ ? 1 : 0); for (j = 0; j < batch->numops; j++) { batch->ops[j].isrdmsr = readflag; } } res = ioctl(batchfd, X86_IOC_MSR_BATCH, batch); if (res < 0) { libmsr_error_handler("do_batch_op(): IOctl failed, does /dev/cpu/msr_batch exist?", LIBMSR_ERROR_MSR_BATCH, getenv("HOSTNAME"), __FILE__, __LINE__); for (i = 0; i < batch->numops; i++) { #if 0 /* Temporarily removed because err has garbage in it. */ if (batch->ops[i].err) { fprintf(stderr, "CPU %d, RDMSR %x, ERR (%s)\n", batch->ops[i].cpu, batch->ops[i].msr, strerror(batch->ops[i].err)); } #endif } } #ifdef BATCH_DEBUG int k; for (k = 0; k < batch->numops; k++) { fprintf(stderr, "BATCH %d: msr 0x%x cpu %u data 0x%lx (at %p)\n", batchnum, batch->ops[k].msr, batch->ops[k].cpu, (uint64_t)batch->ops[k].msrdata, &batch->ops[k].msrdata); } #endif return 0; }