2009-10-10 25 views
22

Khi tôi thực hiện chương trình sau đây và xem bộ đếm hiệu năng, kết quả không có ý nghĩa đối với tôi. Giá trị trung bình bằng không và giá trị min/max là ~ 0.4 khi tôi mong đợi ~ 0.1 hoặc ~ 100.Làm thế nào để sử dụng các bộ đếm hiệu năng AverageTimer32 và AverageBase với System.Diagnostics.Stopwatch?

Vấn đề của tôi là gì?

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 Ảnh chụp màn hình Performance Counter Screenshot http://friendfeed-media.com/50028bb6a0016931a3af5122774b56f93741bb5c

Trả lời

33

Các System.Diagnostics API chứa một nguồn khá tinh tế của sự nhầm lẫn lớn: System.Diagnostics 've' là không giống như DateTime hoặc TimeSpan 've'!

Nếu bạn sử dụng StopWatch.ElapsedTicks thay vì StopWatch.Elapsed.Ticks, nó sẽ hoạt động.

documentation chứa thêm thông tin về việc này.

9

Mark Seemann giải thích nguồn khó hiểu của vấn đề nhưng tôi muốn cung cấp thêm một chút thông tin bổ sung.

Nếu bạn muốn thiết lập AverageTimer32 hiệu suất của bạn truy cập từ một TimeSpan và không phải là một Stopwatch bạn có thể thực hiện việc chuyển đổi sau:.

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

Tại sao bạn cần đúc không được kiểm soát ((Int32) .. .)? performanceCounterTicks được đánh giá là dài, tất cả các giá trị thực sự là số dài. –

+0

@DavideIcardi: Cảm ơn bạn, bạn đúng rằng chữ ký của phương thức 'IncrementBy' chấp nhận một' Int64' do đó không cần thực hiện một dàn diễn viên. Tôi đã xóa đoạn trích khỏi mã. –

+0

Đẹp! đúng những gì tôi đang tìm kiếm! – vtortola

0

Đây là một chủ đề cũ, nhưng tôi nghĩ rằng tôi muốn kêu vang trong tôi được một người nào đó từ Microsoft nói rằng tôi không nên sử dụng TimeSpan, StopWatch hoặc DateTime khi làm việc với Bộ đếm hiệu suất. Thay vào đó, ông đề nghị bổ sung thêm các phương pháp tự nhiên sau đây để dự án của tôi:

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

Khi incrementing một bộ đếm, ông đề nghị làm như vậy như thế này:

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

Ông ấy cũng đưa ra lý do cho điều đó? 'StopWatch' chỉ là một trình bao bọc trên' QueryPerformanceCounter' (với dự phòng nếu nó không có sẵn). Nếu 'StopWatch.IsHighResolution' là true,' StopWatch.GetTimeStamp() 'tương đương với' QueryPerformanceCounter'. – CodesInChaos

+0

Ông trích dẫn một cuốn sách về Thực hành và Mẫu của Microsoft về Hiệu suất. Lý do của anh là bạn muốn càng ít chi phí càng tốt khi thực hiện cùng một hành động nhiều lần. Bộ đếm hiệu suất có thể được tăng lên nhiều lần mỗi giây. Bằng cách sử dụng một Đồng hồ bấm giờ, bạn đang khởi tạo đối tượng Đồng hồ bấm giờ mỗi lần bạn muốn đo hiệu suất của một phương thức và tăng bộ đếm. Các đối tượng Đồng hồ bấm giờ sau đó phải được thu thập rác. Bằng cách gọi trực tiếp 'QueryPerformanceCounter', bạn cắt bỏ người trung gian và lưu cấu trúc và bộ sưu tập đối tượng Đồng hồ bấm giờ. – RobV8R

+3

'StopWatch.GetTimeStamp()' là một phương thức tĩnh và một trình bao bọc mỏng trên 'QueryPerformanceCounter'.Chi phí bổ sung duy nhất là một nhánh trên một trường tĩnh không thay đổi theo thời gian, do đó dự đoán nhánh sẽ hoạt động khá tốt. – CodesInChaos

Các vấn đề liên quan