ITAHPT.cpp 4.83 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <ITAHPT.h>

// Unsichereres aber genaueres Timestamp Register (RDTSC) anstelle der Windows Performance Counters nutzen
//#define USE_INSECURE_RDTSC

// Kein Inline-Assembler unter 64-Bit Windows. RDTSC-Variante deaktivieren
#ifdef PLATFORM_X64
#ifdef USE_INSECURE_RDTSC
#undef USE_INSECURE_RDTSC
#endif
#endif

#include <cmath>

#include <windows.h>

#include "ITAException.h"

#define RDTSC_MEASUREMENT_LOOPS 1000

static bool _bInitialized = false;
static double _dFrequency;

#ifdef USE_INSECURE_RDTSC

// RDTSC Implementierung

void ITAHPT_init() {
	if (_bInitialized) return;

	// Den hochauflsenden Windows-Timer zum Ausmessen verwenden
	LARGE_INTEGER fPC;
	if (! QueryPerformanceFrequency(&fPC))
		ITA_EXCEPT1(UNKNOWN, "Abfrage der Win32-Timerfrequenz fehlgeschlagen");

	// Wir nehmen einen kritischen Bereich zur besseren Messung
	CRITICAL_SECTION cs;
	InitializeCriticalSection(&cs);
	EnterCriticalSection(&cs);
40

Jonas Stienen's avatar
Jonas Stienen committed
41
42
43
44
45
46
47
48
	// Messprinzip: Bestimmung der Frequenz ber die bekannten
	//              Kenngren des Windows Performance Counters
	LARGE_INTEGER t1, t2, t3, t4;
	_dFrequency = 0;
	for (unsigned int i=0; i<RDTSC_MEASUREMENT_LOOPS; i++) {
		QueryPerformanceCounter((LARGE_INTEGER*) &t3);
		__asm {
			rdtsc
49
50
				mov t1.LowPart,  eax
				mov t1.HighPart, edx
Jonas Stienen's avatar
Jonas Stienen committed
51
52
53
		}

		// Verschwende etwas Zeit, um die Messung stabiler zu machen
54

Jonas Stienen's avatar
Jonas Stienen committed
55
56
57
58
59
60
61
62
63
64
65
66
67
		// Hinweis zur Genauigkeit von Frank Wefers:
		//
		// Auf meinem Pentium-M 1400 MHz ThinkPad betrug bei 10000
		// Verschwedungszyklen (siehe unten) die Abweichung der 
		// gemessenen Frequenz (~1395 MHz) <= +/- 2 MHz
		// Dies entspricht einer Messungenauigkeit von ~1/700

		int s=0;
		for (unsigned int i=0; i<10000; i++) s += i;

		QueryPerformanceCounter((LARGE_INTEGER*) &t4);
		__asm {
			rdtsc
68
69
				mov t2.LowPart,  eax
				mov t2.HighPart, edx
Jonas Stienen's avatar
Jonas Stienen committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
		}

		double d1 = (double) (t2.QuadPart - t1.QuadPart);
		double d2 = (double) (t4.QuadPart - t3.QuadPart);
		_dFrequency += d1 / (d2 / ((double) fPC.QuadPart));
	}

	LeaveCriticalSection(&cs);
	DeleteCriticalSection(&cs);

	_dFrequency /= RDTSC_MEASUREMENT_LOOPS;
	_bInitialized = true;
}

#else

// Windows Performance Counter Implementierung

void ITAHPT_init() {
89
	if( _bInitialized ) return;
Jonas Stienen's avatar
Jonas Stienen committed
90
91
92

	// Den hochauflsenden Windows-Timer zum Ausmessen verwenden
	LARGE_INTEGER li;
93
94
	if( !QueryPerformanceFrequency( &li ) )
		ITA_EXCEPT1( UNKNOWN, "Abfrage der Win32-Timerfrequenz fehlgeschlagen" );
Jonas Stienen's avatar
Jonas Stienen committed
95

96
	_dFrequency = ( double ) li.QuadPart;
Jonas Stienen's avatar
Jonas Stienen committed
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	_bInitialized = true;
}

#endif

#ifdef USE_INSECURE_RDTSC

// RDTSC Implementierung

ITATimerTicks ITAHPT_now() {
	if (!_bInitialized) ITAHPT_init();

	LARGE_INTEGER t;
	__asm {
		rdtsc
112
113
			mov t.LowPart,  eax
			mov t.HighPart, edx
Jonas Stienen's avatar
Jonas Stienen committed
114
115
116
117
118
119
120
121
122
	}
	return (ITATimerTicks) t.QuadPart;
}

#else

// Windows Performance Counter Implementierung

