Example #1
0
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;
}
Example #2
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;
}
Example #3
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;
}
Example #4
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;
}
Example #5
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;
}
Example #6
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;
}
Example #7
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;
}
Example #8
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;
}
Example #9
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;
}
Example #10
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;
}
Example #11
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;
}
Example #12
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;
}
Example #13
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;
}
Example #14
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;
}
Example #15
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;
}
Example #16
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;
}
Example #17
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;
}
Example #18
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;
}
Example #19
0
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;
}
Example #20
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);
}
Example #21
0
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;
}
Example #22
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;
}
Example #23
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, &currentval);
            /* 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, &currentval);
            /* 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;
}
Example #24
0
/// @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;
}
Example #25
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;
}
Example #26
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;
}
Example #27
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__);
        }
    }
}
Example #28
0
/// @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;
}