Re: Reduce timing overhead of EXPLAIN ANALYZE using rdtsc?

Lukas Fittl <lukas@fittl.com>

From: Lukas Fittl <lukas@fittl.com>
To: John Naylor <johncnaylorls@gmail.com>
Cc: Andres Freund <andres@anarazel.de>, Jakub Wartak <jakub.wartak@enterprisedb.com>, Hannu Krosing <hannuk@google.com>, Robert Haas <robertmhaas@gmail.com>, Pavel Stehule <pavel.stehule@gmail.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>, David Geier <geidav.pg@gmail.com>
Date: 2026-04-02T08:50:08Z
Lists: pgsql-hackers

Attachments

On Wed, Apr 1, 2026 at 7:18 PM John Naylor <johncnaylorls@gmail.com> wrote:
> -# Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
> +# Check for __get_cpuid_count() and __cpuidex() separately, since we sometimes
> +# need __cpuidex() even if __get_cpuid_count() is available.
>
> I'm not sure we need to document here that we need them separately. It
> seems more important to do that for the __cpuidex helper that's in a
> later patch. I don't feel strongly, though.
>
> I'd probably just do
>
> # Check for __get_cpuid_count()
> ...
>
> # Check for __cpuidex()
> ...
>
> Either way, we do need a space between separate tests (ditto Meson).

Makes sense, updated.

>
> +if cc.links('''
> +    #ifdef _MSC_VER
>      #include <intrin.h>
> +    #else
> +    #include <cpuid.h>
> +    #endif
>      int main(int arg, char **argv)
>      {
> -        unsigned int exx[4] = {0, 0, 0, 0};
> +        int exx[4] = {0, 0, 0, 0};
>          __cpuidex(exx, 7, 0);
>      }
>
> Hmm, maybe we can declare unsigned and cast to signed for MSVC as we
> do where the code is used.

Sure, I think it works either way - updated.

>
> +# __cpuidex()
> +AC_CACHE_CHECK([for __cpuidex], [pgac_cv__cpuidex],
> +[AC_LINK_IFELSE([AC_LANG_PROGRAM([#ifdef _MSC_VER
> +    #include <intrin.h>
> +    #else
> +    #include <cpuid.h>
> +    #endif],
> +  [[int exx[4] = {0, 0, 0, 0};
> +  __cpuidex(exx, 7, 0);
> +  ]])],
> +  [pgac_cv__cpuidex="yes"],
> +  [pgac_cv__cpuidex="no"])])
> +if test x"$pgac_cv__cpuidex" = x"yes"; then
> +  AC_DEFINE(HAVE__CPUIDEX, 1, [Define to 1 if you have __cpuidex.])
>  fi
>
> MSVC doesn't use autoconf, so we can leave out the intrin.h and keep
> using unsigned int.

I think that might be a problem for Clang on Windows, which has MSVC
compatibility headers, and will set _MSC_VER, see [0] and [1].

It probably works in practice, but it seems better to match the
autoconf checks to the actual code?

>
> -#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
> -#include <cpuid.h>
> -#endif
> -
> -#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
> +#if defined(HAVE__CPUID) || defined(HAVE__GET_CPUID) ||
> defined(HAVE__GET_CPUID_COUNT) || defined(HAVE__CPUIDEX)
> +#if defined(_MSC_VER)
>  #include <intrin.h>
> +#else
> +#include <cpuid.h>
> +#endif /* defined(_MSC_VER) */
>  #endif
>
> Now I'm thinking at least one of these will be defined, otherwise we'd
> have an #error, so we can just gate solely on _MSC_VER.

Yeah, makes sense, we would fail to compile in that case anyway.

I'm attaching v15 rebased, with the above changes made to 0001 to
unblock things, but feedback by Andres not addressed yet (will work on
that tomorrow).

John, feel free to adjust as you see fit in case there is any other
minor aspects to fix.

Thanks,
Lukas

[0]: https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
[1]: https://clang.llvm.org/doxygen/intrin_8h_source.html

-- 
Lukas Fittl

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. pg_test_timing: Show additional TSC clock source debug info

  2. instrumentation: Avoid CPUID 0x15/0x16 for Hypervisor TSC frequency

  3. pg_test_timing: Also test RDTSC[P] timing, report time source, TSC frequency

  4. Allow retrieving x86 TSC frequency/flags from CPUID

  5. instrumentation: Standardize ticks to nanosecond conversion method

  6. instrumentation: Use Time-Stamp Counter on x86-64 to lower overhead

  7. Check for __cpuidex and __get_cpuid_count separately

  8. pg_test_timing: Reduce per-loop overhead

  9. Refactor handling of x86 CPUID instructions

  10. instrumentation: Drop INSTR_TIME_SET_CURRENT_LAZY macro

  11. Rename pg_crc32c_sse42_choose.c for general purpose

  12. Zero initialize uses of instr_time about to trigger compiler warnings

  13. instr_time: Represent time as an int64 on all platforms

  14. Add 250c8ee07ed to git-blame-ignore-revs