ITATimerTicks ITAHPT_now() {
123
	if( !_bInitialized ) ITAHPT_init();
Jonas Stienen's avatar
Jonas Stienen committed
124
125

	LARGE_INTEGER li;
126
127
	QueryPerformanceCounter( &li );
	return ( ITATimerTicks ) li.QuadPart;
Jonas Stienen's avatar
Jonas Stienen committed
128
129
130
131
}

#endif

132
double ITAHPT_frequency() {
Jonas Stienen's avatar
Jonas Stienen committed
133
134
135
136
	return _dFrequency;
}

double ITAHPT_resolution() {
137
	return 1 / _dFrequency;
Jonas Stienen's avatar
Jonas Stienen committed
138
139
}

140
141
ITATimerTicks toTimerTicks( double t ) {
	return ( ITATimerTicks ) ceil( t * ( double ) _dFrequency );
Jonas Stienen's avatar
Jonas Stienen committed
142
143
}

144
145
double toSeconds( ITATimerTicks n ) {
	return ( ( double ) n ) / ( ( double ) _dFrequency );
Jonas Stienen's avatar
Jonas Stienen committed
146
147
}

148
149
std::string toString( ITATimerTicks n ) {
	// Der Einfachheit und berlaufsicherheit-halber in 64-Bit rechnen:
Jonas Stienen's avatar
Jonas Stienen committed
150
	__int64 h, m, s, ms, mus, ns;
151
152
	ns = ( __int64 ) floor( toSeconds( n ) * 1000000000.0 );
	mus = ns / 1000;
Jonas Stienen's avatar
Jonas Stienen committed
153
154
155
156
157
158
159
160
161
162
	ns %= 1000;
	ms = mus / 1000; // Idee: Wert im 10^(-3) faktorisieren.
	mus %= 1000;     //   ... Modulus (Rest) brig lassen.
	s = ms / 1000;
	ms %= 1000;
	m = s / 60;
	s %= 60;
	h = m / 60;
	m %= 60;

163
164
165
166
	char buffer[ 255 ];
	sprintf( buffer, "%I64dh%I64dm%I64ds%I64dms%I64dmks%I64dns",
		h, m, s, ms, mus, ns );
	return std::string( buffer );
Jonas Stienen's avatar
Jonas Stienen committed
167
168
169
170
}

/*
std::string cleverFourDigits(double x) {
171
172
173
174
175
176
177
178
179
180
181
182
char buf[255];
if (x < 1)
sprintf(buf, "%0.3f", x);
else
if (x < 10)
sprintf(buf, "%0.2f", x);
else
if (x < 100)
sprintf(buf, "%0.1f", x);
else
sprintf(buf, "%0.0f", x);
return buf;
Jonas Stienen's avatar
Jonas Stienen committed
183
184
185
}
*/

186
187
std::string convertTimeToHumanReadableString( double dSeconds ) {
	char buf[ 255 ];
Jonas Stienen's avatar
Jonas Stienen committed
188
189
190

	//if (dSeconds == 0) return "0 s ";

191
	if( dSeconds < 0.000001 ) { // Kleiner als 1 ms
Jonas Stienen's avatar
Jonas Stienen committed
192
		//return cleverFourDigits(dSeconds*1000000000) + " ns";
193
194
		sprintf( buf, "%0.3f ns", dSeconds * 1000000000 );
		return std::string( buf );
Jonas Stienen's avatar
Jonas Stienen committed
195
196
	}

197
	if( dSeconds < 0.001 ) { // Kleiner als 1 ms
Jonas Stienen's avatar
Jonas Stienen committed
198
		//return cleverFourDigits(dSeconds*1000000) + " us";
199
200
		sprintf( buf, "%0.3f us", dSeconds * 1000000 );
		return std::string( buf );
Jonas Stienen's avatar
Jonas Stienen committed
201
202
	}

203
	if( dSeconds < 1 ) { // Kleiner als 1 ms
Jonas Stienen's avatar
Jonas Stienen committed
204
		//return cleverFourDigits(dSeconds*1000) + " ms";
205
206
		sprintf( buf, "%0.3f ms", dSeconds * 1000 );
		return std::string( buf );
Jonas Stienen's avatar
Jonas Stienen committed
207
	}
208
209
210
	/*
		__int64 iSecs = ceil(dSeconds);
		double iHSecs = dSeconds - iSecs;
Jonas Stienen's avatar
Jonas Stienen committed
211

212
		if (iSecs < 60) {
Jonas Stienen's avatar
Jonas Stienen committed
213
214
		sprintf(buf, "%0.3f s ", dSeconds);
		return buf;
215
216
217
218
		}
		*/
	sprintf( buf, "%0.3f s", dSeconds );
	return std::string( buf );
Jonas Stienen's avatar
Jonas Stienen committed
219
}