checkin of ODE library. Do not modify the ODE source code; instead, follow the
[blender.git] / extern / ode / dist / ode / src / timer.cpp
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
107 static inline void getClockCount (unsigned long cc[2])
108 {
109   asm volatile ("
110         rdtsc
111         movl %%eax,(%%esi)
112         movl %%edx,4(%%esi)"
113         : : "S" (cc) : "%eax","%edx","cc","memory");
114 }
115
116
117 static inline void serialize()
118 {
119   asm volatile ("
120         mov $0,%%eax
121         cpuid"
122         : : : "%eax","%ebx","%ecx","%edx","cc","memory");
123 }
124
125
126 static inline double loadClockCount (unsigned long a[2])
127 {
128   double ret;
129   asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
130                 "cc","memory");
131   return ret;
132 }
133
134
135 double dTimerResolution()
136 {
137   return 1.0/PENTIUM_HZ;
138 }
139
140
141 double dTimerTicksPerSecond()
142 {
143   return PENTIUM_HZ;
144 }
145
146 #endif
147
148 //****************************************************************************
149 // otherwise, do the implementation based on gettimeofday().
150
151 #if !defined(PENTIUM) && !defined(WIN32)
152
153 #ifndef macintosh
154
155 #include <sys/time.h>
156 #include <unistd.h>
157
158
159 static inline void getClockCount (unsigned long cc[2])
160 {
161   struct timeval tv;
162   gettimeofday (&tv,0);
163   cc[0] = tv.tv_usec;
164   cc[1] = tv.tv_sec;
165 }
166
167 #else // macintosh
168
169 #include <MacTypes.h>
170 #include <Timer.h>
171
172 static inline void getClockCount (unsigned long cc[2])
173 {
174   UnsignedWide ms;
175   Microseconds (&ms);
176   cc[1] = ms.lo / 1000000;
177   cc[0] = ms.lo - ( cc[1] * 1000000 );
178 }
179
180 #endif
181
182
183 static inline void serialize()
184 {
185 }
186
187
188 static inline double loadClockCount (unsigned long a[2])
189 {
190   return a[1]*1.0e6 + a[0];
191 }
192
193
194 double dTimerResolution()
195 {
196   unsigned long cc1[2],cc2[2];
197   getClockCount (cc1);
198   do {
199     getClockCount (cc2);
200   }
201   while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
202   do {
203     getClockCount (cc1);
204   }
205   while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
206   double t1 = loadClockCount (cc1);
207   double t2 = loadClockCount (cc2);
208   return (t1-t2) / dTimerTicksPerSecond();
209 }
210
211
212 double dTimerTicksPerSecond()
213 {
214   return 1000000;
215 }
216
217 #endif
218
219 //****************************************************************************
220 // stop watches
221
222 void dStopwatchReset (dStopwatch *s)
223 {
224   s->time = 0;
225   s->cc[0] = 0;
226   s->cc[1] = 0;
227 }
228
229
230 void dStopwatchStart (dStopwatch *s)
231 {
232   serialize();
233   getClockCount (s->cc);
234 }
235
236
237 void dStopwatchStop  (dStopwatch *s)
238 {
239   unsigned long cc[2];
240   serialize();
241   getClockCount (cc);
242   double t1 = loadClockCount (s->cc);
243   double t2 = loadClockCount (cc);
244   s->time += t2-t1;
245 }
246
247
248 double dStopwatchTime (dStopwatch *s)
249 {
250   return s->time / dTimerTicksPerSecond();
251 }
252
253 //****************************************************************************
254 // code timers
255
256 // maximum number of events to record
257 #define MAXNUM 100
258
259 static int num = 0;             // number of entries used in event array
260 static struct {
261   unsigned long cc[2];          // clock counts
262   double total_t;               // total clocks used in this slot.
263   double total_p;               // total percentage points used in this slot.
264   int count;                    // number of times this slot has been updated.
265   char *description;            // pointer to static string
266 } event[MAXNUM];
267
268
269 // make sure all slot totals and counts reset to 0 at start
270
271 static void initSlots()
272 {
273   static int initialized=0;
274   if (!initialized) {
275     for (int i=0; i<MAXNUM; i++) {
276       event[i].count = 0;
277       event[i].total_t = 0;
278       event[i].total_p = 0;
279     }
280     initialized = 1;
281   }
282 }
283
284
285 void dTimerStart (const char *description)
286 {
287   initSlots();
288   event[0].description = const_cast<char*> (description);
289   num = 1;
290   serialize();
291   getClockCount (event[0].cc);
292 }
293
294
295 void dTimerNow (const char *description)
296 {
297   if (num < MAXNUM) {
298     // do not serialize
299     getClockCount (event[num].cc);
300     event[num].description = const_cast<char*> (description);
301     num++;
302   }
303 }
304
305
306 void dTimerEnd()
307 {
308   if (num < MAXNUM) {
309     serialize();
310     getClockCount (event[num].cc);
311     event[num].description = "TOTAL";
312     num++;
313   }
314 }
315
316 //****************************************************************************
317 // print report
318
319 static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt)
320 {
321   if (a >= 0.999999) {
322     fprintf (f,fmt,a);
323     return;
324   }
325   a *= 1000.0;
326   if (a >= 0.999999) {
327     fprintf (f,fmt,a);
328     fprintf (f,"m");
329     return;
330   }
331   a *= 1000.0;
332   if (a >= 0.999999) {
333     fprintf (f,fmt,a);
334     fprintf (f,"u");
335     return;
336   }
337   a *= 1000.0;
338   fprintf (f,fmt,a);
339   fprintf (f,"n");
340 }
341
342
343 void dTimerReport (FILE *fout, int average)
344 {
345   int i,maxl;
346   double ccunit = 1.0/dTimerTicksPerSecond();
347   fprintf (fout,"\nTimer Report (");
348   fprintDoubleWithPrefix (fout,ccunit,"%.2f ");
349   fprintf (fout,"s resolution)\n------------\n");
350   if (num < 1) return;
351
352   // get maximum description length
353   maxl = 0;
354   for (i=0; i<num; i++) {
355     int l = strlen (event[i].description);
356     if (l > maxl) maxl = l;
357   }
358
359   // calculate total time
360   double t1 = loadClockCount (event[0].cc);
361   double t2 = loadClockCount (event[num-1].cc);
362   double total = t2 - t1;
363   if (total <= 0) total = 1;
364
365   // compute time difference for all slots except the last one. update totals
366   double *times = (double*) ALLOCA (num * sizeof(double));
367   for (i=0; i < (num-1); i++) {
368     double t1 = loadClockCount (event[i].cc);
369     double t2 = loadClockCount (event[i+1].cc);
370     times[i] = t2 - t1;
371     event[i].count++;
372     event[i].total_t += times[i];
373     event[i].total_p += times[i]/total * 100.0;
374   }
375
376   // print report (with optional averages)
377   for (i=0; i<num; i++) {
378     double t,p;
379     if (i < (num-1)) {
380       t = times[i];
381       p = t/total * 100.0;
382     }
383     else {
384       t = total;
385       p = 100.0;
386     }
387     fprintf (fout,"%-*s %7.2fms %6.2f%%",maxl,event[i].description,
388              t*ccunit * 1000.0, p);
389     if (average && i < (num-1)) {
390       fprintf (fout,"  (avg %7.2fms %6.2f%%)",
391                (event[i].total_t / event[i].count)*ccunit * 1000.0,
392                event[i].total_p / event[i].count);
393     }
394     fprintf (fout,"\n");
395   }
396   fprintf (fout,"\n");
397 }