进程/pid相对于最大CPU频率的CPU周期数

2024-05-14 07:31:16 发布

您现在位置:Python中文网/ 问答频道 /正文

目前,我通过Python的psutil模块监视几个进程,并以百分比检索CPU使用率,这是基于execution_time/total_time的。这样做的问题是动态电压和频率缩放(DVFS,或ACPI的P-state,或cpufreq等)。当前CPU频率越低,进程需要执行的时间越长,CPU使用率就越高。与此相反,我需要相对于CPU最大性能的固定CPU使用率。在

为了避免在“当前频率”永久变化的情况下进行多次重校准,一种方法是直接使用进程使用的CPU周期。基本上,这可以通过C中的perf_event.h或Linux命令行上的perf来完成。不幸的是,我找不到提供类似功能的Python模块(基于上述功能)。在


Tags: 模块功能time进程动态cpupsutilperf
2条回答

感谢21点的评论

What about implementing it in C as shared library and using it via ctypes in Python?

A library call introduces less overhead. A subprocess call starts a whole external process and communicates the result as string over pipes every time you need the value. The shared library is loaded once into the current process and the result is passed in memory.

我把它作为一个共享库来实现。库cpucycles.c的源代码是(主要基于^{}'s man page的示例):

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                int cpu, int group_fd, unsigned long flags)
{
    int ret;

    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
                    group_fd, flags);
    return ret;
}

long long
cpu_cycles(unsigned int microseconds,
            pid_t pid,
            int cpu,
            int exclude_user,
            int exclude_kernel,
            int exclude_hv,
            int exclude_idle)
{
    struct perf_event_attr pe;
    long long count;
    int fd;

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_CPU_CYCLES;
    pe.disabled = 1;
    pe.exclude_user = exclude_user;
    pe.exclude_kernel = exclude_kernel;
    pe.exclude_hv = exclude_hv;
    pe.exclude_idle = exclude_idle;

    fd = perf_event_open(&pe, pid, cpu, -1, 0);
    if (fd == -1) {
        return -1;
    }
    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
    usleep(microseconds);
    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
    read(fd, &count, sizeof(long long));

    close(fd);
    return count;
}

此代码通过以下两个命令编译到共享库中:

^{pr2}$

最后,Python可以在cpucycles.py

import ctypes
import os

cdll = ctypes.cdll.LoadLibrary(os.path.join(os.path.dirname(__file__), "libcpucycles.so.1.0.1"))
cdll.cpu_cycles.argtypes = (ctypes.c_uint, ctypes.c_int, ctypes.c_int,
                            ctypes.c_int, ctypes.c_int, ctypes.c_int,
                            ctypes.c_int)
cdll.cpu_cycles.restype = ctypes.c_longlong

def cpu_cycles(duration=1.0, pid=0, cpu=-1,
                exclude_user=False, exclude_kernel=False,
                exclude_hv=True, exclude_idle=True):
    """
    See man page of perf_event_open for all the parameters.

    :param duration: duration of counting cpu_cycles [seconds]
    :type duration: float
    :returns: cpu-cycle count of pid
    :rtype: int
    """
    count = cdll.cpu_cycles(int(duration*1000000), pid, cpu,
                            exclude_user, exclude_kernel,
                            exclude_hv, exclude_idle)
    if count < 0:
                raise OSError("cpu_cycles(pid={}, duration={}) from {} exited with code {}.".format(
                    pid, duration, cdll._name, count))

    return count

最后,我通过perf命令行工具读取CPU周期并打包成Python(简化代码):

import subprocess
maximum_cpu_frequency = 3e9
cpu_percent = []
while True:    # some stop criteria
    try:
        cpu_percent.append(int(
                subprocess.check_output(["perf", "stat", "-e", "cycles",
                        "-p", pid, "-x", ",", "sleep", "1"],
                        stderr=subprocess.STDOUT).decode().split(",")[0]
                )/maximum_cpu_frequency)
    except ValueError:
        cpu_percent.append(0.0)

不幸的是,由于不精确的sleep命令,这是不精确的,而且由于为每个示例生成一个新的perf进程,所以这并不精确。在

相关问题 更多 >

    热门问题