Re: Reduce timing overhead of EXPLAIN ANALYZE using rdtsc?
David Geier <geidav.pg@gmail.com>
From: David Geier <geidav.pg@gmail.com>
To: Lukas Fittl <lukas@fittl.com>, Andres Freund <andres@anarazel.de>
Cc: Pavel Stehule <pavel.stehule@gmail.com>,
Tomas Vondra <tomas.vondra@enterprisedb.com>, vignesh C
<vignesh21@gmail.com>, Michael Paquier <michael@paquier.xyz>,
Ibrar Ahmed <ibrar.ahmad@gmail.com>, Maciek Sakrejda <m.sakrejda@gmail.com>,
pgsql-hackers <pgsql-hackers@postgresql.org>
Date: 2025-09-01T10:36:24Z
Lists: pgsql-hackers
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
pg_test_timing: Also test RDTSC[P] timing, report time source, TSC frequency
- 16fca4825483 19 (unreleased) landed
-
Allow retrieving x86 TSC frequency/flags from CPUID
- bcb2cf41f964 19 (unreleased) landed
-
instrumentation: Standardize ticks to nanosecond conversion method
- 0022622c93d9 19 (unreleased) landed
-
instrumentation: Use Time-Stamp Counter on x86-64 to lower overhead
- 294520c44487 19 (unreleased) landed
-
Zero initialize uses of instr_time about to trigger compiler warnings
- 25b2aba0c3a5 16.0 landed
-
instr_time: Represent time as an int64 on all platforms
- 03023a2664f8 16.0 landed
-
Add 250c8ee07ed to git-blame-ignore-revs
- ff23b592ad66 16.0 cited
Hi Lukas! On 01.03.2025 08:45, Lukas Fittl wrote: > On Sun, Jun 2, 2024 at 1:08 AM Andres Freund <andres@anarazel.de> wrote: > >> At some point this patch switched from rdtsc to rdtscp, which imo largely >> negates the point of it. What lead to that? > > > From what I can gather, it appears this was an oversight when David first > reapplied the work on the instr_time changes that were committed. Yes, that was by accident. > > I've come back to this and rebased this, as well as: Thanks for moving this forward. > - Added support for VMs running under KVM/VMware Hypervisors > > On that last item, this does indeed make a difference on VMs, contrary to > the code comment in earlier versions (and I've not seen any odd behaviors > again, FWIW): How can we be sure we've actually covered all hypervisors? How much coverage do we have in the build farm? Are we good if passes on all build animals? > > On a c5.xlarge (Skylake-SP or Cascade Lake) on AWS, with the same test as > done initially in this thread: > > SELECT COUNT(*) FROM lotsarows; > Time: 974.423 ms > > EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM lotsarows; > Time: 1336.196 ms (00:01.336) > > Without patch: > EXPLAIN (ANALYZE) SELECT COUNT(*) FROM lotsarows; > Time: 2165.069 ms (00:02.165) > > Per loop time including overhead: 22.15 ns > > With patch: > EXPLAIN (ANALYZE, TIMING ON) SELECT COUNT(*) FROM lotsarows; > Time: 1654.289 ms (00:01.654) > > Per loop time including overhead: 9.81 ns > > I'm registering this again in the current commitfest to help reviews. > > Open questions I have: > - Could we rely on checking whether the TSC timesource is invariant (via > CPUID), instead of relying on Linux choosing it as a clocksource? Why do you want to do that? Are you concerned that Linux might pick a different clock source even though invariant TSC is available? We could code our own check but looking at the Linux kernel code, this is a bit more involved if we want to do it completely right. They check e.g. if the TSC is also synchronized across different CPUs, which is not the case if they're on different chassis (see unsynchronized_tsc() -> apic_is_clustered_box()). I think it's safer to start with relying on the kernel. Some research suggests that the TSC is the preferred clock source if available. > - For the Hypervisor CPUID checks I had to rely on __cpuidex which is only > available on newer GCC versions ( > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95973), how do we best check > for its presence? (compiler version, or rather configure check?) -- note > this is also the reason the patch fails the clang compiler warning check in > CI, despite clang having support in recent versions ( > https://reviews.llvm.org/D121653) What about instead using #if !__has_builtin(_cpuidex) ... #endif to define the built-in ourselves as a function in case it doesn't exist? -- David Geier