| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /*************************************************************************
- * *
- * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
- * All rights reserved. Email: [email protected] Web: www.q12.org *
- * *
- * This library is free software; you can redistribute it and/or *
- * modify it under the terms of EITHER: *
- * (1) The GNU Lesser General Public License as published by the Free *
- * Software Foundation; either version 2.1 of the License, or (at *
- * your option) any later version. The text of the GNU Lesser *
- * General Public License is included with this library in the *
- * file LICENSE.TXT. *
- * (2) The BSD-style license that is included with this library in *
- * the file LICENSE-BSD.TXT. *
- * *
- * This library is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
- * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
- * *
- *************************************************************************/
- /*
- TODO
- ----
- * gettimeofday() and the pentium time stamp counter return the real time,
- not the process time. fix this somehow!
- */
- #include <ode/common.h>
- #include <ode/timer.h>
- #include "config.h"
- #include "common.h"
- // misc defines
- #define ALLOCA dALLOCA16
- //****************************************************************************
- // implementation for windows based on the multimedia performance counter.
- #ifdef WIN32
- #include "windows.h"
- static inline void getClockCount (unsigned long cc[2])
- {
- LARGE_INTEGER a;
- QueryPerformanceCounter (&a);
- cc[0] = a.LowPart;
- cc[1] = a.HighPart;
- }
- static inline void serialize()
- {
- }
- static inline double loadClockCount (unsigned long cc[2])
- {
- LARGE_INTEGER a;
- a.LowPart = cc[0];
- a.HighPart = cc[1];
- return double(a.QuadPart);
- }
- double dTimerResolution()
- {
- return 1.0/dTimerTicksPerSecond();
- }
- double dTimerTicksPerSecond()
- {
- static int query=0;
- static double hz=0.0;
- if (!query) {
- LARGE_INTEGER a;
- QueryPerformanceFrequency (&a);
- hz = double(a.QuadPart);
- query = 1;
- }
- return hz;
- }
- #endif
- //****************************************************************************
- // implementation based on the pentium time stamp counter. the timer functions
- // can be serializing or non-serializing. serializing will ensure that all
- // instructions have executed and data has been written back before the cpu
- // time stamp counter is read. the CPUID instruction is used to serialize.
- #if defined(PENTIUM) && !defined(WIN32)
- // we need to know the clock rate so that the timing function can report
- // accurate times. this number only needs to be set accurately if we're
- // doing performance tests and care about real-world time numbers - otherwise,
- // just ignore this. i have not worked out how to determine this number
- // automatically yet.
- #define PENTIUM_HZ (500e6)
- static inline void getClockCount (unsigned long cc[2])
- {
- #ifndef X86_64_SYSTEM
- asm volatile (
- "rdtsc\n"
- "movl %%eax,(%%esi)\n"
- "movl %%edx,4(%%esi)\n"
- : : "S" (cc) : "%eax","%edx","cc","memory");
- #else
- asm volatile (
- "rdtsc\n"
- "movl %%eax,(%%rsi)\n"
- "movl %%edx,4(%%rsi)\n"
- : : "S" (cc) : "%eax","%edx","cc","memory");
- #endif
- }
- static inline void serialize()
- {
- #ifndef X86_64_SYSTEM
- asm volatile (
- "mov $0,%%eax\n"
- "push %%ebx\n"
- "cpuid\n"
- "pop %%ebx\n"
- : : : "%eax","%ecx","%edx","cc","memory");
- #else
- asm volatile (
- "mov $0,%%rax\n"
- "push %%rbx\n"
- "cpuid\n"
- "pop %%rbx\n"
- : : : "%rax","%rcx","%rdx","cc","memory");
- #endif
- }
- static inline double loadClockCount (unsigned long a[2])
- {
- double ret;
- #ifndef X86_64_SYSTEM
- asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
- "cc","memory");
- #else
- asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
- "cc","memory");
- #endif
- return ret;
- }
- double dTimerResolution()
- {
- return 1.0/PENTIUM_HZ;
- }
- double dTimerTicksPerSecond()
- {
- return PENTIUM_HZ;
- }
- #endif
- //****************************************************************************
- // otherwise, do the implementation based on gettimeofday().
- #if !defined(PENTIUM) && !defined(WIN32)
- #ifndef macintosh
- #include <sys/time.h>
- #include <unistd.h>
- static inline void getClockCount (unsigned long cc[2])
- {
- struct timeval tv;
- gettimeofday (&tv,0);
- cc[0] = tv.tv_usec;
- cc[1] = tv.tv_sec;
- }
- #else // macintosh
- #include <CoreServices/CoreServices.h>
- #include <ode/Timer.h>
- static inline void getClockCount (unsigned long cc[2])
- {
- UnsignedWide ms;
- Microseconds (&ms);
- cc[1] = ms.lo / 1000000;
- cc[0] = ms.lo - ( cc[1] * 1000000 );
- }
- #endif
- static inline void serialize()
- {
- }
- static inline double loadClockCount (unsigned long a[2])
- {
- return a[1]*1.0e6 + a[0];
- }
- double dTimerResolution()
- {
- unsigned long cc1[2],cc2[2];
- getClockCount (cc1);
- do {
- getClockCount (cc2);
- }
- while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
- do {
- getClockCount (cc1);
- }
- while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
- double t1 = loadClockCount (cc1);
- double t2 = loadClockCount (cc2);
- return (t1-t2) / dTimerTicksPerSecond();
- }
- double dTimerTicksPerSecond()
- {
- return 1000000;
- }
- #endif
- //****************************************************************************
- // stop watches
- void dStopwatchReset (dStopwatch *s)
- {
- s->time = 0;
- s->cc[0] = 0;
- s->cc[1] = 0;
- }
- void dStopwatchStart (dStopwatch *s)
- {
- serialize();
- getClockCount (s->cc);
- }
- void dStopwatchStop (dStopwatch *s)
- {
- unsigned long cc[2];
- serialize();
- getClockCount (cc);
- double t1 = loadClockCount (s->cc);
- double t2 = loadClockCount (cc);
- s->time += t2-t1;
- }
- double dStopwatchTime (dStopwatch *s)
- {
- return s->time / dTimerTicksPerSecond();
- }
- //****************************************************************************
- // code timers
- // maximum number of events to record
- #define MAXNUM 100
- static int num = 0; // number of entries used in event array
- static struct {
- unsigned long cc[2]; // clock counts
- double total_t; // total clocks used in this slot.
- double total_p; // total percentage points used in this slot.
- int count; // number of times this slot has been updated.
- const char *description; // pointer to static string
- } event[MAXNUM];
- // make sure all slot totals and counts reset to 0 at start
- static void initSlots()
- {
- static int initialized=0;
- if (!initialized) {
- for (int i=0; i<MAXNUM; i++) {
- event[i].count = 0;
- event[i].total_t = 0;
- event[i].total_p = 0;
- }
- initialized = 1;
- }
- }
- void dTimerStart (const char *description)
- {
- initSlots();
- event[0].description = const_cast<char*> (description);
- num = 1;
- serialize();
- getClockCount (event[0].cc);
- }
- void dTimerNow (const char *description)
- {
- if (num < MAXNUM) {
- // do not serialize
- getClockCount (event[num].cc);
- event[num].description = const_cast<char*> (description);
- num++;
- }
- }
- void dTimerEnd()
- {
- if (num < MAXNUM) {
- serialize();
- getClockCount (event[num].cc);
- event[num].description = "TOTAL";
- num++;
- }
- }
- //****************************************************************************
- // print report
- static void fprintDoubleWithPrefix (FILE *f, double a, const char *fmt)
- {
- if (a >= 0.999999) {
- fprintf (f,fmt,a);
- return;
- }
- a *= 1000.0;
- if (a >= 0.999999) {
- fprintf (f,fmt,a);
- fprintf (f,"m");
- return;
- }
- a *= 1000.0;
- if (a >= 0.999999) {
- fprintf (f,fmt,a);
- fprintf (f,"u");
- return;
- }
- a *= 1000.0;
- fprintf (f,fmt,a);
- fprintf (f,"n");
- }
- void dTimerReport (FILE *fout, int average)
- {
- int i;
- sizeint maxl;
- double ccunit = 1.0/dTimerTicksPerSecond();
- fprintf (fout,"\nTimer Report (");
- fprintDoubleWithPrefix (fout,ccunit,"%.2f ");
- fprintf (fout,"s resolution)\n------------\n");
- if (num < 1) return;
- // get maximum description length
- maxl = 0;
- for (i=0; i<num; i++) {
- sizeint l = strlen (event[i].description);
- if (l > maxl) maxl = l;
- }
- // calculate total time
- double t1 = loadClockCount (event[0].cc);
- double t2 = loadClockCount (event[num-1].cc);
- double total = t2 - t1;
- if (total <= 0) total = 1;
- // compute time difference for all slots except the last one. update totals
- double *times = (double*) ALLOCA (num * sizeof(double));
- for (i=0; i < (num-1); i++) {
- double t1 = loadClockCount (event[i].cc);
- double t2 = loadClockCount (event[i+1].cc);
- times[i] = t2 - t1;
- event[i].count++;
- event[i].total_t += times[i];
- event[i].total_p += times[i]/total * 100.0;
- }
- // print report (with optional averages)
- for (i=0; i<num; i++) {
- double t,p;
- if (i < (num-1)) {
- t = times[i];
- p = t/total * 100.0;
- }
- else {
- t = total;
- p = 100.0;
- }
- fprintf (fout,"%-*s %7.2fms %6.2f%%",(int)maxl,event[i].description,
- t*ccunit * 1000.0, p);
- if (average && i < (num-1)) {
- fprintf (fout," (avg %7.2fms %6.2f%%)",
- (event[i].total_t / event[i].count)*ccunit * 1000.0,
- event[i].total_p / event[i].count);
- }
- fprintf (fout,"\n");
- }
- fprintf (fout,"\n");
- }
|