v14-0005-pg_test_timing-Also-test-RDTSC-RDTSCP-timing-and.patch

application/octet-stream

Filename: v14-0005-pg_test_timing-Also-test-RDTSC-RDTSCP-timing-and.patch
Type: application/octet-stream
Part: 0
Message: Re: Reduce timing overhead of EXPLAIN ANALYZE using rdtsc?

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v14-0005
Subject: pg_test_timing: Also test RDTSC/RDTSCP timing and report time source
File+
src/bin/pg_test_timing/pg_test_timing.c 89 9
src/include/portability/instr_time.h 6 0
From 6656daf7c3cdc5f110e97a53d70f202c0f6bda4b Mon Sep 17 00:00:00 2001
From: Lukas Fittl <lukas@fittl.com>
Date: Thu, 12 Feb 2026 01:12:19 -0800
Subject: [PATCH v14 5/6] pg_test_timing: Also test RDTSC/RDTSCP timing and
 report time source

Author: David Geier <geidav.pg@gmail.com>
Author: Lukas Fittl <lukas@fittl.com>
Reviewed-by:
Discussion: https://www.postgresql.org/message-id/flat/20200612232810.f46nbqkdhbutzqdg%40alap3.anarazel.de
---
 src/bin/pg_test_timing/pg_test_timing.c | 98 ++++++++++++++++++++++---
 src/include/portability/instr_time.h    |  6 ++
 2 files changed, 95 insertions(+), 9 deletions(-)

diff --git a/src/bin/pg_test_timing/pg_test_timing.c b/src/bin/pg_test_timing/pg_test_timing.c
index ee0e3a3b0ab..1e943fc8d2d 100644
--- a/src/bin/pg_test_timing/pg_test_timing.c
+++ b/src/bin/pg_test_timing/pg_test_timing.c
@@ -30,14 +30,16 @@ static long long int largest_diff_count;
 
 
 static void handle_args(int argc, char *argv[]);
-static uint64 test_timing(unsigned int duration);
+static void test_system_timing(void);
+#if PG_INSTR_TSC_CLOCK
+static void test_tsc_timing(void);
+#endif
+static uint64 test_timing(unsigned int duration, TimingClockSourceType source, bool fast_timing);
 static void output(uint64 loop_count);
 
 int
 main(int argc, char *argv[])
 {
-	uint64		loop_count;
-
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_timing"));
 	progname = get_progname(argv[0]);
 
@@ -48,9 +50,11 @@ main(int argc, char *argv[])
 	 */
 	pg_initialize_timing();
 
-	loop_count = test_timing(test_duration);
+	test_system_timing();
 
-	output(loop_count);
+#if PG_INSTR_TSC_CLOCK
+	test_tsc_timing();
+#endif
 
 	return 0;
 }
@@ -148,20 +152,92 @@ handle_args(int argc, char *argv[])
 		exit(1);
 	}
 
