使用PerformanceCounter.NextValue时的高CPU

时间:2015-08-19 21:40:25

标签: c# performance performancecounter

我们为企业应用程序创建了一个监控应用程序,用于监控我们的应用程序性能计数器。我们监控几个系统计数器(内存,CPU)和10个左右的自定义性能计数器。我们有7或8个exes,我们每隔几秒检查80个计数器。

一切都很有效,除非我们在计数器上循环cpu受到打击,15%左右在我的相当不错的机器上,但在其他机器上我们看到它要高得多。我们希望我们的监控应用程序在后台独立运行以查找问题,而不是占用大量的CPU。

这可以通过这个简单的c#类轻松复制。这将加载所有进程并为每个进程获取Private Bytes。我的机器有150个进程。 CallNextValue需要1.4秒左右和16%cpu

class test
{
    List<PerformanceCounter> m_counters = new List<PerformanceCounter>();

    public void Load()
    {
        var processes = System.Diagnostics.Process.GetProcesses();
        foreach (var p in processes)
        {
            var Counter = new PerformanceCounter();
            Counter.CategoryName = "Process";
            Counter.CounterName = "Private Bytes";
            Counter.InstanceName = p.ProcessName;

            m_counters.Add(Counter);
        }
    }

    private void CallNextValue()
    {
        foreach (var c in m_counters)
        {
            var x = c.NextValue();              
        }
    }
}

在Windows中的Perfmon.exe中执行同样的操作并添加计数器进程 - 所有进程选择的私有字节我看到几乎没有占用CPU,它也绘制了所有进程。

那么Perfmon如何获得价值?是否有更好/不同的方式在c#中获得这些性能计数器?

我尝试使用RawValue而不是NextValue,我没有看到任何差异。

我在c ++中使用过Pdh调用(PdhOpenQuery,PdhCollectQueryData,...)。我的第一次测试看起来似乎没有这些在cpu上更容易,但我还没有创建一个好样本。

2 个答案:

答案 0 :(得分:0)

我对.NET性能计数器API不太熟悉,但我对这个问题有所猜测。

Windows内核实际上没有API来获取有关一个进程的详细信息。相反,它有一个API,可以调用&#34;获取有关所有进程的所有信息&#34;。这是一个相当昂贵的API调用。每次为某个计数器执行c.NextValue()时,系统都会进行该API调用,丢弃99%的数据,并返回有关您询问的单个进程的数据。

PerfMon.exe使用相同的PDH API,但它使用通配符查询 - 它创建一个查询,一次获取所有进程的数据,因此它基本上每秒只调用一次c.NextValue()称之为N次(其中N是进程数)。它获得了大量数据(所有进程的数据),但扫描这些数据相对便宜。

我不确定.NET性能计数器API是否支持通配符查询。 PDH API确实如此,执行一个通配符查询要比执行大量单实例查询要便宜得多。

答案 1 :(得分:0)

很抱歉我的回复很长,但我现在才发现你的问题。无论如何,如果有人需要额外的帮助,我有一个解决方案:

我已经对我的自定义流程进行了一些研究,并且当我们有一个像

这样的代码片段时,我已经明白了
    PerformanceCounter ourPC = new PerformanceCounter("Process", "% Processor time", "processname", true);
    ourPC.NextValue();

然后我们的性能计数器的NextValue()会显示(逻辑核心的数量*进程的任务管理器cpu负载)值,这是合乎逻辑的事情,我想。

所以,你的问题可能是你在任务管理器中有轻微的CPU负载,因为它知道你有一个多核CPU,虽然性能计数器按上面的公式计算它。

我为您的问题找到了一种(一种不同的)可能的解决方案,因此您的代码应该像这样重写:

private void CallNextValue()
{
    foreach (var c in m_counters)
    {
        var x = c.NextValue() / Environment.ProcessorCount;              
    }
}

无论如何,我不建议您使用Environment.ProcessorCount,尽管我已经使用过它:我只是不想在我的简短代码段中添加太多代码。

你可以看到一个很好的方法来找出多少逻辑核心(是的,如果你有核心i7,例如,你必须计算逻辑核心,而不是物理核心)你有没有在系统中如果你& #39;请点击此链接:

How to find the Number of CPU Cores via .NET/C#?

祝你好运!