2727#define NA_FORMAT "%18s"
2828#define OPS_FORMAT "%9.3f ops/sec"
2929
30+ /* These are macros to avoid timing the function call overhead. */
31+ #define START_TIMER \
32+ do { \
33+ alarm_triggered = false; \
34+ alarm(secs_per_test); \
35+ gettimeofday(&start_t, NULL); \
36+ } while (0)
37+
38+ #define STOP_TIMER \
39+ do { \
40+ gettimeofday(&stop_t, NULL); \
41+ print_elapse(start_t, stop_t, ops); \
42+ } while (0)
43+
44+
3045static const char * progname ;
3146
32- static int ops_per_test = 2000 ;
47+ static int secs_per_test = 2 ;
3348static int needs_unlink = 0 ;
3449static char full_buf [XLOG_SEG_SIZE ],
3550* buf ,
3651* filename = FSYNC_FILENAME ;
3752static struct timeval start_t ,
3853stop_t ;
54+ static bool alarm_triggered = false;
3955
4056
4157static void handle_args (int argc ,char * argv []);
@@ -46,12 +62,13 @@ static void test_sync(int writes_per_op);
4662static void test_open_syncs (void );
4763static void test_open_sync (const char * msg ,int writes_size );
4864static void test_file_descriptor_sync (void );
65+ static void process_alarm (int sig );
4966static void signal_cleanup (int sig );
5067
5168#ifdef HAVE_FSYNC_WRITETHROUGH
5269static int pg_fsync_writethrough (int fd );
5370#endif
54- static void print_elapse (struct timeval start_t ,struct timeval stop_t );
71+ static void print_elapse (struct timeval start_t ,struct timeval stop_t , int ops );
5572static void die (const char * str );
5673
5774
@@ -65,6 +82,7 @@ main(int argc, char *argv[])
6582/* Prevent leaving behind the test file */
6683signal (SIGINT ,signal_cleanup );
6784signal (SIGTERM ,signal_cleanup );
85+ signal (SIGALRM ,process_alarm );
6886#ifdef SIGHUP
6987/* Not defined on win32 */
7088signal (SIGHUP ,signal_cleanup );
@@ -96,7 +114,7 @@ handle_args(int argc, char *argv[])
96114{
97115static struct option long_options []= {
98116{"filename" ,required_argument ,NULL ,'f' },
99- {"ops -per-test" ,required_argument ,NULL ,'o ' },
117+ {"secs -per-test" ,required_argument ,NULL ,'s ' },
100118{NULL ,0 ,NULL ,0 }
101119};
102120int option ;/* Command line option */
@@ -107,7 +125,7 @@ handle_args(int argc, char *argv[])
107125if (strcmp (argv [1 ],"--help" )== 0 || strcmp (argv [1 ],"-h" )== 0 ||
108126strcmp (argv [1 ],"-?" )== 0 )
109127{
110- printf ("Usage: %s [-f FILENAME] [-o OPS -PER-TEST]\n" ,progname );
128+ printf ("Usage: %s [-f FILENAME] [-s SECS -PER-TEST]\n" ,progname );
111129exit (0 );
112130}
113131if (strcmp (argv [1 ],"--version" )== 0 || strcmp (argv [1 ],"-V" )== 0 )
@@ -117,7 +135,7 @@ handle_args(int argc, char *argv[])
117135}
118136}
119137
120- while ((option = getopt_long (argc ,argv ,"f:o :" ,
138+ while ((option = getopt_long (argc ,argv ,"f:s :" ,
121139long_options ,& optindex ))!= -1 )
122140{
123141switch (option )
@@ -126,8 +144,8 @@ handle_args(int argc, char *argv[])
126144filename = strdup (optarg );
127145break ;
128146
129- case 'o ' :
130- ops_per_test = atoi (optarg );
147+ case 's ' :
148+ secs_per_test = atoi (optarg );
131149break ;
132150
133151default :
@@ -148,7 +166,7 @@ handle_args(int argc, char *argv[])
148166exit (1 );
149167}
150168
151- printf ("%doperations per test\n" ,ops_per_test );
169+ printf ("%dseconds per test\n" ,secs_per_test );
152170#if PG_O_DIRECT != 0
153171printf ("O_DIRECT supported on this platform for open_datasync and open_sync.\n" );
154172#else
@@ -220,18 +238,17 @@ test_sync(int writes_per_op)
220238{
221239if ((tmpfile = open (filename ,O_RDWR |O_DSYNC |PG_O_DIRECT ,0 ))== -1 )
222240die ("could not open output file" );
223- gettimeofday ( & start_t , NULL ) ;
224- for (ops = 0 ;ops < ops_per_test ;ops ++ )
241+ START_TIMER ;
242+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
225243{
226244for (writes = 0 ;writes < writes_per_op ;writes ++ )
227245if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
228246die ("write failed" );
229247if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
230248die ("seek failed" );
231249}
232- gettimeofday ( & stop_t , NULL ) ;
250+ STOP_TIMER ;
233251close (tmpfile );
234- print_elapse (start_t ,stop_t );
235252}
236253#else
237254printf (NA_FORMAT ,"n/a\n" );
@@ -246,8 +263,8 @@ test_sync(int writes_per_op)
246263#ifdef HAVE_FDATASYNC
247264if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
248265die ("could not open output file" );
249- gettimeofday ( & start_t , NULL ) ;
250- for (ops = 0 ;ops < ops_per_test ;ops ++ )
266+ START_TIMER ;
267+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
251268{
252269for (writes = 0 ;writes < writes_per_op ;writes ++ )
253270if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
@@ -256,9 +273,8 @@ test_sync(int writes_per_op)
256273if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
257274die ("seek failed" );
258275}
259- gettimeofday ( & stop_t , NULL ) ;
276+ STOP_TIMER ;
260277close (tmpfile );
261- print_elapse (start_t ,stop_t );
262278#else
263279printf (NA_FORMAT ,"n/a\n" );
264280#endif
@@ -271,8 +287,8 @@ test_sync(int writes_per_op)
271287
272288if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
273289die ("could not open output file" );
274- gettimeofday ( & start_t , NULL ) ;
275- for (ops = 0 ;ops < ops_per_test ;ops ++ )
290+ START_TIMER ;
291+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
276292{
277293for (writes = 0 ;writes < writes_per_op ;writes ++ )
278294if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
@@ -282,9 +298,8 @@ test_sync(int writes_per_op)
282298if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
283299die ("seek failed" );
284300}
285- gettimeofday ( & stop_t , NULL ) ;
301+ STOP_TIMER ;
286302close (tmpfile );
287- print_elapse (start_t ,stop_t );
288303
289304/*
290305 * If fsync_writethrough is available, test as well
@@ -295,8 +310,8 @@ test_sync(int writes_per_op)
295310#ifdef HAVE_FSYNC_WRITETHROUGH
296311if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
297312die ("could not open output file" );
298- gettimeofday ( & start_t , NULL ) ;
299- for (ops = 0 ;ops < ops_per_test ;ops ++ )
313+ START_TIMER ;
314+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
300315{
301316for (writes = 0 ;writes < writes_per_op ;writes ++ )
302317if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
@@ -306,9 +321,8 @@ test_sync(int writes_per_op)
306321if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
307322die ("seek failed" );
308323}
309- gettimeofday ( & stop_t , NULL ) ;
324+ STOP_TIMER ;
310325close (tmpfile );
311- print_elapse (start_t ,stop_t );
312326#else
313327printf (NA_FORMAT ,"n/a\n" );
314328#endif
@@ -327,18 +341,17 @@ test_sync(int writes_per_op)
327341}
328342else
329343{
330- gettimeofday ( & start_t , NULL ) ;
331- for (ops = 0 ;ops < ops_per_test ;ops ++ )
344+ START_TIMER ;
345+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
332346{
333347for (writes = 0 ;writes < writes_per_op ;writes ++ )
334348if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
335349die ("write failed" );
336350if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
337351die ("seek failed" );
338352}
339- gettimeofday ( & stop_t , NULL ) ;
353+ STOP_TIMER ;
340354close (tmpfile );
341- print_elapse (start_t ,stop_t );
342355}
343356#else
344357printf (NA_FORMAT ,"n/a\n" );
@@ -385,8 +398,8 @@ test_open_sync(const char *msg, int writes_size)
385398printf (NA_FORMAT ,"n/a*\n" );
386399else
387400{
388- gettimeofday ( & start_t , NULL ) ;
389- for (ops = 0 ;ops < ops_per_test ;ops ++ )
401+ START_TIMER ;
402+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
390403{
391404for (writes = 0 ;writes < 16 /writes_size ;writes ++ )
392405if (write (tmpfile ,buf ,writes_size * 1024 )!=
@@ -395,9 +408,8 @@ test_open_sync(const char *msg, int writes_size)
395408if (lseek (tmpfile ,0 ,SEEK_SET )== -1 )
396409die ("seek failed" );
397410}
398- gettimeofday ( & stop_t , NULL ) ;
411+ STOP_TIMER ;
399412close (tmpfile );
400- print_elapse (start_t ,stop_t );
401413}
402414#else
403415printf (NA_FORMAT ,"n/a\n" );
@@ -427,8 +439,8 @@ test_file_descriptor_sync(void)
427439printf (LABEL_FORMAT ,"write, fsync, close" );
428440fflush (stdout );
429441
430- gettimeofday ( & start_t , NULL ) ;
431- for (ops = 0 ;ops < ops_per_test ;ops ++ )
442+ START_TIMER ;
443+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
432444{
433445if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
434446die ("could not open output file" );
@@ -446,8 +458,7 @@ test_file_descriptor_sync(void)
446458die ("could not open output file" );
447459close (tmpfile );
448460}
449- gettimeofday (& stop_t ,NULL );
450- print_elapse (start_t ,stop_t );
461+ STOP_TIMER ;
451462
452463/*
453464 * Now open, write, close, open again and fsync This simulates processes
@@ -456,8 +467,8 @@ test_file_descriptor_sync(void)
456467printf (LABEL_FORMAT ,"write, close, fsync" );
457468fflush (stdout );
458469
459- gettimeofday ( & start_t , NULL ) ;
460- for (ops = 0 ;ops < ops_per_test ;ops ++ )
470+ START_TIMER ;
471+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
461472{
462473if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
463474die ("could not open output file" );
@@ -471,9 +482,7 @@ test_file_descriptor_sync(void)
471482die ("fsync failed" );
472483close (tmpfile );
473484}
474- gettimeofday (& stop_t ,NULL );
475- print_elapse (start_t ,stop_t );
476-
485+ STOP_TIMER ;
477486}
478487
479488static void
@@ -489,17 +498,16 @@ test_non_sync(void)
489498printf (LABEL_FORMAT ,"write" );
490499fflush (stdout );
491500
492- gettimeofday ( & start_t , NULL ) ;
493- for (ops = 0 ;ops < ops_per_test ;ops ++ )
501+ START_TIMER ;
502+ for (ops = 0 ;alarm_triggered == false ;ops ++ )
494503{
495504if ((tmpfile = open (filename ,O_RDWR ,0 ))== -1 )
496505die ("could not open output file" );
497506if (write (tmpfile ,buf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
498507die ("write failed" );
499508close (tmpfile );
500509}
501- gettimeofday (& stop_t ,NULL );
502- print_elapse (start_t ,stop_t );
510+ STOP_TIMER ;
503511}
504512
505513static void
@@ -533,15 +541,21 @@ pg_fsync_writethrough(int fd)
533541 * print out the writes per second for tests
534542 */
535543static void
536- print_elapse (struct timeval start_t ,struct timeval stop_t )
544+ print_elapse (struct timeval start_t ,struct timeval stop_t , int ops )
537545{
538546double total_time = (stop_t .tv_sec - start_t .tv_sec )+
539547(stop_t .tv_usec - start_t .tv_usec )* 0.000001 ;
540- double per_second = ops_per_test /total_time ;
548+ double per_second = ops /total_time ;
541549
542550printf (OPS_FORMAT "\n" ,per_second );
543551}
544552
553+ static void
554+ process_alarm (int sig )
555+ {
556+ alarm_triggered = true;
557+ }
558+
545559static void
546560die (const char * str )
547561{