aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/Makefile1
-rw-r--r--src/bin/pg_test_timing/.gitignore1
-rw-r--r--src/bin/pg_test_timing/Makefile27
-rw-r--r--src/bin/pg_test_timing/pg_test_timing.c188
-rw-r--r--src/tools/msvc/Mkvcbuild.pm6
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'],