diff --git a/contrib/pg_test_fsync/pg_test_fsync.c b/contrib/pg_test_fsync/pg_test_fsync.c
index 3fcb087f2a281c49d567c605fca7527ce94135de..02a9e2112fdbcdd7ea56bfd645f262c9e2ca641e 100644
--- a/contrib/pg_test_fsync/pg_test_fsync.c
+++ b/contrib/pg_test_fsync/pg_test_fsync.c
@@ -27,15 +27,31 @@
 #define NA_FORMAT			"%18s"
 #define OPS_FORMAT			"%9.3f ops/sec"
 
+/* These are macros to avoid timing the function call overhead. */
+#define START_TIMER	\
+do { \
+	alarm_triggered = false; \
+	alarm(secs_per_test); \
+	gettimeofday(&start_t, NULL); \
+} while (0)
+
+#define STOP_TIMER	\
+do { \
+	gettimeofday(&stop_t, NULL); \
+	print_elapse(start_t, stop_t, ops); \
+} while (0)
+		
+
 static const char *progname;
 
-static int	ops_per_test = 2000;
+static int	secs_per_test = 2;
 static int	needs_unlink = 0;
 static char full_buf[XLOG_SEG_SIZE],
 		   *buf,
 		   *filename = FSYNC_FILENAME;
 static struct timeval start_t,
 			stop_t;
+static bool alarm_triggered = false;
 
 
 static void handle_args(int argc, char *argv[]);
@@ -46,12 +62,13 @@ static void test_sync(int writes_per_op);
 static void test_open_syncs(void);
 static void test_open_sync(const char *msg, int writes_size);
 static void test_file_descriptor_sync(void);
+static void process_alarm(int sig);
 static void signal_cleanup(int sig);
 
 #ifdef HAVE_FSYNC_WRITETHROUGH
 static int	pg_fsync_writethrough(int fd);
 #endif
-static void print_elapse(struct timeval start_t, struct timeval stop_t);
+static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
 static void die(const char *str);
 
 
@@ -65,6 +82,7 @@ main(int argc, char *argv[])
 	/* Prevent leaving behind the test file */
 	signal(SIGINT, signal_cleanup);
 	signal(SIGTERM, signal_cleanup);
+	signal(SIGALRM, process_alarm);
 #ifdef SIGHUP
 	/* Not defined on win32 */
 	signal(SIGHUP, signal_cleanup);
@@ -96,7 +114,7 @@ handle_args(int argc, char *argv[])
 {
 	static struct option long_options[] = {
 		{"filename", required_argument, NULL, 'f'},
-		{"ops-per-test", required_argument, NULL, 'o'},
+		{"secs-per-test", required_argument, NULL, 's'},
 		{NULL, 0, NULL, 0}
 	};
 	int			option;			/* Command line option */
@@ -107,7 +125,7 @@ handle_args(int argc, char *argv[])
 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
 			strcmp(argv[1], "-?") == 0)
 		{
-			printf("Usage: %s [-f FILENAME] [-o OPS-PER-TEST]\n", progname);
+			printf("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n", progname);
 			exit(0);
 		}
 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
@@ -117,7 +135,7 @@ handle_args(int argc, char *argv[])
 		}
 	}
 
