C#系统CPU使用情况和与Windows任务pipe理器同步

这是一个两部分的问题,我想把我的代码放在堆栈上,以帮助其他人完成相同的任务。

问题1:

我有一个代码的子集,我相信,根据测量间隔,正确地测量CPU使用率(跨越系统中的许多内核,每次检索时间) – 我在线程调用中使用1秒。

我不得不从networking上的很less的文章和C ++代码中解读这个。 我的问题是,对于第一个问题, 我所做的是否正确?

有时返回的值是一个负数,这就是为什么我乘以-1。 我再一次假设,由于文件很less,这就是我应该做的。

我有以下代码:

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任务pipe理器的线程同步,以便将测量数据(例如CPU使用率)与上面的代码进行匹配?

我的意思是,如果你打开Windows任务pipe理器,你会注意到它每秒轮询一次 – 实际上它不需要less于这个时间。 我想要做的是匹配我的线程的时间。

所以当Windows任务pipe理器轮询时,我的线程轮询。


一些说明:

我不想使用性能计数器或.NET中build立的方法。 实际上,我相信 – 根据我所读到的,.NET没有计算机器CPU使用率的方法,否则性能计数器是必需的。

性能计数器有开销,并且增加了GC, 更不用说延迟调用下一个结果 。 虽然我的软件不需要实时性能,但我确实需要它作为响应,尽可能使用尽可能less的CPU时间。 上面的代码可以在不到一毫秒的时间内被调用并返回。 实际上在我的开发机器上,时间差显示为0ms。 我不相信性能计数器的响应速度。

如果您好奇,我的软件正在收集一些项目,CPU,内存,事件日志项目等,这些项目都需要收集和存储在SQL CE中,在下一次民意测验,1秒之前。 每个任务,项目,但是是在自己的线程,以方便这一点。

另外,上面的代码没有被优化,你会注意到我还没有评论它。 原因是我想在优化之前确定它是正确的

更新1

按照我的做法,我删除了额外的“系统”时间段,因为它不是必需的,并且修改了检索“CPU使用率”的行并适当地进行了转换。

 int cpuUsage = (int)(((sysKernelDifferenceTs.Add(sysUserDifferenceTs).Subtract(sysIdleDifferenceTs).TotalMilliseconds) * 100.00) / sysKernelDifferenceTs.Add(sysUserDifferenceTs).TotalMilliseconds); 

虽然我仍然不确定这个公式。 虽然它似乎是非常准确的,但它有时会返回一个负数,这就是为什么我乘以-1,如果是这样的话。 毕竟,没有这样的事情-2%的CPU使用率等

更新2

所以我做了一个简单的testing使用“System.Diagnostics.PerformanceCounter”。 虽然令人难以置信的方便,并做到了它打算做什么,但确实造成开销。

这是我的观察:

  • 性能计数器花了很长时间才能初始化。 在我的i7 2.6 Ghz大约三秒钟的时间。
  • 性能计数器似乎也仅仅通过使用它而增加了大约5MB的RAM使用量。 我的意思是:用上面的代码,我的应用程序最大可以达到7.5MB RAM。 性能计数器“开始”在12.5MB。
  • 在5秒的时间内,我的线程运行了5次 – 每秒一次,我的应用程序的内存增长了1 MB,这个增加与时间一致,尽pipe在我的情况下它确实平稳了3-4MB以上开始。 所以,在我的应用程序通常是7.5MB内存与上面的代码,电脑代码在16.5 MB内存 – 平均增加了9MB以上的代码。 注意:上面的代码不会导致这个增加。

因此,如果您的应用程序是以资源使用和时间安排为关键的方式构build的,则由于这些原因,我build议不要使用性能计数器。 否则,继续前进,因为它没有任何混乱的工作。

至于我的应用程序,性能计数器将不利于我的软件的目的。

我认为你的公式中有一个错误。 你想基本上这样计算CPU使用率:

 CPU Usage = coreelTimeDiff + UserTimeDiff -------------------------------------------- coreelTimeDiff + UserTimeDiff + IdleTimeDiff 

因此,你的代码快速修改如下:

  // TimeSpan system = syscoreelDiffenceTs.Add(sysUserDiffenceTs); //Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds); TimeSpan totaltime = syscoreelDiffenceTs.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计数器调用,但也许不会)。 我不知道为什么你不使用性能计数器。 “%处理时间”计数器是一个即时样本计数器,不需要计算以前结果的差异。 (每个逻辑CPU有一个)。 使用PDH帮助程序功能而不是传统的注册表项apis来获取它。 你可以从一个非托管的C / C ++ DLL中导出一个“GetCpuUsage”函数回到你的C#代码。 但是我不知道为什么你不能从P#调用C#中的PDH函数。 我不知道你说的这个开销。 我不确定我是否理解你提到“延迟调用下一个结果”。