diff --git a/contrib/pg_test_fsync/pg_test_fsync.c b/contrib/pg_test_fsync/pg_test_fsync.c index 3fcb087f2a..02a9e2112f 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 2889059c82..ba9f0c1eb1 100644 --- a/doc/src/sgml/pgtestfsync.sgml +++ b/doc/src/sgml/pgtestfsync.sgml @@ -47,13 +47,13 @@ pg_test_fsync [options] - - + + - 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.