1.11M Members

VC++: How to get elapsed time with ~1 MICROsecond precision

 
0
 

CPU Performance Counter based clock and stop-watch classes for Win2K++
were implemented in VC++. Details: see sources (I hope, these classes, especially StopWatch, have well-to-do interfaces;)).

Warning: no special precautions for multi-threading/multi-core CPU environment.

It's not so hard work to translate these codes in C (or other C++ implementations).

This codes are in the public domain.

/**
 * Performance Counter based clock for Win2K++.
 * VC++ declaration - version 2008-07-31.
 *
 * This code is in the public domain.
 * No warranties are made concerning
 * their correctness or stability,
 * and no user support is guaranteed.
 *
 * Be careful: it's elapsed (not CPU) time.
 * It's possible to get process time-slice
 * waiting intervals...
 */
class UltraClock
{
public:
	/// Activate UltraClock if it's supported.
	UltraClock();
	/// Get a time in seconds.
	double seconds() const
	{
		return ticks() / ticks_per_second;
	}
	/// Get a time in milliseconds.
	double millis() const 
	{ 
		return ticks() / ticks_per_millis;
	}
	/// Get a time in microseconds.
	double micros() const
	{
		return ticks() / ticks_per_micros;
	}
	/// Syntax shugar proxy for snap().
	double ticks() const { return snap(); }
	/// Is UltraClock supported?
	bool isActive() const { return active; }
	/// To throw away?..
	double operator()() const { return snap(); }
	// No need...
	//	__int64 int64ticks() const;
	// Query and get Performance Counter
	static double snap();
	/// Getters for internal adjusted constants.
	static double Ticks_per_second()
		{ return ticks_per_second; }
	static double Ticks_per_millis()
		{ return ticks_per_millis; }
	static double Ticks_per_micros()
		{ return ticks_per_micros; }
private:
	/// A constructor maiden flight?..
	static bool virgin;
	/// UltraClock is (not?) supported.
	static bool active;
	static double ticks_per_second;
	static double ticks_per_millis;
	static double ticks_per_micros;
};
// End of declarations (ultracloc.h).

/** 
 *  UltraClock implementation.
 *  Dependencies:
 *  - ultraclock.h (see above)
 *  - windows.h - obviously...
 *  - __int64 64-bit integers (not critical;)
 */
bool UltraClock::virgin = true;
bool UltraClock::active = false;
// Dynamically calculated "constants", don't worry:
double UltraClock::ticks_per_second = 1.0;
double UltraClock::ticks_per_millis = 1000.0;
double UltraClock::ticks_per_micros = 1000000.0;
namespace {
union Quad
{
	LARGE_INTEGER large;
	__int64 int64;
};
}
UltraClock::UltraClock()
{
    Quad q;
    if (virgin)
    {
        if (QueryPerformanceCounter(&q.large)
         && QueryPerformanceFrequency(&q.large))
        {
            UltraClock::virgin = false;
            if (q.int64)
            {
                ticks_per_second = static_cast<double>(q.int64);
                ticks_per_millis = ticks_per_second / 1000.0;
                ticks_per_micros = ticks_per_second / 1000000.0;
                UltraClock::active = true;
            }
        }
    }
}

namespace { UltraClock ultra; }

double UltraClock::snap()
{
	double counter = 0.0;
	if (UltraClock::active)
	{
		Quad q;
		if (QueryPerformanceCounter(&q.large))
		{
			counter = static_cast<double>(q.int64);
		}
	}
	return counter;
}

/**
 * UltraClock based stop-watch for Win2K++
 * with ~1.5 microseconds precision.
 */
class StopWatch
{
public:
	StopWatch():base(UltraClock::snap())
	{}
	double millis()
	{
		return (UltraClock::snap() - base) 
			/ UltraClock::Ticks_per_millis(); 
	}
	double millisBase() const 
	{ 
		return base / UltraClock::Ticks_per_millis(); 
	}
	double micros()
	{
		return (UltraClock::snap() - base) 
			/ UltraClock::Ticks_per_micros(); 
	}
	double microsBase() const 
	{ 
		return base / UltraClock::Ticks_per_micros(); 
	}
	double seconds()
	{
		return (UltraClock::snap() - base) 
			/ UltraClock::Ticks_per_second(); 
	}
	double secondsBase() const 
	{ 
		return base / UltraClock::Ticks_per_second(); 
	}
	double reset() 
	{ 
		double oldbase = base;
		base = UltraClock::snap();
		return oldbase;
	}
private:
	double base;
};
// End of UltraClock implementation file

// StopWatch example: 2D array versus vector<vector<...
const int M = 100;
const int N = 100;

namespace { double a[M][N]; }

void TestWatch()
{
    StopWatch ticker;
    double ta, tv;

    ticker.reset();
    for (int i = 0; i < M; ++i)
    {
        for (int j = 0; j < N; ++j)
            a[i][j] = i*N + j;
    }
    ta = ticker.micros();
    
    vector<vector<double> > v(M);
    
    ticker.reset();
    for (int i = 0; i < M; ++i)
    {
        v[i].reserve(N);
        for (int j = 0; j < N; ++j)
            v[i].push_back(a[i][j]);
    }
    tv = ticker.micros();
    cout <<
#ifdef _DEBUG
        "Debug"
#else
        "Release"
#endif
        " mode.\n"
        << "Initialization (in microseconds):\n"
        << "array[100][100]:\t" << ta 
        << ",\nvector<vector<> >:\t" << tv
        << endl;

    double suma, sumv;

    suma = 0.0;
    ticker.reset();
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < N; ++j)
            suma += a[i][j];
    ta = ticker.micros();

    sumv = 0.0;
    ticker.reset();
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < N; ++j)
            sumv += v[i][j];
    tv = ticker.micros();

    cout << "Sum calculation (" 
        << suma << "/" << sumv << "):\n"
        << "array:\t" << ta << ",\nvector:\t" << tv 
        << endl;
}
/* Output (from VC++ 2008):
Release mode.
Initialization (in microseconds):
array[100][100]:        57.2698,
vector<vector<> >:      131.86
Sum calculation (4.9995e+007/4.9995e+007):
array:  17.8794,
vector: 52.8
 -----------
Debug mode.
Initialization (in microseconds):
array[100][100]:        74.0318,
vector<vector<> >:      6598.6
Sum calculation (4.9995e+007/4.9995e+007):
array:  52.8,
vector: 1868.39
*/
Isn't it about time forums rewarded their contributors?

Earn rewards points for helping others. Gain kudos. Cash out. Get better answers yourself.

It's as simple as contributing editorial or replying to discussions labeled or OP Kudos

You
This is an OP Kudos discussion and contributors may be rewarded
Post:
Start New Discussion
Tags Related to this Article