Click here to Skip to main content
Click here to Skip to main content

High-Performance Timer in C#

By , 29 Jul 2002
 

UML Image

Introduction

In some applications exact time measurement methods are very important. The often used Windows API method GetTickCount() retrieves the number of milliseconds that have elapsed since the system was started, but the GetTickCount() function only archieve resolutions of 1ms and on the other side they are very imprecise.

So, for exact time measurement we should find another method.

High resolution timing is supported in Win32 by the QueryPerformanceCounter() and QueryPerformanceFrequency() API methods. This timer functions has much better resolution than the "standard" millisecond-based timer calls, like the GetTickCount() method. On the other side there is also a little bit overhead when calling this "unmanaged" API methods from C#, but it's better than using the very imprecise GetTickCount() API function.

The first call, QueryPerformanceCounter(), queries the actual value of the high-resolution performance counter at any point. The second function, QueryPerformanceFrequency(), will return the number of counts per second that the high-resolution counter performs. To retrieve the elapsed time of a code section you have to get the actual value of the high-resolution performance counter immediately before and immediately after the section of code to be timed. The difference of these values would indicate the counts that elapsed while the code executed.

The elapsed time can be computed then, by dividing this difference by the number of counts per second that the high-resolution counter performs (the frequency of the high-resolution timer).

duration = (stop - start) / frequency

For more information about QueryPerformanceCounter and QueryPerformanceFrequency read the documentation on MSDN.

The Code

The following class implements the functionality of the QueryPerformanceCounter() and QueryPerformanceFrequency() API methods.

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace Win32
{
    internal class HiPerfTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(
            out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(
            out long lpFrequency);

        private long startTime, stopTime;
        private long freq;

        // Constructor
        public HiPerfTimer()
        {
            startTime = 0;
            stopTime  = 0;

            if (QueryPerformanceFrequency(out freq) == false)
            {
                // high-performance counter not supported
                throw new Win32Exception();
            }
        }

        // Start the timer
        public void Start()
        {
            // lets do the waiting threads there work
            Thread.Sleep(0);

            QueryPerformanceCounter(out startTime);
        }

        // Stop the timer
        public void Stop()
        {
            QueryPerformanceCounter(out stopTime);
        }

        // Returns the duration of the timer (in seconds)
        public double Duration
        {
            get
            {
                return (double)(stopTime - startTime) / (double) freq;
            }
        }
    }
}

This class is very simple to use. Just create an instance of HiPerfTimer, call Start() to start timing and call Stop() to stop timing. To retrieve the elapsed time, just call the Duration() function and you will get the elapsed time.

The following sample should explain that.

HiPerfTimer pt = new HiPerfTimer();     // create a new PerfTimer object
pt.Start();                             // start the timer
Console.WriteLine("Test\n");            // the code to be timed
pt.Stop();                              // stop the timer
Console.WriteLine("Duration: {0} sec\n", 
     pt.Duration); // print the duration of the timed code

The following image shows the output of this sample on my system.

Sample Output

History

  • 26.07.2002 - posted (first version)
  • 29.08.2002 - added some code for more robustness of the class

Bugs and comments

If you have any comments or find some bugs, I would love to hear about it and make it better.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Daniel Strigl
Austria Austria
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberBesic Denis24 Apr '13 - 2:58 
SuggestionThis code is obsolete in .NET 2.0 and above [modified]memberPavel Vladov17 Jul '12 - 22:18 
GeneralMy vote of 1memberhsnfrz25 May '12 - 0:51 
QuestionHelp ??????!!!!!!!! About the time calculatedmemberYanbei20 Jan '12 - 7:01 
GeneralMy vote of 5memberBig D4 Feb '11 - 8:20 
GeneralMSDN remarks about using this High Performance TimermemberMember 399685330 Oct '10 - 23:51 
GeneralRe: MSDN remarks about using this High Performance TimermemberJay R. Wren17 May '11 - 5:45 
GeneralMy vote of 5memberJibrohni12 Jul '10 - 1:35 
Questiontimer code in c# to call in a method which id dynamic..ie not static??membermerryjoy00012 Feb '09 - 0:38 
QuestionIs it possible to use this and trigger an Event?memberm.otte28 Jan '09 - 4:00 
AnswerRe: Is it possible to use this and trigger an Event?memberNortuRE21 Aug '10 - 22:05 
Generalnice classmemberEl Corazon7 Sep '08 - 8:40 
GeneralGarbage Colection in .NETmemberNguyen Thanh Luc22 May '08 - 17:22 
GeneralSystem.Diagnostics.Stopwatch classmemberMach0055 Apr '07 - 23:49 
GeneralSome CorrectionsmemberCobaltSoftware27 Mar '07 - 21:43 
GeneralGotcha's to watch out formemberKodiak737 Feb '07 - 22:20 
Hi,
 
