To evaluate average core load of an Intel CPU, you may read IA32_TIME_STAMP_COUNTER
and IA32_MPERF
MSRs.
Pseudocode:
for id in core_size
read_msr(IA32_TIME_STAMP_COUNTER, TSC_1[id], id)
read_msr(IA32_MPERF, MPERF_1[id], id)
do_work()
for id in core_size
read_msr(IA32_TIME_STAMP_COUNTER, TSC_2[id], id)
read_msr(IA32_MPERF, MPERF_2[id], id)
tsc_d = TSC_2[id] - TSC_1[id]
mperf_d = MPERF_2[id] - MPERF_1[id]
if tsc_d < mperf_d
print "core" id "load: 100.0"
else
print "core" id "load:" 100.0 - ((tsc_d - mperf_d) * 100.0 / tsc_d)
Edit - added C code (just for core 0):
// gcc avg_load.c -std=c11 -o avg
// gcc avg_load.c -std=c11 -lmsr -L$LIBMSR_PATH/lib/ -I$LIBMSR_PATH/include/ -DHAVE_MSR_CORE_H -o avg
#ifdef HAVE_MSR_CORE_H
#include <msr_core.h>
#else
#include <sys/types.h>
#include <fcntl.h>
#include <stdint.h>
#endif
#include <stdio.h>
#include <unistd.h>
#ifndef IA32_MPERF
#define IA32_MPERF 0xE7
#endif
#ifndef IA32_TIME_STAMP_COUNTER
#define IA32_TIME_STAMP_COUNTER 0x10
#endif
static int read_msr(int cpuid, off_t MSR_REGISTER_address, uint64_t *MSR_REGISTER_bits)
{
#ifdef HAVE_MSR_CORE_H
return read_msr_by_idx(cpuid, MSR_REGISTER_address, MSR_REGISTER_bits);
#else
char msr_file_name[64];
sprintf(msr_file_name, "/dev/cpu/%d/msr_safe", cpuid);
int fd = open(msr_file_name, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "read msr error [%d]\n", cpuid);
return -1;
}
if (pread(fd, MSR_REGISTER_bits, sizeof MSR_REGISTER_bits, MSR_REGISTER_address) != sizeof MSR_REGISTER_bits)
{
fprintf(stderr, "read msr error [%d]\n", cpuid);
return -1;
}
close(fd);
return 0;
#endif
}
int main()
{
#ifdef HAVE_MSR_CORE_H
init_msr();
#endif
uint64_t mperf_start, mperf_stop;
uint64_t tsc_start, tsc_stop;
read_msr(0, IA32_MPERF, &mperf_start);
read_msr(0, IA32_TIME_STAMP_COUNTER, &tsc_start);
sleep(1);
read_msr(0, IA32_MPERF, &mperf_stop);
read_msr(0, IA32_TIME_STAMP_COUNTER, &tsc_stop);
uint64_t tsc_d = tsc_stop - tsc_start;
uint64_t mperf_d = mperf_stop - mperf_start;
if (tsc_d < mperf_d)
printf ("core 0 load: 100.0\n");
else
printf ("core 0 load: %f %\n", 100.0 - ((tsc_d - mperf_d) * 100.0 / tsc_d));
#ifdef HAVE_MSR_CORE_H
finalize_msr();
#endif
return 0;
}
The code expects to use msr_safe with the two used MSRs in the allowlist. Otherwise rewrite the code to read from /dev/cpu/msr
with sudo rights.
Works without other dependencies or preferably with libmsr, but then requires compilation with -DHAVE_MSR_CORE_H
flag.