File: timeit.c

package info (click to toggle)
judy 1.0.5-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,728 kB
  • sloc: ansic: 25,489; sh: 9,661; makefile: 420
file content (311 lines) | stat: -rw-r--r-- 8,089 bytes parent folder | download | duplicates (7)
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
// @(#) $Revision: 4.12 $ $Source: /judy/judy/src/apps/benchmark/timeit.c,v $
//
// Timer functions.
//
// YOU MUST COMPILE THIS WITH ONE OF THESE DEFINED:
//
//   JU_HPUX_PA
//   JU_HPUX_IPF
//   JU_LINUX_IA32
//   JU_LINUX_IPF
//   JU_WIN_IA32
//
// If NONE of these are defined, this whole code section is ifdef'd out to
// avoid compile/link errors due to usage here of objects not defined in
// timeit.h.  See end of file.
//
// TBD:  Improve on this; possibly it's OK now not to ifdef this out, and get
// default, low-res timing behavior; see timeit.h.
//
// Compile with -D_TIMEIT_TEST to include a main program for testing; see
// main() below.

#if (JU_HPUX_PA || JU_LINUX_IA32 || JU_LINUX_IPF)
#define _TIMEIT_HIGHRES
#endif

#ifdef _TIMEIT_HIGHRES

#include <sys/time.h>		// Win32 uses a whole different paradigm.
#include <unistd.h>		// for getopt(), which Win32 lacks.
#include <time.h>
#include "timeit.h"

double USecPerClock;	// usec per control register count.


// ****************************************************************************
// F I N D   C P U   S P E E D
//
// Return microseconds per control/timer register count.  Examples:
//
// 0.002 for 500 MHz processor
// 0.001 for 1 GHz processor

double find_CPU_speed(void)
{
	double DeltaUSec;	// Timing result in uSec.
	TIMER_vars(tm);		// creates __TVBeg_tm, ...
				// (used for consistency with __START_HRTm)

	gettimeofday(&__TVBeg_tm, NULL);	// get low-res time.
	__START_HRTm(tm);			// get __start_tm (high-res).
	sleep(1);				// time passes; 1 sec suffices.
	__END_HRTm(tm);				// get __stop_tm (high-res).
	gettimeofday(&__TVEnd_tm, NULL);	// get low-res time.

// gettimeofday() returns usec; compute elapsed time:

	DeltaUSec = (((double) __TVEnd_tm.tv_sec * ((double) 1E6))
		    + (double) __TVEnd_tm.tv_usec)
		  - (((double) __TVBeg_tm.tv_sec * ((double) 1E6))
		    + (double) __TVBeg_tm.tv_usec);

// Control register returns ticks, and the ratio can now be computed:

	return (DeltaUSec / ((double) (__stop_tm - __start_tm)));

} // find_CPU_speed()

#else // _TIMEIT_HIGHRES
void dummy() {}	 // avoid "empty source file" warnings when no _TIMEIT_TEST.
#endif


// ****************************************************************************
//
// Ifdef the test main() separately, including #includes, for platforms that do
// not define find_CPU_speed() above.

#ifdef _TIMEIT_TEST

#include <sys/time.h>		// Win32 uses a whole different paradigm.
#include <unistd.h>		// for getopt(), which Win32 lacks.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//#include <values.h>             // for MAXDOUBLE
#define MAXDOUBLE       (10e99)
#include "timeit.h"


// ****************************************************************************
// M A I N
//
// Example code for timeit:
//
// To compile and test this program on HP-UX, run the next lines as commands.
//
//   cc -Wl,-a,archive -DJU_HPUX_PA -D__HPUX__ -D_TIMEIT_TEST -o timeit timeit.c
//   timeit			# run test program.
//   rm -f timeit		# clean up after test.