There a couple of gotcha's you have to watch out for when using Query... API.
 
First, and most important is that on some platforms (namely mobile platforms, but also some servers too), the frequecy can change dynamically during executation of your code. If this happens, then you'll need to take this into account in more complicated way.
 
Second, is the question of Multi-core. Your thread may begin timing on one core and then finish on another core. If you are using the classic RDTSC method (Read TimeStamp) then you can be in big trouble because the clocks between cores are not synchronized and definitely start at different times.
 
QueryPerformanceCounter is supposed to take this into account. However if you read the fine print in MSDN, there seems to suggest that this method is not guaranteed either.
 
In general, when I'm trying to get precise measurements, I will use SetThreadAffinity (don't remember the C# equivalent off top of my head) to tie the thread to a single core and then measure. If you have multiple threads involved in the part you are timing, then well it gets more complicated....
 
Aaron
GeneralMeasurementmemberGary Kirkham7 May '06 - 2:00 
GeneralRe: MeasurementmemberSOUL_REAPER26 Dec '07 - 4:14 
GeneralSeems pretty consistent to me!membersklett11 Apr '06 - 13:49 
GeneralA clarification of the Sleep(0) call in Start()memberDrGary833 Jan '06 - 9:32 
GeneralStopwatch class from .net 2.0 framework ported .net 1.1memberPaul Welter30 Jun '05 - 19:50 
GeneralErrors using codememberperkash7 Apr '05 - 0:14 
GeneralRe: Errors using codesussAnonymous29 Sep '05 - 8:55 
GeneralRe: Errors using codememberRi Qen-Sin13 Sep '07 - 4:41 
GeneralParameters should be ref longmemberaxelriet21 Feb '05 - 16:50 
GeneralRe: Parameters should be ref longsussAnonymous18 Mar '05 - 3:39 
GeneralRe: Parameters should be ref longmemberaxelriet18 Mar '05 - 7:13 
QuestionWhat is this returning?memberjobobner6 Jan '05 - 4:52 
AnswerRe: What is this returning?memberSander van Driel17 Jan '05 - 7:26 
GeneralRe: What is this returning?memberBig D7 Feb '11 - 4:15 
GeneralInaccurate Timer durationmemberJoseph McGowan3 Dec '04 - 4:10 
GeneralRe: Inaccurate Timer durationsussAnonymous12 Jan '05 - 8:28 
GeneralRe: Inaccurate Timer durationmemberLiu Junfeng5 Apr '05 - 3:04 
GeneralRe: Inaccurate Timer durationmemberSuperMegaProg8 Mar '06 - 7:45 
GeneralRe: Inaccurate Timer durationmemberBrian Clifton11 May '07 - 11:04 
GeneralRe: Inaccurate Timer durationmembermbelshe13 Aug '07 - 11:05 
GeneralRe: Inaccurate Timer durationmemberBrian Clifton26 Sep '07 - 10:36 
GeneralOptimizationsussAnonymous28 Sep '04 - 6:16 
GeneralRe: OptimizationsussAnonymous28 Sep '04 - 6:18 
GeneralAdding a new propery for split timingmemberjimboc426 Apr '04 - 6:01 
GeneralUsing this in a GPL applicationmemberBjornar Henden18 Sep '03 - 11:24 
GeneralRe: Using this in a GPL applicationmemberDaniel S.11 Oct '03 - 2:34 
GeneralRe: Using this in a GPL applicationmemberBjornar Henden11 Oct '03 - 2:52 
GeneralEXCELLENTmembereggie527 Jul '03 - 20:51 
GeneralRe: EXCELLENTmemberDaniel S.16 Sep '03 - 21:52 
GeneralRe: EXCELLENTmemberJaime Olivares29 Oct '05 - 8:36 
GeneralFor Windows CE.NETmemberFrank Dzaebel25 Jul '03 - 4:23 
GeneralRe: For Windows CE.NETmemberDaniel S.25 Jul '03 - 4:54 
GeneralTimer adjustmentsmemberDean Wyant25 Jun '03 - 17:22 
GeneralCorrectnessmemberRob Walker28 Mar '03 - 5:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 30 Jul 2002
Article Copyright 2002 by Daniel Strigl
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid