Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/ode/src/timer.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 17 years ago

[Physik] add ode-0.9

File size: 9.4 KB
Line 
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
25TODO
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
46static 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
55static inline void serialize()
56{
57}
58
59
60static 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
69double dTimerResolution()
70{
71  return 1.0/dTimerTicksPerSecond();
72}
73
74
75double 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
106static 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
124static 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
144static 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
158double dTimerResolution()
159{
160  return 1.0/PENTIUM_HZ;
161}
162
163
164double 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
182static 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
195static 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
206static inline void serialize()
207{
208}
209
210
211static inline double loadClockCount (unsigned long a[2])
212{
213  return a[1]*1.0e6 + a[0];
214}
215
216
217double 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
235double dTimerTicksPerSecond()
236{
237  return 1000000;
238}
239
240#endif
241
242//****************************************************************************
243// stop watches
244
245void dStopwatchReset (dStopwatch *s)
246{
247  s->time = 0;
248  s->cc[0] = 0;
249  s->cc[1] = 0;
250}
251
252
253void dStopwatchStart (dStopwatch *s)
254{
255  serialize();
256  getClockCount (s->cc);
257}
258
259
260void 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
271double 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
282static int num = 0;             // number of entries used in event array
283static 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
294static 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
308void 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
318void 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
329void 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
342static 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
366void 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}
Note: See TracBrowser for help on using the repository browser.