-	while ((option = getopt_long(argc, argv, "f:o:",
+	while ((option = getopt_long(argc, argv, "f:s:",
 								 long_options, &optindex)) != -1)
 	{
 		switch (option)
@@ -126,8 +144,8 @@ handle_args(int argc, char *argv[])
 				filename = strdup(optarg);
 				break;
 
-			case 'o':
-				ops_per_test = atoi(optarg);
+			case 's':
+				secs_per_test = atoi(optarg);
 				break;
 
 			default:
@@ -148,7 +166,7 @@ handle_args(int argc, char *argv[])
 		exit(1);
 	}
 
-	printf("%d operations per test\n", ops_per_test);
+	printf("%d seconds per test\n", secs_per_test);
 #if PG_O_DIRECT != 0
 	printf("O_DIRECT supported on this platform for open_datasync and open_sync.\n");
 #else
@@ -220,8 +238,8 @@ test_sync(int writes_per_op)
 	{
 		if ((tmpfile = open(filename, O_RDWR | O_DSYNC | PG_O_DIRECT, 0)) == -1)
 			die("could not open output file");
-		gettimeofday(&start_t, NULL);
-		for (ops = 0; ops < ops_per_test; ops++)
+		START_TIMER;
+		for (ops = 0; alarm_triggered == false; ops++)
 		{
 			for (writes = 0; writes < writes_per_op; writes++)
 				if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
@@ -229,9 +247,8 @@ test_sync(int writes_per_op)
 			if (lseek(tmpfile, 0, SEEK_SET) == -1)
 				die("seek failed");
 		}
-		gettimeofday(&stop_t, NULL);
+		STOP_TIMER;
 		close(tmpfile);
-		print_elapse(start_t, stop_t);
 	}
 #else
 	printf(NA_FORMAT, "n/a\n");
@@ -246,8 +263,8 @@ test_sync(int writes_per_op)
 #ifdef HAVE_FDATASYNC
 	if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 		die("could not open output file");
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		for (writes = 0; writes < writes_per_op; writes++)
 			if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
@@ -256,9 +273,8 @@ test_sync(int writes_per_op)
 		if (lseek(tmpfile, 0, SEEK_SET) == -1)
 			die("seek failed");
 	}
-	gettimeofday(&stop_t, NULL);
+	STOP_TIMER;
 	close(tmpfile);
-	print_elapse(start_t, stop_t);
 #else
 	printf(NA_FORMAT, "n/a\n");
 #endif
@@ -271,8 +287,8 @@ test_sync(int writes_per_op)
 
 	if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 		die("could not open output file");
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		for (writes = 0; writes < writes_per_op; writes++)
 			if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
@@ -282,9 +298,8 @@ test_sync(int writes_per_op)
 		if (lseek(tmpfile, 0, SEEK_SET) == -1)
 			die("seek failed");
 	}
-	gettimeofday(&stop_t, NULL);
+	STOP_TIMER;
 	close(tmpfile);
-	print_elapse(start_t, stop_t);
 
 /*
  * If fsync_writethrough is available, test as well
@@ -295,8 +310,8 @@ test_sync(int writes_per_op)
 #ifdef HAVE_FSYNC_WRITETHROUGH
 	if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 		die("could not open output file");
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		for (writes = 0; writes < writes_per_op; writes++)
 			if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
@@ -306,9 +321,8 @@ test_sync(int writes_per_op)
 		if (lseek(tmpfile, 0, SEEK_SET) == -1)
 			die("seek failed");
 	}
-	gettimeofday(&stop_t, NULL);
+	STOP_TIMER;
 	close(tmpfile);
-	print_elapse(start_t, stop_t);
 #else
 	printf(NA_FORMAT, "n/a\n");
 #endif
@@ -327,8 +341,8 @@ test_sync(int writes_per_op)
 	}
 	else
 	{
-		gettimeofday(&start_t, NULL);
-		for (ops = 0; ops < ops_per_test; ops++)
+		START_TIMER;
+		for (ops = 0; alarm_triggered == false; ops++)
 		{
 			for (writes = 0; writes < writes_per_op; writes++)
 				if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
@@ -336,9 +350,8 @@ test_sync(int writes_per_op)
 			if (lseek(tmpfile, 0, SEEK_SET) == -1)
 				die("seek failed");
 		}
-		gettimeofday(&stop_t, NULL);
+		STOP_TIMER;
 		close(tmpfile);
-		print_elapse(start_t, stop_t);
 	}
 #else
 	printf(NA_FORMAT, "n/a\n");
@@ -385,8 +398,8 @@ test_open_sync(const char *msg, int writes_size)
 		printf(NA_FORMAT, "n/a*\n");
 	else
 	{
-		gettimeofday(&start_t, NULL);
-		for (ops = 0; ops < ops_per_test; ops++)
+		START_TIMER;
+		for (ops = 0; alarm_triggered == false; ops++)
 		{
 			for (writes = 0; writes < 16 / writes_size; writes++)
 				if (write(tmpfile, buf, writes_size * 1024) !=
@@ -395,9 +408,8 @@ test_open_sync(const char *msg, int writes_size)
 			if (lseek(tmpfile, 0, SEEK_SET) == -1)
 				die("seek failed");
 		}
-		gettimeofday(&stop_t, NULL);
+		STOP_TIMER;
 		close(tmpfile);
-		print_elapse(start_t, stop_t);
 	}
 #else
 	printf(NA_FORMAT, "n/a\n");
@@ -427,8 +439,8 @@ test_file_descriptor_sync(void)
 	printf(LABEL_FORMAT, "write, fsync, close");
 	fflush(stdout);
 
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 			die("could not open output file");
@@ -446,8 +458,7 @@ test_file_descriptor_sync(void)
 			die("could not open output file");
 		close(tmpfile);
 	}
-	gettimeofday(&stop_t, NULL);
-	print_elapse(start_t, stop_t);
+	STOP_TIMER;
 
 	/*
 	 * Now open, write, close, open again and fsync This simulates processes
@@ -456,8 +467,8 @@ test_file_descriptor_sync(void)
 	printf(LABEL_FORMAT, "write, close, fsync");
 	fflush(stdout);
 
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 			die("could not open output file");
@@ -471,9 +482,7 @@ test_file_descriptor_sync(void)
 			die("fsync failed");
 		close(tmpfile);
 	}
-	gettimeofday(&stop_t, NULL);
-	print_elapse(start_t, stop_t);
-
+	STOP_TIMER;
 }
 
 static void
@@ -489,8 +498,8 @@ test_non_sync(void)
 	printf(LABEL_FORMAT, "write");
 	fflush(stdout);
 
-	gettimeofday(&start_t, NULL);
-	for (ops = 0; ops < ops_per_test; ops++)
+	START_TIMER;
+	for (ops = 0; alarm_triggered == false; ops++)
 	{
 		if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
 			die("could not open output file");
@@ -498,8 +507,7 @@ test_non_sync(void)
 			die("write failed");
 		close(tmpfile);
 	}
-	gettimeofday(&stop_t, NULL);
-	print_elapse(start_t, stop_t);
+	STOP_TIMER;
 }
 
 static void
@@ -533,15 +541,21 @@ pg_fsync_writethrough(int fd)
  * print out the writes per second for tests
  */
 static void
-print_elapse(struct timeval start_t, struct timeval stop_t)
+print_elapse(struct timeval start_t, struct timeval stop_t, int ops)
 {
 	double		total_time = (stop_t.tv_sec - start_t.tv_sec) +
 	(stop_t.tv_usec - start_t.tv_usec) * 0.000001;
-	double		per_second = ops_per_test / total_time;
+	double		per_second = ops / total_time;
 
 	printf(OPS_FORMAT "\n", per_second);
 }
 
+static void
+process_alarm(int sig)
+{
+	alarm_triggered = true;
+}
+
 static void
 die(const char *str)
 {
diff --git a/doc/src/sgml/pgtestfsync.sgml b/doc/src/sgml/pgtestfsync.sgml
index 2889059c82cdf438e3f61c4eb866ea55ca11b0c2..ba9f0c1eb18f4fbd3314e856a599fc114ddec04a 100644
--- a/doc/src/sgml/pgtestfsync.sgml
+++ b/doc/src/sgml/pgtestfsync.sgml
@@ -47,13 +47,13 @@ pg_test_fsync [options]
      </varlistentry>
 
      <varlistentry>
-      <term><option>-o</option></term>
-      <term><option>--ops-per-test</option></term>
+      <term><option>-s</option></term>
+      <term><option>--secs-per-test</option></term>
       <listitem>
        <para>
-        Specifies the number of operations per test.  The more operations
+        Specifies the number of seconds for each test.  The more time
         per test, the greater the test's accuracy, but the longer it takes
-        to run.  The default is 2000.
+        to run.  The default is 2 seconds.
        </para>
       </listitem>
      </varlistentry>