Overview

This article describes a timer component that allows timing to be done to an accuracy of microseconds.

Introduction

One of the tasks in software development that is often overlooked is performance testing. Most of the time, code is designed to run fast and then tested to make sure that it really is. Whilst there are many ways to test performance and identify slow bits of code, it is quite often difficult to precisely locate or time, specific sections of the code. Using normal time functions, including timer tick functions is only accurate to milliseconds at best. Also, you don't want to have to copy library classes or lots of code around in order to simply time a piece of code. Because of this, I decided to write a general purpose timer that would:

Be able to time code to a resolution of a few microseconds.

Be very easy to use.

Background

In order to have a timer that has a resolution in the order of microseconds, there are 2 possibilities that I am aware of:

The RDTSC instruction: This is available on all Pentium and Athlon processors.

QueryPerformanceCounter: This is a Windows API call to a performance counter which is generally running at speeds well in excess of 1MHz.

Although the first option is the most accurate and fastest, I decided to use the second option because that is much more portable. QueryPerformanceCounter is supported on all Windows platforms, including Pocket PC devices.

The second requirement was for the timer to be very easy to use. It was fairly obvious to me that the timer should be a strongly named class so that it could be put in the GAC. This would make it very easy to include in an assembly. I also felt that it would be even easier to use if it was a component. That way, if timing was being done on a form (Windows or Web), the component could be dragged from the toolbox onto the page.

Public Methods in the StopWatch Component

The component is very simple to use and has 2 main methods:

Reset(): This resets the count to 0 and can be called anytime.

Trace(): This has 2 overloads. One takes no parameters, and just displays the elapsed time in the debug output window. The other takes a string as a parameter, and displays the string before displaying the time. The time is displayed as either microseconds (us), milliseconds (ms), or seconds (s), depending on the elapsed time.

Implementation

The code relies on the two API calls:

QueryPerformanceFrequency

QueryPerformanceCounter

These are defined in KERNEL.DLL on Windows platforms, and CoreDll.dll on the Pocket PC, and are called using P/Invoke as follows:

The Trace.WriteLine statement takes a considerable time to execute (milliseconds). As the code is at the moment, this would seriously affect the displayed times. In order to try and compensate for this, I decided to get the time after the Trace statement has executed and subtract this from the start time. This means that if you call Trace continuously, you will get times that are different by about 1 or 2 us instead of times that are different by milliseconds. Although this means the displayed time is not a true indication of the elapsed time, I felt that this behavior was more useful. Unfortunately, I could not reliably compensate for the QueryPerformanceCounter call, so continuous calls to Trace resulted in increasing times of about 1.4us on my PC. Most of this time is because of the P/Invoke overhead. The code for this is shown below:

The final part of the implementation is the deployment of the component. I wrote a batch file (as part of the build process) to copy the assembly to the Visual Studio directory and install it in the global assembly cache. This way, it can easily be added to the References and Component Toolbox. (In the Add References dialog, look for "Nethercott.Timing". And in the Add/Remove Items dialog in the Toolbox, look for "StopWatch".) Obviously, the component only has to be added once to the toolbox (e.g., under the Components tab) in order to be used on multiple solutions.

Using the Component

The component is very easy to use. There are two ways that it can be included. The easiest way is to drag the component from the toolbox onto a Windows or Web Form. The Reset() and Trace() methods can then be called as required in the code behind page. The other way to use the component is to include the component manually. This means adding a reference to the class, constructing the StopWatch object, and then calling the Reset() and Trace() methods as required. Although not absolutely necessary, it's probably a good idea to call Dispose() when the object is no longer required.

References

There are several other CodeProject articles on timing, and timer classes. Here are some of them:

This is a very detailed article that shows how you can include performance measures as part of your unit tests. It also shows how to limit the misleading effect of JIT compilation, garbage collection, and task switching, to make the results more reliable.

Comments and Discussions

