使用C#和WMI计算的CPU使用率错误

时间:2010-12-15 21:38:07

标签: c# wmi cpu-usage

这是我的功能,用于枚举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;
}

修改

我发现我的功能都错了。

我正在为最佳工作解决方案赢得奖励。解决方案需要适用于本地和远程系统,并且应该很快。

3 个答案:

答案 0 :(得分:2)

以下是带有性能计数器的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 你不能真的比这更快,原因在文章中解释。基本上,您必须读取该值两次以使其正确,因此您需要在样本之间等待。

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

答案 1 :(得分:1)

        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);
            }
        }

答案 2 :(得分:0)

这是一个经过测试和验证的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;
    }

}