最简单的性能计数器示例

16

如何编写最简单的C#代码来启动性能计数器?

我只想测量我的代码中两个时间点之间的CPU周期数和/或时间。我已经浏览了很多相关网页,但似乎对于这样一个微不足道的任务,需要的代码远比实际需要的要多得多。我只是想快速地启动一个测量,并更加专注于我的工作。

3个回答

33

我认为你不需要性能计数器。你是否需要比从StopWatch获取的时间更多的信息?它非常准确。

Stopwatch watch = Stopwatch.StartNew();

// Do work

watch.Stop();
// elapsed time is in watch.Elapsed

然而,回答你实际提出的问题:如果你只想查询现有的计数器,那么这实际上非常简单。以下是完整示例:

using System;
using System.Diagnostics;
using System.Linq;

static class Test
{
    static void Main()
    {
        var processorCategory = PerformanceCounterCategory.GetCategories()
            .FirstOrDefault(cat => cat.CategoryName == "Processor");
        var countersInCategory = processorCategory.GetCounters("_Total");

        DisplayCounter(countersInCategory.First(cnt => cnt.CounterName == "% Processor Time"));
    }

    private static void DisplayCounter(PerformanceCounter performanceCounter)
    {
        while (!Console.KeyAvailable)
        {
            Console.WriteLine("{0}\t{1} = {2}",
                performanceCounter.CategoryName, performanceCounter.CounterName, performanceCounter.NextValue());
            System.Threading.Thread.Sleep(1000);
        }
    }
}

当然,该过程需要适当的权限才能访问您需要的性能计数器。

也许我应该详细说明一下,我正在尝试实现一个简单的正则表达式引擎。秒表的精度是否足够呢? - Paul Matthews
1
@Paul Matthews - 没问题。秒表的分辨率是以滴答为单位的。 - Oded
1
如果你想要衡量代码的性能,它足够准确了。记得在测量性能时,在 Visual Studio 之外以 Release 模式运行代码。另外,我建议你使用分析器来衡量性能,它会告诉你比简单的点对点时间测量更多关于你的代码性能的信息。 - driis
Q: 使用性能计数器的最简单方法是什么? A:别用!(哈哈 :) - yoyo
有史以来从未被问过的问题的最佳答案。 - user1228
这是一个错误的例子:严重程度代码描述项目文件行抑制状态 错误CS0103:在当前上下文中不存在名称“PerformanceCounterCategory”。 MyPerfCounter C:\Users\user\Documents\Visual Studio 2017\Projects\MyPerfCounter\MyPerfCounter\Program.cs 9 活动的 - Draif Kroneg

11

我喜欢能够将任何代码块包装在秒表分析代码中,以测量执行它所花费的时间:

    using System.Diagnostics;
    using System.Threading;

    public static T Profile<T>(Func<T> codeBlock, string description = "")
    {
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        T res = codeBlock();
        stopWatch.Stop();
        TimeSpan ts = stopWatch.Elapsed;
        const double thresholdSec = 2;
        double elapsed = ts.TotalSeconds;
        if(elapsed > thresholdSec)
          System.Diagnostics.Debug.Write(description + " code was too slow! It took " +
             elapsed + " second(s).");
        return res;
    }

然后像这样调用它:

    Profile(() => MyObj.MySlowMethod());

或者:

    Profile(() => MyObj.MySlowMethod(), "I can explain why");

3

在.NET中,没有简单的方法来启动和运行此功能。然而,我发现最简单的方法是在企业库的基础上构建,该库提供了一些开箱即用的功能来处理性能计数器。例如:性能计数器处理程序

企业库还提供了一些功能,更容易地管理性能计数器的安装。

此外,它让您在其基础上构建,因此您可以创建一个AvergeTimeMeter,使您只需执行以下操作:

private static EnterpriseLibraryPerformanceCounter averageRequestTimeCounter = PerformanceCounterManager.GetEnterpriseLibraryCounter(MadPerformanceCountersListener.AverageRequestTime);
private static EnterpriseLibraryPerformanceCounter averageRequestTimeCounterBase = PerformanceCounterManager.GetEnterpriseLibraryCounter(MadPerformanceCountersListener.AverageRequestTimeBase);

public void DoSomethingWeWantToMonitor()
{
    using (new AverageTimeMeter(averageRequestTimeCounter, averageRequestTimeCounterBase))
    {
        // code here that you want to perf mon
    }
}

这样,您只需在 using 块中封装要监视的代码即可,无需担心所有性能计数器基础设施,而可以专注于实际想要处理的代码。
为此,您需要创建一个可重用的 AverageTimeMeter 类,如下所示:
public sealed class AverageTimeMeter : IDisposable
{
    private EnterpriseLibraryPerformanceCounter averageCounter;
    private EnterpriseLibraryPerformanceCounter baseCounter;
    private Stopwatch stopWatch;
    private string instanceName;

    public AverageTimeMeter(EnterpriseLibraryPerformanceCounter averageCounter, EnterpriseLibraryPerformanceCounter baseCounter, string instanceName = null)
    {
        this.stopWatch = new Stopwatch();
        this.averageCounter = averageCounter;
        this.baseCounter = baseCounter;
        this.instanceName = instanceName;
        this.stopWatch.Start();
    }

    public void Dispose()
    {
        this.stopWatch.Stop();
        if (this.baseCounter != null)
        {
            this.baseCounter.Increment();
        }

        if (this.averageCounter != null)
        {
            if (string.IsNullOrEmpty(this.instanceName))
            {
                this.averageCounter.IncrementBy(this.stopWatch.ElapsedTicks);
            }
            else
            {
                this.averageCounter.SetValueFor(this.instanceName, this.averageCounter.Value + this.stopWatch.ElapsedTicks);
            }
        }
    }

}

您需要注册性能计数器(在EntLib示例中显示),但这应该可以让您开始。


根据我现在看到的评论,似乎你的问题更多地与代码测量有关,而不是特别针对性能计数器。我总是从性能计数器的角度来具体提问 - 如果你不需要它,那么我同意Stopwatch是最简单的方法。 - Steve Michelotti
我上一次使用性能计数器是在Delphi中,所以术语可能有些变化。如果我让你走了弯路,对不起 :) - Paul Matthews

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接