如何在System.Diagnostics.Stopwatch中使用AverageTimer32和AverageBase性能计数器?

当我执行以下程序并查看性能计数器时,结果对我来说没有意义。 平均值为零,当我期望~0.1或~100时,最小/最大值为~0.4。

我的问题是什么?

class Program { const string CategoryName = "____Test Category"; const string CounterName = "Average Operation Time"; const string BaseCounterName = "Average Operation Time Base"; static void Main(string[] args) { if (PerformanceCounterCategory.Exists(CategoryName)) PerformanceCounterCategory.Delete(CategoryName); var counterDataCollection = new CounterCreationDataCollection(); var avgOpTimeCounter = new CounterCreationData() { CounterName = CounterName, CounterHelp = "Average Operation Time Help", CounterType = PerformanceCounterType.AverageTimer32 }; counterDataCollection.Add(avgOpTimeCounter); var avgOpTimeBaseCounter = new CounterCreationData() { CounterName = BaseCounterName, CounterHelp = "Average Operation Time Base Help", CounterType = PerformanceCounterType.AverageBase }; counterDataCollection.Add(avgOpTimeBaseCounter); PerformanceCounterCategory.Create(CategoryName, "Test Perf Counters", PerformanceCounterCategoryType.SingleInstance, counterDataCollection); var counter = new PerformanceCounter(CategoryName, CounterName, false); var baseCounter = new PerformanceCounter(CategoryName, BaseCounterName, false); for (int i = 0; i < 500; i++) { var sw = Stopwatch.StartNew(); Thread.Sleep(100); sw.Stop(); Console.WriteLine(string.Format("t({0}) ms({1})", sw.Elapsed.Ticks, sw.Elapsed.TotalMilliseconds)); counter.IncrementBy(sw.Elapsed.Ticks); baseCounter.Increment(); } Console.Read(); } } 

性能计数器屏幕截图 性能计数器屏幕截图http://friendfeed-media.com/50028bb6a0016931a3af5122774b56f93741bb5c

System.Diagnostics API包含一个非常微妙的混乱源:System.Diagnostics’ticks’与DateTime或TimeSpan’ticks’不同!

如果你使用StopWatch.ElapsedTicks而不是StopWatch.Elapsed.Ticks,它应该工作。

该文档包含有关此内容的更多信息。

Mark Seemann解释了问题的混乱来源,但我想提供一些额外的信息。

如果要从TimeSpan而不是Stopwatch设置AverageTimer32性能计数器,可以执行以下转换:

 var performanceCounterTicks = timeSpan.Ticks*Stopwatch.Frequency/TimeSpan.TicksPerSecond; averageTimerCounter.IncrementBy(performanceCounterTicks); averageTimerCounterBase.Increment(); 

这是一个老线程,但我想我会插话。微软的某个人告诉我,在使用性能计数器时我不应该使用TimeSpanStopWatchDateTime 。 相反,他建议在我的项目中添加以下本机方法:

 internal static class NativeMethods { [DllImport("Kernel32.dll")] public static extern void QueryPerformanceCounter(ref long ticks); } 

在递增计数器时,他建议这样做:

 public void Foo() { var beginTicks = 0L; var endTicks = 0L; NativeMethods.QueryPerformanceCounter(ref beginTicks); // Do stuff NativeMethods.QueryPerformanceCounter(ref endTicks); this.Counter.IncrementBy(endTicks - beginTicks); this.BaseCounter.Increment(); }