I've been using this timer to evaluate performance. The first time the code runs it is very slow ... around 2 seconds. This is after compiling the code and running it for the first time in debug mode. After that the time it takes to add a transaction to the database decreases to around 60-80 milliseconds (ms) and stays there.

Is there a way to evaluate acceptable tolerances? Who is to say what is fast enough?

I suspect that the poor performance on the first transaction is for two main reasons:
a) The JIT compiler has to convert the code from MSIL to executable code. This only has to be done once however.
b) The database connection needs to be established. Subsequent transactions will use a cached (pooled) connection.

I would suggest having a look at Marc Clifton's article (the first link in the references on my article). He has a much more sophisticated solution, for automated testing, and covers some of the problems such as JIT compilation.

My only justification for the widely varying numbers is that if it says it has taken 2 seconds, it really has... and if the user is waiting for this transaction to complete they will see a 2 second delay.

As you can see, void Reset() should be renamed to void Start(), because the method is actually used to (re)start the timer.

The property double Timer_us clearly shows multiple errors. Because you use a non-specific property type, you have to a) resort to weird naming and b) specify the unit of time in the name. A better signature would be TimeSpan Current. Why Current? Because the property returns the elapsed time since start.

void Trace() and void Trace(string msg) should also return the elapsed time. The signatures should be changed to TimeSpan Trace() and TimeSpan Trace(string msg), respectively.
IMO, you should avoid writing to the trace log (or anything else) altogether. Just let the user decide what to do with the returned timing information. Maybe he wants to compute something like bytes/sec and show that on a statusbar? I'd just override the string ToString() method to provide a formatted string of the current time.

Thanks for the comments. It's always nice when people read your articles

I guess I could have called it Start instead of Reset, but you can call Reset as often as you like, whereas Start seems to suggest a one off operation. I suppose I could have called it Restart - I will probably change it to that on the next release.

The Timer_us property does break all sorts of naming rules; again I'll probably change that on the next release.

I put the Trace method in because I primarily designed this class to be a quick way to time things during development or debugging. That's also why I put it in the GAC.

Anyway, thanks for the suggestions, I'll try to incorporate them into the next release, which hopefully I will find some time to do soon - because I noticed some problems using it on the compact framework - which need to be fixed!

The guy's provided his time, expertise and code for free and you're worried about cosmetics? Screw the guidelines. And remember I say that having run a site just as big as this one. I'd rather have someone contribute something that has to be edited a bit than not to contribute because they don't have the time or desire to follow the "guidelines".

Tom Archer wrote:The guy's provided his time, expertise and code for free and you're worried about cosmetics? Screw the guidelines. And remember I say that having run a site just as big as this one
Ageed!

Tom Archer wrote: expertise and code for free and you're worried about cosmetics? Screw the guidelines. And remember I say that having run a site just as big as this one. I'd rather have someone contribute something that has to be edited a bit than not to contribute because they don't have the time or desire to follow the "guidelines".
Agreed!

But Tom, this site has matured, and if everybody contributed there own style of formatting, this site would be ugly, consistency is a good thing. I certainly wasn't out to witch hunt, like some of the sheep on this site, I was merely getting at if he took the time to write the article, he could at of least got the formatting correct, which has corrected, by guess now was a missing . Apologies for upsetting you.

Actually, you're quite correct with regards that consistency is important. However, my point was that this is an unedited article. In my opinion, as long as the author comes close to the guidelines and presents something that is of value and requires just a bit of editing, then I'm personally fine with that. I don't expect unedited articles to be perfect; that's what editors are for.

I guess it really comes down to the whole issue of an "unedited articles" section. It's a trade-off of having more articles online quicker in return for the fact that they won't be of the best quality in terms of formatting and/or grammar/spelling/etc.

Tom,
On a general note you'd expect (excluding this article), that people who submit articles (by downloading or submitting online) to at least follow the general theme of the site. I suppose if that can't be bother to do that, then they should expect the worst and get a lousy vote, and negative comments. I think you and I both know the type of articles I'm referring to.