diff options
author | dan miller | 2007-10-19 05:24:38 +0000 |
---|---|---|
committer | dan miller | 2007-10-19 05:24:38 +0000 |
commit | f205de7847da7ae1c10212d82e7042d0100b4ce0 (patch) | |
tree | 9acc9608a6880502aaeda43af52c33e278e95b9c /libraries/ode-0.9/ode/src/timer.cpp | |
parent | trying to fix my screwup part deux (diff) | |
download | opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.zip opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.gz opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.bz2 opensim-SC-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.xz |
from the start... checking in ode-0.9
Diffstat (limited to 'libraries/ode-0.9/ode/src/timer.cpp')
-rw-r--r-- | libraries/ode-0.9/ode/src/timer.cpp | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/libraries/ode-0.9/ode/src/timer.cpp b/libraries/ode-0.9/ode/src/timer.cpp new file mode 100644 index 0000000..f754bf1 --- /dev/null +++ b/libraries/ode-0.9/ode/src/timer.cpp | |||
@@ -0,0 +1,421 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | TODO | ||
26 | ---- | ||
27 | |||
28 | * gettimeofday() and the pentium time stamp counter return the real time, | ||
29 | not the process time. fix this somehow! | ||
30 | |||
31 | */ | ||
32 | |||
33 | #include <ode/common.h> | ||
34 | #include <ode/timer.h> | ||
35 | |||
36 | // misc defines | ||
37 | #define ALLOCA dALLOCA16 | ||
38 | |||
39 | //**************************************************************************** | ||
40 | // implementation for windows based on the multimedia performance counter. | ||
41 | |||
42 | #ifdef WIN32 | ||
43 | |||
44 | #include "windows.h" | ||
45 | |||
46 | static inline void getClockCount (unsigned long cc[2]) | ||
47 | { | ||
48 | LARGE_INTEGER a; | ||
49 | QueryPerformanceCounter (&a); | ||
50 | cc[0] = a.LowPart; | ||
51 | cc[1] = a.HighPart; | ||
52 | } | ||
53 | |||
54 | |||
55 | static inline void serialize() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | |||
60 | static inline double loadClockCount (unsigned long cc[2]) | ||
61 | { | ||
62 | LARGE_INTEGER a; | ||
63 | a.LowPart = cc[0]; | ||
64 | a.HighPart = cc[1]; | ||
65 | return double(a.QuadPart); | ||
66 | } | ||
67 | |||
68 | |||
69 | double dTimerResolution() | ||
70 | { | ||
71 | return 1.0/dTimerTicksPerSecond(); | ||
72 | } | ||
73 | |||
74 | |||
75 | double dTimerTicksPerSecond() | ||
76 | { | ||
77 | static int query=0; | ||
78 | static double hz=0.0; | ||
79 | if (!query) { | ||
80 | LARGE_INTEGER a; | ||
81 | QueryPerformanceFrequency (&a); | ||
82 | hz = double(a.QuadPart); | ||
83 | query = 1; | ||
84 | } | ||
85 | return hz; | ||
86 | } | ||
87 | |||
88 | #endif | ||
89 | |||
90 | //**************************************************************************** | ||
91 | // implementation based on the pentium time stamp counter. the timer functions | ||
92 | // can be serializing or non-serializing. serializing will ensure that all | ||
93 | // instructions have executed and data has been written back before the cpu | ||
94 | // time stamp counter is read. the CPUID instruction is used to serialize. | ||
95 | |||
96 | #if defined(PENTIUM) && !defined(WIN32) | ||
97 | |||
98 | // we need to know the clock rate so that the timing function can report | ||
99 | // accurate times. this number only needs to be set accurately if we're | ||
100 | // doing performance tests and care about real-world time numbers - otherwise, | ||
101 | // just ignore this. i have not worked out how to determine this number | ||
102 | // automatically yet. | ||
103 | |||
104 | #define PENTIUM_HZ (500e6) | ||
105 | |||
106 | static inline void getClockCount (unsigned long cc[2]) | ||
107 | { | ||
108 | #ifndef X86_64_SYSTEM | ||
109 | asm volatile ( | ||
110 | "rdtsc\n" | ||
111 | "movl %%eax,(%%esi)\n" | ||
112 | "movl %%edx,4(%%esi)\n" | ||
113 | : : "S" (cc) : "%eax","%edx","cc","memory"); | ||
114 | #else | ||
115 | asm volatile ( | ||
116 | "rdtsc\n" | ||
117 | "movl %%eax,(%%rsi)\n" | ||
118 | "movl %%edx,4(%%rsi)\n" | ||
119 | : : "S" (cc) : "%eax","%edx","cc","memory"); | ||
120 | #endif | ||
121 | } | ||
122 | |||
123 | |||
124 | static inline void serialize() | ||
125 | { | ||
126 | #ifndef X86_64_SYSTEM | ||
127 | asm volatile ( | ||
128 | "mov $0,%%eax\n" | ||
129 | "push %%ebx\n" | ||
130 | "cpuid\n" | ||
131 | "pop %%ebx\n" | ||
132 | : : : "%eax","%ecx","%edx","cc","memory"); | ||
133 | #else | ||
134 | asm volatile ( | ||
135 | "mov $0,%%rax\n" | ||
136 | "push %%rbx\n" | ||
137 | "cpuid\n" | ||
138 | "pop %%rbx\n" | ||
139 | : : : "%rax","%rcx","%rdx","cc","memory"); | ||
140 | #endif | ||
141 | } | ||
142 | |||
143 | |||
144 | static inline double loadClockCount (unsigned long a[2]) | ||
145 | { | ||
146 | double ret; | ||
147 | #ifndef X86_64_SYSTEM | ||
148 | asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : | ||
149 | "cc","memory"); | ||
150 | #else | ||
151 | asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : | ||
152 | "cc","memory"); | ||
153 | #endif | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | |||
158 | double dTimerResolution() | ||
159 | { | ||
160 | return 1.0/PENTIUM_HZ; | ||
161 | } | ||
162 | |||
163 | |||
164 | double dTimerTicksPerSecond() | ||
165 | { | ||
166 | return PENTIUM_HZ; | ||
167 | } | ||
168 | |||
169 | #endif | ||
170 | |||
171 | //**************************************************************************** | ||
172 | // otherwise, do the implementation based on gettimeofday(). | ||
173 | |||
174 | #if !defined(PENTIUM) && !defined(WIN32) | ||
175 | |||
176 | #ifndef macintosh | ||
177 | |||
178 | #include <sys/time.h> | ||
179 | #include <unistd.h> | ||
180 | |||
181 | |||
182 | static inline void getClockCount (unsigned long cc[2]) | ||
183 | { | ||
184 | struct timeval tv; | ||
185 | gettimeofday (&tv,0); | ||
186 | cc[0] = tv.tv_usec; | ||
187 | cc[1] = tv.tv_sec; | ||
188 | } | ||
189 | |||
190 | #else // macintosh | ||
191 | |||
192 | #include <MacTypes.h> | ||
193 | #include <Timer.h> | ||
194 | |||
195 | static inline void getClockCount (unsigned long cc[2]) | ||
196 | { | ||
197 | UnsignedWide ms; | ||
198 | Microseconds (&ms); | ||
199 | cc[1] = ms.lo / 1000000; | ||
200 | cc[0] = ms.lo - ( cc[1] * 1000000 ); | ||
201 | } | ||
202 | |||
203 | #endif | ||
204 | |||
205 | |||
206 | static inline void serialize() | ||
207 | { | ||
208 | } | ||
209 | |||
210 | |||
211 | static inline double loadClockCount (unsigned long a[2]) | ||
212 | { | ||
213 | return a[1]*1.0e6 + a[0]; | ||
214 | } | ||
215 | |||
216 | |||
217 | double dTimerResolution() | ||
218 | { | ||
219 | unsigned long cc1[2],cc2[2]; | ||
220 | getClockCount (cc1); | ||
221 | do { | ||
222 | getClockCount (cc2); | ||
223 | } | ||
224 | while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); | ||
225 | do { | ||
226 | getClockCount (cc1); | ||
227 | } | ||
228 | while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); | ||
229 | double t1 = loadClockCount (cc1); | ||
230 | double t2 = loadClockCount (cc2); | ||
231 | return (t1-t2) / dTimerTicksPerSecond(); | ||
232 | } | ||
233 | |||
234 | |||
235 | double dTimerTicksPerSecond() | ||
236 | { | ||
237 | return 1000000; | ||
238 | } | ||
239 | |||
240 | #endif | ||
241 | |||
242 | //**************************************************************************** | ||
243 | // stop watches | ||
244 | |||
245 | void dStopwatchReset (dStopwatch *s) | ||
246 | { | ||
247 | s->time = 0; | ||
248 | s->cc[0] = 0; | ||
249 | s->cc[1] = 0; | ||
250 | } | ||
251 | |||
252 | |||
253 | void dStopwatchStart (dStopwatch *s) | ||
254 | { | ||
255 | serialize(); | ||
256 | getClockCount (s->cc); | ||
257 | } | ||
258 | |||
259 | |||
260 | void dStopwatchStop (dStopwatch *s) | ||
261 | { | ||
262 | unsigned long cc[2]; | ||
263 | serialize(); | ||
264 | getClockCount (cc); | ||
265 | double t1 = loadClockCount (s->cc); | ||
266 | double t2 = loadClockCount (cc); | ||
267 | s->time += t2-t1; | ||
268 | } | ||
269 | |||
270 | |||
271 | double dStopwatchTime (dStopwatch *s) | ||
272 | { | ||
273 | return s->time / dTimerTicksPerSecond(); | ||
274 | } | ||
275 | |||
276 | //**************************************************************************** | ||
277 | // code timers | ||
278 | |||
279 | // maximum number of events to record | ||
280 | #define MAXNUM 100 | ||
281 | |||
282 | static int num = 0; // number of entries used in event array | ||
283 | static struct { | ||
284 | unsigned long cc[2]; // clock counts | ||
285 | double total_t; // total clocks used in this slot. | ||
286 | double total_p; // total percentage points used in this slot. | ||
287 | int count; // number of times this slot has been updated. | ||
288 | char *description; // pointer to static string | ||
289 | } event[MAXNUM]; | ||
290 | |||
291 | |||
292 | // make sure all slot totals and counts reset to 0 at start | ||
293 | |||
294 | static void initSlots() | ||
295 | { | ||
296 | static int initialized=0; | ||
297 | if (!initialized) { | ||
298 | for (int i=0; i<MAXNUM; i++) { | ||
299 | event[i].count = 0; | ||
300 | event[i].total_t = 0; | ||
301 | event[i].total_p = 0; | ||
302 | } | ||
303 | initialized = 1; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | |||
308 | void dTimerStart (const char *description) | ||
309 | { | ||
310 | initSlots(); | ||
311 | event[0].description = const_cast<char*> (description); | ||
312 | num = 1; | ||
313 | serialize(); | ||
314 | getClockCount (event[0].cc); | ||
315 | } | ||
316 | |||
317 | |||
318 | void dTimerNow (const char *description) | ||
319 | { | ||
320 | if (num < MAXNUM) { | ||
321 | // do not serialize | ||
322 | getClockCount (event[num].cc); | ||
323 | event[num].description = const_cast<char*> (description); | ||
324 | num++; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | |||
329 | void dTimerEnd() | ||
330 | { | ||
331 | if (num < MAXNUM) { | ||
332 | serialize(); | ||
333 | getClockCount (event[num].cc); | ||
334 | event[num].description = "TOTAL"; | ||
335 | num++; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | //**************************************************************************** | ||
340 | // print report | ||
341 | |||
342 | static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt) | ||
343 | { | ||
344 | if (a >= 0.999999) { | ||
345 | fprintf (f,fmt,a); | ||
346 | return; | ||
347 | } | ||
348 | a *= 1000.0; | ||
349 | if (a >= 0.999999) { | ||
350 | fprintf (f,fmt,a); | ||
351 | fprintf (f,"m"); | ||
352 | return; | ||
353 | } | ||
354 | a *= 1000.0; | ||
355 | if (a >= 0.999999) { | ||
356 | fprintf (f,fmt,a); | ||
357 | fprintf (f,"u"); | ||
358 | return; | ||
359 | } | ||
360 | a *= 1000.0; | ||
361 | fprintf (f,fmt,a); | ||
362 | fprintf (f,"n"); | ||
363 | } | ||
364 | |||
365 | |||
366 | void dTimerReport (FILE *fout, int average) | ||
367 | { | ||
368 | int i; | ||
369 | size_t maxl; | ||
370 | double ccunit = 1.0/dTimerTicksPerSecond(); | ||
371 | fprintf (fout,"\nTimer Report ("); | ||
372 | fprintDoubleWithPrefix (fout,ccunit,"%.2f "); | ||
373 | fprintf (fout,"s resolution)\n------------\n"); | ||
374 | if (num < 1) return; | ||
375 | |||
376 | // get maximum description length | ||
377 | maxl = 0; | ||
378 | for (i=0; i<num; i++) { | ||
379 | size_t l = strlen (event[i].description); | ||
380 | if (l > maxl) maxl = l; | ||
381 | } | ||
382 | |||
383 | // calculate total time | ||
384 | double t1 = loadClockCount (event[0].cc); | ||
385 | double t2 = loadClockCount (event[num-1].cc); | ||
386 | double total = t2 - t1; | ||
387 | if (total <= 0) total = 1; | ||
388 | |||
389 | // compute time difference for all slots except the last one. update totals | ||
390 | double *times = (double*) ALLOCA (num * sizeof(double)); | ||
391 | for (i=0; i < (num-1); i++) { | ||
392 | double t1 = loadClockCount (event[i].cc); | ||
393 | double t2 = loadClockCount (event[i+1].cc); | ||
394 | times[i] = t2 - t1; | ||
395 | event[i].count++; | ||
396 | event[i].total_t += times[i]; | ||
397 | event[i].total_p += times[i]/total * 100.0; | ||
398 | } | ||
399 | |||
400 | // print report (with optional averages) | ||
401 | for (i=0; i<num; i++) { | ||
402 | double t,p; | ||
403 | if (i < (num-1)) { | ||
404 | t = times[i]; | ||
405 | p = t/total * 100.0; | ||
406 | } | ||
407 | else { | ||
408 | t = total; | ||
409 | p = 100.0; | ||
410 | } | ||
411 | fprintf (fout,"%-*s %7.2fms %6.2f%%",maxl,event[i].description, | ||
412 | t*ccunit * 1000.0, p); | ||
413 | if (average && i < (num-1)) { | ||
414 | fprintf (fout," (avg %7.2fms %6.2f%%)", | ||
415 | (event[i].total_t / event[i].count)*ccunit * 1000.0, | ||
416 | event[i].total_p / event[i].count); | ||
417 | } | ||
418 | fprintf (fout,"\n"); | ||
419 | } | ||
420 | fprintf (fout,"\n"); | ||
421 | } | ||