PageRenderTime 37ms CodeModel.GetById 23ms app.highlight 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ode/ode_source/ode/src/timer.cpp

http://narutortsproject.googlecode.com/
C++ | 423 lines | 288 code | 77 blank | 58 comment | 24 complexity | ea84ff575c0d3f13ab4f017208b7c215 MD5 | raw file
  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#include "config.h"
 36#include "util.h"
 37
 38// misc defines
 39#define ALLOCA dALLOCA16
 40
 41//****************************************************************************
 42// implementation for windows based on the multimedia performance counter.
 43
 44#ifdef WIN32
 45
 46#include "windows.h"
 47
 48static inline void getClockCount (unsigned long cc[2])
 49{
 50  LARGE_INTEGER a;
 51  QueryPerformanceCounter (&a);
 52  cc[0] = a.LowPart;
 53  cc[1] = a.HighPart;
 54}
 55
 56
 57static inline void serialize()
 58{
 59}
 60
 61
 62static inline double loadClockCount (unsigned long cc[2])
 63{
 64  LARGE_INTEGER a;
 65  a.LowPart = cc[0];
 66  a.HighPart = cc[1];
 67  return double(a.QuadPart);
 68}
 69
 70
 71double dTimerResolution()
 72{
 73  return 1.0/dTimerTicksPerSecond();
 74}
 75
 76
 77double dTimerTicksPerSecond()
 78{
 79  static int query=0;
 80  static double hz=0.0;
 81  if (!query) {
 82    LARGE_INTEGER a;
 83    QueryPerformanceFrequency (&a);
 84    hz = double(a.QuadPart);
 85    query = 1;
 86  }
 87  return hz;
 88}
 89
 90#endif
 91
 92//****************************************************************************
 93// implementation based on the pentium time stamp counter. the timer functions
 94// can be serializing or non-serializing. serializing will ensure that all
 95// instructions have executed and data has been written back before the cpu
 96// time stamp counter is read. the CPUID instruction is used to serialize.
 97
 98#if defined(PENTIUM) && !defined(WIN32)
 99