int main(int argc, char **argv)
{
	int     i = 0;		// loop index.
	long    i_max = 10;	// number of loops.
	int     preload = 1;	// loops to throw away (preload cache).
	double  ztime;		// timer overhead.
	double  usec[4];	// for early timing tests.
	double  DeltaUSec;	// timing result in usec.
	double  prevtime;	// from previous loop.
	double  mintime;	// minimum event time.
	struct timeval tmjunk;	// for throw-away syscall.
	TIMER_vars(tm1);	// overall timer variables.
	TIMER_vars(tm2);	// misc + loop timer variables.


// INITIALIZE:

	STARTTm(tm1);		// whole program timer.

	i_max += preload;

// The first arg is the number of iterations (default is i_max):

	if (argc > 1)
	{
	    i = atoi(argv[1]) + preload;
	    if (i > 0) i_max = (long)i;
	}

// Calculate timer overhead (ztime):

#ifdef _TIMEIT_HIGHRES
	(void) puts("Possible slight delay here due to find_CPU_speed()...");
#else
	(void) puts("No high-res clock or find_CPU_speed() for this platform.");
#endif

	ztime = 0.0;

	for (i = 0; i < 100; ++i)	// average many runs.
	{
	    STARTTm(tm2);
	    ENDTm(DeltaUSec, tm2);
	    ztime += DeltaUSec;
	}
	ztime = ztime / ((double) i);


// SIMPLE TESTS OF TIMER OVERHEAD:
//
// Make two passes at both the high-res (if any) and slower timers.

	(void) puts("\nTiming timers themselves: start, end, end");

#define	PRINTPASS(Desc,Pass)						\
	(void) printf("%-8s pass %d:  %f - %f = %f usec\n", Desc, Pass,	\
		      usec[((Pass) * 2) - 1],  usec[((Pass) * 2) - 2],	\
		      usec[((Pass) * 2) - 1] - usec[((Pass) * 2) - 2])

#ifdef _TIMEIT_HIGHRES
	START_HRTm(tm2);
	END_HRTm(usec[0], tm2);	// throw away in case of sleep(1) here.

	START_HRTm(tm2);
	END_HRTm(usec[0], tm2);
	END_HRTm(usec[1], tm2);

	START_HRTm(tm2);
	END_HRTm(usec[2], tm2);
	END_HRTm(usec[3], tm2);

	PRINTPASS("High-res", 1);
	PRINTPASS("High-res", 2);
#endif

	STARTTm(tm2);
	ENDTm(usec[0], tm2);	// throw away in case of sleep(1) here.

	STARTTm(tm2);
	ENDTm(usec[0], tm2);
	ENDTm(usec[1], tm2);

	STARTTm(tm2);
	ENDTm(usec[2], tm2);
	ENDTm(usec[3], tm2);

	PRINTPASS("Non-HR", 1);
	PRINTPASS("Non-HR", 2);


// PRINT INITIAL INFO:

#ifdef _TIMEIT_HIGHRES

// Print the CPU speed:
//
// Note:  USecPerClock is a global set by the first instance of STARTTm.  You
// can also get this number by calling find_CPU_speed().

	(void) printf("\nClock step = %.3f nsec => %.1f MHz.\n",
		      USecPerClock * 1000.0, 1.0 / USecPerClock);
#endif

// Print timer overhead even though it's been subtracted from the reported
// results.

	(void) printf("Timer overhead subtracted from the times below = %f "
		      "usec.\n", ztime);


// DO A FAST TIMER CHECK:

	(void) puts("\nCheck timer precision by repeating the same action:");
	(void) puts("Times in each group should be close together.");
	(void) puts("\nTiming something very fast: \"++i\":");

	mintime = MAXDOUBLE;

	for (i = 1; i <= i_max; ++i)
	{
	    prevtime = DeltaUSec;
	    STARTTm(tm2);		// start the timer.
	    ++i;			// statement to time.
	    ENDTm(DeltaUSec, tm2);	// stop the timer.
	    DeltaUSec -= ztime;		// remove timer overhead.

// Throw away the first loop iteration to warm up the cache:

	    if (--i > preload)
	    {
		if (mintime == MAXDOUBLE) mintime = DeltaUSec;

		(void) printf("%3d. %8.3f nanosec,\tmintime diff %8.1f %%\n",
			      i - preload, DeltaUSec * 1000.0,
			      ((DeltaUSec - mintime) * 100) / mintime);

		if (DeltaUSec < mintime) mintime = DeltaUSec;
	    }
	}


// TIME A FUNCTION CALL:

	(void) puts("\nTiming a function: \"gettimeofday()\":");
	mintime = MAXDOUBLE;

	for (i = 1; i <= i_max; ++i)
	{
	    prevtime = DeltaUSec;
	    STARTTm(tm2);			// start the timer.
	    gettimeofday(&tmjunk, NULL);	// burn some cycles.
	    ENDTm(DeltaUSec, tm2);		// stop the timer.
	    DeltaUSec -= ztime;			// remove timer overhead.

// Throw away the first loop iteration to warm up the cache:

	    if (i > preload)
	    {
		if (mintime == MAXDOUBLE) mintime = DeltaUSec;

		(void) printf("%3d. %8.3f usec,\tmintime diff %8.1f %%\n",
			      i - preload, DeltaUSec,
			      ((DeltaUSec - mintime) * 100) / mintime);

		if (DeltaUSec < mintime) mintime = DeltaUSec;
	    }
	}


// TIME SOMETHING SLOW:

	(void) puts("\nTiming something slow: \"sleep(1)\":");
	mintime = MAXDOUBLE;

	for (i = 1; i <= i_max; ++i)
	{
	    prevtime = DeltaUSec;
	    STARTTm(tm2);		// start the timer.
	    sleep(1);
	    ENDTm(DeltaUSec, tm2);	// stop the timer.
	    DeltaUSec -= ztime;		// remove timer overhead.

// Throw away the first loop iteration to warm up the cache:

	    if (i > preload)
	    {
		if (mintime == MAXDOUBLE) mintime = DeltaUSec;

		(void) printf("%3d. %8.3f sec,\tmintime diff %8.1f %%\n",
			      i - preload, DeltaUSec/1E6,
			      ((DeltaUSec - mintime) * 100) / mintime);

		if (DeltaUSec < mintime) mintime = DeltaUSec;
	    }
	}


// FINISH UP:
//
// Print program execution time:

	ENDTm(DeltaUSec, tm1);
	(void) printf("\nProgram execution time: %.3f sec\n", DeltaUSec / 1E6);
	return(0);

} // main()

#endif // #ifdef _TIMEIT_TEST