2009-10-10 1 views
22

다음 프로그램을 실행하고 성능 카운터를 보면 결과가 나에게 적합하지 않습니다. ~ 0.1 또는 ~ 100을 예상 할 때 평균값은 0이고 최소/최대 값은 ~ 0.4입니다.System.Diagnostics.Stopwatch에서 AverageTimer32 및 AverageBase 성능 카운터를 사용하는 방법?

내 문제는 무엇인가?

코드

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(); 
    } 
} 

성능 카운터 스크린 샷 Performance Counter Screenshot http://friendfeed-media.com/50028bb6a0016931a3af5122774b56f93741bb5c

답변

33

열고 System.Diagnostics API는 큰 혼란 꽤 미묘한 소스를 포함 System.Diagnostics 네임 '틱'은하지와 동일 DateTime 또는 TimeSpan '틱'!

StopWatch.Elapsed.Ticks 대신 StopWatch.ElapsedTicks을 사용하면 정상적으로 작동합니다.

documentation에 대한 자세한 내용이 나와 있습니다.

9

Mark Seemann은 문제의 혼란스러운 원인을 설명했지만 약간의 추가 정보를 제공하고자합니다.

당신이 TimeSpan 아니라 다음과 같은 변환을 수행 할 수있는 Stopwatch에서 AverageTimer32 성능 카운터를 설정하려면 :.

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

을 당신이 선택하지 않은 ((INT32를 캐스팅해야합니까 왜 .. : 카운터를 증가하면

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

, 그는이 같은 일을 권장 .)? performanceCounterTicks는 오랫동안 평가되며, 모든 값은 실제로 긴 숫자입니다. –

+0

@DavideIcardi : 감사합니다.'IncrementBy' 메서드의 서명이'Int64'을 받아들이므로 캐스트를 수행 할 필요가 없습니다. 코드에서 캐스트를 제거했습니다. –

+0

니스! 내가 무엇을 찾고 있었는지 맞아! – vtortola

0

이 오래된 스레드를,하지만 난 삐 소리라고 생각 I 성능 카운터로 작업 할 때 TimeSpan, StopWatch 또는 DateTime을 사용하지 말 것을 Microsoft의 누군가가 말했습니다. 대신, 그는 내 프로젝트에 다음과 같은 기본 방법을 추가 권장 :)

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(); 
} 
+1

그는 또한 이유를 밝혔습니까? 'StopWatch'는'QueryPerformanceCounter'에 대한 래퍼 일뿐입니다 (사용할 수없는 경우 폴백 포함). 'StopWatch.IsHighResolution'이 true이면'StopWatch.GetTimeStamp()'는'QueryPerformanceCounter'와 같습니다. – CodesInChaos

+0

그는 성능에 관한 Microsoft Patterns and Practices 책을 인용했습니다. 그의 추론은 같은 행동을 여러 번 할 때 가능한 한 적은 오버 헤드를 원했다는 것이 었습니다. 성능 카운터는 초당 여러 번 증가 할 수 있습니다. StopWatch를 사용하여 메소드의 성능을 측정하고 카운터를 증가시킬 때마다 StopWatch 오브젝트를 인스턴스화합니다. 그런 다음 스톱워치 개체를 가비지 수집해야합니다. 'QueryPerformanceCounter'를 직접 호출하여 중도를 없애고 Stopwatch 객체의 생성 및 콜렉션을 저장합니다. – RobV8R

+3

'StopWatch.GetTimeStamp()'는 정적 메소드이고'QueryPerformanceCounter'에 대한 씬 래퍼입니다.유일한 추가 비용은 시간이 지남에 따라 변하지 않는 정적 필드의 분기이므로 분기 예측이 잘 작동해야합니다. – CodesInChaos