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

发布于 2024-10-07 15:44:03 字数 1274 浏览 0 评论 0原文

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

编辑:

我发现我的功能全部错误。

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

This is my function for enumerating processes on windows box and calculating percentage of CPU usage for each process but results are not correct.

CPU usage does't add up to 100% but more like to 120% or 130% and I don't know what I'm doing wrong.
It seems like it calculats right CPU usage for varoius apps like firefox, VS2010, office,.. but has problems with System Idle Process.

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

EDIT:

I found that my function is all wrong.

I'm starting a bounty for the best working solution. Solution needs to work for local and remote system and should be fast.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

四叶草在未来唯美盛开 2024-10-14 15:44:03

下面是带有性能计数器的 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());
    }
}

它的灵感来自于:https://learn.microsoft.com/en-us/archive/blogs/bclteam/how-to-read-performance-counters-ryan-byington
你真的不可能比这更快,文章中解释了原因。基本上,您必须读取该值两次才能正确,因此您需要在样本之间等待。

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

Here is a C# code with performance counters:

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

It's inspired from here: https://learn.microsoft.com/en-us/archive/blogs/bclteam/how-to-read-performance-counters-ryan-byington
You can't really be faster than this, the reason why is explained in the article. Basically, you'll have to read the value twice to get it right, so you need to wait between samples.

However, depending on what you want to do, for example, suppose you want to write a "remote task manager", you can code all this in a background task (thread) and regularly update the values so the end-user will not really see the delay between samples.

谁对谁错谁最难过 2024-10-14 15:44:03

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

}

Here is a C# block of code tested and validated and thanks to fejesjoco, I used his code and made the test to get it to work.

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

}
苍风燃霜 2024-10-14 15:44:03
        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);
            }
        }
        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);
            }
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文