diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/Makefile | 1 | ||||
-rw-r--r-- | src/bin/pg_test_timing/.gitignore | 1 | ||||
-rw-r--r-- | src/bin/pg_test_timing/Makefile | 27 | ||||
-rw-r--r-- | src/bin/pg_test_timing/pg_test_timing.c | 188 | ||||
-rw-r--r-- | src/tools/msvc/Mkvcbuild.pm | 6 |
5 files changed, 219 insertions, 4 deletions
diff --git a/src/bin/Makefile b/src/bin/Makefile index 06a0ab75b6b..d23c95c581c 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -24,6 +24,7 @@ SUBDIRS = \ pg_resetxlog \ pg_rewind \ pg_test_fsync \ + pg_test_timing \ pg_upgrade \ pgbench \ psql \ diff --git a/src/bin/pg_test_timing/.gitignore b/src/bin/pg_test_timing/.gitignore new file mode 100644 index 00000000000..f6c664c7657 --- /dev/null +++ b/src/bin/pg_test_timing/.gitignore @@ -0,0 +1 @@ +/pg_test_timing diff --git a/src/bin/pg_test_timing/Makefile b/src/bin/pg_test_timing/Makefile new file mode 100644 index 00000000000..d1f35954f0f --- /dev/null +++ b/src/bin/pg_test_timing/Makefile @@ -0,0 +1,27 @@ +# src/bin/pg_test_timing/Makefile + +PGFILEDESC = "pg_test_timing - test timing overhead" +PGAPPICON = win32 + +subdir = src/bin/pg_test_timing +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +OBJS = pg_test_timing.o $(WIN32RES) + +all: pg_test_timing + +pg_test_timing: $(OBJS) | submake-libpgport + $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + +install: all installdirs + $(INSTALL_PROGRAM) pg_test_timing$(X) '$(DESTDIR)$(bindir)/pg_test_timing$(X)' + +installdirs: + $(MKDIR_P) '$(DESTDIR)$(bindir)' + +uninstall: + rm -f '$(DESTDIR)$(bindir)/pg_test_timing$(X)' + +clean distclean maintainer-clean: + rm -f pg_test_timing$(X) $(OBJS) diff --git a/src/bin/pg_test_timing/pg_test_timing.c b/src/bin/pg_test_timing/pg_test_timing.c new file mode 100644 index 00000000000..e5c11de6bb4 --- /dev/null +++ b/src/bin/pg_test_timing/pg_test_timing.c @@ -0,0 +1,188 @@ +/* + * pg_test_timing.c + * tests overhead of timing calls and their monotonicity: that + * they always move forward + */ + +#include "postgres_fe.h" + +#include "getopt_long.h" +#include "portability/instr_time.h" + +static const char *progname; + +static int32 test_duration = 3; + +static void handle_args(int argc, char *argv[]); +static uint64 test_timing(int32); +static void output(uint64 loop_count); + +/* record duration in powers of 2 microseconds */ +int64 histogram[32]; + +int +main(int argc, char *argv[]) +{ + uint64 loop_count; + + progname = get_progname(argv[0]); + + handle_args(argc, argv); + + loop_count = test_timing(test_duration); + + output(loop_count); + + return 0; +} + +static void +handle_args(int argc, char *argv[]) +{ + static struct option long_options[] = { + {"duration", required_argument, NULL, 'd'}, + {NULL, 0, NULL, 0} + }; + + int option; /* Command line option */ + int optindex = 0; /* used by getopt_long */ + + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + printf("Usage: %s [-d DURATION]\n", progname); + exit(0); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + puts("pg_test_timing (PostgreSQL) " PG_VERSION); + exit(0); + } + } + + while ((option = getopt_long(argc, argv, "d:", + long_options, &optindex)) != -1) + { + switch (option) + { + case 'd': + test_duration = atoi(optarg); + break; + + default: + fprintf(stderr, "Try \"%s --help\" for more information.\n", + progname); + exit(1); + break; + } + } + + if (argc > optind) + { + fprintf(stderr, + "%s: too many command-line arguments (first is \"%s\")\n", + progname, argv[optind]); + fprintf(stderr, "Try \"%s --help\" for more information.\n", + progname); + exit(1); + } + + if (test_duration > 0) + { + printf("Testing timing overhead for %d seconds.\n", test_duration); + } + else + { + fprintf(stderr, + "%s: duration must be a positive integer (duration is \"%d\")\n", + progname, test_duration); + fprintf(stderr, "Try \"%s --help\" for more information.\n", + progname); + exit(1); + } +} + +static uint64 +test_timing(int32 duration) +{ + uint64 total_time; + int64 time_elapsed = 0; + uint64 loop_count = 0; + uint64 prev, + cur; + instr_time start_time, + end_time, + temp; + + total_time = duration > 0 ? duration * INT64CONST(1000000) : 0; + + INSTR_TIME_SET_CURRENT(start_time); + cur = INSTR_TIME_GET_MICROSEC(start_time); + + while (time_elapsed < total_time) + { + int32 diff, + bits = 0; + + prev = cur; + INSTR_TIME_SET_CURRENT(temp); + cur = INSTR_TIME_GET_MICROSEC(temp); + diff = cur - prev; + + /* Did time go backwards? */ + if (diff < 0) + { + printf("Detected clock going backwards in time.\n"); + printf("Time warp: %d microseconds\n", diff); + exit(1); + } + + /* What is the highest bit in the time diff? */ + while (diff) + { + diff >>= 1; + bits++; + } + + /* Update appropriate duration bucket */ + histogram[bits]++; + + loop_count++; + INSTR_TIME_SUBTRACT(temp, start_time); + time_elapsed = INSTR_TIME_GET_MICROSEC(temp); + } + + INSTR_TIME_SET_CURRENT(end_time); + + INSTR_TIME_SUBTRACT(end_time, start_time); + + printf("Per loop time including overhead: %0.2f nsec\n", + INSTR_TIME_GET_DOUBLE(end_time) * 1e9 / loop_count); + + return loop_count; +} + +static void +output(uint64 loop_count) +{ + int64 max_bit = 31, + i; + + /* find highest bit value */ + while (max_bit > 0 && histogram[max_bit] == 0) + max_bit--; + + printf("Histogram of timing durations:\n"); + printf("%6s %10s %10s\n", "< usec", "% of total", "count"); + + for (i = 0; i <= max_bit; i++) + { + char buf[100]; + + /* lame hack to work around INT64_FORMAT deficiencies */ + snprintf(buf, sizeof(buf), INT64_FORMAT, histogram[i]); + printf("%6ld %9.5f %10s\n", 1l << i, + (double) histogram[i] * 100 / loop_count, buf); + } +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 5b86c805ae6..6dd429a8b68 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -35,13 +35,11 @@ my @contrib_uselibpq = my @contrib_uselibpgport = ( 'oid2name', 'pg_standby', - 'pg_test_timing', 'pg_xlogdump', 'vacuumlo'); my @contrib_uselibpgcommon = ( 'oid2name', 'pg_standby', - 'pg_test_timing', 'pg_xlogdump', 'vacuumlo'); my $contrib_extralibs = undef; @@ -55,8 +53,8 @@ my @contrib_excludes = ('pgcrypto', 'commit_ts', 'intagg', 'sepgsql'); # Set of variables for frontend modules my $frontend_defines = { 'initdb' => 'FRONTEND' }; my @frontend_uselibpq = ('pg_ctl', 'pg_upgrade', 'pgbench', 'psql'); -my @frontend_uselibpgport = ( 'pg_archivecleanup', 'pg_test_fsync', 'pg_upgrade', 'pgbench' ); -my @frontend_uselibpgcommon = ( 'pg_archivecleanup', 'pg_test_fsync', 'pg_upgrade', 'pgbench' ); +my @frontend_uselibpgport = ( 'pg_archivecleanup', 'pg_test_fsync', 'pg_test_timing', 'pg_upgrade', 'pgbench' ); +my @frontend_uselibpgcommon = ( 'pg_archivecleanup', 'pg_test_fsync', 'pg_test_timing', 'pg_upgrade', 'pgbench' ); my $frontend_extralibs = { 'initdb' => ['ws2_32.lib'], 'pg_restore' => ['ws2_32.lib'], |