我正在尝试推出自己的系统性能监视器,以便在出现过载时延迟执行部分服务器代码(在IIS下运行某些Web服务)。我要解决的第一件事就是CPU过载。
我知道PerformanceCounter
问题必须通过第一次调用NextValue()
来初始化它(参见this question等),所以我实现了一个非常简单的静态类来缓存一秒钟的数据,实际上每秒只能访问一次PerformanceCounter
对象。我知道它目前不是线程安全的,但在当前的原型设计阶段我并不关心它。
所以,说了这么多,这是我现在的代码:
public static class SystemPerformance
{
private static PerformanceCounter TotalProcessorTimeCounter =
new PerformanceCounter("Process", "% Processor Time", "_Total");
private static DateTime CacheRefreshed;
private static float CachedValue = 0f;
private const float MIN_DELTA_SECONDS = 1f;
public static float ReadCPU()
{
if ((DateTime.Now - CacheRefreshed).TotalSeconds > MIN_DELTA_SECONDS)
// Stale cache
return ReadFromCounter();
// Good cache
return CachedValue;
}
private static float ReadFromCounter()
{
CachedValue = TotalProcessorTimeCounter.NextValue();
CacheRefreshed = DateTime.Now;
return CachedValue;
}
}
...这一切都很好,花花公子,直到我执行它。我尝试在具有4个内核的Windows 10 x64 VM上运行它,在具有4个内核的Windows 7 x64铁上运行它 - 在这两种情况下,无论我做什么,返回值都会徘徊在400左右。
我得到的典型值在395-401范围内,偶尔下降到365或跳到405.我读到的值与我测试的任何一台机器上的实际CPU负载没有任何关联,如任务管理器,性能监视器或实际常识所示。
测试方法很简单:SystemPerformance.ReadCPU()
由简单的Windows窗体中的按钮触发,输出以相同的形式显示在文本框中。当CPU处于准空闲状态时,我按下那个按钮,当其他进程正在执行操作并加载CPU时,我也按下它。
我做错了什么?这应该只返回应用程序线程的CPU使用率吗?我是否误解了数据?
答案 0 :(得分:2)
new PerformanceCounter("Process", "% Processor Time", "_Total");
是的,_Total进程数所占用的处理器时间,包括您在任务管理器中看到的虚假“系统空闲进程”,在4核计算机上总是会增加400%。
如果将“处理”更改为“处理器”,您可能更喜欢这个数字。如果要匹配任务管理器显示的值,则需要将“处理”更改为“处理器信息”。尝试生成更实际数字的新类别,该数字补偿了具有turbo boost的处理器,具有NUMA节点的计算机以及从超线程获得的较低性能。您需要阅读this blog post了解细节。