|
Boost Users : |
From: Jim.Hyslop (jim.hyslop_at_[hidden])
Date: 2003-07-15 16:39:32
Jeff Garland wrote:
> It actually shouldn't be too hard. It is really a matter of
> swapping out the
> Windows API function calls to return the times and then adjusting
> appropriately.
(follow-ups should probably be diverted to the Boost developers list)
I'm not sure if this has been discussed or not, but it may be harder than
you imagine. The Windows API functions dealing with time have a resolution
of approximately 10 milliseconds. Even the functions that return values of
hectonanoseconds (100 nanoseconds) are limited to this resolution.
To see what I mean, run this program:
#include <windows.h>
#include <iostream>
#include <map>
const int numElements=10000;
DWORD WINAPI timeThread(void *)
{
// Step 1: fill in an array of FILETIME elements with the time
// returned by GetSystemTimeAsFileTime. Make sure each element
// is unique - don't increment index until the time we just read
// is actually different from the last time we read.
FILETIME ft[numElements];
memset(&ft[0], 0, sizeof(ft));
GetSystemTimeAsFileTime(&ft[0]);
int index=1;
while (index < numElements)
{
GetSystemTimeAsFileTime(&ft[index]);
if (ft[index].dwLowDateTime != ft[index-1].dwLowDateTime) index++;
}
// Step 2: calculate the delta from one timestamp to the next. Store
// this delta in a map<int, int> where the key is the delta, and the
value
// is the number of times that delta appears. For example, with the
timestamps:
// 0, 5, 11, 16, 21, 25
// we get the deltas:
// 5, 6, 5, 5, 4
// the map will contain three entries: pair(4, 1 ), pair( 5, 3 ), pair(
6, 1 )
unsigned smallestDiff=(unsigned)-1,
largestDiff=0;
ULARGE_INTEGER endTime;
ULARGE_INTEGER startTime;
startTime.LowPart = ft[0].dwLowDateTime;
startTime.HighPart = ft[0].dwHighDateTime;
std::map<int, int> distribution;
for (index=1; index<numElements; ++index)
{
endTime.LowPart = ft[index].dwLowDateTime;
endTime.HighPart = ft[index].dwHighDateTime;
unsigned difference = endTime.QuadPart - startTime.QuadPart;
std::cout << difference << "\n";
if (difference < smallestDiff) smallestDiff = difference;
if (difference > largestDiff) largestDiff = difference;
startTime = endTime;
distribution[difference]++;
}
// step 3: dump the stats.
endTime.LowPart = ft[numElements-1].dwLowDateTime;
endTime.HighPart = ft[numElements-1].dwHighDateTime;
startTime.LowPart = ft[0].dwLowDateTime;
startTime.HighPart = ft[0].dwHighDateTime;
std::cout << numElements << " samples. Smallest delta: " <<
smallestDiff/10000.0
<< "ms; Largest delta: " << largestDiff/10000.0
<< "ms; Average: " << unsigned long (endTime.QuadPart -
startTime.QuadPart) / (numElements * 10000.0)
<< "ms\nDistribution:" << std::endl;
for (std::map<int, int>::iterator i = distribution.begin();
i != distribution.end();
++i)
{
std::cout << (*i).first << ": " << (*i).second << "\n";
}
return 0;
}
int main()
{
std::cout << "Note: this program will run for approximately "
<< numElements/100
<< " seconds\nwith no output, at real-time priority. \n"
"Your system may appear to hang while this program is running.\n"
"Rest assured it *will* terminate." << std::endl;
HANDLE threadHandle = CreateThread(NULL, 0, timeThread, 0,
CREATE_SUSPENDED, 0);
SetThreadPriority(threadHandle, THREAD_PRIORITY_TIME_CRITICAL);
ResumeThread(threadHandle);
WaitForSingleObject(threadHandle, -1);
}
When I ran it on NT4 SP6, the distribution was as follows:
100136: 7614
100137: 2359
200272: 1
500680: 17
500685: 7
600822: 1
(the units are hectonanoseconds, divide by 10 to get microseconds). I'm
guessing the 50 and 60 ms timings are related to task switching or other O/S
overhead.
On a machine running Windows 2000 SP 3, the results were:
100144: 9999
-- Jim
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net