【发布时间】:2011-04-23 05:45:01
【问题描述】:
要启动并运行性能计数器,最少需要多少 C# 代码?
我只是想测量代码中两点之间的 CPU 周期数和/或时间。我浏览了网络上所有的华夫饼,但对于这样一个微不足道的任务来说,代码似乎比所需的要多得多。我只想快速启动并运行测量,并更多地专注于我正在做的事情。
【问题讨论】:
标签: c# performancecounter
要启动并运行性能计数器,最少需要多少 C# 代码?
我只是想测量代码中两点之间的 CPU 周期数和/或时间。我浏览了网络上所有的华夫饼,但对于这样一个微不足道的任务来说,代码似乎比所需的要多得多。我只想快速启动并运行测量,并更多地专注于我正在做的事情。
【问题讨论】:
标签: c# performancecounter
我认为您不需要为此设置性能计数器。您需要的不仅仅是从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);
}
}
}
当然,该进程需要适当的权限才能访问您需要的性能计数器。
【讨论】:
我喜欢可以采用任何代码块并用秒表分析代码包装它以测量执行它所花费的时间的东西:
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");
【讨论】:
没有简单的方法可以在 .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
}
}
这使您可以简单地将要监视的代码封装在 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 示例中显示),但这应该可以让您开始。
【讨论】: