1 | // ===========================================================================
|
---|
2 | // (C) 1999 Vienna University of Technology
|
---|
3 | // ===========================================================================
|
---|
4 | // NAME: RDTSCTimer
|
---|
5 | // TYPE: c++ code
|
---|
6 | // PROJECT: Urban Viz/yare (yet another rendering engine)
|
---|
7 | // CONTENT: Very accurate timer for Win32 systems
|
---|
8 | // (uses QueryPerformanceCounter, usually microseconds)
|
---|
9 | // VERSION: 0.1
|
---|
10 | // ===========================================================================
|
---|
11 | // AUTHORS: mw Michael Wimmer
|
---|
12 | // ===========================================================================
|
---|
13 | // HISTORY:
|
---|
14 | //
|
---|
15 | // 15-jul-99 14:00:00 mw created
|
---|
16 | // ===========================================================================
|
---|
17 | // $Header: /usr/local/cvsyare/cvsyare/src/yareutils/RDTSCTimer.cpp,v 1.2 2005/03/07 17:32:09 wimmer Exp $
|
---|
18 | // ===========================================================================
|
---|
19 |
|
---|
20 | #ifdef WIN32
|
---|
21 |
|
---|
22 | #include "RDTSCTimer.h"
|
---|
23 |
|
---|
24 | #include "merror.h"
|
---|
25 |
|
---|
26 |
|
---|
27 | // ---------------------------------------------------------------------------
|
---|
28 | // class RDTSCTimer implementation
|
---|
29 | // ---------------------------------------------------------------------------
|
---|
30 |
|
---|
31 | LARGE_INTEGER RDTSCTimer::frequency = {0,1};
|
---|
32 | bool RDTSCTimer::isinitialized = false;
|
---|
33 | bool RDTSCTimer::available = false;
|
---|
34 |
|
---|
35 | // this retrieves the timer frequency - will be called by constructor
|
---|
36 | void RDTSCTimer::InitClass(bool verbose)
|
---|
37 | {
|
---|
38 | isinitialized = true;
|
---|
39 | available = true;
|
---|
40 |
|
---|
41 | if (verbose)
|
---|
42 | OUT1(("Calibrating RDTSC-Timer at real-time priority...."));
|
---|
43 |
|
---|
44 | // Increase process class
|
---|
45 | HANDLE hProcess = GetCurrentProcess();
|
---|
46 | DWORD iPriorityClass = GetPriorityClass(hProcess);
|
---|
47 | ASM_ELSE(iPriorityClass, "couldnt change priority class")
|
---|
48 | SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
|
---|
49 |
|
---|
50 | // Increase thread priority
|
---|
51 | HANDLE hThread = GetCurrentThread();
|
---|
52 | DWORD iPriority = GetThreadPriority(hThread);
|
---|
53 | ASM_ELSE(iPriority != THREAD_PRIORITY_ERROR_RETURN, "couldnt change thread priority")
|
---|
54 | SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
---|
55 |
|
---|
56 |
|
---|
57 | // Measure CPU frequency
|
---|
58 | LARGE_INTEGER PerfFreq;
|
---|
59 | LARGE_INTEGER calStart, calEnd;
|
---|
60 | LARGE_INTEGER perfStart, perfEnd;
|
---|
61 |
|
---|
62 | // warmup
|
---|
63 | RDTSC(calStart);
|
---|
64 | RDTSC(calStart);
|
---|
65 | RDTSC(calStart);
|
---|
66 |
|
---|
67 | ASM_RET( QueryPerformanceFrequency( &PerfFreq ), "QueryPerformanceCounter not available for calibrating!");
|
---|
68 | QueryPerformanceCounter( &perfStart );
|
---|
69 | RDTSC(calStart);
|
---|
70 | LARGE_INTEGER endmark; endmark.QuadPart = perfStart.QuadPart + PerfFreq.QuadPart;
|
---|
71 | do {
|
---|
72 | QueryPerformanceCounter( &perfEnd );
|
---|
73 | } while (perfEnd.QuadPart < endmark.QuadPart);
|
---|
74 | RDTSC(calEnd);
|
---|
75 |
|
---|
76 |
|
---|
77 | // number of Bench cycles counted
|
---|
78 | LARGE_INTEGER perfcounts; perfcounts.QuadPart = perfEnd.QuadPart - perfStart.QuadPart;
|
---|
79 | // number of RDTSC cycles counted
|
---|
80 | LARGE_INTEGER calcounts; calcounts.QuadPart = calEnd.QuadPart - calStart.QuadPart;
|
---|
81 | // note: this might overflow if processor is over 6GHz:
|
---|
82 | unsigned __int64 temp = calcounts.QuadPart * PerfFreq.QuadPart;
|
---|
83 | frequency.QuadPart = temp / perfcounts.QuadPart;
|
---|
84 |
|
---|
85 | //if (verbose)
|
---|
86 | // OUT1( SV(perfcounts.LowPart)<<SV(calcounts.LowPart)<<SV(calcounts.HighPart)<<SV(PerfFreq.LowPart));
|
---|
87 |
|
---|
88 | //
|
---|
89 | // Number of calibration loops
|
---|
90 | //
|
---|
91 | #define CALIBRATION_LOOPS 50000
|
---|
92 |
|
---|
93 | ///--- measure overhead of different calling conventions
|
---|
94 |
|
---|
95 | ULONG i;
|
---|
96 |
|
---|
97 | //-- Start/Elapsed overhead
|
---|
98 |
|
---|
99 | RDTSCTimer mytimer2;
|
---|
100 | RDTSC(calStart);
|
---|
101 | for( i = 0; i < CALIBRATION_LOOPS; i++ ) {
|
---|
102 | PERF_ENTRY(mytimer2);
|
---|
103 | PERF_EXIT(mytimer2);
|
---|
104 | }
|
---|
105 | RDTSC(calEnd);
|
---|
106 |
|
---|
107 | LARGE_INTEGER CalEntryExitCycles, CalCountedCycles;
|
---|
108 | CalEntryExitCycles.QuadPart = (calEnd.QuadPart - calStart.QuadPart)/CALIBRATION_LOOPS;
|
---|
109 | CalCountedCycles.QuadPart = mytimer2.total_count.QuadPart / CALIBRATION_LOOPS;
|
---|
110 |
|
---|
111 |
|
---|
112 | /* RDTSCTimer mytimer;
|
---|
113 | RDTSC(calStart);
|
---|
114 | for( i = 0; i < CALIBRATION_LOOPS; i++ ) {
|
---|
115 | mytimer.Start();
|
---|
116 | mytimer.Elapsed();
|
---|
117 | }
|
---|
118 | RDTSC(calEnd);
|
---|
119 |
|
---|
120 | LARGE_INTEGER CalStartElapsedCycles;
|
---|
121 | CalStartElapsedCycles.QuadPart = (calEnd.QuadPart - calStart.QuadPart)/CALIBRATION_LOOPS;
|
---|
122 |
|
---|
123 |
|
---|
124 | RDTSCTimer mytimer3;
|
---|
125 | RDTSC(calStart);
|
---|
126 | for( i = 0; i < CALIBRATION_LOOPS; i++ ) {
|
---|
127 | mytimer3.Entry();
|
---|
128 | mytimer3.Exit();
|
---|
129 | }
|
---|
130 | RDTSC(calEnd);
|
---|
131 |
|
---|
132 | LARGE_INTEGER CalEntryExitCycles2, CalCountedCycles2;
|
---|
133 | CalEntryExitCycles2.QuadPart = (calEnd.QuadPart - calStart.QuadPart)/CALIBRATION_LOOPS;
|
---|
134 | CalCountedCycles2.QuadPart = mytimer3.total_count.QuadPart / CALIBRATION_LOOPS;
|
---|
135 | */
|
---|
136 |
|
---|
137 | RDTSC(calStart);
|
---|
138 | for( i = 0; i < CALIBRATION_LOOPS; i++ ) {
|
---|
139 | QueryPerformanceCounter( &perfStart );
|
---|
140 | QueryPerformanceCounter( &perfStart );
|
---|
141 | }
|
---|
142 | RDTSC(calEnd);
|
---|
143 |
|
---|
144 | LARGE_INTEGER PerfEntryExitCycles;
|
---|
145 | PerfEntryExitCycles.QuadPart = (calEnd.QuadPart - calStart.QuadPart)/CALIBRATION_LOOPS;
|
---|
146 |
|
---|
147 | // Restore thread and process priority
|
---|
148 | if (iPriority != THREAD_PRIORITY_ERROR_RETURN)
|
---|
149 | SetThreadPriority(hThread, iPriority);
|
---|
150 |
|
---|
151 | if (iPriorityClass)
|
---|
152 | SetPriorityClass(hProcess, iPriorityClass);
|
---|
153 |
|
---|
154 |
|
---|
155 | if (verbose)
|
---|
156 | {
|
---|
157 | OUT2("RDTSC frequency: " << frequency.LowPart << ", QueryPerformanceCounter frequency: " << PerfFreq.LowPart);
|
---|
158 | OUT2("Overhead for timer calls in clock cycles:");
|
---|
159 | //OUT2(CalStartElapsedCycles.LowPart << " for timer.start;timer.elapsed;");
|
---|
160 | OUT2(CalEntryExitCycles.LowPart << " for PERF_ENTRY/PERF_EXIT, cycles counted per call: " << CalCountedCycles.LowPart);
|
---|
161 | //OUT2(CalEntryExitCycles2.LowPart << " for Entry()/Exit(), cycles counted per call: " << CalCountedCycles2.LowPart);
|
---|
162 | OUT2(PerfEntryExitCycles.LowPart << " for QueryPerformanceCounter twice");
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | /// returns the frequency
|
---|
167 | double RDTSCTimer::GetFrequency(bool verbose)
|
---|
168 | {
|
---|
169 | if (!isinitialized)
|
---|
170 | InitClass(verbose);
|
---|
171 |
|
---|
172 | return (double)frequency.QuadPart;
|
---|
173 | }
|
---|
174 |
|
---|
175 | #endif // WIN32
|
---|