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 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; }
/// @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 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; }
/// @brief Determine how the user setup the package domain RAPL power limits /// and setup other limit accordingly. /// /// @param [in] socket Unique socket/package identifier. /// /// @param [out] limit1 Data for desired power limit 1 (lower). /// /// @param [out] limit2 Data for desired power limit 2 (upper). /// /// @return 0 if successful, else -1 if calc_rapl_bits() or /// calc_rapl_from_bits() fails. static int calc_pkg_rapl_limit(const unsigned socket, struct rapl_limit *limit1, struct rapl_limit *limit2) { sockets_assert(&socket, __LINE__, __FILE__); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (calc_pkg_rapl_limit)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif /* If we have been given a lower rapl limit. */ if (limit1 != NULL) { if (limit1->bits) { if (calc_rapl_from_bits(socket, limit1, 0)) { return -1; } } else { if (calc_rapl_bits(socket, limit1, 0)) { return -1; } } } /* If we have been given an upper rapl limit. */ if (limit2 != NULL) { if (limit2->bits) { if (calc_rapl_from_bits(socket, limit2, 32)) { return -1; } } else { if (calc_rapl_bits(socket, limit2, 32)) { return -1; } } } #ifdef LIBMSR_DEBUG fprintf(stderr, "pkg calculated\n"); #endif return 0; }
int write_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; sockets_assert(&socket, __LINE__, __FILE__); cores_assert(&core, __LINE__, __FILE__); threads_assert(&thread, __LINE__, __FILE__); if (coresPerSocket == 0 || threadsPerCore == 0) { core_config(&coresPerSocket, &threadsPerCore, NULL, NULL); } #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s %s::%d (write_msr_by_coord) socket=%d core=%d thread=%d msr=%lu (0x%lx) val=%lu\n", getenv("HOSTNAME"), LIBMSR_DEBUG_TAG, __FILE__, __LINE__, socket, core, thread, msr, msr, val); return write_msr_by_idx_and_verify(devidx(socket, core, thread), msr, val); #endif return write_msr_by_idx(devidx(socket, core, thread), msr, val); }
int read_msr_by_coord_batch(unsigned socket, unsigned core, unsigned thread, off_t msr, uint64_t **val, int batchnum) { static uint64_t coresPerSocket = 0; static uint64_t threadsPerCore = 0; #ifdef BATCH_DEBUG fprintf(stderr, "%s %s %s::%d (read_msr_by_coord_batch) 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 (coresPerSocket == 0 || threadsPerCore == 0) { core_config(&coresPerSocket, &threadsPerCore, NULL, NULL); } #ifdef BATCH_DEBUG fprintf(stderr, "DEBUG: passed operation on msr 0x%lx (socket %u, core %u, thread %u) to BATCH OPS with destination %p\n", msr, socket, core, thread, val); #endif create_batch_op(msr, devidx(socket, core, thread), val, batchnum); 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); }
/// @brief Determine how the user setup non-package RAPL power limits and setup /// the data for the other limit accordingly. /// /// @param [in] socket Unique socket/package identifier. /// /// @param [out] limit Data for desired power limit. /// /// @return 0 if successful, else -1 if calc_rapl_from_bits() or /// calc_rapl_bits() fails. static int calc_std_rapl_limit(const unsigned socket, struct rapl_limit *limit) { sockets_assert(&socket, __LINE__, __FILE__); #ifdef LIBMSR_DEBUG fprintf(stderr, "%s %s::%d DEBUG: (calc_std_rapl_limit)\n", getenv("HOSTNAME"), __FILE__, __LINE__); #endif if (limit->bits) { if (calc_rapl_from_bits(socket, limit, 0)) { return -1; } } else { if (calc_rapl_bits(socket, limit, 0)) { return -1; } } 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 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; }