-	printf(ngettext("Testing timing overhead for %u second.\n",
-					"Testing timing overhead for %u seconds.\n",
+	printf(ngettext("Testing timing overhead for %u second.\n\n",
+					"Testing timing overhead for %u seconds.\n\n",
 					test_duration),
 		   test_duration);
 }
 
+/*
+ * This tests default (non-fast) timing code. A clock source for that is
+ * always available. Hence, we can unconditionally output the result.
+ */
+static void
+test_system_timing(void)
+{
+	uint64		loop_count;
+
+	loop_count = test_timing(test_duration, TIMING_CLOCK_SOURCE_SYSTEM, false);
+	output(loop_count);
+}
+
+/*
+ * If on a supported architecture, test the TSC clock source. This clock
+ * source is not always available. In that case we print an informational
+ * message indicating as such.
+ *
+ * We first emit "slow" timings (RDTSCP on x86), which are used for higher
+ * precision measurements when the TSC clock source is enabled. We emit
+ * "fast" timings second (RDTSC on x86), which is used for faster timing
+ * measurements with lower precision.
+ */
+#if PG_INSTR_TSC_CLOCK
+static void
+test_tsc_timing(void)
+{
+	uint64		loop_count;
+
+	printf("\n");
+	loop_count = test_timing(test_duration, TIMING_CLOCK_SOURCE_TSC, false);
+	if (loop_count > 0)
+	{
+		output(loop_count);
+		printf("\n");
+
+		/* Now, emit fast timing measurements */
+		loop_count = test_timing(test_duration, TIMING_CLOCK_SOURCE_TSC, true);
+		output(loop_count);
+		printf("\n");
+
+		printf(_("TSC frequency: %u kHz\n"), tsc_frequency_khz);
+
+		pg_set_timing_clock_source(TIMING_CLOCK_SOURCE_AUTO);
+		if (pg_current_timing_clock_source() == TIMING_CLOCK_SOURCE_TSC)
+			printf(_("TSC clock source will be used by default, unless timing_clock_source is set to 'system'.\n"));
+		else
+			printf(_("TSC clock source will not be used by default, unless timing_clock_source is set to 'tsc'.\n"));
+	}
+	else
+		printf(_("TSC clock source is not usable. Likely unable to determine TSC frequency. are you running in an unsupported virtualized environment?.\n"));
+}
+#endif
+
 static uint64
-test_timing(unsigned int duration)
+test_timing(unsigned int duration, TimingClockSourceType source, bool fast_timing)
 {
 	uint64		loop_count = 0;
 	instr_time	start_time,
 				end_time,
 				prev,
 				cur;
+	char	   *time_source = NULL;
+
+	if (!pg_set_timing_clock_source(source))
+		return 0;
+
+	time_source = PG_INSTR_SYSTEM_CLOCK_NAME;
+
+#if PG_INSTR_TSC_CLOCK
+	if (pg_current_timing_clock_source() == TIMING_CLOCK_SOURCE_TSC)
+		time_source = fast_timing ? PG_INSTR_TSC_CLOCK_NAME_FAST : PG_INSTR_TSC_CLOCK_NAME;
+#endif
+
+	if (fast_timing)
+		printf(_("Fast clock source: %s\n"), time_source);
+	else if (source == TIMING_CLOCK_SOURCE_SYSTEM)
+		printf(_("System clock source: %s\n"), time_source);
+	else
+		printf(_("Clock source: %s\n"), time_source);
 
 	/*
 	 * Pre-zero the statistics data structures.  They're already zero by
@@ -186,7 +262,11 @@ test_timing(unsigned int duration)
 		instr_time	diff_time;
 
 		prev = cur;
-		INSTR_TIME_SET_CURRENT(cur);
+
+		if (fast_timing)
+			INSTR_TIME_SET_CURRENT_FAST(cur);
+		else
+			INSTR_TIME_SET_CURRENT(cur);
 
 		diff_time = cur;
 		INSTR_TIME_SUBTRACT(diff_time, prev);
diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h
index ce6794c0ada..f0d1118fc4d 100644
--- a/src/include/portability/instr_time.h
+++ b/src/include/portability/instr_time.h
@@ -133,6 +133,8 @@ extern bool pg_set_timing_clock_source(TimingClockSourceType source);
 
 #if defined(__x86_64__) || defined(_M_X64)
 #define PG_INSTR_TSC_CLOCK 1
+#define PG_INSTR_TSC_CLOCK_NAME_FAST  "RDTSC"
+#define PG_INSTR_TSC_CLOCK_NAME "RDTSCP"
 #define PG_INSTR_TICKS_TO_NS 1
 #elif defined(WIN32)
 #define PG_INSTR_TSC_CLOCK 0
@@ -196,10 +198,13 @@ pg_current_timing_clock_source(void)
  */
 #if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW)
 #define PG_INSTR_SYSTEM_CLOCK	CLOCK_MONOTONIC_RAW
+#define PG_INSTR_SYSTEM_CLOCK_NAME	"clock_gettime (CLOCK_MONOTONIC_RAW)"
 #elif defined(CLOCK_MONOTONIC)
 #define PG_INSTR_SYSTEM_CLOCK	CLOCK_MONOTONIC
+#define PG_INSTR_SYSTEM_CLOCK_NAME	"clock_gettime (CLOCK_MONOTONIC)"
 #else
 #define PG_INSTR_SYSTEM_CLOCK	CLOCK_REALTIME
+#define PG_INSTR_SYSTEM_CLOCK_NAME	"clock_gettime (CLOCK_REALTIME)"
 #endif
 
 static inline instr_time
@@ -220,6 +225,7 @@ pg_get_ticks_system(void)
 
 /* On Windows, use QueryPerformanceCounter() for system clock source */
 
+#define PG_INSTR_SYSTEM_CLOCK_NAME	"QueryPerformanceCounter"
 static inline instr_time
 pg_get_ticks_system(void)
 {
-- 
2.47.1