13

这是我的代码。

        PerformanceCounter cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

        // will always start at 0
        dynamic firstValue = cpuCounter.NextValue();
        System.Threading.Thread.Sleep(1000);


        dynamic secondValue = cpuCounter.NextValue();
        return secondValue;

这里有很多人遇到返回零的问题,但是我一直得到 100,而且我确信我的软件不会占用那么多 CPU 功率。关于我可以做些什么来使其正常工作的任何想法。需要明确的是,我试图从运行此代码的应用程序中检索处理器使用情况,而不是单独的。我也在虚拟机上运行,​​但这似乎并不重要。有任何想法吗?

4

2 回答 2

13

它有助于了解 CPU 是如何工作的,以找出发生这种情况的原因。我将通过谈论只有一个核心的 CPU 来简化它,对于具有多个核心的 CPU,故事不会改变。

一个 CPU 内核在不处于睡眠模式时只能处于两种不同的状态。它要么正在执行代码,要么以执行指令的最快速度全速运行。或者它没有执行代码,因为不需要做任何事情。在这种情况下,它会被物理关闭。当它执行 HLT 指令时会发生这种情况。停下来,什么都不做,不消耗能量。

只有一种方法可以使处理器从 Halt 状态中恢复,即需要中断。那是芯片上的一个物理引脚,该引脚上的电压会使其恢复活力。该电压是由一个中断控制器产生的,另一个芯片接收来自机器各个部分的请求,以让 CPU 做一些有用的事情。

该中断的最重要来源是时钟。它以 0.0156 秒滴答作响,每秒使 CPU 恢复活力 64 次。这会激活操作系统中的一段代码,该代码基本上检查两件事。“我睡着的时候发生什么事了吗?” 并且“我根本没有睡着,是时候做一些其他也很重要的事情了”。或者换句话说,它不只是让 cpu 活跃起来,它还会打断它正在做的事情。因此信号的名称。

时钟不是唯一的中断源,CPU 上还有其他硬件。输入/输出设备。任何机器都有的重要部件是磁盘控制器、光驱控制器、网卡、鼠标和键盘。以及您在设备管理器小程序中看到的任何其他内容。它们是具有自己的小处理器的子系统,可以处理事情。并告诉主cpu他们已经完成了。因此,您机器上等待结果的任何线程都可以使用提供的数据继续执行。

大多数时候,你身边的那台个人电脑并没有做任何重要的事情。比如说,等待你阅读这个答案。由视频适配器和液晶显示器负责的东西,cpu 不必帮忙。您可以在 TaskMgr.exe 中看到它,cpu 利用率在 0 附近徘徊。您移动鼠标,单击滚动条以阅读此(长)答案,然后发生了一些事情。鼠标会产生一个中断,该中断会通过几层软件,最终告诉浏览器滚动视图。这需要大约几毫秒,给予或接受。

几毫秒的工作后,cpu 马上又睡着了。因此,当您通过性能计数器向 CPU 询问“您最近做了多少工作”时,它会说:“好吧,我花了几毫秒的时间来燃烧核心并竭尽全力更新您的屏幕。但是没有,其他比我睡在豌豆上”

所以重要的是你问的频率。样板方式是 Perfmon 使用的方式。它每秒问一次“你做了什么”。处理器会说:“好吧,在最后一秒,我执行了 20 毫秒的有用工作。其余时间我都死了,没有什么有用的事情可做”。所以任务管理器显示2%。

现在让我们按照你的方式去做吧。您要求 perf 计数器值,然后一纳秒后您再次要求它。处理器会说:“好吧,我返回了一个性能计数器值并试图回到睡眠状态。没有工作,程序一直在运行代码并问我同样的事情!”。

所以结果是准确的,处理器被你的请求占用了,你没有给它关机的机会。CPU 利用率为 100%。

解决方案:像 Perfmon 那样做。用计时器询问一次。让它更短,数字上升和下降更快。让它太短,它将是 100%

于 2012-07-12T22:18:21.157 回答
2

这是与您可能尝试做的类似的事情

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

cpuCounter = new PerformanceCounter();

cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor Time";
cpuCounter.InstanceName = "_Total";

ramCounter = new PerformanceCounter("Memory", "Available MBytes");


public string getCurrentCpuUsage(){
            return cpuCounter.NextValue()+"%";
}

public string getAvailableRAM(){
            return ramCounter.NextValue()+"MB";
} 
于 2012-07-12T20:38:05.440 回答