(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.
authorDarkvater
Sun, 26 Mar 2006 21:15:09 +0000
changeset 3341 b8febc9509d7
parent 3340 eb5021cb6639
child 3342 0de5e6997611
(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
debug.h
functions.h
openttd.dsp
openttd.vcproj
os_timer.c
train_cmd.c
win32.c
--- a/Makefile	Sun Mar 26 21:13:16 2006 +0000
+++ b/Makefile	Sun Mar 26 21:15:09 2006 +0000
@@ -670,6 +670,7 @@
 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
--- a/debug.h	Sun Mar 26 21:13:16 2006 +0000
+++ b/debug.h	Sun Mar 26 21:15:09 2006 +0000
@@ -26,4 +26,27 @@
 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 */
--- a/functions.h	Sun Mar 26 21:13:16 2006 +0000
+++ b/functions.h	Sun Mar 26 21:15:09 2006 +0000
@@ -116,12 +116,6 @@
 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);
--- a/openttd.dsp	Sun Mar 26 21:13:16 2006 +0000
+++ b/openttd.dsp	Sun Mar 26 21:15:09 2006 +0000
@@ -339,6 +339,12 @@
 # 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
--- a/openttd.vcproj	Sun Mar 26 21:13:16 2006 +0000
+++ b/openttd.vcproj	Sun Mar 26 21:15:09 2006 +0000
@@ -299,6 +299,9 @@
 				RelativePath=".\ottdres.rc">
 			</File>
 			<File
+				RelativePath=".\os_timer.c">
+			</File>
+			<File
 				RelativePath=".\pathfind.c">
 			</File>
 			<File
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/os_timer.c	Sun Mar 26 21:15:09 2006 +0000
@@ -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
--- a/train_cmd.c	Sun Mar 26 21:13:16 2006 +0000
+++ b/train_cmd.c	Sun Mar 26 21:15:09 2006 +0000
@@ -2087,29 +2087,6 @@
 };
 
 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 @@
 	TrainTrackFollowerData fd;
 	uint best_track;
 #ifdef PF_BENCHMARK
-	int time = _rdtsc();
-	static float f;
+	TIC()
 #endif
 
 	assert((trackdirbits & ~0x3F) == 0);
@@ -2171,9 +2147,7 @@
 	}
 
 #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;
--- a/win32.c	Sun Mar 26 21:13:16 2006 +0000
+++ b/win32.c	Sun Mar 26 21:15:09 2006 +0000
@@ -62,11 +62,6 @@
 }
 
 #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 void Win32InitializeExceptions(void)
 {
 #ifdef _M_AMD64
+	extern void *_get_save_esp(void);
 	_safe_esp = _get_save_esp();
 #else
 	_asm {
@@ -603,7 +599,7 @@
 
 	SetUnhandledExceptionFilter(ExceptionHandler);
 }
-#endif
+#endif /* _MSC_VER */
 
 static char *_fios_path;
 static char *_fios_save_path;
@@ -1057,17 +1053,6 @@
 	return n;
 }
 
-
-#if defined(_MSC_VER) && !defined(_M_AMD64)
-uint64 _declspec(naked) _rdtsc(void)
-{
-	_asm {
-		rdtsc
-		ret
-	}
-}
-#endif
-
 void CreateConsole(void)
 {
 	HANDLE hand;