【问题标题】:Wrong calculated CPU usage using C# and WMI使用 C# 和 WMI 计算的 CPU 使用率错误
【发布时间】:2010-12-15 21:38:06
【问题描述】:

这是我在 windows 框中枚举进程并计算每个进程的 CPU 使用百分比的函数,但结果不正确。

CPU 使用率加起来不是 100%,但更像是 120% 或 130%,我不知道我做错了什么。 似乎它可以计算各种应用程序(如 firefox、VS2010、office 等)的正确 CPU 使用率,但系统空闲进程存在问题。

public List<ProcInfo> GetRunningProcesses()
{
    List<ProcInfo> allProcesses = new List<ProcInfo>();
    UInt64 currentProcessCpuTime = 0;
    UInt64 allProcessCpuTime = 0;

    SelectQuery wmiQuery = new SelectQuery("SELECT Name, Description, ProcessId, KernelModeTime, UserModeTime FROM Win32_Process");
    ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(connectionScope, wmiQuery);
    ManagementObjectCollection moc = oSearcher.Get();

    foreach (ManagementObject mo in moc)
    {
        allProcessCpuTime += (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"];
    }

    foreach (ManagementObject mo in moc)
    {
        currentProcessCpuTime = (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"];
        allProcesses.Add(new ProcInfo((string)mo["Name"], (string)mo["Description"], (UInt32)mo["ProcessId"], (currentProcessCpuTime / (double)allProcessCpuTime * 100));
    }

    return allProcesses;
}

编辑:

我发现我的功能全错了。

我开始赏金寻找最佳可行的解决方案。解决方案需要适用于本地和远程系统,并且应该很快。

【问题讨论】:

  • 如果不强制使用 WMI,还有另一种使用性能计数器的方法:stackoverflow.com/questions/278071/…
  • 循环迭代之间的值是否可能发生变化?也就是说,一个项目在循环的一个点具有处理器时间,然后另一个在下一次迭代中获得时间?只是一个想法......
  • 我同意 Mark 的观点 - 您应该对性能指标进行快照(如果可以最大限度地同时获得所有指标,最好同时进行),然后对它们进行数学计算。他们处于波动状态。
  • @Simon Mourier:我需要查询远程机器,我可以使用 perf counters 吗? @Mark Avenius:据我所知,当我调用 oSearcher.Get();这些值是一成不变的,不会刷新和更改。
  • 当然可以,如果您有适当的权利(与 WMI 或其他任何东西一样,安全性有点一致:-)。

标签: c# wmi cpu-usage


【解决方案1】:

这是带有性能计数器的 C# 代码:

public static void DumpProcessesCpu(string machineName)
{
    List<PerformanceCounter> counters = new List<PerformanceCounter>();

    foreach (Process process in Process.GetProcesses(machineName))
    {
        PerformanceCounter processorTimeCounter = new PerformanceCounter(
            "Process",
            "% Processor Time",
            process.ProcessName,
            machineName);

        processorTimeCounter.NextValue();
        counters.Add(processorTimeCounter);
    }

    Thread.Sleep(1000); // 1 second wait, needed to get a sample

    foreach (PerformanceCounter processorTimeCounter in counters)
    {
        Console.WriteLine("Process:{0} CPU% {1}",
            processorTimeCounter.InstanceName,
            processorTimeCounter.NextValue());
    }
}

灵感来自这里:http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx 你真的不能比这更快,原因在文章中解释。基本上,您必须读取该值两次才能使其正确,因此您需要在样本之间等待。

但是,根据您想要做的事情,例如,假设您想编写一个“远程任务管理器”,您可以在后台任务(线程)中编写所有这些代码并定期更新值,以便最终用户不会真正看到样本之间的延迟。

【讨论】:

    【解决方案2】:
            var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process");
            var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value);
            Thread.Sleep(570); // can be an arbitrary number
            var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value);
    
            var total = run2["_Total"] - run1["_Total"];
    
            foreach (var kvp in run1)
            {
                var proc = kvp.Key;
                var p1 = kvp.Value;
                if (run2.ContainsKey(proc))
                {
                    var p2 = run2[proc];
                    Console.WriteLine("{0}: {1:P}", proc, (double)(p2 - p1) / total);
                }
            }
    

    【讨论】:

    【解决方案3】:

    这是一个经过测试和验证的 C# 代码块,感谢 fejesjoco,我使用了他的代码并进行了测试以使其正常工作。

    public class CPUUtilizationTests
    {
    
        [Test]
        public void TestPercentProcessorTime()
        {
            Assert.That(PercentProcessorTime("Idle"), Is.Not.GreaterThan(100.0));
        }
    
        public float PercentProcessorTime(string processName)
        {
            var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process");
            var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo);
            System.Threading.Thread.Sleep(1000); // can be an arbitrary number
            var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo);
    
            if (!run2.ContainsKey(processName)) throw new Exception(string.Format("Process not found: {0}", processName));
    
            string percentageProcessorTime = "PercentProcessorTime";
            string total = "_Total";
    
            ulong percentageDiff = (ulong)run2[processName][percentageProcessorTime] - (ulong)run1[processName][percentageProcessorTime];
            ulong totalDiff = (ulong)run2[total][percentageProcessorTime] - (ulong)run1[total][percentageProcessorTime];
    
            return ((float)percentageDiff / (float)totalDiff)*100.0f;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 2012-01-06
      • 2010-11-19
      相关资源
      最近更新 更多