Age Owner TLA Line data Source code
1 : /*
2 : * pg_test_fsync.c
3 : * tests all supported fsync() methods
4 : */
5 :
6 : #include "postgres_fe.h"
7 :
8 : #include <limits.h>
9 : #include <sys/stat.h>
10 : #include <sys/time.h>
11 : #include <fcntl.h>
12 : #include <time.h>
13 : #include <unistd.h>
14 : #include <signal.h>
15 :
16 : #include "access/xlogdefs.h"
17 : #include "common/logging.h"
18 : #include "common/pg_prng.h"
19 : #include "getopt_long.h"
20 :
21 : /*
22 : * put the temp files in the local directory
23 : * unless the user specifies otherwise
24 : */
25 : #define FSYNC_FILENAME "./pg_test_fsync.out"
26 :
27 : #define XLOG_BLCKSZ_K (XLOG_BLCKSZ / 1024)
28 :
29 : #define LABEL_FORMAT " %-30s"
30 : #define NA_FORMAT "%21s\n"
31 : /* translator: maintain alignment with NA_FORMAT */
32 : #define OPS_FORMAT gettext_noop("%13.3f ops/sec %6.0f usecs/op\n")
33 : #define USECS_SEC 1000000
34 :
35 : /* These are macros to avoid timing the function call overhead. */
36 : #ifndef WIN32
37 : #define START_TIMER \
38 : do { \
39 : alarm_triggered = false; \
40 : alarm(secs_per_test); \
41 : gettimeofday(&start_t, NULL); \
42 : } while (0)
43 : #else
44 : /* WIN32 doesn't support alarm, so we create a thread and sleep there */
45 : #define START_TIMER \
46 : do { \
47 : alarm_triggered = false; \
48 : if (CreateThread(NULL, 0, process_alarm, NULL, 0, NULL) == \
49 : INVALID_HANDLE_VALUE) \
50 : pg_fatal("could not create thread for alarm"); \
51 : gettimeofday(&start_t, NULL); \
52 : } while (0)
53 : #endif
54 :
55 : #define STOP_TIMER \
56 : do { \
57 : gettimeofday(&stop_t, NULL); \
58 : print_elapse(start_t, stop_t, ops); \
59 : } while (0)
60 :
61 :
62 : static const char *progname;
63 :
64 : static unsigned int secs_per_test = 5;
65 : static int needs_unlink = 0;
66 : static char full_buf[DEFAULT_XLOG_SEG_SIZE],
67 : *buf,
68 : *filename = FSYNC_FILENAME;
69 : static struct timeval start_t,
70 : stop_t;
71 : static sig_atomic_t alarm_triggered = false;
72 :
73 :
74 : static void handle_args(int argc, char *argv[]);
75 : static void prepare_buf(void);
76 : static void test_open(void);
77 : static void test_non_sync(void);
78 : static void test_sync(int writes_per_op);
79 : static void test_open_syncs(void);
80 : static void test_open_sync(const char *msg, int writes_size);
81 : static void test_file_descriptor_sync(void);
82 :
83 : #ifndef WIN32
84 : static void process_alarm(SIGNAL_ARGS);
85 : #else
86 : static DWORD WINAPI process_alarm(LPVOID param);
87 : #endif
88 : static void signal_cleanup(SIGNAL_ARGS);
89 :
90 : #ifdef HAVE_FSYNC_WRITETHROUGH
91 : static int pg_fsync_writethrough(int fd);
92 : #endif
93 : static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
94 :
95 : #define die(msg) pg_fatal("%s: %m", _(msg))
96 :
97 :
98 : int
6961 bruce 99 CBC 5 : main(int argc, char *argv[])
100 : {
1469 peter 101 5 : pg_logging_init(argv[0]);
2368 peter_e 102 5 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync"));
4460 tgl 103 5 : progname = get_progname(argv[0]);
104 :
4467 bruce 105 5 : handle_args(argc, argv);
106 :
107 : /* Prevent leaving behind the test file */
3675 tgl 108 UBC 0 : pqsignal(SIGINT, signal_cleanup);
109 0 : pqsignal(SIGTERM, signal_cleanup);
110 : #ifndef WIN32
111 0 : pqsignal(SIGALRM, process_alarm);
112 : #endif
113 : #ifdef SIGHUP
114 : /* Not defined on win32 */
115 0 : pqsignal(SIGHUP, signal_cleanup);
116 : #endif
117 :
497 118 0 : pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
119 :
4467 bruce 120 0 : prepare_buf();
121 :
122 0 : test_open();
123 :
124 : /* Test using 1 XLOG_BLCKSZ write */
125 0 : test_sync(1);
126 :
127 : /* Test using 2 XLOG_BLCKSZ writes */
128 0 : test_sync(2);
129 :
130 0 : test_open_syncs();
131 :
132 0 : test_file_descriptor_sync();
133 :
4464 134 0 : test_non_sync();
135 :
4467 136 0 : unlink(filename);
137 :
138 0 : return 0;
139 : }
140 :
141 : static void
4467 bruce 142 CBC 5 : handle_args(int argc, char *argv[])
143 : {
144 : static struct option long_options[] = {
145 : {"filename", required_argument, NULL, 'f'},
146 : {"secs-per-test", required_argument, NULL, 's'},
147 : {NULL, 0, NULL, 0}
148 : };
149 :
150 : int option; /* Command line option */
4465 151 5 : int optindex = 0; /* used by getopt_long */
152 : unsigned long optval; /* used for option parsing */
153 : char *endptr;
154 :
155 5 : if (argc > 1)
156 : {
3569 157 5 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
158 : {
2368 peter_e 159 1 : printf(_("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n"), progname);
4465 bruce 160 1 : exit(0);
161 : }
162 4 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
163 : {
4352 peter_e 164 1 : puts("pg_test_fsync (PostgreSQL) " PG_VERSION);
4465 bruce 165 1 : exit(0);
166 : }
167 : }
168 :
4072 169 3 : while ((option = getopt_long(argc, argv, "f:s:",
4382 170 3 : long_options, &optindex)) != -1)
171 : {
4465 172 3 : switch (option)
173 : {
4465 bruce 174 UBC 0 : case 'f':
1436 michael 175 0 : filename = pg_strdup(optarg);
4465 bruce 176 0 : break;
177 :
4072 bruce 178 CBC 2 : case 's':
923 michael 179 2 : errno = 0;
180 2 : optval = strtoul(optarg, &endptr, 10);
181 :
182 2 : if (endptr == optarg || *endptr != '\0' ||
183 1 : errno != 0 || optval != (unsigned int) optval)
184 : {
185 1 : pg_log_error("invalid argument for option %s", "--secs-per-test");
366 tgl 186 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
923 michael 187 1 : exit(1);
188 : }
189 :
190 1 : secs_per_test = (unsigned int) optval;
191 1 : if (secs_per_test == 0)
366 tgl 192 1 : pg_fatal("%s must be in range %u..%u",
193 : "--secs-per-test", 1, UINT_MAX);
4465 bruce 194 UBC 0 : break;
195 :
4465 bruce 196 CBC 1 : default:
197 : /* getopt_long already emitted a complaint */
366 tgl 198 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4465 bruce 199 1 : exit(1);
200 : }
201 : }
202 :
4460 tgl 203 UBC 0 : if (argc > optind)
204 : {
1469 peter 205 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
206 : argv[optind]);
366 tgl 207 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4460 208 0 : exit(1);
209 : }
210 :
923 michael 211 0 : printf(ngettext("%u second per test\n",
212 : "%u seconds per test\n",
213 : secs_per_test),
214 : secs_per_test);
215 : #if defined(O_DIRECT)
2368 peter_e 216 0 : printf(_("O_DIRECT supported on this platform for open_datasync and open_sync.\n"));
217 : #elif defined(F_NOCACHE)
218 : printf(_("F_NOCACHE supported on this platform for open_datasync and open_sync.\n"));
219 : #else
220 : printf(_("Direct I/O is not supported on this platform.\n"));
221 : #endif
4467 bruce 222 0 : }
223 :
224 : static void
225 0 : prepare_buf(void)
226 : {
227 : int ops;
228 :
229 : /* write random data into buffer */
2028 andres 230 0 : for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
497 tgl 231 0 : full_buf[ops] = (char) pg_prng_int32(&pg_global_prng_state);
232 :
3562 heikki.linnakangas 233 0 : buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
4467 bruce 234 0 : }
235 :
236 : static void
237 0 : test_open(void)
238 : {
239 : int tmpfile;
240 :
241 : /*
242 : * test if we can open the target file
243 : */
997 michael 244 0 : if ((tmpfile = open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1)
4460 tgl 245 0 : die("could not open output file");
4139 rhaas 246 0 : needs_unlink = 1;
2028 andres 247 0 : if (write(tmpfile, full_buf, DEFAULT_XLOG_SEG_SIZE) !=
248 : DEFAULT_XLOG_SEG_SIZE)
5979 bruce 249 0 : die("write failed");
250 :
251 : /* fsync now so that dirty buffers don't skew later tests */
252 0 : if (fsync(tmpfile) != 0)
253 0 : die("fsync failed");
254 :
4467 255 0 : close(tmpfile);
256 0 : }
257 :
258 : static int
629 tmunro 259 0 : open_direct(const char *path, int flags, mode_t mode)
260 : {
261 : int fd;
262 :
263 : #ifdef O_DIRECT
264 0 : flags |= O_DIRECT;
265 : #endif
266 :
267 0 : fd = open(path, flags, mode);
268 :
269 : #if !defined(O_DIRECT) && defined(F_NOCACHE)
270 : if (fd >= 0 && fcntl(fd, F_NOCACHE, 1) < 0)
271 : {
272 : int save_errno = errno;
273 :
274 : close(fd);
275 : errno = save_errno;
276 : return -1;
277 : }
278 : #endif
279 :
280 0 : return fd;
281 : }
282 :
283 : static void
4467 bruce 284 0 : test_sync(int writes_per_op)
285 : {
286 : int tmpfile,
287 : ops,
288 : writes;
289 0 : bool fs_warning = false;
290 :
291 0 : if (writes_per_op == 1)
2368 peter_e 292 0 : printf(_("\nCompare file sync methods using one %dkB write:\n"), XLOG_BLCKSZ_K);
293 : else
294 0 : printf(_("\nCompare file sync methods using two %dkB writes:\n"), XLOG_BLCKSZ_K);
295 0 : printf(_("(in wal_sync_method preference order, except fdatasync is Linux's default)\n"));
296 :
297 : /*
298 : * Test open_datasync if available
299 : */
4413 bruce 300 0 : printf(LABEL_FORMAT, "open_datasync");
4653 301 0 : fflush(stdout);
302 :
303 : #ifdef O_DSYNC
629 tmunro 304 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_DSYNC | PG_BINARY, 0)) == -1)
305 : {
2053 peter_e 306 0 : printf(NA_FORMAT, _("n/a*"));
4467 bruce 307 0 : fs_warning = true;
308 : }
309 : else
310 : {
4072 311 0 : START_TIMER;
312 0 : for (ops = 0; alarm_triggered == false; ops++)
313 : {
4467 314 0 : for (writes = 0; writes < writes_per_op; writes++)
192 tmunro 315 0 : if (pg_pwrite(tmpfile,
316 : buf,
317 : XLOG_BLCKSZ,
318 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
4467 bruce 319 0 : die("write failed");
320 : }
4072 321 0 : STOP_TIMER;
4467 322 0 : close(tmpfile);
323 : }
324 : #else
325 : printf(NA_FORMAT, _("n/a"));
326 : #endif
327 :
328 : /*
329 : * Test fdatasync if available
330 : */
4464 331 0 : printf(LABEL_FORMAT, "fdatasync");
4653 332 0 : fflush(stdout);
333 :
997 michael 334 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 335 0 : die("could not open output file");
4072 bruce 336 0 : START_TIMER;
4072 bruce 337 UIC 0 : for (ops = 0; alarm_triggered == false; ops++)
4948 bruce 338 EUB : {
4467 bruce 339 UBC 0 : for (writes = 0; writes < writes_per_op; writes++)
192 tmunro 340 UIC 0 : if (pg_pwrite(tmpfile,
341 : buf,
192 tmunro 342 EUB : XLOG_BLCKSZ,
192 tmunro 343 UBC 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
4467 bruce 344 0 : die("write failed");
4880 bruce 345 UIC 0 : fdatasync(tmpfile);
4948 bruce 346 EUB : }
4072 bruce 347 UBC 0 : STOP_TIMER;
6961 bruce 348 UIC 0 : close(tmpfile);
6961 bruce 349 EUB :
4467 350 : /*
351 : * Test fsync
352 : */
4464 bruce 353 UBC 0 : printf(LABEL_FORMAT, "fsync");
4653 354 0 : fflush(stdout);
4467 bruce 355 EUB :
997 michael 356 UIC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 357 UBC 0 : die("could not open output file");
4072 bruce 358 0 : START_TIMER;
4072 bruce 359 UIC 0 : for (ops = 0; alarm_triggered == false; ops++)
360 : {
4467 bruce 361 UBC 0 : for (writes = 0; writes < writes_per_op; writes++)
192 tmunro 362 0 : if (pg_pwrite(tmpfile,
192 tmunro 363 EUB : buf,
364 : XLOG_BLCKSZ,
192 tmunro 365 UIC 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
4467 bruce 366 UBC 0 : die("write failed");
4880 367 0 : if (fsync(tmpfile) != 0)
4880 bruce 368 UIC 0 : die("fsync failed");
369 : }
4072 370 0 : STOP_TIMER;
6961 371 0 : close(tmpfile);
4461 tgl 372 EUB :
4467 bruce 373 : /*
374 : * If fsync_writethrough is available, test as well
375 : */
4464 bruce 376 UIC 0 : printf(LABEL_FORMAT, "fsync_writethrough");
4467 377 0 : fflush(stdout);
378 :
379 : #ifdef HAVE_FSYNC_WRITETHROUGH
380 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
381 : die("could not open output file");
382 : START_TIMER;
383 : for (ops = 0; alarm_triggered == false; ops++)
384 : {
385 : for (writes = 0; writes < writes_per_op; writes++)
386 : if (pg_pwrite(tmpfile,
387 : buf,
388 : XLOG_BLCKSZ,
389 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
390 : die("write failed");
391 : if (pg_fsync_writethrough(tmpfile) != 0)
392 : die("fsync failed");
4467 bruce 393 EUB : }
394 : STOP_TIMER;
395 : close(tmpfile);
396 : #else
2053 peter_e 397 UIC 0 : printf(NA_FORMAT, _("n/a"));
398 : #endif
6961 bruce 399 EUB :
4467 400 : /*
401 : * Test open_sync if available
402 : */
4413 bruce 403 UBC 0 : printf(LABEL_FORMAT, "open_sync");
4653 bruce 404 UIC 0 : fflush(stdout);
4467 bruce 405 EUB :
406 : #ifdef O_SYNC
261 tmunro 407 UNC 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
408 : {
2053 peter_e 409 UIC 0 : printf(NA_FORMAT, _("n/a*"));
4467 bruce 410 UBC 0 : fs_warning = true;
4467 bruce 411 EUB : }
412 : else
413 : {
4072 bruce 414 UBC 0 : START_TIMER;
4072 bruce 415 UIC 0 : for (ops = 0; alarm_triggered == false; ops++)
416 : {
4467 bruce 417 UBC 0 : for (writes = 0; writes < writes_per_op; writes++)
192 tmunro 418 UIC 0 : if (pg_pwrite(tmpfile,
419 : buf,
420 : XLOG_BLCKSZ,
421 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
422 :
423 : /*
424 : * This can generate write failures if the filesystem has
3260 bruce 425 EUB : * a large block size, e.g. 4k, and there is no support
426 : * for O_DIRECT writes smaller than the file system block
427 : * size, e.g. XFS.
428 : */
4467 bruce 429 UIC 0 : die("write failed");
430 : }
4072 431 0 : STOP_TIMER;
4467 432 0 : close(tmpfile);
433 : }
4467 bruce 434 EUB : #else
435 : printf(NA_FORMAT, _("n/a"));
436 : #endif
437 :
4467 bruce 438 UIC 0 : if (fs_warning)
4467 bruce 439 EUB : {
2368 peter_e 440 UIC 0 : printf(_("* This file system and its mount options do not support direct\n"
441 : " I/O, e.g. ext4 in journaled mode.\n"));
4467 bruce 442 EUB : }
4467 bruce 443 UIC 0 : }
6961 bruce 444 EUB :
4461 tgl 445 : static void
4467 bruce 446 UIC 0 : test_open_syncs(void)
447 : {
2368 peter_e 448 UBC 0 : printf(_("\nCompare open_sync with different write sizes:\n"));
449 0 : printf(_("(This is designed to compare the cost of writing 16kB in different write\n"
2368 peter_e 450 EUB : "open_sync sizes.)\n"));
451 :
2368 peter_e 452 UBC 0 : test_open_sync(_(" 1 * 16kB open_sync write"), 16);
453 0 : test_open_sync(_(" 2 * 8kB open_sync writes"), 8);
2368 peter_e 454 UIC 0 : test_open_sync(_(" 4 * 4kB open_sync writes"), 4);
455 0 : test_open_sync(_(" 8 * 2kB open_sync writes"), 2);
456 0 : test_open_sync(_("16 * 1kB open_sync writes"), 1);
4464 bruce 457 0 : }
458 :
4460 tgl 459 EUB : /*
460 : * Test open_sync with different size files
461 : */
462 : static void
4464 bruce 463 UIC 0 : test_open_sync(const char *msg, int writes_size)
464 : {
465 : #ifdef O_SYNC
466 : int tmpfile,
4382 bruce 467 EUB : ops,
468 : writes;
469 : #endif
470 :
4413 bruce 471 UBC 0 : printf(LABEL_FORMAT, msg);
472 0 : fflush(stdout);
473 :
474 : #ifdef O_SYNC
261 tmunro 475 UNC 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
2053 peter_e 476 UBC 0 : printf(NA_FORMAT, _("n/a*"));
477 : else
6961 bruce 478 EUB : {
4072 bruce 479 UBC 0 : START_TIMER;
4072 bruce 480 UIC 0 : for (ops = 0; alarm_triggered == false; ops++)
4467 bruce 481 EUB : {
4464 bruce 482 UBC 0 : for (writes = 0; writes < 16 / writes_size; writes++)
192 tmunro 483 0 : if (pg_pwrite(tmpfile,
192 tmunro 484 EUB : buf,
192 tmunro 485 UIC 0 : writes_size * 1024,
192 tmunro 486 UBC 0 : writes * writes_size * 1024) !=
4458 bruce 487 0 : writes_size * 1024)
4464 bruce 488 UIC 0 : die("write failed");
489 : }
4072 490 0 : STOP_TIMER;
4467 491 0 : close(tmpfile);
4467 bruce 492 EUB : }
493 : #else
494 : printf(NA_FORMAT, _("n/a"));
6022 495 : #endif
4467 bruce 496 UIC 0 : }
497 :
498 : static void
499 0 : test_file_descriptor_sync(void)
500 : {
501 : int tmpfile,
502 : ops;
503 :
504 : /*
505 : * Test whether fsync can sync data written on a different descriptor for
4382 bruce 506 EUB : * the same file. This checks the efficiency of multi-process fsyncs
507 : * against the same file. Possibly this should be done with writethrough
508 : * on platforms which support it.
509 : */
2368 peter_e 510 UIC 0 : printf(_("\nTest if fsync on non-write file descriptor is honored:\n"));
511 0 : printf(_("(If the times are similar, fsync() can sync data written on a different\n"
512 : "descriptor.)\n"));
513 :
4461 tgl 514 EUB : /*
4382 bruce 515 : * first write, fsync and close, which is the normal behavior without
516 : * multiple descriptors
4467 517 : */
4464 bruce 518 UBC 0 : printf(LABEL_FORMAT, "write, fsync, close");
4653 bruce 519 UIC 0 : fflush(stdout);
4467 bruce 520 EUB :
4072 bruce 521 UBC 0 : START_TIMER;
522 0 : for (ops = 0; alarm_triggered == false; ops++)
6961 bruce 523 EUB : {
997 michael 524 UBC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 525 0 : die("could not open output file");
4458 bruce 526 0 : if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
5979 bruce 527 UIC 0 : die("write failed");
4880 528 0 : if (fsync(tmpfile) != 0)
529 0 : die("fsync failed");
530 0 : close(tmpfile);
531 :
4467 bruce 532 EUB : /*
4382 533 : * open and close the file again to be consistent with the following
534 : * test
535 : */
997 michael 536 UBC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 537 UIC 0 : die("could not open output file");
4880 bruce 538 0 : close(tmpfile);
539 : }
4072 540 0 : STOP_TIMER;
541 :
4467 bruce 542 EUB : /*
4382 543 : * Now open, write, close, open again and fsync This simulates processes
544 : * fsyncing each other's writes.
4467 545 : */
4461 tgl 546 UBC 0 : printf(LABEL_FORMAT, "write, close, fsync");
4461 tgl 547 UIC 0 : fflush(stdout);
4467 bruce 548 EUB :
4072 bruce 549 UBC 0 : START_TIMER;
550 0 : for (ops = 0; alarm_triggered == false; ops++)
6961 bruce 551 EUB : {
997 michael 552 UBC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 553 UIC 0 : die("could not open output file");
4458 bruce 554 UBC 0 : if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
5979 555 0 : die("write failed");
4880 556 0 : close(tmpfile);
4880 bruce 557 EUB : /* reopen file */
997 michael 558 UBC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
4460 tgl 559 UIC 0 : die("could not open output file");
5979 bruce 560 UBC 0 : if (fsync(tmpfile) != 0)
561 0 : die("fsync failed");
4880 bruce 562 UIC 0 : close(tmpfile);
563 : }
4072 bruce 564 UBC 0 : STOP_TIMER;
6961 bruce 565 UIC 0 : }
566 :
567 : static void
4464 568 0 : test_non_sync(void)
569 : {
570 : int tmpfile,
571 : ops;
4464 bruce 572 EUB :
573 : /*
574 : * Test a simple write without fsync
575 : */
2368 peter_e 576 UBC 0 : printf(_("\nNon-sync'ed %dkB writes:\n"), XLOG_BLCKSZ_K);
4464 bruce 577 0 : printf(LABEL_FORMAT, "write");
578 0 : fflush(stdout);
4464 bruce 579 EUB :
783 tmunro 580 UIC 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
783 tmunro 581 UBC 0 : die("could not open output file");
4072 bruce 582 0 : START_TIMER;
4072 bruce 583 UIC 0 : for (ops = 0; alarm_triggered == false; ops++)
4464 bruce 584 EUB : {
192 tmunro 585 UBC 0 : if (pg_pwrite(tmpfile, buf, XLOG_BLCKSZ, 0) != XLOG_BLCKSZ)
4464 bruce 586 0 : die("write failed");
587 : }
4072 bruce 588 UIC 0 : STOP_TIMER;
783 tmunro 589 UBC 0 : close(tmpfile);
4464 bruce 590 UIC 0 : }
591 :
4139 rhaas 592 EUB : static void
207 tgl 593 UNC 0 : signal_cleanup(SIGNAL_ARGS)
594 : {
4139 rhaas 595 EUB : /* Delete the file if it exists. Ignore errors */
4139 rhaas 596 UBC 0 : if (needs_unlink)
4139 rhaas 597 UIC 0 : unlink(filename);
598 : /* Finish incomplete line on stdout */
599 0 : puts("");
207 tgl 600 UNC 0 : exit(1);
601 : }
602 :
603 : #ifdef HAVE_FSYNC_WRITETHROUGH
604 :
605 : static int
606 : pg_fsync_writethrough(int fd)
607 : {
608 : #ifdef WIN32
609 : return _commit(fd);
610 : #elif defined(F_FULLFSYNC)
611 : return (fcntl(fd, F_FULLFSYNC, 0) == -1) ? -1 : 0;
612 : #else
613 : errno = ENOSYS;
614 : return -1;
615 : #endif
616 : }
617 : #endif
618 :
4461 tgl 619 EUB : /*
620 : * print out the writes per second for tests
4467 bruce 621 : */
4461 tgl 622 : static void
4072 bruce 623 UBC 0 : print_elapse(struct timeval start_t, struct timeval stop_t, int ops)
6961 bruce 624 EUB : {
4660 bruce 625 UIC 0 : double total_time = (stop_t.tv_sec - start_t.tv_sec) +
4660 bruce 626 UBC 0 : (stop_t.tv_usec - start_t.tv_usec) * 0.000001;
4072 627 0 : double per_second = ops / total_time;
3834 simon 628 UIC 0 : double avg_op_time_us = (total_time / ops) * USECS_SEC;
629 :
2053 peter_e 630 0 : printf(_(OPS_FORMAT), per_second, avg_op_time_us);
6961 bruce 631 UBC 0 : }
632 :
4071 bruce 633 EUB : #ifndef WIN32
4072 634 : static void
207 tgl 635 UNC 0 : process_alarm(SIGNAL_ARGS)
636 : {
4072 bruce 637 UIC 0 : alarm_triggered = true;
4071 638 0 : }
639 : #else
640 : static DWORD WINAPI
641 : process_alarm(LPVOID param)
642 : {
643 : /* WIN32 doesn't support alarm, so we create a thread and sleep here */
644 : Sleep(secs_per_test * 1000);
645 : alarm_triggered = true;
646 : ExitThread(0);
647 : }
648 : #endif
|