|
|
|
|
@ -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) |
|
|
|
|
{ |
|
|
|
|
|