From a91c52e16909976b40951cf2893f2349e9ebf25d Mon Sep 17 00:00:00 2001 From: Darkvater Date: Sun, 26 Mar 2006 21:15:09 +0000 Subject: [PATCH] (svn r4125) - Feature: Add a general TIC() TOC() mechanism using rdtsc or something similar on non-i386 architectures to performance-tune (critical) code. Some systems are probably missing, but those can be added later. --- Makefile | 1 + debug.h | 23 +++++++++++++++++ functions.h | 6 ----- openttd.dsp | 6 +++++ openttd.vcproj | 3 +++ os_timer.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ train_cmd.c | 30 ++-------------------- win32.c | 19 ++------------ 8 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 os_timer.c diff --git a/Makefile b/Makefile index c7b53f17ed..d732b971ce 100644 --- a/Makefile +++ b/Makefile @@ -670,6 +670,7 @@ SRCS += oldloader.c SRCS += openttd.c SRCS += order_cmd.c SRCS += order_gui.c +SRCS += os_timer.c SRCS += pathfind.c SRCS += player_gui.c SRCS += players.c diff --git a/debug.h b/debug.h index 71d0dcbd18..9721fb882c 100644 --- a/debug.h +++ b/debug.h @@ -26,4 +26,27 @@ void CDECL debug(const char *s, ...); void SetDebugString(const char *s); const char *GetDebugString(void); +/* MSVC of course has to have a different syntax for long long *sigh* */ +#ifdef _MSC_VER +# define OTTD_PRINTF64 "I64" +#else +# define OTTD_PRINTF64 "ll" +#endif + +// Used for profiling +#define TIC() {\ + extern uint64 _rdtsc(void);\ + uint64 _xxx_ = _rdtsc();\ + static uint64 __sum__ = 0;\ + static uint32 __i__ = 0; + +#define TOC(str, count)\ + __sum__ += _rdtsc() - _xxx_;\ + if (++__i__ == count) {\ + printf("[%s]: %" OTTD_PRINTF64 "u [avg: %.1f]\n", str, __sum__, __sum__/(double)__i__);\ + __i__ = 0;\ + __sum__ = 0;\ + }\ +} + #endif /* DEBUG_H */ diff --git a/functions.h b/functions.h index cf558f3ae1..18fd82d5e1 100644 --- a/functions.h +++ b/functions.h @@ -116,12 +116,6 @@ static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); } uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */ uint InteractiveRandomRange(uint max); - -// Used for profiling -#define TIC() { extern uint32 _rdtsc(void); uint32 _xxx_ = _rdtsc(); static float __avg__; -#define TOC(s) _xxx_ = _rdtsc() - _xxx_; __avg__=__avg__*0.99+_xxx_*0.01; printf("%s: %8d %f\n", s, _xxx_,__avg__); } - - void SetDate(uint date); /* facedraw.c */ void DrawPlayerFace(uint32 face, int color, int x, int y); diff --git a/openttd.dsp b/openttd.dsp index 550d7c6610..b8e28ed7f3 100644 --- a/openttd.dsp +++ b/openttd.dsp @@ -339,6 +339,12 @@ SOURCE=.\ottdres.rc # End Source File # Begin Source File +SOURCE=.\os_timer.c +# End Source File +# Begin Source File + +# Begin Source File + SOURCE=.\pathfind.c # End Source File # Begin Source File diff --git a/openttd.vcproj b/openttd.vcproj index 1f9028ee4b..1fa63899de 100644 --- a/openttd.vcproj +++ b/openttd.vcproj @@ -298,6 +298,9 @@ + + diff --git a/os_timer.c b/os_timer.c new file mode 100644 index 0000000000..89c25d010c --- /dev/null +++ b/os_timer.c @@ -0,0 +1,69 @@ +#include "stdafx.h" + +#undef RDTSC_AVAILABLE + +/* rdtsc for MSC_VER, uses simple inline assembly, or _rdtsc + * from external win64.asm because VS2005 does not support inline assembly */ +#if defined(_MSC_VER) && !defined(RDTSC_AVAILABLE) +# if defined (_M_AMD64) +extern uint64 _rdtsc(void); +# else +uint64 _declspec(naked) _rdtsc(void) +{ + _asm { + rdtsc + ret + } +} +# endif +# define RDTSC_AVAILABLE +#endif + +/* rdtsc for OS/2. Hopefully this works, who knows */ +#if defined (__WATCOMC__) && !defined(RDTSC_AVAILABLE) +unsigned __int64 _rdtsc( void); +# pragma aux _rdtsc = 0x0F 0x31 value [edx eax] parm nomemory modify exact [edx eax] nomemory; +# define RDTSC_AVAILABLE +#endif + +/* rdtsc for all other *nix-en (hopefully). Use GCC syntax */ +#if defined(__i386__) || defined(__x86_64__) && !defined(RDTSC_AVAILABLE) +uint64 _rdtsc(void) +{ + uint32 high, low; + __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high)); + return ((uint64)high << 32) | low; +} +# define RDTSC_AVAILABLE +#endif + +/* rdtsc for PPC which has this not */ +#if defined(__POWERPC__) && !defined(RDTSC_AVAILABLE) +uint64 _rdtsc(void) +{ + uint32 high, low; + uint32 high2 = 0; + /* PPC does not have rdtsc, so we cheat by reading the two 32-bit time-counters + * it has, 'Move From Time Base (Upper)'. Since these are two reads, in the + * very unlikely event that the lower part overflows to the upper part while we + * read it; we double-check and reread the registers */ + asm volatile ( + "mftbu %0\n" + "mftb %1\n" + "mftbu %2\n" + "cmpw %3,%4\n" + "bne- $-16\n" + : "=r" (high), "=r" (low), "=r" (high2) + : "0" (high), "2" (high2) + ); + return ((uint64)high << 32) | low; +} +# define RDTSC_AVAILABLE +#endif + +/* In all other cases we have no support for rdtsc. No major issue, + * you just won't be able to profile your code with TIC()/TOC() */ +#if !defined(RDTSC_AVAILABLE) +#warning "OS has no support for rdtsc()" +uint64 _rdtsc(void) {return 0;} +#endif diff --git a/train_cmd.c b/train_cmd.c index 245f37e3e3..e5fd267724 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -2087,29 +2087,6 @@ static const byte _search_directions[6][4] = { }; static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0}; -#ifdef PF_BENCHMARK -#if !defined(_MSC_VER) -unsigned int _rdtsc() -{ - unsigned int high, low; - - __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high)); - return low; -} -#else -#ifndef _M_AMD64 -static unsigned int _declspec(naked) _rdtsc(void) -{ - _asm { - rdtsc - ret - } -} -#endif -#endif -#endif - - /* choose a track */ static byte ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirbits) @@ -2117,8 +2094,7 @@ static byte ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrainTrackFollowerData fd; uint best_track; #ifdef PF_BENCHMARK - int time = _rdtsc(); - static float f; + TIC() #endif assert((trackdirbits & ~0x3F) == 0); @@ -2171,9 +2147,7 @@ static byte ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, } #ifdef PF_BENCHMARK - time = _rdtsc() - time; - f = f * 0.99 + 0.01 * time; - printf("PF time = %d %f\n", time, f); + TOC("PF time = ", 1) #endif return best_track; diff --git a/win32.c b/win32.c index b95650cca9..6987ffcf2f 100644 --- a/win32.c +++ b/win32.c @@ -62,11 +62,6 @@ bool LoadLibraryList(Function proc[], const char* dll) } #ifdef _MSC_VER -# ifdef _M_AMD64 -void* _get_save_esp(void); -uint64 _rdtsc(void); -# endif - static const char *_exception_string; #endif @@ -594,6 +589,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) static void Win32InitializeExceptions(void) { #ifdef _M_AMD64 + extern void *_get_save_esp(void); _safe_esp = _get_save_esp(); #else _asm { @@ -603,7 +599,7 @@ static void Win32InitializeExceptions(void) SetUnhandledExceptionFilter(ExceptionHandler); } -#endif +#endif /* _MSC_VER */ static char *_fios_path; static char *_fios_save_path; @@ -1057,17 +1053,6 @@ static int ParseCommandLine(char *line, char **argv, int max_argc) return n; } - -#if defined(_MSC_VER) && !defined(_M_AMD64) -uint64 _declspec(naked) _rdtsc(void) -{ - _asm { - rdtsc - ret - } -} -#endif - void CreateConsole(void) { HANDLE hand;