2010-10-09 22 views
9

使性能计数器启动并运行的最小C#代码量是多少?最简单的可能性能计数器示例

我只是想测量我的代码中两个点之间的CPU周期数和/或时间。我已经浏览了网页上的所有华夫饼,但它看起来像WAY更多的代码比这样一个琐碎的任务所需的代码。我只想快速测量并运行,并将更多精力放在我正在进行的工作上。

回答

26

我不认为你需要一个性能计数器。你是否需要超过从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); 
     } 
    } 
} 

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

+0

也许我应该阐述一下,我试图实现一个简单的正则表达式引擎。秒表会精确到足够吗? – 2010-10-09 09:21:39

+0

@保罗马修斯 - 它会好的。秒表分辨率为 – Oded 2010-10-09 09:24:44

+1

如果您正在询问您的代码,那么测量代码的性能就足够准确。如果要测量性能,请记住在Visual Studio之外的版本模式下运行代码。另外,我建议您使用分析器来衡量性能,它会告诉您更多关于代码性能的信息,而不仅仅是简单的点对点时间测量。 – driis 2010-10-09 09:27:18

2

有没有微不足道的方式来得到这个启动和运行在.NET中。但是,我发现的最简单的方法是在企业库的基础上构建,它提供了一些开箱即用的性能计数器功能。例如:the Performance Counter Handler

企业库还为您提供了一些功能,可以更轻松地管理性能计数器的安装。

此外,它让你建立在它之上的话,你可以创建一个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 
    } 
} 

这可以让你简单地封装代码要在监视使用块 - 并专注于您实际需要处理的代码,而不必担心所有性能计数器基础结构。

要做到这一点,你需要创建一个可重用的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例所示),但是这应该让你开始。

+0

根据我现在看到的评论,看起来或许你的问题更多地涉及到测量代码,而不是特别针对性能计数器。我总是从性能计数器的角度来看这个问题 - 如果你不需要这个,我同意Stopwatch是最简单的方法。 – 2010-10-09 09:29:10

+0

我最后一次使用性能计数器是在Delphi中,所以也许术语有所改变。对不起,如果我带领你走上花园的道路:) – 2010-10-09 09:38:11

-1

您可以使称为计数器的静态变量长,并使一个线程增加它。您可以随时启动并中止该线程,只要您需要和/或需要。在线程运行时,可以使用静态计数器的整数值来测量代码中CPU周期数和/或两点之间的时间。线程和静态计数器技术可以与Stopwatch Start Stop重新启动重置方法和ElapsedTicks属性的使用进行比较。

+1

听起来像一个有趣的方法。我真的不明白如何使用另一个线程来衡量CPU周期会给我们一个准确的测量?我们是否确保该线程占用与我们测量的线程完全相同的CPU时间片? – 2013-10-06 21:39:41

6

我喜欢的东西,可以采取任何代码块,并用秒表剖析代码包装它来测量时间花在执行它:

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"); 
+0

确实非常酷! – 2015-03-10 02:01:15