【问题标题】:Obtain load average on single CPU core on SMP system获取 SMP 系统上单个 CPU 内核的平均负载
【发布时间】:2021-10-14 06:31:24
【问题描述】:

Linux 中有一个 API 可以获取平均负载指标 - 系统调用 getloadavg()

它获得 1、5 和 15 分钟的平均负载,但似乎是所有 CPU(所有 CPU 内核)的共同负载。但是如何从常规 C 文件中获取 SMP 系统上单个(特定)CPU 内核的平均负载?

【问题讨论】:

  • 您可能会从 /proc/stat - this thread 中的每个 CPU 数据中获得所需的信息
  • 我认为没有每个 CPU 进程队列。有一个单一的、系统范围的进程队列,当一个进程准备好运行时,它会被分配给适当的 CPU。平均负载是该队列的平均长度。
  • 因此不存在特定 CPU 上的平均负载。
  • @Barmar 好的!但是 CPU 亲和力呢?假设我有一个与特定 CPU 内核相关的用户模式进程,我如何评估该内核的过载情况?
  • 你没有“超载”那个核心。您只是增加了总体平均负载,因为当该进程准备好运行时,CPU 可能不可用,因此它将留在运行队列中。

标签: c linux cpu cpu-usage


【解决方案1】:

要评估 Intel CPU 的平均核心负载,您可以阅读 IA32_TIME_STAMP_COUNTERIA32_MPERF MSR。

伪代码:

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)

编辑 - 添加 C 代码(仅用于核心 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;
}

代码预计将msr_safe 与允许列表中的两个使用的 MSR 一起使用。否则重写代码以使用 sudo 权限从 /dev/cpu/msr 读取。

在没有其他依赖项的情况下工作,或者最好使用 libmsr,但随后需要使用 -DHAVE_MSR_CORE_H 标志进行编译。

【讨论】:

  • 根据我的问题和标签,我正在尝试从 C 文件中执行此操作。有 C API 吗?
  • 另外 IA32 的东西也不是便携的。我需要我的代码不仅可以在 Intel CPU 上工作
  • msr_safe (github.com/LLNL/msr-safe) + libmsr (github.com/LLNL/libmsr) 提供 C API 以安全的方式从用户空间读取 MSR。使用 TSC 和 MPERF MSR 适用于 Intel 和 AMD。我不知道有任何 sysfs 接口或实用程序可以为每个硬件平台提供负载。
  • 请注意,msr_safe 适用于 AMD CPU 很好,但 libmsr 不能,但是可以轻松实现读/写功能,请参阅code.it4i.cz/vys0053/meric/-/blob/dev/src/basis/msrutil.h
  • 我有Intel(R) Core(TM) i7-6800K CPU,Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit,但您的 bash 脚本无法正常工作,出现错误:.请提供完整的可执行示例。 ./1.sh:第 4 行:意外标记附近的语法错误 read_msr' ./1.sh: line 4: read_msr(IA32_TIME_STAMP_COUNTER, TSC_1[id], id)'
猜你喜欢
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 2014-08-12
  • 2014-07-08
  • 2015-05-02
  • 1970-01-01
  • 2011-04-10
相关资源
最近更新 更多