微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么psutil CPU使用率太低?

如何解决为什么psutil CPU使用率太低?

我已经使用psutil用Python编写了性能监控器功能,以测量cpu,GPU和磁盘I / O,以对另一个应用程序进行基准测试。在我最初的测试中,它工作得很好,但是当它接近100%时,我发现它严重低估了cpu使用率。我正在寻求帮助,以找出发生这种情况的原因。

功能似乎过于复杂,但是我试图做两件事:实时显示当前用法;并在最后报告最高的5秒滚动平均值。这是因为我无法预测子流程将花费多长时间,并且我想消除短期波动。

下面是该函数的简化版本。在此示例中,我删除了所有GPU和磁盘度量,并对打印语句作了一些改动以进行调试。尽管我尝试每秒采样一次,但我发现elapsed时间有时会在cpu使用率很高时波动高达1.8。

这是在Windows 10上运行的。任务管理器显示cpu使用率恒定为100%,没有波动,如果我在另一个显示100%的窗口中运行psutil.cpu_times_percent(),则此处的功能显示为大约90%。

import psutil
import time
import shlex
import subprocess
from concurrent.futures import ThreadPoolExecutor


def perf_monitor(proc):
    # measure cpu,GPU,and disk R/W every 1 seconds,and calculate a rolling average every 5 seconds
    # return the maximum of each rolling average
    rolling_interval = 5
    sample_interval = 1
    rolling_samples = []
    stats = {
        'cpu': 0,}
    cpu_count = psutil.cpu_count()

    while True: # loop until subprocess is finished
        # reset starting values
        start = time.time()
        cpu1 = psutil.cpu_times()
        cpu1 = cpu1.user + cpu1.system

        # measure again after the interval
        time.sleep(sample_interval)
        cpu2 = psutil.cpu_times()
        cpu2 = cpu2.user + cpu2.system
        
        # list starts at zero and counts up,then remains at 5
        elapsed = time.time() - start # may be slightly longer than sample_interval
        rolling_samples.append({
            'cpu': (cpu2 - cpu1) / cpu_count / elapsed,})
        # skip reporting for the first 5 seconds warm up
        if len(rolling_samples) < rolling_interval:
            continue
        
        # get the rolling average over a defined interval (5 seconds)
        rolling_avg_cpu = sum([sample['cpu'] for sample in rolling_samples]) / rolling_interval

        print([sample['cpu'] for sample in rolling_samples],elapsed) # for debugging
        print(f"cpu: {rolling_avg_cpu:.1%}  ",end='\n',)

        # update each stat only if it has increased
        if rolling_avg_cpu > stats['cpu']:
            stats['cpu'] = rolling_avg_cpu
        
        # remove oldest sample so we always keep 5
        del rolling_samples[0]

        # return stats when render is finished
        if proc.poll() is not None:
            return stats

if __name__ == "__main__":
    command = '"MyApp.exe'
    with ThreadPoolExecutor() as executor:
        proc = subprocess.Popen(shlex.split(command))
        thread = executor.submit(perf_monitor,proc)
        stats = thread.result()
    
    print(stats)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。