C#系统CPU使用率并与Windows任务管理器同步
这是一个两部分问题,我想在堆栈上发布我的代码,以帮助其他人完成相同的任务.
问题1: 我有一个代码子集,我相信,根据测量间隔正确地测量CPU使用率(在系统中,根据检索的次数) – 我在线程调用中使用1秒. 我不得不从网上和C代码中的极少数文章中解读这个.我的问题是,对于问题1,这是正确的我做了什么? 有时返回的值是负数,这就是我乘以-1的原因.我再次假设,因为文档很少,这就是我应该做的. 我有以下代码: public static class Processor { [DllImport("kernel32.dll",SetLastError = true)] static extern bool GetSystemTimes(out ComTypes.FILETIME lpIdleTime,out ComTypes.FILETIME lpKernelTime,out ComTypes.FILETIME lpUserTime); private static TimeSpan _sysIdleOldTs; private static TimeSpan _sysKernelOldTs; private static TimeSpan _sysUserOldTs; static Processor() { } public static void Test() { ComTypes.FILETIME sysIdle,sysKernel,sysUser; if(GetSystemTimes(out sysIdle,out sysKernel,out sysUser)) { TimeSpan sysIdleTs = GetTimeSpanFromFileTime(sysIdle); TimeSpan sysKernelTs = GetTimeSpanFromFileTime(sysKernel); TimeSpan sysUserTs = GetTimeSpanFromFileTime(sysUser); TimeSpan sysIdleDiffenceTs = sysIdleTs.Subtract(_sysIdleOldTs); TimeSpan sysKernelDiffenceTs = sysKernelTs.Subtract(_sysKernelOldTs); TimeSpan sysUserDiffenceTs = sysUserTs.Subtract(_sysUserOldTs); _sysIdleOldTs = sysIdleTs; _sysKernelOldTs = sysKernelTs; _sysUserOldTs = sysUserTs; TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs); Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds); if (cpuUsage < 0) { Console.WriteLine("CPU: " + ((int) (cpuUsage)*-1) + "%"); } else { Console.WriteLine("CPU: " + (int) (cpuUsage) + "%"); } Console.WriteLine(""); } else { Console.WriteLine("Couldn't get CPU usage!"); Console.WriteLine(""); } } private static TimeSpan GetTimeSpanFromFileTime(ComTypes.FILETIME time) { return TimeSpan.FromMilliseconds((((ulong)time.dwHighDateTime << 32) + (uint)time.dwLowDateTime) * 0.000001); } } 问题2: 在我的程序中,我是否有同步线程与Windows任务管理器的线程,以便匹配测量数据,例如CPU使用率与上述代码? 我的意思是,如果你打开Windows任务管理器,你会注意到它每秒轮询一次 – 实际上它不需要小于那个.我想要做的是将时间与我的线程相匹配. 因此,当Windows任务管理器轮询时,我的线程轮询. 一些说明: 我不想使用性能计数器或.NET内置方法.事实上,我相信 – 从我所读到的,.NET没有计算机器上CPU使用率的方法,否则就需要性能计数器. 性能计数器有开销,此外使GC增长,更不用说调用下一个结果的延迟.虽然我的软件不需要是实时性能,但我确实需要它作为响应并尽可能少地使用CPU时间.上述代码可以在不到一毫秒的时间内调用和返回.实际上在我的开发机器上,时间跨度差异显示为0ms.我不相信性能计数器具有响应性. 如果你很好奇,我的软件收集了许多项目,CPU,内存,事件日志项等,这些项目都需要在SQL CE中收集和存储,在下一次轮询之前,1秒钟之后.然而,每个任务,项目都在其自己的线程上以促进这一点. 此外,上面的代码无论如何都没有优化,你会注意到我还没有评论它.原因是我想在优化之前确保它是正确的. 更新1 根据我做出的改进,我删除了额外的“系统”时间跨度,因为它不是必需的,并修改了检索“CPU使用率”并适当地投射它的行. int cpuUsage = (int)(((sysKernelDifferenceTs.Add(sysUserDifferenceTs).Subtract(sysIdleDifferenceTs).TotalMilliseconds) * 100.00) / sysKernelDifferenceTs.Add(sysUserDifferenceTs).TotalMilliseconds); 虽然我仍然不确定这个公式.虽然它看起来非常准确,但它有时会返回一个负数,这就是为什么我将它乘以-1,如果是这样的话.毕竟,没有这样的事情,CPU使用率为-2%等. 更新2 所以我使用“System.Diagnostics.PerformanceCounter”做了一个简单的测试.虽然非常方便,并且确实完成了它的目的,但确实会产生开销. 以下是我的观察: >性能计数器的初始化时间要长得多.我的i7 2.6 Ghz大约延长了三秒钟. 因此,如果您的应用程序是以资源使用和时间关键的方式构建的,那么我建议不要使用性能计数器,因为这些原因.否则继续前进,因为它没有所有的混乱. 至于我的应用程序,性能计数器将不利于我的软件的目的. 解决方法
我觉得你的公式中有一个错误.您希望基本上计算CPU使用率,如下所示:
CPU Usage = KernelTimeDiff + UserTimeDiff -------------------------------------------- KernelTimeDiff + UserTimeDiff + IdleTimeDiff 因此,快速修改代码如下: // TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs); //Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds); TimeSpan totaltime = sysKernelDiffenceTs.Add(sysUserDiffenceTs); totaltime = totaltime.Add(sysIdleDifferenceTs); int cpuUsage = 100 - (sysIdleDifferenceTs.TotalMilliseconds * 100) / totaltime.TotalMilliseconds; Console.WriteLine("CPU: " + cpuUsage + "%"); 您最初将cpuUsage声明为“Double”.我不确定你是否想要浮点精度,但在你的代码中,你肯定没有得到除整数精度之外的任何东西,因为赋值语句只是在进行整数运算.如果你需要更高的计算精度,你可以通过混合一些浮点来轻松获得它: Double cpuUsage = 100.0 - (sysIdleDifferenceTs.TotalMilliseconds * 100.0) /totaltime.TotalMilliseconds; 此外,关于与任务管理器同步.据我所知,任务管理器使用perf计数器. (而且我怀疑GetSystemTimes正在进行全面反击调用,但可能没有).而且我不确定你为什么不使用perf计数器. “%Process Time”计数器是一个即时样本计数器,不需要计算具有先前结果的差异. (每个逻辑cpu有一个).使用PDH帮助程序函数而不是旧的注册表项apis来获取它.您可以从非托管C/C++ DLL执行此操作,该DLL将“GetCpuUsage”函数导出回您的C#代码.但是我不知道为什么你不能只用P#从P#中调用PDH函数.我不知道你说的这个开销.我不确定我是否理解你提到“延迟调用下一个结果”. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |