A Stopwatch Class for .NET 1.1

The first rule of performance testing is to measure, then measure again, then measure one more time just to be sure. NET 2.0 adds a handy Diagnostics.Stopwatch which is perfect for this kind of ad-hoc precision timing.


This is a companion discussion topic for the original blog entry at: http://www.codinghorror.com/blog/2005/12/a-stopwatch-class-for-net-11.html

Shouldn’t line 37 be
if (IsRunning) this.Stop();
instead of
if (!IsRunning) this.Stop();
? Although, it really doesn’t have an effect on its operation.

Jeff, I’ve filed a bug report about this but I’m thinking that they won’t be able to do anything about it. The computer is a Dell 5150 laptop with HyperThreading enabled. The problem appears to be that QueryPerformanceCounter and QueryPerformanceFrequency are not returning the correct results (the counter is slow). This is probably a HAL issue from what I’m reading on Google. It’s too bad because I really don’t need precise timing. I’m just tired of always having to roll my own stopwatch functions using DateTime.Now and such.

Thanks anyway!

Oops, yes. Thanks. Let me fix that.

That’s interesting. Unfortunately, your implementation AND the System.Diagnostics.StopWatch implementation both run at only about half speed on my computer. What good is a “high resolution timer” if it doesn’t keep time any better than that? I’ve googled for this issue and haven’t found anything yet. I’m wondering if Microsoft is aware of this problem? Is anyone else having this issue? Here is some dirty code to show what I’m doing. If I watch the clock on my wall and let the thing run for about 30 seconds I get the results below. Note that the StopWatch2 class is your implementation.

public partial class Form1 : Form
{
private Stopwatch _stopWatch;
private Stopwatch2 _stopWatch2;
private DateTime _start;
private DateTime _end;
private TimeSpan _total;

    public Form1()
    {
        InitializeComponent();
        _stopWatch = new Stopwatch();
        _stopWatch2 = new Stopwatch2();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (!_stopWatch.IsRunning)
        {
            button1.Text = "Stop";
            _stopWatch.Reset();
            _stopWatch.Start();
            _stopWatch2.Reset();
            _stopWatch2.Start();
            _start = DateTime.UtcNow;
        }
        else
        {
            button1.Text = "Start";
            _stopWatch.Stop();
            _stopWatch2.Stop();
            _end = DateTime.UtcNow;
            _total = _end - _start;
            MessageBox.Show("Total: " + _stopWatch.Elapsed.TotalSeconds.ToString() + ", " + _stopWatch2.Elapsed.TotalSeconds.ToString() + ", " + _total.TotalSeconds.ToString());
        }
    }

RESULTS:

StopWatch - 16.6576836 seconds
StopWatch2 - 16.657 seconds
Manual Way - 30.015625 seconds (correct)

That’s really strange. I just tested it to be sure, and I get accurate results in both .NET 1.1 (using my class) and 2.0 (using the built-in Stopwatch class).

static void Main(string[] args)
{
Stopwatch s = new Stopwatch();
Thread newThread = new Thread(new ThreadStart(ThreadMethod));
s.Start();
newThread.Start();
Thread.Sleep(300);
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds.ToString());
Console.ReadLine();
}
static void ThreadMethod()
{
Thread.Sleep(1000);
}

I suspect it’s something about your computer, since the QueryPerformance* APIs require interaction between the CPU and BIOS… what kind of PC do you have?

Hello guys.

yes, unforunately QueryPerformanceCounter is unusable in real life, especially on laptops. Due to Intel’s SpeedStep technology or similar power-saving methods using a variable CPU speed, the timer will return strange results because in most cases it is just a wrapper function for the RDTSC instruction which depends on a fixed clock speed.

This is a major problem in game development where it is critical to have a fast and reliable timer for consistant game logic updates and all that.

Your class is still useful for e.g. if you want to profile your code on a system that’s known to have a reliable perf. counter,but for everything else you should use a reliable timer like GetTickCount.

Thanks ^jacob. That seems to be the same advice that I am seeing out on Google (especially with respect to game timing). I’m surprised that Microsoft chose this method for the stopwatch class if it can be so problematic. They should at least put in a boolean flag that lets me chose whether or not I want high performance results (along with a disclaimer telling me that they may not always be accurate). I never have a need for such high performance results and I would assume that very few other users do either. It seems to be a shame that they have over-engineer this class.

As a side note, I have at least two kids video games that appear to run slow on my laptop for no reason. I would assume that they are using the QueryPerformanceCounter method of timing which is causing issues. At least it is starting to make sense.

Since ^jacob mentioned SpeedStep I decided to turn it off in my BIOS settings. The StopWatch class seems to work just fine now. However, my computer appears to generally run slower. :frowning:

Won’t everyone who has SpeedStep turned on (default on most Intel laptops) see issues with the StopWatch class? Hmmmm… it sounds like Microsoft has opened up a big can of worms by relying on the QueryPerformanceCounter calls for this new class.

Anyway, thanks for all the info!

Ok. Sorry for using this blog to debug this issue but I thought I’d post one more little detail for those that end up having to deal with this issue on their own computers.

It appears that SpeedStep is controlled in Windows XP through the power management settings. I have re-enabled SpeedStep in the BIOS and then used the Power Management applet in Control Panel to force the processor to run at maximum speed. Set the Power Scheme to “Always On” and your processor will always run at top speed. Set the Power Scheme to “Portable/Laptop” and SpeedStep will be enabled such that the processor’s speed is variable. If the current power scheme is “Always On” the StopWatch class works just fine. If it is set to “Portable/Laptop” the StopWatch class runs slow. I can even change the scheme on the fly without a reboot and see the difference between the two settings.

Good luck!

Sorry for using this blog to debug this issue

That’s what it’s for, since this is totally on topic…

Hi Jeff

Would it be a good ER to pass the original tickcount as a parameter to a new Elapsed method? That way multiple clients could share a single instance. Each client would only have to remember the original tickcount and then ask the stopwatch for the elapsed time since it started the process?

Maybe, but this class is designed to mirror exactly what is in the 2.0 stopwatch class-- that makes it easier to port code back and forth.

the link to the api is very, very broken. it gives like 50000000 authentication requests

No vacation after school.

Thanks for the class!

It was exactly what I needed when I discovered .net 1.1 didn’t have it.