100// we need to know the clock rate so that the timing function can report
101// accurate times. this number only needs to be set accurately if we're
102// doing performance tests and care about real-world time numbers - otherwise,
103// just ignore this. i have not worked out how to determine this number
104// automatically yet.
105
106#define PENTIUM_HZ (500e6)
107
108static inline void getClockCount (unsigned long cc[2])
109{
110#ifndef X86_64_SYSTEM	
111  asm volatile (
112	"rdtsc\n"
113	"movl %%eax,(%%esi)\n"
114	"movl %%edx,4(%%esi)\n"
115	: : "S" (cc) : "%eax","%edx","cc","memory");
116#else
117  asm volatile (
118	"rdtsc\n"
119	"movl %%eax,(%%rsi)\n"
120	"movl %%edx,4(%%rsi)\n"
121	: : "S" (cc) : "%eax","%edx","cc","memory");
122#endif  
123}
124
125
126static inline void serialize()
127{
128#ifndef X86_64_SYSTEM
129  asm volatile (
130	"mov $0,%%eax\n"
131	"push %%ebx\n"
132	"cpuid\n"
133	"pop %%ebx\n"
134	: : : "%eax","%ecx","%edx","cc","memory");
135#else
136  asm volatile (
137	"mov $0,%%rax\n"
138	"push %%rbx\n"
139	"cpuid\n"
140	"pop %%rbx\n"
141	: : : "%rax","%rcx","%rdx","cc","memory");
142#endif
143}
144
145
146static inline double loadClockCount (unsigned long a[2])
147{
148  double ret;
149#ifndef X86_64_SYSTEM
150  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
151		"cc","memory");
152#else
153  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
154		"cc","memory");
155#endif  
156  return ret;
157}
158
159
160double dTimerResolution()
161{
162  return 1.0/PENTIUM_HZ;
163}
164
165
166double dTimerTicksPerSecond()
167{
168  return PENTIUM_HZ;
169}
170
171#endif
172
173//****************************************************************************
174// otherwise, do the implementation based on gettimeofday().
175
176#if !defined(PENTIUM) && !defined(WIN32)
177
178#ifndef macintosh
179
180#include <sys/time.h>
181#include <unistd.h>
182
183
184static inline void getClockCount (unsigned long cc[2])
185{
186  struct timeval tv;
187  gettimeofday (&tv,0);
188  cc[0] = tv.tv_usec;
189  cc[1] = tv.tv_sec;
190}
191
192#else // macintosh
193
194#include <CoreServices/CoreServices.h>
195#include <ode/Timer.h>
196
197static inline void getClockCount (unsigned long cc[2])
198{
199  UnsignedWide ms;
200  Microseconds (&ms);
201  cc[1] = ms.lo / 1000000;
202  cc[0] = ms.lo - ( cc[1] * 1000000 );
203}
204
205#endif
206
207
208static inline void serialize()
209{
210}
211
212
213static inline double loadClockCount (unsigned long a[2])
214{
215  return a[1]*1.0e6 + a[0];
216}
217
218
219double dTimerResolution()
220{
221  unsigned long cc1[2],cc2[2];
222  getClockCount (cc1);
223  do {
224    getClockCount (cc2);
225  }
226  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
227  do {
228    getClockCount (cc1);
229  }
230  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
231  double t1 = loadClockCount (cc1);
232  double t2 = loadClockCount (cc2);
233  return (t1-t2) / dTimerTicksPerSecond();
234}
235
236
237double dTimerTicksPerSecond()
238{
239  return 1000000;
240}
241
242#endif
243
244//****************************************************************************
245// stop watches
246
247void dStopwatchReset (dStopwatch *s)
248{
249  s->time = 0;
250  s->cc[0] = 0;
251  s->cc[1] = 0;
252}
253
254
255void dStopwatchStart (dStopwatch *s)
256{
257  serialize();
258  getClockCount (s->cc);
259}
260
261
262void dStopwatchStop  (dStopwatch *s)
263{
264  unsigned long cc[2];
265  serialize();
266  getClockCount (cc);
267  double t1 = loadClockCount (s->cc);
268  double t2 = loadClockCount (cc);
269  s->time += t2-t1;
270}
271
272
273double dStopwatchTime (dStopwatch *s)
274{
275  return s->time / dTimerTicksPerSecond();
276}
277
278//****************************************************************************
279// code timers
280
281// maximum number of events to record
282#define MAXNUM 100
283
284static int num = 0;		// number of entries used in event array
285static struct {
286  unsigned long cc[2];		// clock counts
287  double total_t;		// total clocks used in this slot.
288  double total_p;		// total percentage points used in this slot.
289  int count;			// number of times this slot has been updated.
290  const char *description;		// pointer to static string
291} event[MAXNUM];
292
293
294// make sure all slot totals and counts reset to 0 at start
295
296static void initSlots()
297{
298  static int initialized=0;
299  if (!initialized) {
300    for (int i=0; i<MAXNUM; i++) {
301      event[i].count = 0;
302      event[i].total_t = 0;
303      event[i].total_p = 0;
304    }
305    initialized = 1;
306  }
307}
308
309
310void dTimerStart (const char *description)
311{
312  initSlots();
313  event[0].description = const_cast<char*> (description);
314  num = 1;
315  serialize();
316  getClockCount (event[0].cc);
317}
318
319
320void dTimerNow (const char *description)
321{
322  if (num < MAXNUM) {
323    // do not serialize
324    getClockCount (event[num].cc);
325    event[num].description = const_cast<char*> (description);
326    num++;
327  }
328}
329
330
331void dTimerEnd()
332{
333  if (num < MAXNUM) {
334    serialize();
335    getClockCount (event[num].cc);
336    event[num].description = "TOTAL";
337    num++;
338  }
339}
340
341//****************************************************************************
342// print report
343
344static void fprintDoubleWithPrefix (FILE *f, double a, const char *fmt)
345{
346  if (a >= 0.999999) {
347    fprintf (f,fmt,a);
348    return;
349  }
350  a *= 1000.0;
351  if (a >= 0.999999) {
352    fprintf (f,fmt,a);
353    fprintf (f,"m");
354    return;
355  }
356  a *= 1000.0;
357  if (a >= 0.999999) {
358    fprintf (f,fmt,a);
359    fprintf (f,"u");
360    return;
361  }
362  a *= 1000.0;
363  fprintf (f,fmt,a);
364  fprintf (f,"n");
365}
366
367
368void dTimerReport (FILE *fout, int average)
369{
370  int i;
371  size_t maxl;
372  double ccunit = 1.0/dTimerTicksPerSecond();
373  fprintf (fout,"\nTimer Report (");
374  fprintDoubleWithPrefix (fout,ccunit,"%.2f ");
375  fprintf (fout,"s resolution)\n------------\n");
376  if (num < 1) return;
377
378  // get maximum description length
379  maxl = 0;
380  for (i=0; i<num; i++) {
381    size_t l = strlen (event[i].description);
382    if (l > maxl) maxl = l;
383  }
384
385  // calculate total time
386  double t1 = loadClockCount (event[0].cc);
387  double t2 = loadClockCount (event[num-1].cc);
388  double total = t2 - t1;
389  if (total <= 0) total = 1;
390
391  // compute time difference for all slots except the last one. update totals
392  double *times = (double*) ALLOCA (num * sizeof(double));
393  for (i=0; i < (num-1); i++) {
394    double t1 = loadClockCount (event[i].cc);
395    double t2 = loadClockCount (event[i+1].cc);
396    times[i] = t2 - t1;
397    event[i].count++;
398    event[i].total_t += times[i];
399    event[i].total_p += times[i]/total * 100.0;
400  }
401
402  // print report (with optional averages)
403  for (i=0; i<num; i++) {
404    double t,p;
405    if (i < (num-1)) {
406      t = times[i];
407      p = t/total * 100.0;
408    }
409    else {
410      t = total;
411      p = 100.0;
412    }
413    fprintf (fout,"%-*s %7.2fms %6.2f%%",(int)maxl,event[i].description,
414	     t*ccunit * 1000.0, p);
415    if (average && i < (num-1)) {
416      fprintf (fout,"  (avg %7.2fms %6.2f%%)",
417	       (event[i].total_t / event[i].count)*ccunit * 1000.0,
418	       event[i].total_p / event[i].count);
419    }
420    fprintf (fout,"\n");
421  }
422  fprintf (fout,"\n");
423}