|
1 /***************************************************************************** |
|
2 |
|
3 ClockCycleCounter.cpp |
|
4 Copyright (c) 2003 Laurent de Soras |
|
5 |
|
6 --- Legal stuff --- |
|
7 |
|
8 This library is free software; you can redistribute it and/or |
|
9 modify it under the terms of the GNU Lesser General Public |
|
10 License as published by the Free Software Foundation; either |
|
11 version 2.1 of the License, or (at your option) any later version. |
|
12 |
|
13 This library is distributed in the hope that it will be useful, |
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 Lesser General Public License for more details. |
|
17 |
|
18 You should have received a copy of the GNU Lesser General Public |
|
19 License along with this library; if not, write to the Free Software |
|
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
21 |
|
22 *Tab=3***********************************************************************/ |
|
23 |
|
24 |
|
25 |
|
26 #if defined (_MSC_VER) |
|
27 #pragma warning (1 : 4130) // "'operator' : logical operation on address of string constant" |
|
28 #pragma warning (1 : 4223) // "nonstandard extension used : non-lvalue array converted to pointer" |
|
29 #pragma warning (1 : 4705) // "statement has no effect" |
|
30 #pragma warning (1 : 4706) // "assignment within conditional expression" |
|
31 #pragma warning (4 : 4786) // "identifier was truncated to '255' characters in the debug information" |
|
32 #pragma warning (4 : 4800) // "forcing value to bool 'true' or 'false' (performance warning)" |
|
33 #pragma warning (4 : 4355) // "'this' : used in base member initializer list" |
|
34 #endif |
|
35 |
|
36 |
|
37 |
|
38 /*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
|
39 |
|
40 #include "ClockCycleCounter.h" |
|
41 |
|
42 #include <cassert> |
|
43 |
|
44 |
|
45 |
|
46 namespace stopwatch |
|
47 { |
|
48 |
|
49 |
|
50 |
|
51 /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
|
52 |
|
53 |
|
54 |
|
55 /* |
|
56 ============================================================================== |
|
57 Name: ctor |
|
58 Description: |
|
59 The first object constructed initialise global data. This first |
|
60 construction may be a bit slow. |
|
61 Throws: Nothing |
|
62 ============================================================================== |
|
63 */ |
|
64 |
|
65 ClockCycleCounter::ClockCycleCounter () |
|
66 : _start_time (0) |
|
67 , _state (0) |
|
68 , _best_score (-1) |
|
69 { |
|
70 if (! _init_flag) |
|
71 { |
|
72 // Should be executed in this order |
|
73 compute_clk_mul (); |
|
74 compute_measure_time_total (); |
|
75 compute_measure_time_lap (); |
|
76 |
|
77 // Restores object state |
|
78 _start_time = 0; |
|
79 _state = 0; |
|
80 _best_score = -1; |
|
81 |
|
82 _init_flag = true; |
|
83 } |
|
84 } |
|
85 |
|
86 |
|
87 |
|
88 /* |
|
89 ============================================================================== |
|
90 Name: get_time_total |
|
91 Description: |
|
92 Gives the time elapsed between the latest stop_lap() and start() calls. |
|
93 Returns: |
|
94 The duration, in clock cycles. |
|
95 Throws: Nothing |
|
96 ============================================================================== |
|
97 */ |
|
98 |
|
99 Int64 ClockCycleCounter::get_time_total () const |
|
100 { |
|
101 const Int64 duration = _state - _start_time; |
|
102 assert (duration >= 0); |
|
103 |
|
104 const Int64 t = max ( |
|
105 duration - _measure_time_total, |
|
106 static_cast <Int64> (0) |
|
107 ); |
|
108 |
|
109 return (t * _clk_mul); |
|
110 } |
|
111 |
|
112 |
|
113 |
|
114 /* |
|
115 ============================================================================== |
|
116 Name: get_time_best_lap |
|
117 Description: |
|
118 Gives the smallest time between two consecutive stop_lap() or between |
|
119 the stop_lap() and start(). The value is reset by a call to start(). |
|
120 Call this function only after a stop_lap(). |
|
121 The time is amputed from the duration of the stop_lap() call itself. |
|
122 Returns: |
|
123 The smallest duration, in clock cycles. |
|
124 Throws: Nothing |
|
125 ============================================================================== |
|
126 */ |
|
127 |
|
128 Int64 ClockCycleCounter::get_time_best_lap () const |
|
129 { |
|
130 assert (_best_score >= 0); |
|
131 |
|
132 const Int64 t1 = max ( |
|
133 _best_score - _measure_time_lap, |
|
134 static_cast <Int64> (0) |
|
135 ); |
|
136 const Int64 t = min (t1, get_time_total ()); |
|
137 |
|
138 return (t * _clk_mul); |
|
139 } |
|
140 |
|
141 |
|
142 |
|
143 /*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
|
144 |
|
145 |
|
146 |
|
147 /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
|
148 |
|
149 |
|
150 |
|
151 #if defined (__MACOS__) |
|
152 |
|
153 static inline double stopwatch_ClockCycleCounter_get_time_s () |
|
154 { |
|
155 const Nanoseconds ns = AbsoluteToNanoseconds (UpTime ()); |
|
156 |
|
157 return (ns.hi * 4294967296e-9 + ns.lo * 1e-9); |
|
158 } |
|
159 |
|
160 #endif // __MACOS__ |
|
161 |
|
162 |
|
163 |
|
164 /* |
|
165 ============================================================================== |
|
166 Name: compute_clk_mul |
|
167 Description: |
|
168 This function, only for PowerPC/MacOS computers, computes the multiplier |
|
169 required to deduce clock cycles from the internal counter. |
|
170 Throws: Nothing |
|
171 ============================================================================== |
|
172 */ |
|
173 |
|
174 void ClockCycleCounter::compute_clk_mul () |
|
175 { |
|
176 assert (! _init_flag); |
|
177 |
|
178 #if defined (__MACOS__) |
|
179 |
|
180 long clk_speed_mhz = CurrentProcessorSpeed (); |
|
181 const Int64 clk_speed = |
|
182 static_cast <Int64> (clk_speed_mhz) * (1000L*1000L); |
|
183 |
|
184 const double start_time_s = stopwatch_ClockCycleCounter_get_time_s (); |
|
185 start (); |
|
186 |
|
187 const double duration = 0.01; // Seconds |
|
188 while (stopwatch_ClockCycleCounter_get_time_s () - start_time_s < duration) |
|
189 { |
|
190 continue; |
|
191 } |
|
192 |
|
193 const double stop_time_s = stopwatch_ClockCycleCounter_get_time_s (); |
|
194 stop (); |
|
195 |
|
196 const double diff_time_s = stop_time_s - start_time_s; |
|
197 const double nbr_cycles = diff_time_s * static_cast <double> (clk_speed); |
|
198 |
|
199 const Int64 diff_time_c = _state - _start_time; |
|
200 const double clk_mul = nbr_cycles / static_cast <double> (diff_time_c); |
|
201 |
|
202 _clk_mul = round_int (clk_mul); |
|
203 |
|
204 #endif // __MACOS__ |
|
205 } |
|
206 |
|
207 |
|
208 |
|
209 void ClockCycleCounter::compute_measure_time_total () |
|
210 { |
|
211 start (); |
|
212 spend_time (); |
|
213 |
|
214 Int64 best_result = 0x7FFFFFFFL; // Should be enough |
|
215 long nbr_tests = 100; |
|
216 for (long cnt = 0; cnt < nbr_tests; ++cnt) |
|
217 { |
|
218 start (); |
|
219 stop_lap (); |
|
220 const Int64 duration = _state - _start_time; |
|
221 best_result = min (best_result, duration); |
|
222 } |
|
223 |
|
224 _measure_time_total = best_result; |
|
225 } |
|
226 |
|
227 |
|
228 |
|
229 /* |
|
230 ============================================================================== |
|
231 Name: compute_measure_time_lap |
|
232 Description: |
|
233 Computes the duration of one stop_lap() call and store it. It will be used |
|
234 later to get the real duration of the measured operation (by substracting |
|
235 the measurement duration). |
|
236 Throws: Nothing |
|
237 ============================================================================== |
|
238 */ |
|
239 |
|
240 void ClockCycleCounter::compute_measure_time_lap () |
|
241 { |
|
242 start (); |
|
243 spend_time (); |
|
244 |
|
245 long nbr_tests = 10; |
|
246 for (long cnt = 0; cnt < nbr_tests; ++cnt) |
|
247 { |
|
248 stop_lap (); |
|
249 stop_lap (); |
|
250 stop_lap (); |
|
251 stop_lap (); |
|
252 } |
|
253 |
|
254 _measure_time_lap = _best_score; |
|
255 } |
|
256 |
|
257 |
|
258 |
|
259 void ClockCycleCounter::spend_time () |
|
260 { |
|
261 const Int64 nbr_clocks = 500; // Number of clock cycles to spend |
|
262 |
|
263 const Int64 start = read_clock_counter (); |
|
264 Int64 current; |
|
265 |
|
266 do |
|
267 { |
|
268 current = read_clock_counter (); |
|
269 } |
|
270 while ((current - start) * _clk_mul < nbr_clocks); |
|
271 } |
|
272 |
|
273 |
|
274 |
|
275 Int64 ClockCycleCounter::_measure_time_total = 0; |
|
276 Int64 ClockCycleCounter::_measure_time_lap = 0; |
|
277 int ClockCycleCounter::_clk_mul = 1; |
|
278 bool ClockCycleCounter::_init_flag = false; |
|
279 |
|
280 |
|
281 } // namespace stopwatch |
|
282 |
|
283 |
|
284 |
|
285 /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |