public inbox for [email protected]
help / color / mirror / Atom feedProposal for enabling auto-vectorization for checksum calculations
36+ messages / 9 participants
[nested] [flat]
* Proposal for enabling auto-vectorization for checksum calculations
@ 2025-04-04 22:03 Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Matthew Sterrett @ 2025-04-04 22:03 UTC (permalink / raw)
To: [email protected]; +Cc: Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>; Matthew Sterrett <[email protected]>
Hello,
This patch enables more compiler autovectorization for the checksum
calculations.
This code is particularly well suited for autovectorization, so just
adding pg_attribute_target and some simple dynamic dispatch logic we
can get improved vectorization.
This gives about a 2x speedup in a synthetic benchmark for
pg_checksum, which is also included as a seperate patch file.
Additionally, another 2x performance increase in the synthetic
benchmark with AVX2 can be obtained if N_SUMS was changed to 64.
However, this would change the results of the checksum. This isn't
included in this patch, but I think it is worth considering for the
future
One additional factor, without explicitly passing some optimization
flag like -O2 the makefile build won't autovectorize any of the code.
However, the meson based build does this automatically.
Attachments:
[application/octet-stream] v1-0001-Enable-autovectorizing-pg_checksum_block.patch (10.5K, 2-v1-0001-Enable-autovectorizing-pg_checksum_block.patch)
download | inline diff:
From e485110192c208becad0153e51a39514cace1377 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:45 -0800
Subject: [PATCH v1 1/2] Enable autovectorizing pg_checksum_block
---
config/c-compiler.m4 | 31 ++++++
configure | 52 ++++++++++
configure.ac | 9 ++
meson.build | 28 ++++++
src/include/pg_config.h.in | 3 +
src/include/storage/checksum_impl.h | 150 +++++++++++++++++++++++-----
6 files changed, 250 insertions(+), 23 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 8534cc54c1..143a8a40dd 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -670,6 +670,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index ceeef9b091..87080b8844 100755
--- a/configure
+++ b/configure
@@ -17113,6 +17113,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index d713360f34..7effbf40e2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2012,6 +2012,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index 8e128f4982..4fd96fee1d 100644
--- a/meson.build
+++ b/meson.build
@@ -2159,6 +2159,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 07b2f798ab..0fcd9f05a7 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -645,6 +645,9 @@
/* Define to 1 to build with assertion checks. (--enable-cassert) */
#undef USE_ASSERT_CHECKING
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index da87d61ba5..5ea1f698b5 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -101,12 +101,83 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#include <immintrin.h>
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Does CPUID say there's support for AVX-2
+ */
+static inline bool
+avx2_available(void)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ unsigned int exx[4] = {0, 0, 0, 0};
+ if (!xsave_available() || !ymm_regs_available()) return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -142,35 +213,68 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
-{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
+
+#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+
+#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+pg_attribute_target(#ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+{ \
+ uint32 sums[N_SUMS]; \
+ uint32 result = 0; \
+ uint32 i, \
+ j; \
+ \
+ /* ensure that the size is compatible with the algorithm */ \
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ); \
+ \
+ /* initialize partial checksums to their corresponding offsets */ \
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets)); \
+ \
+ /* main checksum calculation */ \
+ /* this is the main place that autovectorization occurs */ \
+ for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], page->data[i][j]); \
+ \
+ /* finally add in two rounds of zeroes for additional mixing */ \
+ for (i = 0; i < 2; i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], 0); \
+ \
+ /* xor fold partial checksums together */ \
+ for (i = 0; i < N_SUMS; i++) \
+ result ^= sums[i]; \
+ \
+ return result; \
+}
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+/* Declarations are always defined to make dynamic dispatch code simpler */
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+PG_DECLARE_CHECKSUM_ISA(default);
+PG_DECLARE_CHECKSUM_ISA(avx2);
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
+PG_DEFINE_CHECKSUM_ISA(default);
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DEFINE_CHECKSUM_ISA(avx2);
+#endif
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page);
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
+static uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_dispatch;
- return result;
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page){
+ if (avx2_available()){
+ pg_checksum_block = pg_checksum_block_avx2;
+ }else{
+ pg_checksum_block = pg_checksum_block_default;
+ }
+ return pg_checksum_block(page);
}
/*
--
2.43.0
[application/octet-stream] v1-0002-Benchmark-code-for-postgres-checksums.patch (4.7K, 3-v1-0002-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From 0013d718f95abb2ea7997e4dc374d80c5560ff2b Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:27 -0800
Subject: [PATCH v1 2/2] Benchmark code for postgres checksums
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
6 files changed, 87 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index 1ba73ebd67..d7cad22ac8 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 0000000000..32ccd9efa0
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 0000000000..5f13cbe3c5
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 0000000000..f40f335ff5
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "storage/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 0000000000..4a4e2c9363
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 0000000000..4b34769995
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
@ 2025-05-07 23:57 ` Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Matthew Sterrett @ 2025-05-07 23:57 UTC (permalink / raw)
To: [email protected]; +Cc: Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
Hello! I'm still trying to figure out those CI failures, I just wanted
to update things.
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
@ 2025-05-10 11:01 ` Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Stepan Neretin @ 2025-05-10 11:01 UTC (permalink / raw)
To: Matthew Sterrett <[email protected]>; +Cc: [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
On Thu, May 8, 2025 at 6:57 AM Matthew Sterrett <[email protected]>
wrote:
> Hello! I'm still trying to figure out those CI failures, I just wanted
> to update things.
>
> From my testing, with this patch repeatedly disabling/enabling
> checksums is about 12.4% on an approximately 15 GB database.
>
> By the way, I'd love it if anyone could help me figure out how to
> replicate a CI failure in the Cirrus CI.
> I haven't been able to figure out how to test CI runs locally, does
> anyone know a good method to do that?
>
>
>
Hi Matthew,
Thanks for the patch!
I ran some timing tests:
(without avx2)
Time: 4034.351 ms
SELECT drive_pg_checksum(512);
(with avx2)
Time: 3559.076 ms
SELECT drive_pg_checksum(512);
Also attached two patches that should fix the CI issues.
Best,
Stepan Neretin
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
@ 2025-05-10 11:01 ` Stepan Neretin <[email protected]>
2025-05-19 23:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Stepan Neretin @ 2025-05-10 11:01 UTC (permalink / raw)
To: Matthew Sterrett <[email protected]>; +Cc: [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
--0000000000006a9d5c0634c60302
Content-Type: multipart/alternative; boundary="0000000000006a9d5b0634c60300"
--0000000000006a9d5b0634c60300
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Sat, May 10, 2025 at 6:01=E2=80=AFPM Stepan Neretin <[email protected]> w=
rote:
>
>
> On Thu, May 8, 2025 at 6:57=E2=80=AFAM Matthew Sterrett <
> [email protected]> wrote:
>
>> Hello! I'm still trying to figure out those CI failures, I just wanted
>> to update things.
>>
>> From my testing, with this patch repeatedly disabling/enabling
>> checksums is about 12.4% on an approximately 15 GB database.
>>
>> By the way, I'd love it if anyone could help me figure out how to
>> replicate a CI failure in the Cirrus CI.
>> I haven't been able to figure out how to test CI runs locally, does
>> anyone know a good method to do that?
>>
>>
>>
> Hi Matthew,
>
> Thanks for the patch!
>
> I ran some timing tests:
>
> (without avx2)
>
> Time: 4034.351 ms
> SELECT drive_pg_checksum(512);
>
> (with avx2)
>
>
> Time: 3559.076 ms
> SELECT drive_pg_checksum(512);
>
> Also attached two patches that should fix the CI issues.
>
> Best,
>
> Stepan Neretin
>
>
>
Oops, forgot to attach patches :)
Best,
Stepan Neretin
--0000000000006a9d5b0634c60300
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr"><br></div><br><div class=3D"gmail_quote g=
mail_quote_container"><div dir=3D"ltr" class=3D"gmail_attr">On Sat, May 10,=
2025 at 6:01=E2=80=AFPM Stepan Neretin <<a href=3D"mailto:slpmcf@gmail.=
com">[email protected]</a>> wrote:<br></div><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex"><div dir=3D"ltr"><div dir=3D"ltr"><br></div><br><div c=
lass=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Thu, May 8, 2=
025 at 6:57=E2=80=AFAM Matthew Sterrett <<a href=3D"mailto:matthewsterre=
[email protected]" target=3D"_blank">[email protected]</a>> wrote:<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello! I'm s=
till trying to figure out those CI failures, I just wanted<br>
to update things.<br>
<br>
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
@ 2025-05-19 23:54 ` Matthew Sterrett <[email protected]>
2025-05-20 14:42 ` Re: Proposal for enabling auto-vectorization for checksum calculations Nazir Bilal Yavuz <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Matthew Sterrett @ 2025-05-19 23:54 UTC (permalink / raw)
To: Stepan Neretin <[email protected]>; +Cc: [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
Hello! Thanks for helping me with this.
I'm still trying to figure out what is going on with the Bookworm test
failures. I'm pretty sure this patchset should resolve all the issues
with the macOS build, but I don't think it will help the linux
failures unfortunately.
On Sat, May 10, 2025 at 4:02 AM Stepan Neretin <[email protected]> wrote:
>
>
>
> On Sat, May 10, 2025 at 6:01 PM Stepan Neretin <[email protected]> wrote:
>>
>>
>>
>> On Thu, May 8, 2025 at 6:57 AM Matthew Sterrett <[email protected]> wrote:
>>>
>>> Hello! I'm still trying to figure out those CI failures, I just wanted
>>> to update things.
>>>
>>> From my testing, with this patch repeatedly disabling/enabling
>>> checksums is about 12.4% on an approximately 15 GB database.
>>>
>>> By the way, I'd love it if anyone could help me figure out how to
>>> replicate a CI failure in the Cirrus CI.
>>> I haven't been able to figure out how to test CI runs locally, does
>>> anyone know a good method to do that?
>>>
>>>
>>
>> Hi Matthew,
>>
>> Thanks for the patch!
>>
>> I ran some timing tests:
>>
>> (without avx2)
>>
>> Time: 4034.351 ms
>> SELECT drive_pg_checksum(512);
>>
>> (with avx2)
>>
>> Time: 3559.076 ms
>> SELECT drive_pg_checksum(512);
>>
>> Also attached two patches that should fix the CI issues.
>>
>> Best,
>>
>> Stepan Neretin
>>
>>
>>
>
> Oops, forgot to attach patches :)
>
> Best,
>
> Stepan Neretin
>
>
Attachments:
[application/octet-stream] v3-0002-Fix-compilation-on-systems-where-immintrin.h-is-n.patch (1.1K, 2-v3-0002-Fix-compilation-on-systems-where-immintrin.h-is-n.patch)
download | inline diff:
From 30d916546860d3d19f8d91a0ab4bc99f9c350aaa Mon Sep 17 00:00:00 2001
From: Stepan Neretin <[email protected]>
Date: Sat, 10 May 2025 16:37:13 +0700
Subject: [PATCH v3 2/5] Fix compilation on systems where <immintrin.h> is not
available or inappropriate, such as older GCC versions or non-x86 platforms.
---
src/include/storage/checksum_impl.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 5ea1f698b57..042ee8af120 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -112,7 +112,9 @@
#include <cpuid.h>
#endif
+#ifdef HAVE_XSAVE_INTRINSICS
#include <immintrin.h>
+#endif
#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
#include <intrin.h>
@@ -253,10 +255,6 @@ pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
}
/* Declarations are always defined to make dynamic dispatch code simpler */
-
-PG_DECLARE_CHECKSUM_ISA(default);
-PG_DECLARE_CHECKSUM_ISA(avx2);
-
PG_DEFINE_CHECKSUM_ISA(default);
#ifdef USE_AVX2_WITH_RUNTIME_CHECK
PG_DEFINE_CHECKSUM_ISA(avx2);
--
2.43.0
[application/octet-stream] v3-0005-Use-dummy-function-to-avoid-linker-error-move-dec.patch (1.9K, 3-v3-0005-Use-dummy-function-to-avoid-linker-error-move-dec.patch)
download | inline diff:
From f7b28c6378db9cc98371e89e830a2ae8a571e9a0 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Mon, 19 May 2025 13:23:55 -0700
Subject: [PATCH v3 5/5] Use dummy function to avoid linker error, move
declarations
---
src/include/storage/checksum_impl.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 042ee8af120..4070646e23e 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -163,7 +163,7 @@ ymm_regs_available(void)
static inline bool
avx2_available(void)
{
-#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+#if defined (USE_AVX2_WITH_RUNTIME_CHECK) && defined(__x86_64__)
unsigned int exx[4] = {0, 0, 0, 0};
if (!xsave_available() || !ymm_regs_available()) return false;
@@ -220,7 +220,20 @@ do { \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+#define PG_DEFINE_CHECKSUM_DUMMY(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page); \
+pg_attribute_target(#ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+{ \
+ Assert(false); /* This function should never be called */ \
+ return pg_checksum_block_default(page); /* Just in case it somehow is */ \
+}
+
#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page); \
pg_attribute_target(#ISANAME) \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
@@ -254,10 +267,11 @@ pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
return result; \
}
-/* Declarations are always defined to make dynamic dispatch code simpler */
PG_DEFINE_CHECKSUM_ISA(default);
#ifdef USE_AVX2_WITH_RUNTIME_CHECK
PG_DEFINE_CHECKSUM_ISA(avx2);
+#else
+PG_DEFINE_CHECKSUM_DUMMY(avx2);
#endif
static uint32
--
2.43.0
[application/octet-stream] v3-0004-fix-bench-compiling.patch (692B, 4-v3-0004-fix-bench-compiling.patch)
download | inline diff:
From 78873aec488678accbed1c4d1fc7ce15d12df303 Mon Sep 17 00:00:00 2001
From: Stepan Neretin <[email protected]>
Date: Sat, 10 May 2025 17:57:47 +0700
Subject: [PATCH v3 4/5] fix bench compiling
---
contrib/pg_checksum_bench/pg_checksum_bench.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
index f40f335ff59..0296dcfd259 100644
--- a/contrib/pg_checksum_bench/pg_checksum_bench.c
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -1,5 +1,6 @@
#include "postgres.h"
#include "fmgr.h"
+#include "storage/checksum.h"
#include "storage/checksum_impl.h"
#include <stdio.h>
--
2.43.0
[application/octet-stream] v3-0003-Benchmark-code-for-postgres-checksums.patch (4.7K, 5-v3-0003-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From cd6dc517b897faf3d960fafe8ea6b2cf9bbc2e05 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:27 -0800
Subject: [PATCH v3 3/5] Benchmark code for postgres checksums
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
6 files changed, 87 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..f40f335ff59
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "storage/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
[application/octet-stream] v3-0001-Enable-autovectorizing-pg_checksum_block.patch (10.5K, 6-v3-0001-Enable-autovectorizing-pg_checksum_block.patch)
download | inline diff:
From 58122ebe1bbebc70da90c7ec3e77f3c3d524aa85 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:45 -0800
Subject: [PATCH v3 1/5] Enable autovectorizing pg_checksum_block
---
config/c-compiler.m4 | 31 ++++++
configure | 52 ++++++++++
configure.ac | 9 ++
meson.build | 28 ++++++
src/include/pg_config.h.in | 3 +
src/include/storage/checksum_impl.h | 150 +++++++++++++++++++++++-----
6 files changed, 250 insertions(+), 23 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 5f3e1d1faf9..4d5bceafe9e 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -710,6 +710,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index 4f15347cc95..0b328dc22db 100755
--- a/configure
+++ b/configure
@@ -17724,6 +17724,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index 4b8335dc613..b980429282f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2089,6 +2089,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index d142e3e408b..e0ab1f9cf2f 100644
--- a/meson.build
+++ b/meson.build
@@ -2301,6 +2301,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 726a7c1be1f..34fa398ee8c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -672,6 +672,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index da87d61ba52..5ea1f698b57 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -101,12 +101,83 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#include <immintrin.h>
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Does CPUID say there's support for AVX-2
+ */
+static inline bool
+avx2_available(void)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ unsigned int exx[4] = {0, 0, 0, 0};
+ if (!xsave_available() || !ymm_regs_available()) return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -142,35 +213,68 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
-{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
+
+#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+
+#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+pg_attribute_target(#ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+{ \
+ uint32 sums[N_SUMS]; \
+ uint32 result = 0; \
+ uint32 i, \
+ j; \
+ \
+ /* ensure that the size is compatible with the algorithm */ \
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ); \
+ \
+ /* initialize partial checksums to their corresponding offsets */ \
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets)); \
+ \
+ /* main checksum calculation */ \
+ /* this is the main place that autovectorization occurs */ \
+ for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], page->data[i][j]); \
+ \
+ /* finally add in two rounds of zeroes for additional mixing */ \
+ for (i = 0; i < 2; i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], 0); \
+ \
+ /* xor fold partial checksums together */ \
+ for (i = 0; i < N_SUMS; i++) \
+ result ^= sums[i]; \
+ \
+ return result; \
+}
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+/* Declarations are always defined to make dynamic dispatch code simpler */
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+PG_DECLARE_CHECKSUM_ISA(default);
+PG_DECLARE_CHECKSUM_ISA(avx2);
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
+PG_DEFINE_CHECKSUM_ISA(default);
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DEFINE_CHECKSUM_ISA(avx2);
+#endif
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page);
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
+static uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_dispatch;
- return result;
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page){
+ if (avx2_available()){
+ pg_checksum_block = pg_checksum_block_avx2;
+ }else{
+ pg_checksum_block = pg_checksum_block_default;
+ }
+ return pg_checksum_block(page);
}
/*
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-19 23:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
@ 2025-05-20 14:42 ` Nazir Bilal Yavuz <[email protected]>
2025-05-22 21:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Nazir Bilal Yavuz @ 2025-05-20 14:42 UTC (permalink / raw)
To: Matthew Sterrett <[email protected]>; +Cc: Stepan Neretin <[email protected]>; [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
Hi,
On Tue, 20 May 2025 at 02:54, Matthew Sterrett
<[email protected]> wrote:
>
> Hello! Thanks for helping me with this.
> I'm still trying to figure out what is going on with the Bookworm test
> failures. I'm pretty sure this patchset should resolve all the issues
> with the macOS build, but I don't think it will help the linux
> failures unfortunately.
You can see the failure at the artifacts ->
'log/tmp_install/log/install.log' file on the CI web page [1].
If you want to replicate that on your local:
$ ./configure --with-llvm CLANG="ccache clang-16"
$ make -s -j8 world-bin
$ make -j8 check-world
should be enough. I was able to replicate it with these commands. I
hope these help.
[1] https://cirrus-ci.com/task/4834162550505472
--
Regards,
Nazir Bilal Yavuz
Microsoft
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-19 23:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-20 14:42 ` Re: Proposal for enabling auto-vectorization for checksum calculations Nazir Bilal Yavuz <[email protected]>
@ 2025-05-22 21:54 ` Matthew Sterrett <[email protected]>
2025-06-02 12:11 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Matthew Sterrett @ 2025-05-22 21:54 UTC (permalink / raw)
To: Nazir Bilal Yavuz <[email protected]>; +Cc: Stepan Neretin <[email protected]>; [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
> You can see the failure at the artifacts ->
> 'log/tmp_install/log/install.log' file on the CI web page [1].
>
> If you want to replicate that on your local:
>
> $ ./configure --with-llvm CLANG="ccache clang-16"
> $ make -s -j8 world-bin
> $ make -j8 check-world
>
> should be enough. I was able to replicate it with these commands. I
> hope these help.
Thanks so much for helping me figure this out!
Okay, I've determined that versions of LLVM/Clang before 19 crash when
compiling this patch for some reason; it seems that both make
check-world and make install will crash with the affected LLVM
versions.
Unfortunately, what matters seems to be the version of the linker/LTO
optimizer, which I don't think we can check at compile time.
I added a check for Clang>=19 which works at preventing the crash on my system.
I think it's possible some unusual combination of clang/LLVM might
still crash during the build, but I think this is a reasonable
solution
Attachments:
[application/octet-stream] v4-0005-Use-dummy-function-to-avoid-linker-error-move-dec.patch (1.9K, 2-v4-0005-Use-dummy-function-to-avoid-linker-error-move-dec.patch)
download | inline diff:
From f7b28c6378db9cc98371e89e830a2ae8a571e9a0 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Mon, 19 May 2025 13:23:55 -0700
Subject: [PATCH v4 5/6] Use dummy function to avoid linker error, move
declarations
---
src/include/storage/checksum_impl.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 042ee8af120..4070646e23e 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -163,7 +163,7 @@ ymm_regs_available(void)
static inline bool
avx2_available(void)
{
-#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+#if defined (USE_AVX2_WITH_RUNTIME_CHECK) && defined(__x86_64__)
unsigned int exx[4] = {0, 0, 0, 0};
if (!xsave_available() || !ymm_regs_available()) return false;
@@ -220,7 +220,20 @@ do { \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+#define PG_DEFINE_CHECKSUM_DUMMY(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page); \
+pg_attribute_target(#ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+{ \
+ Assert(false); /* This function should never be called */ \
+ return pg_checksum_block_default(page); /* Just in case it somehow is */ \
+}
+
#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page); \
pg_attribute_target(#ISANAME) \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
@@ -254,10 +267,11 @@ pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
return result; \
}
-/* Declarations are always defined to make dynamic dispatch code simpler */
PG_DEFINE_CHECKSUM_ISA(default);
#ifdef USE_AVX2_WITH_RUNTIME_CHECK
PG_DEFINE_CHECKSUM_ISA(avx2);
+#else
+PG_DEFINE_CHECKSUM_DUMMY(avx2);
#endif
static uint32
--
2.43.0
[application/octet-stream] v4-0004-fix-bench-compiling.patch (692B, 3-v4-0004-fix-bench-compiling.patch)
download | inline diff:
From 78873aec488678accbed1c4d1fc7ce15d12df303 Mon Sep 17 00:00:00 2001
From: Stepan Neretin <[email protected]>
Date: Sat, 10 May 2025 17:57:47 +0700
Subject: [PATCH v4 4/6] fix bench compiling
---
contrib/pg_checksum_bench/pg_checksum_bench.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
index f40f335ff59..0296dcfd259 100644
--- a/contrib/pg_checksum_bench/pg_checksum_bench.c
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -1,5 +1,6 @@
#include "postgres.h"
#include "fmgr.h"
+#include "storage/checksum.h"
#include "storage/checksum_impl.h"
#include <stdio.h>
--
2.43.0
[application/octet-stream] v4-0002-Fix-compilation-on-systems-where-immintrin.h-is-n.patch (1.1K, 4-v4-0002-Fix-compilation-on-systems-where-immintrin.h-is-n.patch)
download | inline diff:
From 30d916546860d3d19f8d91a0ab4bc99f9c350aaa Mon Sep 17 00:00:00 2001
From: Stepan Neretin <[email protected]>
Date: Sat, 10 May 2025 16:37:13 +0700
Subject: [PATCH v4 2/6] Fix compilation on systems where <immintrin.h> is not
available or inappropriate, such as older GCC versions or non-x86 platforms.
---
src/include/storage/checksum_impl.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 5ea1f698b57..042ee8af120 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -112,7 +112,9 @@
#include <cpuid.h>
#endif
+#ifdef HAVE_XSAVE_INTRINSICS
#include <immintrin.h>
+#endif
#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
#include <intrin.h>
@@ -253,10 +255,6 @@ pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
}
/* Declarations are always defined to make dynamic dispatch code simpler */
-
-PG_DECLARE_CHECKSUM_ISA(default);
-PG_DECLARE_CHECKSUM_ISA(avx2);
-
PG_DEFINE_CHECKSUM_ISA(default);
#ifdef USE_AVX2_WITH_RUNTIME_CHECK
PG_DEFINE_CHECKSUM_ISA(avx2);
--
2.43.0
[application/octet-stream] v4-0001-Enable-autovectorizing-pg_checksum_block.patch (10.5K, 5-v4-0001-Enable-autovectorizing-pg_checksum_block.patch)
download | inline diff:
From 58122ebe1bbebc70da90c7ec3e77f3c3d524aa85 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:45 -0800
Subject: [PATCH v4 1/6] Enable autovectorizing pg_checksum_block
---
config/c-compiler.m4 | 31 ++++++
configure | 52 ++++++++++
configure.ac | 9 ++
meson.build | 28 ++++++
src/include/pg_config.h.in | 3 +
src/include/storage/checksum_impl.h | 150 +++++++++++++++++++++++-----
6 files changed, 250 insertions(+), 23 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 5f3e1d1faf9..4d5bceafe9e 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -710,6 +710,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index 4f15347cc95..0b328dc22db 100755
--- a/configure
+++ b/configure
@@ -17724,6 +17724,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index 4b8335dc613..b980429282f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2089,6 +2089,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index d142e3e408b..e0ab1f9cf2f 100644
--- a/meson.build
+++ b/meson.build
@@ -2301,6 +2301,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 726a7c1be1f..34fa398ee8c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -672,6 +672,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index da87d61ba52..5ea1f698b57 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -101,12 +101,83 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#include <immintrin.h>
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Does CPUID say there's support for AVX-2
+ */
+static inline bool
+avx2_available(void)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ unsigned int exx[4] = {0, 0, 0, 0};
+ if (!xsave_available() || !ymm_regs_available()) return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -142,35 +213,68 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
-{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
+
+#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+
+#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+pg_attribute_target(#ISANAME) \
+static uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+{ \
+ uint32 sums[N_SUMS]; \
+ uint32 result = 0; \
+ uint32 i, \
+ j; \
+ \
+ /* ensure that the size is compatible with the algorithm */ \
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ); \
+ \
+ /* initialize partial checksums to their corresponding offsets */ \
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets)); \
+ \
+ /* main checksum calculation */ \
+ /* this is the main place that autovectorization occurs */ \
+ for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], page->data[i][j]); \
+ \
+ /* finally add in two rounds of zeroes for additional mixing */ \
+ for (i = 0; i < 2; i++) \
+ for (j = 0; j < N_SUMS; j++) \
+ CHECKSUM_COMP(sums[j], 0); \
+ \
+ /* xor fold partial checksums together */ \
+ for (i = 0; i < N_SUMS; i++) \
+ result ^= sums[i]; \
+ \
+ return result; \
+}
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+/* Declarations are always defined to make dynamic dispatch code simpler */
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+PG_DECLARE_CHECKSUM_ISA(default);
+PG_DECLARE_CHECKSUM_ISA(avx2);
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
+PG_DEFINE_CHECKSUM_ISA(default);
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DEFINE_CHECKSUM_ISA(avx2);
+#endif
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page);
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
+static uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_dispatch;
- return result;
+static uint32
+pg_checksum_block_dispatch(const PGChecksummablePage *page){
+ if (avx2_available()){
+ pg_checksum_block = pg_checksum_block_avx2;
+ }else{
+ pg_checksum_block = pg_checksum_block_default;
+ }
+ return pg_checksum_block(page);
}
/*
--
2.43.0
[application/octet-stream] v4-0003-Benchmark-code-for-postgres-checksums.patch (4.7K, 6-v4-0003-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From cd6dc517b897faf3d960fafe8ea6b2cf9bbc2e05 Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Fri, 7 Mar 2025 11:33:27 -0800
Subject: [PATCH v4 3/6] Benchmark code for postgres checksums
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
6 files changed, 87 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..f40f335ff59
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "storage/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
[application/octet-stream] v4-0006-Workaround-for-clang-19-crash.patch (2.0K, 7-v4-0006-Workaround-for-clang-19-crash.patch)
download | inline diff:
From 5fbb374a397d22febcee97b08564967afaacf37e Mon Sep 17 00:00:00 2001
From: Matthew Sterrett <[email protected]>
Date: Wed, 21 May 2025 16:00:22 -0700
Subject: [PATCH v4 6/6] Workaround for clang<19 crash
---
src/include/storage/checksum_impl.h | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 4070646e23e..81dfecff17d 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -132,7 +132,7 @@ xsave_available(void)
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
#elif defined(HAVE__CPUID)
__cpuid(exx, 1);
-#else
+#elif defined(__x86_64__)
#error cpuid instruction not available
#endif
return (exx[2] & (1 << 27)) != 0; /* osxsave */
@@ -215,15 +215,10 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-
-#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
-static uint32 \
-pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
#define PG_DEFINE_CHECKSUM_DUMMY(ISANAME) \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page); \
-pg_attribute_target(#ISANAME) \
static uint32 \
pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
{ \
@@ -267,6 +262,9 @@ pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
return result; \
}
+/* Older Clang versions crash during LTO with this code */
+#if !(__clang_major__) || __clang_major__ >= 19
+
PG_DEFINE_CHECKSUM_ISA(default);
#ifdef USE_AVX2_WITH_RUNTIME_CHECK
PG_DEFINE_CHECKSUM_ISA(avx2);
@@ -289,6 +287,15 @@ pg_checksum_block_dispatch(const PGChecksummablePage *page){
return pg_checksum_block(page);
}
+#else
+/* The same as before the patch, for the crashing Clang versions */
+PG_DEFINE_CHECKSUM_ISA(default);
+static uint32 pg_checksum_block(const PGChecksummablePage *page) {
+ return pg_checksum_block_default(page);
+}
+
+#endif
+
/*
* Compute the checksum for a Postgres page.
*
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations Stepan Neretin <[email protected]>
2025-05-19 23:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-20 14:42 ` Re: Proposal for enabling auto-vectorization for checksum calculations Nazir Bilal Yavuz <[email protected]>
2025-05-22 21:54 ` Re: Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
@ 2025-06-02 12:11 ` John Naylor <[email protected]>
0 siblings, 0 replies; 36+ messages in thread
From: John Naylor @ 2025-06-02 12:11 UTC (permalink / raw)
To: Matthew Sterrett <[email protected]>; +Cc: Nazir Bilal Yavuz <[email protected]>; Stepan Neretin <[email protected]>; [email protected]; Devulapalli, Raghuveer <[email protected]>; Shankaran, Akash <[email protected]>
On Fri, May 23, 2025 at 4:54 AM Matthew Sterrett
<[email protected]> wrote:
> Okay, I've determined that versions of LLVM/Clang before 19 crash when
> compiling this patch for some reason; it seems that both make
> check-world and make install will crash with the affected LLVM
> versions.
> Unfortunately, what matters seems to be the version of the linker/LTO
> optimizer, which I don't think we can check at compile time.
> I added a check for Clang>=19 which works at preventing the crash on my system.
> I think it's possible some unusual combination of clang/LLVM might
> still crash during the build, but I think this is a reasonable
> solution
I don't know if this is related to the crashes, but it doesn't seem
like a good idea to #include the function pointer stuff everywhere,
that should probably go into src/port like the others.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
@ 2025-09-11 05:42 root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: root @ 2025-09-11 05:42 UTC (permalink / raw)
To: [email protected]; +Cc: [email protected]; [email protected]
Hi John,
Thanks for the feedback. This is v5 of the patchset, updated following your comments:
- Moved the function pointer definitions out of common headers and
into src/port, consistent with existing practice.
Thanks again for the guidance.
Best regards,
Kim Andrew
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
@ 2025-09-24 06:32 ` John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-09-24 06:32 UTC (permalink / raw)
To: root <[email protected]>; +Cc: [email protected]
On Thu, Sep 11, 2025 at 1:55 PM root <[email protected]> wrote:
> Thanks for the feedback. This is v5 of the patchset, updated following your comments:
>
> - Moved the function pointer definitions out of common headers and
> into src/port, consistent with existing practice.
There is no attachment in this thread, so it's not showing up in the
commitfest entry (which will need to be moved to next open
commitfest), so it's not getting CI testing:
https://commitfest.postgresql.org/patch/5726/
Note that the whole series must be attached in a single email, or it
won't get automated testing.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-09-24 21:50 ` Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-09-24 21:50 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]
On Tue, Sep 23, 2025 at 11:32 PM John Naylor [email protected] wrote:
There is no attachment in this thread, so it's not showing up in the
commitfest entry (which will need to be moved to next open
commitfest), so it's not getting CI testing:
https://commitfest.postgresql.org/patch/5726/
Note that the whole series must be attached in a single email, or it
won't get automated testing.
Thanks, John. I see the issue now — I’ll attach the entire patch
series in a single email so it shows up properly in the commitfest and
gets CI coverage.
Please find attached v6 of the patchset, updated per your feedback.
Best regards,
Andrew Kim
On Tue, Sep 23, 2025 at 11:32 PM John Naylor <[email protected]> wrote:
>
> On Thu, Sep 11, 2025 at 1:55 PM root <[email protected]> wrote:
> > Thanks for the feedback. This is v5 of the patchset, updated following your comments:
> >
> > - Moved the function pointer definitions out of common headers and
> > into src/port, consistent with existing practice.
>
> There is no attachment in this thread, so it's not showing up in the
> commitfest entry (which will need to be moved to next open
> commitfest), so it's not getting CI testing:
>
> https://commitfest.postgresql.org/patch/5726/
>
> Note that the whole series must be attached in a single email, or it
> won't get automated testing.
>
> --
> John Naylor
> Amazon Web Services
Attachments:
[application/octet-stream] v5-0002-Benchmark-code-for-postgres-checksums.patch (4.7K, 2-v5-0002-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From 94160dca5478e713bcaab42389207ee1eac3d553 Mon Sep 17 00:00:00 2001
From: Andrew kim <[email protected]>
Date: Wed, 10 Sep 2025 16:12:44 -0700
Subject: [PATCH 2/2] Benchmark code for postgres checksums
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
6 files changed, 87 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..f40f335ff59
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "storage/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
[application/octet-stream] v5-0001-Enable-autovectorizing-pg_checksum_block.patch (15.3K, 3-v5-0001-Enable-autovectorizing-pg_checksum_block.patch)
download | inline diff:
From 982be9006cdb584f0287548da637f41c3f898747 Mon Sep 17 00:00:00 2001
From: Andrew kim <[email protected]>
Date: Tue, 23 Sep 2025 17:44:18 -0700
Subject: [PATCH 1/1] Enable-autovectorizing-pg_checksum_block
---
config/c-compiler.m4 | 31 +++++
configure | 52 ++++++++
configure.ac | 9 ++
meson.build | 28 ++++
src/include/pg_config.h.in | 3 +
src/include/storage/checksum_impl.h | 90 +++----------
src/port/Makefile | 1 +
src/port/meson.build | 1 +
src/port/pg_checksum_dispatch.c | 195 ++++++++++++++++++++++++++++
9 files changed, 339 insertions(+), 71 deletions(-)
create mode 100644 src/port/pg_checksum_dispatch.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..bcc1398d51a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -711,6 +711,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index 22cd866147b..209849c773c 100755
--- a/configure
+++ b/configure
@@ -17562,6 +17562,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..c061b1a854c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2091,6 +2091,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index 395416a6060..a37ef88bf16 100644
--- a/meson.build
+++ b/meson.build
@@ -2292,6 +2292,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c4dc5d72bdb..987f9b5c77c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -675,6 +675,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index da87d61ba52..82e525529f4 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -101,12 +101,14 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -142,74 +144,20 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
-{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
-
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
-
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
-
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
-
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
-
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
-
- return result;
-}
-
-/*
- * Compute the checksum for a Postgres page.
- *
- * The page must be adequately aligned (at least on a 4-byte boundary).
- * Beware also that the checksum field of the page is transiently zeroed.
- *
- * The checksum includes the block number (to detect the case where a page is
- * somehow moved to a different location), the page header (excluding the
- * checksum itself), and the page data.
- */
-uint16
-pg_checksum_page(char *page, BlockNumber blkno)
-{
- PGChecksummablePage *cpage = (PGChecksummablePage *) page;
- uint16 save_checksum;
- uint32 checksum;
-
- /* We only calculate the checksum for properly-initialized pages */
- Assert(!PageIsNew((Page) page));
-
- /*
- * Save pd_checksum and temporarily set it to zero, so that the checksum
- * calculation isn't affected by the old checksum stored on the page.
- * Restore it after, because actually updating the checksum is NOT part of
- * the API of this function.
- */
- save_checksum = cpage->phdr.pd_checksum;
- cpage->phdr.pd_checksum = 0;
- checksum = pg_checksum_block(cpage);
- cpage->phdr.pd_checksum = save_checksum;
-
- /* Mix in the block number to detect transposed pages */
- checksum ^= blkno;
-
- /*
- * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
- * one. That avoids checksums of zero, which seems like a good idea.
- */
- return (uint16) ((checksum % 65535) + 1);
-}
+#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
+uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+
+#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+pg_attribute_target(#ISANAME) \
+uint32 pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
+
+/* Declare ISA implementations (declarations only in header) */
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DECLARE_CHECKSUM_ISA(avx2);
+#endif
+PG_DECLARE_CHECKSUM_ISA(default);
+
+uint32 pg_checksum_block_dispatch(const PGChecksummablePage *page);
+extern uint32 (*pg_checksum_block)(const PGChecksummablePage *page);
+extern uint16 pg_checksum_page(char *page, BlockNumber blkno);
diff --git a/src/port/Makefile b/src/port/Makefile
index 4274949dfa4..27423f1058b 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -48,6 +48,7 @@ OBJS = \
pg_numa.o \
pg_popcount_aarch64.o \
pg_popcount_avx512.o \
+ pg_checksum_dispatch.o \
pg_strong_random.o \
pgcheckdir.o \
pgmkdirp.o \
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..c4bbe9f2ece 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -11,6 +11,7 @@ pgport_sources = [
'pg_numa.c',
'pg_popcount_aarch64.c',
'pg_popcount_avx512.c',
+ 'pg_checksum_dispatch.c',
'pg_strong_random.c',
'pgcheckdir.c',
'pgmkdirp.c',
diff --git a/src/port/pg_checksum_dispatch.c b/src/port/pg_checksum_dispatch.c
new file mode 100644
index 00000000000..b4b297c831f
--- /dev/null
+++ b/src/port/pg_checksum_dispatch.c
@@ -0,0 +1,195 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_checksum_dispatch.c
+ * Holds the AVX2 pg_popcount() implementation.
+ *
+ * Copyright (c) 2024-2025, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/pg_checksum_dispatch.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+#include "storage/checksum_impl.h"
+
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#ifdef HAVE_XSAVE_INTRINSICS
+#include <immintrin.h>
+#endif
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+#include "port/pg_bitutils.h"
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#elif defined(__x86_64__)
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Does CPUID say there's support for AVX-2
+ */
+static inline bool
+avx2_available(void)
+{
+#if defined (USE_AVX2_WITH_RUNTIME_CHECK) && defined(__x86_64__)
+ unsigned int exx[4] = {0, 0, 0, 0};
+ if (!xsave_available() || !ymm_regs_available()) return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+
+
+/* default checksum implementation */
+PG_DEFINE_CHECKSUM_ISA(default)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
+
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ for (i = 0; i < (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DEFINE_CHECKSUM_ISA(avx2)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
+
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ for (i = 0; i < (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+#endif
+
+/* Function pointer - external linkage (declared extern in header) */
+uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_dispatch;
+
+/* Dispatch function: simple, safe */
+uint32 pg_checksum_block_dispatch(const PGChecksummablePage *page)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (avx2_available())
+ {
+ /* optional: patch pointer so next call goes directly */
+ pg_checksum_block = pg_checksum_block_avx2;
+ return pg_checksum_block_avx2(page);
+ }
+#endif
+ /* fallback */
+ pg_checksum_block = pg_checksum_block_default;
+ return pg_checksum_block_default(page);
+}
+
+/*
+ * Compute the checksum for a Postgres page.
+ *
+ * The page must be adequately aligned (at least on a 4-byte boundary).
+ * Beware also that the checksum field of the page is transiently zeroed.
+ *
+ * The checksum includes the block number (to detect the case where a page is
+ * somehow moved to a different location), the page header (excluding the
+ * checksum itself), and the page data.
+ */
+uint16 pg_checksum_page(char *page, BlockNumber blkno)
+{
+ PGChecksummablePage *cpage = (PGChecksummablePage *) page;
+ uint16 save_checksum;
+ uint32 checksum;
+
+ /* We only calculate the checksum for properly-initialized pages */
+ Assert(!PageIsNew((Page) page));
+
+ /*
+ * Save pd_checksum and temporarily set it to zero, so that the checksum
+ * calculation isn't affected by the old checksum stored on the page.
+ * Restore it after, because actually updating the checksum is NOT part of
+ * the API of this function.
+ */
+ save_checksum = cpage->phdr.pd_checksum;
+ cpage->phdr.pd_checksum = 0;
+ checksum = pg_checksum_block(cpage);
+ cpage->phdr.pd_checksum = save_checksum;
+
+ /* Mix in the block number to detect transposed pages */
+ checksum ^= blkno;
+
+ /*
+ * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
+ * one. That avoids checksums of zero, which seems like a good idea.
+ */
+ return (uint16)((checksum % 65535) + 1);
+}
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-10-02 05:25 ` John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-10-02 05:25 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: [email protected]
On Thu, Sep 25, 2025 at 4:50 AM Andrew Kim <[email protected]> wrote:
>
> Thanks, John. I see the issue now — I’ll attach the entire patch
> series in a single email so it shows up properly in the commitfest and
> gets CI coverage.
It's still picking up v4, and the archive link doesn't show any
further replies. Something must have happened with the email
threading, since you weren't on the thread at first. Please create an
account and edit the entry to point to a more recent message ID:
https://commitfest.postgresql.org/patch/5726/
> Please find attached v6 of the patchset, updated per your feedback.
Thanks. (BTW, we discourage top-posting and prefer to cut to size and
use inline responses)
This is not a complete review, but some architectural thoughts and
some things I've noticed.
The top of the checksum_impl.h has this:
* This file exists for the benefit of external programs that may wish to
* check Postgres page checksums. They can #include this to get the code
* referenced by storage/checksum.h. (Note: you may need to redefine
* Assert() as empty to compile this successfully externally.)
It's going to be a bit tricky to preserve this ability while allowing
the core server and client programs to dispatch to a specialized
implementation, but we should at least try. That means keeping
pg_checksum_block() and pg_checksum_page() where they live now.
I think a good first refactoring patch would be to move
src/backend/storage/checksum.c (which your patch doesn't even touch)
to src/port (and src/include/storage/checksum.h to src/include/port)
and have all callers use that. With that, I imagine only that
checksum.c file would include checksum_impl.h.
If that poses a problem, let us know -- we may have to further juggle
things. If that works without issue, we can proceed with the
specialization. On that, just a few things to note here, although the
next patch doesn't need to worry about any of this yet:
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
If we're just testing if the target works, we can just use an empty
function, right?
+#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
+uint32 \
+pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
+
+#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
+pg_attribute_target(#ISANAME) \
+uint32 pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
I find this hard to read compared to just using the actual name.
+avx2_available(void)
+{
+#if defined (USE_AVX2_WITH_RUNTIME_CHECK) && defined(__x86_64__)
Why guard on __x86_64__?
+PG_DEFINE_CHECKSUM_ISA(default)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
[...]
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+PG_DEFINE_CHECKSUM_ISA(avx2)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
[...]
With the single src/port file idea above, these would just do "return
pg_checksum_block()" (or pg_checksum_page, whichever makes more
sense).
+ if (avx2_available())
+ {
+ /* optional: patch pointer so next call goes directly */
+ pg_checksum_block = pg_checksum_block_avx2;
+ return pg_checksum_block_avx2(page);
+ }
Not sure what your referring to here by "patching" the pointer, but it
sounds dangerous. Besides, the cost of indirection is basically zero
for multi-kilobyte inputs, so there is not even any motivation to
consider doing differently.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-10-17 07:15 ` Andrew Kim <[email protected]>
2025-10-17 10:53 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 2 replies; 36+ messages in thread
From: Andrew Kim @ 2025-10-17 07:15 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]
Hi John,
Thank you for your detailed and constructive feedback on the checksum
AVX2 optimization patch.
I've carefully addressed all of your concerns and am pleased to share
the updated V6 implementation.
V6 Implementation adds SIMD-optimized checksum calculation using AVX2
instructions with automatic fallback to portable implementation,
incorporating all of your recommended improvements:
1. Code Organization
Consolidated architecture: Moved all checksum logic into a single
checksum.c file, eliminating the complexity of separate dispatch files
Simplified build integration: Streamlined both autoconf and meson
build configurations
2. Safety & Robustness
Eliminated dangerous runtime patching: Replaced direct function
pointer manipulation with safe dispatch through static function
pointers
Thread-safe design: All operations are now inherently thread-safe
without requiring locks or synchronization
3. Code Readability
Removed macro complexity: Replaced PG_DECLARE_CHECKSUM_ISA macros with
explicit, clear function declarations
PostgreSQL coding compliance: Follows established PostgreSQL
conventions throughout
Simplified conditional compilation: Removed redundant __x86_64__
guards, relying on configure script's platform detection
4. Compiler Detection & Compatibility
Preserved robust testing: Maintained the comprehensive avx2_test
function that validates both __attribute__((target("avx2"))) support
and AVX2 intrinsics functionality
Runtime feature detection: Uses __builtin_cpu_supports("avx2") for
reliable CPU capability detection
Build cleanly across all library variants (static, shared, server)
Compile without warnings under strict compiler flags
I believe this V6 implementation fully addresses your concerns while
delivering the performance benefits of AVX2 optimization.
Please find the V6 patch attached. I welcome any additional feedback
you may have.
Best regards,
Andrew Kim
On Wed, Oct 1, 2025 at 10:26 PM John Naylor <[email protected]> wrote:
>
> On Thu, Sep 25, 2025 at 4:50 AM Andrew Kim <[email protected]> wrote:
> >
> > Thanks, John. I see the issue now — I’ll attach the entire patch
> > series in a single email so it shows up properly in the commitfest and
> > gets CI coverage.
>
> It's still picking up v4, and the archive link doesn't show any
> further replies. Something must have happened with the email
> threading, since you weren't on the thread at first. Please create an
> account and edit the entry to point to a more recent message ID:
>
> https://commitfest.postgresql.org/patch/5726/
>
> > Please find attached v6 of the patchset, updated per your feedback.
>
> Thanks. (BTW, we discourage top-posting and prefer to cut to size and
> use inline responses)
>
> This is not a complete review, but some architectural thoughts and
> some things I've noticed.
>
> The top of the checksum_impl.h has this:
>
> * This file exists for the benefit of external programs that may wish to
> * check Postgres page checksums. They can #include this to get the code
> * referenced by storage/checksum.h. (Note: you may need to redefine
> * Assert() as empty to compile this successfully externally.)
>
> It's going to be a bit tricky to preserve this ability while allowing
> the core server and client programs to dispatch to a specialized
> implementation, but we should at least try. That means keeping
> pg_checksum_block() and pg_checksum_page() where they live now.
>
> I think a good first refactoring patch would be to move
> src/backend/storage/checksum.c (which your patch doesn't even touch)
> to src/port (and src/include/storage/checksum.h to src/include/port)
> and have all callers use that. With that, I imagine only that
> checksum.c file would include checksum_impl.h.
>
> If that poses a problem, let us know -- we may have to further juggle
> things. If that works without issue, we can proceed with the
> specialization. On that, just a few things to note here, although the
> next patch doesn't need to worry about any of this yet:
>
> + #if defined(__has_attribute) && __has_attribute (target)
> + __attribute__((target("avx2")))
> + #endif
> + static int avx2_test(void)
> + {
> + const char buf@<:@sizeof(__m256i)@:>@;
> + __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
> + accum = _mm256_add_epi32(accum, accum);
> + int result = _mm256_extract_epi32(accum, 0);
> + return (int) result;
> + }],
>
> If we're just testing if the target works, we can just use an empty
> function, right?
>
> +#define PG_DECLARE_CHECKSUM_ISA(ISANAME) \
> +uint32 \
> +pg_checksum_block_##ISANAME(const PGChecksummablePage *page);
> +
> +#define PG_DEFINE_CHECKSUM_ISA(ISANAME) \
> +pg_attribute_target(#ISANAME) \
> +uint32 pg_checksum_block_##ISANAME(const PGChecksummablePage *page) \
>
> I find this hard to read compared to just using the actual name.
>
> +avx2_available(void)
> +{
> +#if defined (USE_AVX2_WITH_RUNTIME_CHECK) && defined(__x86_64__)
>
> Why guard on __x86_64__?
>
> +PG_DEFINE_CHECKSUM_ISA(default)
> +{
> + uint32 sums[N_SUMS], result = 0;
> + uint32 i, j;
> [...]
>
> +#ifdef USE_AVX2_WITH_RUNTIME_CHECK
> +PG_DEFINE_CHECKSUM_ISA(avx2)
> +{
> + uint32 sums[N_SUMS], result = 0;
> + uint32 i, j;
> [...]
>
> With the single src/port file idea above, these would just do "return
> pg_checksum_block()" (or pg_checksum_page, whichever makes more
> sense).
>
> + if (avx2_available())
> + {
> + /* optional: patch pointer so next call goes directly */
> + pg_checksum_block = pg_checksum_block_avx2;
> + return pg_checksum_block_avx2(page);
> + }
>
> Not sure what your referring to here by "patching" the pointer, but it
> sounds dangerous. Besides, the cost of indirection is basically zero
> for multi-kilobyte inputs, so there is not even any motivation to
> consider doing differently.
>
> --
> John Naylor
> Amazon Web Services
Attachments:
[application/octet-stream] v6-0001-Enable-autovectorizing-pg_checksum_block-with-AVX2-runtime-detection.patch (17.0K, 2-v6-0001-Enable-autovectorizing-pg_checksum_block-with-AVX2-runtime-detection.patch)
download | inline diff:
From 5ac0e8ce0c3cdb973044b70a7b7f8838981ac974 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Thu, 16 Oct 2025 19:39:48 -0700
Subject: [PATCH] Enable autovectorizing pg_checksum_block with AVX2 runtime
detection
Add SIMD-optimized checksum calculation using AVX2 instructions when
available, with automatic fallback to portable implementation. Uses
__builtin_cpu_supports() for runtime CPU feature detection.
Key improvements:
- Consolidate checksum logic into single src/port/checksum.c file
- Implement safe function pointer dispatch instead of runtime patching
- Remove complex macros in favor of explicit function declarations
- Add comprehensive AVX2 compiler support detection in configure
- Maintain full backward compatibility on non-AVX2 systems
Performance testing shows significant improvement in checksum calculation
throughput on AVX2-capable processors while maintaining code safety
and PostgreSQL coding standards compliance.
Addresses reviewer feedback on code organization, safety, and maintainability.
---
config/c-compiler.m4 | 31 +++++
configure | 52 +++++++
configure.ac | 9 ++
meson.build | 28 ++++
src/backend/storage/page/checksum.c | 6 +-
src/include/pg_config.h.in | 3 +
src/include/storage/checksum_impl.h | 82 ++---------
src/port/Makefile | 1 +
src/port/checksum.c | 203 ++++++++++++++++++++++++++++
src/port/meson.build | 1 +
10 files changed, 342 insertions(+), 74 deletions(-)
create mode 100644 src/port/checksum.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..bcc1398d51a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -711,6 +711,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index 22cd866147b..209849c773c 100755
--- a/configure
+++ b/configure
@@ -17562,6 +17562,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..c061b1a854c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2091,6 +2091,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index 395416a6060..a37ef88bf16 100644
--- a/meson.build
+++ b/meson.build
@@ -2292,6 +2292,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c
index c913459b5a3..9ec11068b93 100644
--- a/src/backend/storage/page/checksum.c
+++ b/src/backend/storage/page/checksum.c
@@ -15,8 +15,8 @@
#include "storage/checksum.h"
/*
- * The actual code is in storage/checksum_impl.h. This is done so that
- * external programs can incorporate the checksum code by #include'ing
- * that file from the exported Postgres headers. (Compare our CRC code.)
+ * The actual checksum implementation is now in src/port/checksum.c
+ * for better modularity and to support AVX2 optimizations.
+ * We only need to include the header for function declarations.
*/
#include "storage/checksum_impl.h" /* IWYU pragma: keep */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c4dc5d72bdb..987f9b5c77c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -675,6 +675,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index da87d61ba52..1744333e7eb 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -101,12 +101,14 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -142,74 +144,12 @@ do { \
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
-{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
-
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
-
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
-
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
-
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
-
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
-
- return result;
-}
-
-/*
- * Compute the checksum for a Postgres page.
- *
- * The page must be adequately aligned (at least on a 4-byte boundary).
- * Beware also that the checksum field of the page is transiently zeroed.
- *
- * The checksum includes the block number (to detect the case where a page is
- * somehow moved to a different location), the page header (excluding the
- * checksum itself), and the page data.
- */
-uint16
-pg_checksum_page(char *page, BlockNumber blkno)
-{
- PGChecksummablePage *cpage = (PGChecksummablePage *) page;
- uint16 save_checksum;
- uint32 checksum;
-
- /* We only calculate the checksum for properly-initialized pages */
- Assert(!PageIsNew((Page) page));
-
- /*
- * Save pd_checksum and temporarily set it to zero, so that the checksum
- * calculation isn't affected by the old checksum stored on the page.
- * Restore it after, because actually updating the checksum is NOT part of
- * the API of this function.
- */
- save_checksum = cpage->phdr.pd_checksum;
- cpage->phdr.pd_checksum = 0;
- checksum = pg_checksum_block(cpage);
- cpage->phdr.pd_checksum = save_checksum;
-
- /* Mix in the block number to detect transposed pages */
- checksum ^= blkno;
-
- /*
- * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
- * one. That avoids checksums of zero, which seems like a good idea.
- */
- return (uint16) ((checksum % 65535) + 1);
-}
+/* Function declarations for ISA-specific implementations */
+uint32 pg_checksum_block_default(const PGChecksummablePage *page);
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+uint32 pg_checksum_block_avx2(const PGChecksummablePage *page);
+#endif
+
+uint32 pg_checksum_block_dispatch(const PGChecksummablePage *page);
+extern uint32 (*pg_checksum_block)(const PGChecksummablePage *page);
+extern uint16 pg_checksum_page(char *page, BlockNumber blkno);
diff --git a/src/port/Makefile b/src/port/Makefile
index 4274949dfa4..a211ddbdd83 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -48,6 +48,7 @@ OBJS = \
pg_numa.o \
pg_popcount_aarch64.o \
pg_popcount_avx512.o \
+ checksum.o \
pg_strong_random.o \
pgcheckdir.o \
pgmkdirp.o \
diff --git a/src/port/checksum.c b/src/port/checksum.c
new file mode 100644
index 00000000000..b2cb61f58a0
--- /dev/null
+++ b/src/port/checksum.c
@@ -0,0 +1,203 @@
+/*-------------------------------------------------------------------------
+ *
+ * checksum.c
+ * Checksum implementation for data pages with AVX2 optimization.
+ *
+ * This file consolidates all checksum-related functionality including:
+ * - Runtime CPU feature detection
+ * - Default and AVX2-optimized implementations
+ * - Function dispatch logic
+ * - Page checksum calculation
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/port/checksum.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+#include "storage/checksum_impl.h"
+
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#ifdef HAVE_XSAVE_INTRINSICS
+#include <immintrin.h>
+#endif
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+#include "port/pg_bitutils.h"
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#elif defined(__x86_64__)
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Does CPUID say there's support for AVX-2
+ */
+static inline bool
+avx2_available(void)
+{
+#if defined (USE_AVX2_WITH_RUNTIME_CHECK)
+ unsigned int exx[4] = {0, 0, 0, 0};
+ if (!xsave_available() || !ymm_regs_available()) return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+
+/* default checksum implementation */
+uint32
+pg_checksum_block_default(const PGChecksummablePage *page)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
+
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ for (i = 0; i < (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+pg_attribute_target("avx2")
+uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
+
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ for (i = 0; i < (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+#endif
+
+/* Function pointer - external linkage (declared extern in header) */
+uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_dispatch;
+
+/* Dispatch function: simple, safe */
+uint32 pg_checksum_block_dispatch(const PGChecksummablePage *page)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (avx2_available())
+ {
+ pg_checksum_block = pg_checksum_block_avx2;
+ return pg_checksum_block(page);
+ }
+#endif
+ /* fallback */
+ pg_checksum_block = pg_checksum_block_default;
+ return pg_checksum_block(page);
+}
+
+/*
+ * Compute the checksum for a Postgres page.
+ *
+ * The page must be adequately aligned (at least on a 4-byte boundary).
+ * Beware also that the checksum field of the page is transiently zeroed.
+ *
+ * The checksum includes the block number (to detect the case where a page is
+ * somehow moved to a different location), the page header (excluding the
+ * checksum itself), and the page data.
+ */
+uint16 pg_checksum_page(char *page, BlockNumber blkno)
+{
+ PGChecksummablePage *cpage = (PGChecksummablePage *) page;
+ uint16 save_checksum;
+ uint32 checksum;
+
+ /* We only calculate the checksum for properly-initialized pages */
+ Assert(!PageIsNew((Page) page));
+
+ /*
+ * Save pd_checksum and temporarily set it to zero, so that the checksum
+ * calculation isn't affected by the old checksum stored on the page.
+ * Restore it after, because actually updating the checksum is NOT part of
+ * the API of this function.
+ */
+ save_checksum = cpage->phdr.pd_checksum;
+ cpage->phdr.pd_checksum = 0;
+ checksum = pg_checksum_block(cpage);
+ cpage->phdr.pd_checksum = save_checksum;
+
+ /* Mix in the block number to detect transposed pages */
+ checksum ^= blkno;
+
+ /*
+ * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
+ * one. That avoids checksums of zero, which seems like a good idea.
+ */
+ return (uint16)((checksum % 65535) + 1);
+}
\ No newline at end of file
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..fb2fb55c61b 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -11,6 +11,7 @@ pgport_sources = [
'pg_numa.c',
'pg_popcount_aarch64.c',
'pg_popcount_avx512.c',
+ 'checksum.c',
'pg_strong_random.c',
'pgcheckdir.c',
'pgmkdirp.c',
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-10-17 10:53 ` Oleg Tselebrovskiy <[email protected]>
2025-10-18 21:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
1 sibling, 1 reply; 36+ messages in thread
From: Oleg Tselebrovskiy @ 2025-10-17 10:53 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: John Naylor <[email protected]>; [email protected]
Greetings!
I've also tried to use AVX2 to speedup checksums and I've found your
approach quite interesting
But I see some issues with v6 patch
1) checksum.c was moved to src/port, but special meson rules are left in
src/backend/storage/page/meson.build. As a result, assembly code for
moved src/port/checksum.c doesn't use -funroll-loops and
-ftree-vectorize (latter isn't probably needed now, due to the nature of
the patch). The same is true for src/port/Makefile, there are no
instructions to use CFLAGS_UNROLL_LOOPS and CFLAGS_VECTORIZE
2) checksum.c was moved to src/port, but checksum.h and checksum_impl.h
are left in src/include/storage. I think they both should be moved to
src/include/port, as John Naylor suggested in his review of v5
3) checksum_impl.h now doesn't provide any code, so including it in
external programs won't allow checksum calculation. I think that all
code should be in checksum_impl.h, and external programs could just
define USE_AVX2_WITH_RUNTIME_CHECK (probably using similar checks as we
are) to use AVX2 implementation. If not - then they will default to
default realisation
4) I don't understand why do we need to check for AVX2 intrinsics if we
don't use those in code (at least I don't see them directly)? As in
review of v5, couldn't test functions in configure, config/c-compiler.m4
and ./meson.build just be {return 0;} or {return 1;}?
5) Why do we need both src/backend/storage/page/checksum.c and
src/port/checksum.c?
6)
> +/* Function declarations for ISA-specific implementations */
> +uint32 pg_checksum_block_default(const PGChecksummablePage *page);
> +#ifdef USE_AVX2_WITH_RUNTIME_CHECK
> +uint32 pg_checksum_block_avx2(const PGChecksummablePage *page);
> +#endif
What is "ISA-specific implementations" in this comment? Maybe I'm just
not familiar with the term? Or is it an artifact from macro
implementation?
7) Why remove all comments from code of pg_checksum_block_default? I
could understand if you just removed comments from
pg_checksum_block_avx2, since it just duplicates code (though I
personally would leave all the comments even when duplicating code), but
I don't understand removing comments from pg_checksum_block_default
8) It might be a personal taste, but pg_checksum_block_dispatch looks
more like "choose" function from src/port/pg_crc32c_sse42_choose.c and
alike. "dispatch" from src/include/port/pg_crc32c looks a little
different - we don't choose function pointer once there, we choose
between inlined computation and calling a function with runtime check.
So I'd suggest changing name of pg_checksum_block_dispatch to
pg_checksum_block_choose
Other than those, I think the core of this patch is good
Oleg Tselebrovskiy, PostgresPro
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-17 10:53 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
@ 2025-10-18 21:30 ` Andrew Kim <[email protected]>
2025-10-20 15:05 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-10-18 21:30 UTC (permalink / raw)
To: Oleg Tselebrovskiy <[email protected]>; +Cc: John Naylor <[email protected]>; [email protected]
Hi Oleg,
Thank you very much for the detailed and constructive feedback on v6 patch.
It was extremely helpful in refining the architecture and ensuring
compliance with PostgreSQL coding standards.
I have updated the patch to V7, which I believe addresses all of your
points, including the critical architectural concerns regarding file
organization and linking.
Key Changes and Feedback Resolution in V7
The architecture is now consolidated in the src/port module.
1. Compiler Flags (Unroll/Vectorize)Resolved: Compiler flags
(CFLAGS_UNROLL_LOOPS) are now correctly placed and applied to
checksum.c in src/port/Makefile and src/port/meson.
2. Header OrganizationResolved: checksum.h and checksum_impl.h have
been moved from src/include/storage/ to src/include/port/ for
consistent module organization.
3. External Program CompatibilityResolved: checksum_impl.h is now
fully self-contained. It provides the static inline implementations
(pg_checksum_block_default, pg_checksum_block_avx2) and all required
constants, ensuring external tools can calculate checksums without
linking to the backend library.
4. Duplicate FilesResolved: The redundant
src/backend/storage/page/checksum.c file has been removed,
consolidating all implementation logic into src/port/checksum.c.
5. Function NamingResolved: The dispatch pattern now uses
pg_checksum_block_choose, aligning with the established naming
conventions (e.g., CRC32C module). The implementations use the clear
names pg_checksum_block_default and pg_checksum_block_avx2.
7. Documentation/CommentsResolved: Comprehensive documentation,
including the detailed FNV-1a algorithm comments, has been restored to
the portable implementation (pg_checksum_block_default).
Best regards,
Andrew Kim
On Fri, Oct 17, 2025 at 3:53 AM Oleg Tselebrovskiy
<[email protected]> wrote:
>
> Greetings!
>
> I've also tried to use AVX2 to speedup checksums and I've found your
> approach quite interesting
>
> But I see some issues with v6 patch
>
> 1) checksum.c was moved to src/port, but special meson rules are left in
> src/backend/storage/page/meson.build. As a result, assembly code for
> moved src/port/checksum.c doesn't use -funroll-loops and
> -ftree-vectorize (latter isn't probably needed now, due to the nature of
> the patch). The same is true for src/port/Makefile, there are no
> instructions to use CFLAGS_UNROLL_LOOPS and CFLAGS_VECTORIZE
>
> 2) checksum.c was moved to src/port, but checksum.h and checksum_impl.h
> are left in src/include/storage. I think they both should be moved to
> src/include/port, as John Naylor suggested in his review of v5
>
> 3) checksum_impl.h now doesn't provide any code, so including it in
> external programs won't allow checksum calculation. I think that all
> code should be in checksum_impl.h, and external programs could just
> define USE_AVX2_WITH_RUNTIME_CHECK (probably using similar checks as we
> are) to use AVX2 implementation. If not - then they will default to
> default realisation
>
> 4) I don't understand why do we need to check for AVX2 intrinsics if we
> don't use those in code (at least I don't see them directly)? As in
> review of v5, couldn't test functions in configure, config/c-compiler.m4
> and ./meson.build just be {return 0;} or {return 1;}?
>
> 5) Why do we need both src/backend/storage/page/checksum.c and
> src/port/checksum.c?
>
> 6)
> > +/* Function declarations for ISA-specific implementations */
> > +uint32 pg_checksum_block_default(const PGChecksummablePage *page);
> > +#ifdef USE_AVX2_WITH_RUNTIME_CHECK
> > +uint32 pg_checksum_block_avx2(const PGChecksummablePage *page);
> > +#endif
>
> What is "ISA-specific implementations" in this comment? Maybe I'm just
> not familiar with the term? Or is it an artifact from macro
> implementation?
>
> 7) Why remove all comments from code of pg_checksum_block_default? I
> could understand if you just removed comments from
> pg_checksum_block_avx2, since it just duplicates code (though I
> personally would leave all the comments even when duplicating code), but
> I don't understand removing comments from pg_checksum_block_default
>
> 8) It might be a personal taste, but pg_checksum_block_dispatch looks
> more like "choose" function from src/port/pg_crc32c_sse42_choose.c and
> alike. "dispatch" from src/include/port/pg_crc32c looks a little
> different - we don't choose function pointer once there, we choose
> between inlined computation and calling a function with runtime check.
> So I'd suggest changing name of pg_checksum_block_dispatch to
> pg_checksum_block_choose
>
> Other than those, I think the core of this patch is good
>
> Oleg Tselebrovskiy, PostgresPro
Attachments:
[application/octet-stream] v7-0001-Enable-autovectorizing-pg_checksum_block-with-AVX2-runtime-detection.patch (23.3K, 2-v7-0001-Enable-autovectorizing-pg_checksum_block-with-AVX2-runtime-detection.patch)
download | inline diff:
From fe7d2e4061042c4fd30c9c7095889fcf777be105 Mon Sep 17 00:00:00 2001
From: Andrew kim <[email protected]>
Date: Sat, 18 Oct 2025 12:13:50 -0700
Subject: [PATCH 1/2] Enable autovectorizing pg_checksum_block with AVX2
runtime-detection
1. Compiler flags: Moved CFLAGS_UNROLL_LOOPS and CFLAGS_VECTORIZE to
proper port module build files
2. Header organization: Relocated headers from src/include/storage/
to src/include/port/ for correct module classification
3. External compatibility: Made checksum_impl.h fully self-contained with
inline implementations, required constants, and external interface
4. Simplified AVX2 detection: Replaced complex CPUID logic with
__builtin_cpu_supports('avx2')
5. File consolidation: Removed duplicate backend/storage/page/checksum.c,
moved pg_checksum_page to unified port implementation
6. Documentation: Restored comprehensive algorithm comments
7. Comment clarity: Replaced confusing ISA-specific references
---
config/c-compiler.m4 | 31 +++++
configure | 52 ++++++++
configure.ac | 9 ++
meson.build | 28 +++++
src/backend/backup/basebackup.c | 2 +-
src/backend/storage/page/Makefile | 4 -
src/backend/storage/page/bufpage.c | 2 +-
src/backend/storage/page/checksum.c | 22 ----
src/backend/storage/page/meson.build | 9 --
src/bin/pg_checksums/pg_checksums.c | 4 +-
src/bin/pg_upgrade/file.c | 4 +-
src/include/pg_config.h.in | 3 +
src/include/{storage => port}/checksum.h | 2 +-
src/include/{storage => port}/checksum_impl.h | 104 ++++++++--------
src/port/Makefile | 6 +
src/port/checksum.c | 116 ++++++++++++++++++
src/port/meson.build | 5 +-
src/test/modules/test_aio/test_aio.c | 2 +-
src/tools/pginclude/headerscheck | 2 +-
19 files changed, 310 insertions(+), 97 deletions(-)
delete mode 100644 src/backend/storage/page/checksum.c
rename src/include/{storage => port}/checksum.h (94%)
rename src/include/{storage => port}/checksum_impl.h (77%)
create mode 100644 src/port/checksum.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..bcc1398d51a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -711,6 +711,37 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_XSAVE_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# -----------------------------
+# Check if the compiler supports AVX2 in attribute((target))
+# and using AVX2 intrinsics in those functions
+#
+# If the intrinsics are supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 support], [Ac_cachevar],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf@<:@sizeof(__m256i)@:>@;
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_POPCNT_INTRINSICS
# -----------------------------
# Check if the compiler supports the AVX-512 popcount instructions using the
diff --git a/configure b/configure
index 22cd866147b..209849c773c 100755
--- a/configure
+++ b/configure
@@ -17562,6 +17562,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..c061b1a854c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2091,6 +2091,15 @@ if test x"$pgac_xsave_intrinsics" = x"yes"; then
AC_DEFINE(HAVE_XSAVE_INTRINSICS, 1, [Define to 1 if you have XSAVE intrinsics.])
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/meson.build b/meson.build
index 395416a6060..a37ef88bf16 100644
--- a/meson.build
+++ b/meson.build
@@ -2292,6 +2292,34 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+int main(void)
+{
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index bb7d90aa5d9..d84ced4b47c 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -39,7 +39,7 @@
#include "replication/walsender.h"
#include "replication/walsender_private.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/dsm_impl.h"
#include "storage/ipc.h"
#include "storage/reinit.h"
diff --git a/src/backend/storage/page/Makefile b/src/backend/storage/page/Makefile
index da539b113a6..5d8a3d2f5ac 100644
--- a/src/backend/storage/page/Makefile
+++ b/src/backend/storage/page/Makefile
@@ -14,10 +14,6 @@ include $(top_builddir)/src/Makefile.global
OBJS = \
bufpage.o \
- checksum.o \
itemptr.o
include $(top_srcdir)/src/backend/common.mk
-
-# Provide special optimization flags for checksum.c
-checksum.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index dbb49ed9197..b8f889efb88 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -18,7 +18,7 @@
#include "access/itup.h"
#include "access/xlog.h"
#include "pgstat.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c
deleted file mode 100644
index c913459b5a3..00000000000
--- a/src/backend/storage/page/checksum.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * checksum.c
- * Checksum implementation for data pages.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * IDENTIFICATION
- * src/backend/storage/page/checksum.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "storage/checksum.h"
-/*
- * The actual code is in storage/checksum_impl.h. This is done so that
- * external programs can incorporate the checksum code by #include'ing
- * that file from the exported Postgres headers. (Compare our CRC code.)
- */
-#include "storage/checksum_impl.h" /* IWYU pragma: keep */
diff --git a/src/backend/storage/page/meson.build b/src/backend/storage/page/meson.build
index 112f00ff365..cf92a8f55f0 100644
--- a/src/backend/storage/page/meson.build
+++ b/src/backend/storage/page/meson.build
@@ -1,14 +1,5 @@
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
-checksum_backend_lib = static_library('checksum_backend_lib',
- 'checksum.c',
- dependencies: backend_build_deps,
- kwargs: internal_lib_args,
- c_args: vectorize_cflags + unroll_loops_cflags,
-)
-
-backend_link_with += checksum_backend_lib
-
backend_sources += files(
'bufpage.c',
'itemptr.c',
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index f20be82862a..5231eb33207 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -28,8 +28,8 @@
#include "getopt_long.h"
#include "pg_getopt.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
+#include "port/checksum_impl.h"
static int64 files_scanned = 0;
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 91ed16acb08..084392ae54d 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -24,8 +24,8 @@
#include "common/file_perm.h"
#include "pg_upgrade.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
+#include "port/checksum_impl.h"
/*
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c4dc5d72bdb..987f9b5c77c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -675,6 +675,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/storage/checksum.h b/src/include/port/checksum.h
similarity index 94%
rename from src/include/storage/checksum.h
rename to src/include/port/checksum.h
index 25d13a798d1..c2faed83ede 100644
--- a/src/include/storage/checksum.h
+++ b/src/include/port/checksum.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum.h
+ * src/include/port/checksum.h
*
*-------------------------------------------------------------------------
*/
diff --git a/src/include/storage/checksum_impl.h b/src/include/port/checksum_impl.h
similarity index 77%
rename from src/include/storage/checksum_impl.h
rename to src/include/port/checksum_impl.h
index da87d61ba52..357b2089f01 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/port/checksum_impl.h
@@ -5,13 +5,13 @@
*
* This file exists for the benefit of external programs that may wish to
* check Postgres page checksums. They can #include this to get the code
- * referenced by storage/checksum.h. (Note: you may need to redefine
+ * referenced by port/checksum.h. (Note: you may need to redefine
* Assert() as empty to compile this successfully externally.)
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum_impl.h
+ * src/include/port/checksum_impl.h
*
*-------------------------------------------------------------------------
*/
@@ -101,12 +101,15 @@
*/
#include "storage/bufpage.h"
+#include "pg_config.h"
+#include <string.h> /* for memcpy */
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
#define FNV_PRIME 16777619
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
{
@@ -139,77 +142,76 @@ do { \
} while (0)
/*
- * Block checksum algorithm. The page must be adequately aligned
- * (at least on 4-byte boundary).
+ * Default checksum implementation (always available)
*/
-static uint32
-pg_checksum_block(const PGChecksummablePage *page)
+static inline uint32
+pg_checksum_block_default_impl(const PGChecksummablePage *page)
{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
-
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+ uint32 sums[N_SUMS], result = 0;
+ uint32 i, j;
- /* initialize partial checksums to their corresponding offsets */
+ /* Initialize each parallel checksum with different base offsets */
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ /* Main checksum calculation loop - process page data in parallel */
+ for (i = 0; i < (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
for (j = 0; j < N_SUMS; j++)
CHECKSUM_COMP(sums[j], page->data[i][j]);
- /* finally add in two rounds of zeroes for additional mixing */
+ /* Two final rounds with zero to mix remaining bits */
for (i = 0; i < 2; i++)
for (j = 0; j < N_SUMS; j++)
CHECKSUM_COMP(sums[j], 0);
- /* xor fold partial checksums together */
+ /* Combine all parallel checksums with XOR to get final result */
for (i = 0; i < N_SUMS; i++)
result ^= sums[i];
return result;
}
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
/*
- * Compute the checksum for a Postgres page.
- *
- * The page must be adequately aligned (at least on a 4-byte boundary).
- * Beware also that the checksum field of the page is transiently zeroed.
- *
- * The checksum includes the block number (to detect the case where a page is
- * somehow moved to a different location), the page header (excluding the
- * checksum itself), and the page data.
+ * AVX2 optimized implementation (may not be available on all systems)
*/
-uint16
-pg_checksum_page(char *page, BlockNumber blkno)
+pg_attribute_target("avx2")
+static inline uint32
+pg_checksum_block_avx2_impl(const PGChecksummablePage *page)
{
- PGChecksummablePage *cpage = (PGChecksummablePage *) page;
- uint16 save_checksum;
- uint32 checksum;
-
- /* We only calculate the checksum for properly-initialized pages */
- Assert(!PageIsNew((Page) page));
-
- /*
- * Save pd_checksum and temporarily set it to zero, so that the checksum
- * calculation isn't affected by the old checksum stored on the page.
- * Restore it after, because actually updating the checksum is NOT part of
- * the API of this function.
+ /* For now, AVX2 implementation is identical to default
+ * The compiler will auto-vectorize this with proper flags
+ * Future versions could use explicit AVX2 intrinsics here
*/
- save_checksum = cpage->phdr.pd_checksum;
- cpage->phdr.pd_checksum = 0;
- checksum = pg_checksum_block(cpage);
- cpage->phdr.pd_checksum = save_checksum;
+ return pg_checksum_block_default_impl(page);
+}
+#endif
- /* Mix in the block number to detect transposed pages */
- checksum ^= blkno;
+/* Function declarations for checksum implementations */
+uint32 pg_checksum_block_default(const PGChecksummablePage *page);
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+uint32 pg_checksum_block_avx2(const PGChecksummablePage *page);
+#endif
- /*
- * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
- * one. That avoids checksums of zero, which seems like a good idea.
- */
- return (uint16) ((checksum % 65535) + 1);
+uint32 pg_checksum_block_choose(const PGChecksummablePage *page);
+extern uint32 (*pg_checksum_block)(const PGChecksummablePage *page);
+
+/*
+ * Simple interface for external programs
+ * Define USE_AVX2_WITH_RUNTIME_CHECK before including to enable AVX2 if available
+ */
+#ifndef PG_CHECKSUM_EXTERNAL_INTERFACE
+#define PG_CHECKSUM_EXTERNAL_INTERFACE
+
+static inline uint32
+pg_checksum_block_simple(const PGChecksummablePage *page)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ /* External programs can use AVX2 if they define the macro and have CPU support */
+ if (__builtin_cpu_supports("avx2"))
+ return pg_checksum_block_avx2_impl(page);
+ else
+#endif
+ return pg_checksum_block_default_impl(page);
}
+
+#endif /* PG_CHECKSUM_EXTERNAL_INTERFACE */
diff --git a/src/port/Makefile b/src/port/Makefile
index 4274949dfa4..430b7bbbcb6 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -48,6 +48,7 @@ OBJS = \
pg_numa.o \
pg_popcount_aarch64.o \
pg_popcount_avx512.o \
+ checksum.o \
pg_strong_random.o \
pgcheckdir.o \
pgmkdirp.o \
@@ -90,6 +91,11 @@ pg_crc32c_armv8.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_shlib.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_srv.o: CFLAGS+=$(CFLAGS_CRC)
+# all versions of checksum.o need vectorization and unroll-loops flags
+checksum.o: CFLAGS+=$(CFLAGS_VECTORIZE) $(CFLAGS_UNROLL_LOOPS)
+checksum_shlib.o: CFLAGS+=$(CFLAGS_VECTORIZE) $(CFLAGS_UNROLL_LOOPS)
+checksum_srv.o: CFLAGS+=$(CFLAGS_VECTORIZE) $(CFLAGS_UNROLL_LOOPS)
+
#
# Shared library versions of object files
#
diff --git a/src/port/checksum.c b/src/port/checksum.c
new file mode 100644
index 00000000000..df1a1b4ce83
--- /dev/null
+++ b/src/port/checksum.c
@@ -0,0 +1,116 @@
+/*-------------------------------------------------------------------------
+ *
+ * checksum.c
+ * Checksum implementation for data pages with AVX2 optimization.
+ *
+ * This file consolidates all checksum-related functionality including:
+ * - Runtime CPU feature detection
+ * - Default and AVX2-optimized implementations
+ * - Function dispatch logic
+ * - Page checksum calculation
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/port/checksum.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+#include "port/checksum_impl.h"
+
+#ifndef FRONTEND
+#include "postgres.h"
+#include "storage/bufpage.h"
+#endif
+
+
+
+/*
+ * Check for AVX2 support using GCC builtin
+ */
+static inline bool
+avx2_available(void)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ return __builtin_cpu_supports("avx2");
+#else
+ return false;
+#endif
+}
+
+/* default checksum implementation */
+uint32
+pg_checksum_block_default(const PGChecksummablePage *page)
+{
+ return pg_checksum_block_default_impl(page);
+}
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+pg_attribute_target("avx2")
+uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+ return pg_checksum_block_avx2_impl(page);
+}
+#endif
+
+/* Function pointer - external linkage (declared extern in header) */
+uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_choose;
+
+/* Choose the best available checksum implementation */
+uint32 pg_checksum_block_choose(const PGChecksummablePage *page)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (avx2_available())
+ {
+ pg_checksum_block = pg_checksum_block_avx2;
+ return pg_checksum_block(page);
+ }
+#endif
+ /* fallback */
+ pg_checksum_block = pg_checksum_block_default;
+ return pg_checksum_block(page);
+}
+
+/*
+ * Compute the checksum for a Postgres page.
+ *
+ * The page must be adequately aligned (at least on a 4-byte boundary).
+ * Beware also that the checksum field of the page is transiently zeroed.
+ *
+ * The checksum includes the block number (to detect the case where a page is
+ * somehow moved to a different location), the page header (excluding the
+ * checksum itself), and the page data.
+ */
+uint16
+pg_checksum_page(char *page, BlockNumber blkno)
+{
+ PGChecksummablePage *cpage = (PGChecksummablePage *) page;
+ uint16 save_checksum;
+ uint32 checksum;
+
+ /* We only calculate the checksum for properly-initialized pages */
+ Assert(!PageIsNew((Page) page));
+
+ /*
+ * Save pd_checksum and temporarily set it to zero, so that the checksum
+ * calculation isn't affected by the old checksum stored on the page.
+ * Restore it after, because actually updating the checksum is NOT part of
+ * the API of this function.
+ */
+ save_checksum = cpage->phdr.pd_checksum;
+ cpage->phdr.pd_checksum = 0;
+ checksum = pg_checksum_block(cpage);
+ cpage->phdr.pd_checksum = save_checksum;
+
+ /* Mix in the block number to detect transposed pages */
+ checksum ^= blkno;
+
+ /*
+ * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
+ * one. That avoids checksums of zero, which seems like a good idea.
+ */
+ return (uint16)((checksum % 65535) + 1);
+}
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..2074553f9a5 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -102,10 +102,11 @@ replace_funcs_pos = [
# generic fallback
['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'],
+
]
-pgport_cflags = {'crc': cflags_crc}
-pgport_sources_cflags = {'crc': []}
+pgport_cflags = {'crc': cflags_crc, 'checksum': unroll_loops_cflags + vectorize_cflags}
+pgport_sources_cflags = {'crc': [], 'checksum': [files('checksum.c')]}
foreach f : replace_funcs_neg
func = f.get(0)
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index c55cf6c0aac..175e491c0bc 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -24,7 +24,7 @@
#include "storage/aio_internal.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "utils/builtins.h"
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index a52a5580bdc..35ac0caaa43 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -167,7 +167,7 @@ do
test "$f" = src/test/isolation/specparse.h && continue
# This produces a "no previous prototype" warning.
- ! $cplusplus && test "$f" = src/include/storage/checksum_impl.h && continue
+ ! $cplusplus && test "$f" = src/include/port/checksum_impl.h && continue
# SectionMemoryManager.h is C++
test "$f" = src/include/jit/SectionMemoryManager.h && continue
--
2.43.0
[application/octet-stream] v7-0002-Benchmark-code-for-postgres-checksums.patch (5.2K, 3-v7-0002-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From 2fbafd83f0133b5737a47c9226dd72f86c2eb999 Mon Sep 17 00:00:00 2001
From: Andrew kim <[email protected]>
Date: Sat, 18 Oct 2025 13:13:05 -0700
Subject: [PATCH 2/2] Benchmark code for postgres checksums
---
contrib/meson.build | 1 +
contrib/pageinspect/rawpage.c | 2 +-
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
7 files changed, 88 insertions(+), 1 deletion(-)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index aef442b5db3..7beb7765da9 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -23,7 +23,7 @@
#include "miscadmin.h"
#include "pageinspect.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
#include "utils/rel.h"
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..e5b150e6b13
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "port/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-17 10:53 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
2025-10-18 21:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-10-20 15:05 ` Oleg Tselebrovskiy <[email protected]>
2025-10-24 08:09 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Oleg Tselebrovskiy @ 2025-10-20 15:05 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: John Naylor <[email protected]>; [email protected]
Thanks for the new patch version!
Another round of review:
1) I think that changes to contrib/pageinspect/rawpage.c should be in
the main patch, not in the benchmark patch. Also, without those chages
the main patch can't compile using make world-bin
2) I still don't get why you check for working intrinsics in configure,
config/c-compiler.m4 and meson.build, if your patch later uses them.
I've gotten correct assembly code with this avx2_test function:
#include <stdint.h>
#if defined(__has_attribute) && __has_attribute (target)
__attribute__((target("avx2")))
static int avx2_test(void)
{
return 0;
}
#endif
Please, check if this works for you and consider using something similar
3) __builtin_cpu_supports doesn't work on Windows at all. We still have
to use approach with __get_cpuid
4) Looks like you can safely remove "port/checksum_impl.h" from
src/bin/pg_checksums/pg_checksums.c. It probably links with libpgport
and/or libpgcommon, so it gets pg_checksum_page from there. Same with
src/bin/pg_upgrade/file.c. Maybe those includes are "for clarity" and
you don't need to remove them, but pg_checksums and pg_upgrade seem to
work without them
5) You don't need #include <string.h> /* for memcpy */ in
checksum_impl.h. At the very least, memcpy was used before your patch
without string.h
6) Why did you remove Assert(sizeof(PGChecksummablePage) == BLCKSZ)? Is
it always false?
7) Is reformatted variable declaration in pg_checksum_block_default_impl
really needed? Is there a good reason for it? Or is it auto-formatting
programm output?
8) Your patch removes one whitespace in this line - for (i = 0; i <
(uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
If you wish to fix formatting like that - please, do it in a separate
patch. If this was done automatically by some formatting tool - please,
revert this change
9) Unneeded empty string
#define FNV_PRIME 16777619
+
/* Use a union so that this code is valid under strict aliasing */
typedef union
10) You need one line with just /* at the beginning of the comment, look
at other multiline comments in this file
+ /* For now, AVX2 implementation is identical to default
+ * The compiler will auto-vectorize this with proper flags
+ * Future versions could use explicit AVX2 intrinsics here
*/
11) Function pg_checksum_block_simple isn't used at all.
12) Why do you need those?
+#ifndef PG_CHECKSUM_EXTERNAL_INTERFACE
+#define PG_CHECKSUM_EXTERNAL_INTERFACE
13) Object files are added according to alphabetical order, not logical
order (src/port/Makefile)
pg_popcount_aarch64.o \
pg_popcount_avx512.o \
+ checksum.o \
pg_strong_random.o \
pgcheckdir.o \
14) I still think that src/port/checksum.c needs to just include
src/include/port/checksum_impl.h and have no other logic to keep
checksum_impl.h's role as "header with full implementation"
Now checksum_impl.h doesn't have any mention of pg_checksum_page
15) Assembly for pg_checksum_block_choose now has full code of
pg_checksum_block_default. This is probably a result of using inline
functions
Don't know if this is bad, but it is at least strange
Also, some CFBot checks have failed. Two of them with this error/warning
checksum.c:88:1: error: no previous prototype for ‘pg_checksum_page’
[-Werror=missing-prototypes]
88 | pg_checksum_page(char *page, BlockNumber blkno)
| ^~~~~~~~~~~~~~~~
Please, address those
Oleg Tselebrovskiy, PostgresPro
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-17 10:53 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
2025-10-18 21:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-20 15:05 ` Re: Proposal for enabling auto-vectorization for checksum calculations Oleg Tselebrovskiy <[email protected]>
@ 2025-10-24 08:09 ` Andrew Kim <[email protected]>
0 siblings, 0 replies; 36+ messages in thread
From: Andrew Kim @ 2025-10-24 08:09 UTC (permalink / raw)
To: Oleg Tselebrovskiy <[email protected]>; +Cc: John Naylor <[email protected]>; [email protected]
Hi Oleg,
Thank you for the detailed review on v7 patch.
On Mon, Oct 20, 2025 at 8:05 AM Oleg Tselebrovskiy
<[email protected]> wrote:
>
> Thanks for the new patch version!
>
> Another round of review:
>
> 1) I think that changes to contrib/pageinspect/rawpage.c should be in
> the main patch, not in the benchmark patch. Also, without those chages
> the main patch can't compile using make world-bin
>
This is already correctly handled in v8. The
contrib/pageinspect/rawpage.c change is in the main patch (v8-0001),
not in the benchmark patch. The include statement was updated from
#include "storage/checksum.h" to #include "port/checksum.h" in the
refactoring patch, which is the correct placement.
> 2) I still don't get why you check for working intrinsics in configure,
> config/c-compiler.m4 and meson.build, if your patch later uses them.
> I've gotten correct assembly code with this avx2_test function:
> #include <stdint.h>
> #if defined(__has_attribute) && __has_attribute (target)
> __attribute__((target("avx2")))
> static int avx2_test(void)
> {
> return 0;
> }
> #endif
> Please, check if this works for you and consider using something similar
>
I agree. In v8, I've simplified the configure tests significantly. The
config/c-compiler.m4 now uses exactly the pattern you suggested:
> 3) __builtin_cpu_supports doesn't work on Windows at all. We still have
> to use approach with __get_cpuid
>
Completely fixed in v8. I've removed all usage of
__builtin_cpu_supports and implemented proper cross-platform CPU
detection using __get_cpuid (Linux/GCC) and __cpuid (Windows/MSVC)
with proper preprocessor guards
> 4) Looks like you can safely remove "port/checksum_impl.h" from
> src/bin/pg_checksums/pg_checksums.c. It probably links with libpgport
> and/or libpgcommon, so it gets pg_checksum_page from there. Same with
> src/bin/pg_upgrade/file.c. Maybe those includes are "for clarity" and
> you don't need to remove them, but pg_checksums and pg_upgrade seem to
> work without them
>
In v8-0001, both files now only include "port/checksum.h". The direct
inclusion of checksum_impl.h has been removed:
src/bin/pg_checksums/pg_checksums.c: Only includes "port/checksum.h"
src/bin/pg_upgrade/file.c: Only includes "port/checksum.h"
> 5) You don't need #include <string.h> /* for memcpy */ in
> checksum_impl.h. At the very least, memcpy was used before your patch
> without string.h
>
Confirmed there's no explicit #include <string.h> in the v8
checksum_impl.h. The memcpy usage relies on the standard PostgreSQL
includes.
> 6) Why did you remove Assert(sizeof(PGChecksummablePage) == BLCKSZ)? Is
> it always false?
>
I didn't remove it - it's still present in both implementations in
v8. In both pg_checksum_block_default and pg_checksum_block_avx2, you
can see:
/* ensure that the size is compatible with the algorithm */
Assert(sizeof(PGChecksummablePage) == BLCKSZ);
> 7) Is reformatted variable declaration in pg_checksum_block_default_impl
> really needed? Is there a good reason for it? Or is it auto-formatting
> programm output?
>
Sorry, that's my mistake, In v8, I've kept the variable declarations
consistent with PostgreSQL style without unnecessary reformatting. The
declarations in both functions follow the same pattern as the original
code.
> 8) Your patch removes one whitespace in this line - for (i = 0; i <
> (uint32)(BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
> If you wish to fix formatting like that - please, do it in a separate
> patch. If this was done automatically by some formatting tool - please,
> revert this change
>
In v8, I've preserved the original formatting. The for loop maintains
the original spacing: for (i = 0; i < (uint32) (BLCKSZ /
(sizeof(uint32) * N_SUMS)); i++) with proper space after (uint32).
> 9) Unneeded empty string
> #define FNV_PRIME 16777619
>
> +
> /* Use a union so that this code is valid under strict aliasing */
> typedef union
>
Fixed, removed unnecessary blank lines in v8.
> 10) You need one line with just /* at the beginning of the comment, look
> at other multiline comments in this file
> + /* For now, AVX2 implementation is identical to default
> + * The compiler will auto-vectorize this with proper flags
> + * Future versions could use explicit AVX2 intrinsics here
> */
>
Fixed, it's started style with the opening /* on its own line:
/*
* AVX2-optimized block checksum algorithm.
* Same algorithm as default, but compiled with AVX2 target for
auto-vectorization.
*/
> 11) Function pg_checksum_block_simple isn't used at all.
>
There's no pg_checksum_block_simple function in v8. The implementation
only has the necessary functions: pg_checksum_block_default,
pg_checksum_block_avx2, and pg_checksum_block_choose.
> 12) Why do you need those?
> +#ifndef PG_CHECKSUM_EXTERNAL_INTERFACE
> +#define PG_CHECKSUM_EXTERNAL_INTERFACE
>
These macros are not present in v8. The implementation is cleaner
without unnecessary preprocessor guards.
> 13) Object files are added according to alphabetical order, not logical
> order (src/port/Makefile)
> pg_popcount_aarch64.o \
> pg_popcount_avx512.o \
> + checksum.o \
> pg_strong_random.o \
> pgcheckdir.o \
>
In v8, checksum.o is correctly placed in alphabetical order in the
OBJS list in src/port/Makefile:
OBJS = \
$(LIBOBJS) \
$(PG_CRC32C_OBJS) \
bsearch_arg.o \
checksum.o \
chklocale.o \
> 14) I still think that src/port/checksum.c needs to just include
> src/include/port/checksum_impl.h and have no other logic to keep
> checksum_impl.h's role as "header with full implementation"
> Now checksum_impl.h doesn't have any mention of pg_checksum_page
>
The current v8 approach has checksum.c simply include
checksum_impl.h, which maintains the "header with full implementation"
pattern you prefer. However, the function pointer mechanism and
runtime detection logic is in checksum_impl.h, which means
pg_checksum_page (the external interface) is also defined there. This
keeps the external interface clean while maintaining the
implementation details in the header.
> 15) Assembly for pg_checksum_block_choose now has full code of
> pg_checksum_block_default. This is probably a result of using inline
> functions
> Don't know if this is bad, but it is at least strange
>
I think that is expected behavior with the function pointer approach.
The compiler inlines the first call, but subsequent calls use the
cached function pointer, which is the standard PostgreSQL pattern for
runtime CPU feature detection (see CRC32C implementation).
> Also, some CFBot checks have failed. Two of them with this error/warning
> checksum.c:88:1: error: no previous prototype for ‘pg_checksum_page’
> [-Werror=missing-prototypes]
> 88 | pg_checksum_page(char *page, BlockNumber blkno)
> | ^~~~~~~~~~~~~~~~
> Please, address those
>
In v8, pg_checksum_page is declared in src/include/port/checksum.h,
which is included by checksum.c. This should resolve the missing
prototype error.
> Oleg Tselebrovskiy, PostgresPro
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-10-21 03:30 ` John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
1 sibling, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-10-21 03:30 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
On Fri, Oct 17, 2025 at 2:15 PM Andrew Kim <[email protected]> wrote:
>
> Hi John,
>
> Thank you for your detailed and constructive feedback on the checksum
> AVX2 optimization patch.
> I've carefully addressed all of your concerns and am pleased to share
> the updated V6 implementation.
Great! I know we're on v7 now, but I'm going to make a request for
next time you respond to a review: Respond in-line to each point. As I
mentioned before,
> On Wed, Oct 1, 2025 at 10:26 PM John Naylor <[email protected]> wrote:
> > (BTW, we discourage top-posting and prefer to cut to size and
> > use inline responses)
Please don't top-post again, as it clutters our archives in addition
to making it easy to forget things. I'm now going to copy the things
that were either not addressed or misunderstood:
> > I think a good first refactoring patch would be to move
> > src/backend/storage/checksum.c (which your patch doesn't even touch)
> > to src/port (and src/include/storage/checksum.h to src/include/port)
> > and have all callers use that. With that, I imagine only that
> > checksum.c file would include checksum_impl.h.
> >
> > If that poses a problem, let us know -- we may have to further juggle
> > things. If that works without issue, we can proceed with the
> > specialization.
That means the first patch moves things around without adding any
platform-specific code, and the next patch adds the specialization. I
think that would be a lot easier to review and test, especially to
avoid breaking external programs (see below for more on this). A
committer can always squash things together if it make sense to do so.
> > + #if defined(__has_attribute) && __has_attribute (target)
> > + __attribute__((target("avx2")))
> > + #endif
> > + static int avx2_test(void)
> > + {
> > + const char buf@<:@sizeof(__m256i)@:>@;
> > + __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
> > + accum = _mm256_add_epi32(accum, accum);
> > + int result = _mm256_extract_epi32(accum, 0);
> > + return (int) result;
> > + }],
> >
> > If we're just testing if the target works, we can just use an empty
> > function, right?
Oleg mentioned the same thing later. It's a waste of time for us to
repeat ourselves. I said you didn't have to worry about it yet,
because I was hoping to see the refactoring first.
Now, aside from that I looked further into this:
> > The top of the checksum_impl.h has this:
> >
> > * This file exists for the benefit of external programs that may wish to
> > * check Postgres page checksums. They can #include this to get the code
> > * referenced by storage/checksum.h. (Note: you may need to redefine
> > * Assert() as empty to compile this successfully externally.)
> >
> > It's going to be a bit tricky to preserve this ability while allowing
> > the core server and client programs to dispatch to a specialized
> > implementation, but we should at least try. That means keeping
> > pg_checksum_block() and pg_checksum_page() where they live now.
Looking at commit f04216341dd1, we have at least one example of an
external program, pg_filedump. If we can keep this working with
minimal fuss, it should be fine everywhere.
https://github.com/df7cb/pg_filedump/blob/master/pg_filedump.c#L29
```
/* checksum_impl.h uses Assert, which doesn't work outside the server */
#undef Assert
#define Assert(X)
#include "storage/checksum.h"
#include "storage/checksum_impl.h"
```
Elsewhere they already have to do things like
```
#if PG_VERSION_NUM < 110000
" Previous Checkpoint Record: Log File (%u) Offset (0x%08x)\n"
#endif
```
...so it's probably okay if they have to adjust for a new #include
path, but I want to verify that actually works, and I don't want to
make it any more invasive than that. As we proceed, I can volunteer to
do the work to test that pg_filedump still builds fine with small
changes. Feel free to try building it yourself, but I'm happy to do
it.
Oleg posted another review recently, so I won't complicate things
further, but from a brief glance I will suggest for next time not to
change any comments that haven't been invalidated by the patch.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-10-24 07:48 ` Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-10-24 07:48 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
Hi John,
Thank you for your review on the previous patch versions.
I've carefully addressed your concerns and those raised by Oleg,
specifically focusing on patch separation and simplification of the
configure tests. I am submitting the new version (V8) as two distinct
patches:
V8-0001: Pure refactoring (moving files, updating includes).
V8-0002: Adding the AVX2 feature (detection, dispatch, and optimization).
As requested, I've used in-line responses below to clarify how each
point was handled.
On Mon, Oct 20, 2025 at 8:30 PM John Naylor <[email protected]> wrote:
>
> On Fri, Oct 17, 2025 at 2:15 PM Andrew Kim <[email protected]> wrote:
> >
> > Hi John,
> >
> > Thank you for your detailed and constructive feedback on the checksum
> > AVX2 optimization patch.
> > I've carefully addressed all of your concerns and am pleased to share
> > the updated V6 implementation.
>
> Great! I know we're on v7 now, but I'm going to make a request for
> next time you respond to a review: Respond in-line to each point. As I
> mentioned before,
>
> > On Wed, Oct 1, 2025 at 10:26 PM John Naylor <[email protected]> wrote:
> > > (BTW, we discourage top-posting and prefer to cut to size and
> > > use inline responses)
>
> Please don't top-post again, as it clutters our archives in addition
> to making it easy to forget things. I'm now going to copy the things
> that were either not addressed or misunderstood:
>
I apologize for the top-posting in the previous response. I've
switched to the preferred in-line response format for this and all
future correspondence.
> > > I think a good first refactoring patch would be to move
> > > src/backend/storage/checksum.c (which your patch doesn't even touch)
> > > to src/port (and src/include/storage/checksum.h to src/include/port)
> > > and have all callers use that. With that, I imagine only that
> > > checksum.c file would include checksum_impl.h.
> > >
> > > If that poses a problem, let us know -- we may have to further juggle
> > > things. If that works without issue, we can proceed with the
> > > specialization.
>
> That means the first patch moves things around without adding any
> platform-specific code, and the next patch adds the specialization. I
> think that would be a lot easier to review and test, especially to
> avoid breaking external programs (see below for more on this). A
> committer can always squash things together if it make sense to do so.
>
Patch V8-0001 (Move-checksum-functions...): This is now a pure
refactoring patch. It simply moves checksum.c and its headers from
storage/ to port/ and updates the #include paths in all callers
(rawpage.c, pg_checksums.c, etc.). It contains no AVX2 or ISA-specific
code.
Patch V8-0002 (Add-AVX2-optimization...): This patch builds upon the
first, adding all the new AVX2 functionality, detection, and dispatch
logic.
> > > + #if defined(__has_attribute) && __has_attribute (target)
> > > + __attribute__((target("avx2")))
> > > + #endif
> > > + static int avx2_test(void)
> > > + {
> > > + const char buf@<:@sizeof(__m256i)@:>@;
> > > + __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
> > > + accum = _mm256_add_epi32(accum, accum);
> > > + int result = _mm256_extract_epi32(accum, 0);
> > > + return (int) result;
> > > + }],
> > >
> > > If we're just testing if the target works, we can just use an empty
> > > function, right?
>
> Oleg mentioned the same thing later. It's a waste of time for us to
> repeat ourselves. I said you didn't have to worry about it yet,
> because I was hoping to see the refactoring first.
>
I have implemented this simplification in Patch V8-0002. The test in
config/c-compiler.m4 is now a simple, empty function with only the
__attribute__((target("avx2"))) to verify compiler support for the
attribute, as suggested.
> Now, aside from that I looked further into this:
>
> > > The top of the checksum_impl.h has this:
> > >
> > > * This file exists for the benefit of external programs that may wish to
> > > * check Postgres page checksums. They can #include this to get the code
> > > * referenced by storage/checksum.h. (Note: you may need to redefine
> > > * Assert() as empty to compile this successfully externally.)
> > >
> > > It's going to be a bit tricky to preserve this ability while allowing
> > > the core server and client programs to dispatch to a specialized
> > > implementation, but we should at least try. That means keeping
> > > pg_checksum_block() and pg_checksum_page() where they live now.
>
> Looking at commit f04216341dd1, we have at least one example of an
> external program, pg_filedump. If we can keep this working with
> minimal fuss, it should be fine everywhere.
The v8 patch series preserves external compatibility. External
programs like pg_filedump will only need to update their include
paths:
/* OLD */
#include "storage/checksum.h"
#include "storage/checksum_impl.h"
/* NEW */
#include "port/checksum.h"
#include "port/checksum_impl.h"
The function signatures (pg_checksum_block, pg_checksum_page) remain
identical, and checksum_impl.h still contains the complete
implementation that external programs can include. The runtime
dispatch only affects internal PostgreSQL usage.
/* OLD */#include "storage/checksum.h"#include
"storage/checksum_impl.h"/* NEW */ #include "port/checksum.h"#include
"port/checksum_impl.h"
> https://github.com/df7cb/pg_filedump/blob/master/pg_filedump.c#L29
>
> ```
> /* checksum_impl.h uses Assert, which doesn't work outside the server */
> #undef Assert
> #define Assert(X)
>
> #include "storage/checksum.h"
> #include "storage/checksum_impl.h"
> ```
>
> Elsewhere they already have to do things like
>
> ```
> #if PG_VERSION_NUM < 110000
> " Previous Checkpoint Record: Log File (%u) Offset (0x%08x)\n"
> #endif
> ```
>
> ...so it's probably okay if they have to adjust for a new #include
> path, but I want to verify that actually works, and I don't want to
> make it any more invasive than that. As we proceed, I can volunteer to
> do the work to test that pg_filedump still builds fine with small
> changes. Feel free to try building it yourself, but I'm happy to do
> it.
I appreciate your offer to test pg_filedump compatibility. The changes
in v8 should be minimal for external programs - just the include path
updates. If you're willing to test this, it would be very valuable
validation.
>
> Oleg posted another review recently, so I won't complicate things
> further, but from a brief glance I will suggest for next time not to
> change any comments that haven't been invalidated by the patch.
>
In v8, I've been much more conservative about comment changes. I only
updated comments that were directly invalidated by the code changes
(like file path references that changed from storage/ to port/). Other
comments remain untouched unless they were factually incorrect due to
the refactoring.
> --
> John Naylor
> Amazon Web Services
Attachments:
[application/octet-stream] v8-0001-Move-checksum-functions-from-backend-storage-to-port.patch (8.8K, 2-v8-0001-Move-checksum-functions-from-backend-storage-to-port.patch)
download | inline diff:
From adb9981eae786ed7be0e4f78d51d527da2527402 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Thu, 23 Oct 2025 10:42:24 -0700
Subject: [PATCH] Move checksum functions from backend storage to port
This refactoring moves checksum implementation from src/backend/storage/page/
to src/port/
---
contrib/pageinspect/rawpage.c | 2 +-
src/backend/backup/basebackup.c | 2 +-
src/backend/storage/page/Makefile | 6 +-----
src/backend/storage/page/bufpage.c | 2 +-
src/backend/storage/page/meson.build | 9 ---------
src/bin/pg_checksums/pg_checksums.c | 3 +--
src/bin/pg_upgrade/file.c | 3 +--
src/include/{storage => port}/checksum.h | 2 +-
src/include/{storage => port}/checksum_impl.h | 4 ++--
src/port/Makefile | 6 ++++++
src/{backend/storage/page => port}/checksum.c | 8 ++++----
src/port/meson.build | 4 ++--
src/test/modules/test_aio/test_aio.c | 2 +-
13 files changed, 22 insertions(+), 31 deletions(-)
rename src/include/{storage => port}/checksum.h (94%)
rename src/include/{storage => port}/checksum_impl.h (98%)
rename src/{backend/storage/page => port}/checksum.c (73%)
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index aef442b5db3..7beb7765da9 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -23,7 +23,7 @@
#include "miscadmin.h"
#include "pageinspect.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
#include "utils/rel.h"
diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index bb7d90aa5d9..d84ced4b47c 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -39,7 +39,7 @@
#include "replication/walsender.h"
#include "replication/walsender_private.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/dsm_impl.h"
#include "storage/ipc.h"
#include "storage/reinit.h"
diff --git a/src/backend/storage/page/Makefile b/src/backend/storage/page/Makefile
index da539b113a6..788fee403f6 100644
--- a/src/backend/storage/page/Makefile
+++ b/src/backend/storage/page/Makefile
@@ -12,12 +12,8 @@ subdir = src/backend/storage/page
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = \
+OBJS = \
bufpage.o \
- checksum.o \
itemptr.o
include $(top_srcdir)/src/backend/common.mk
-
-# Provide special optimization flags for checksum.c
-checksum.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index dbb49ed9197..b8f889efb88 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -18,7 +18,7 @@
#include "access/itup.h"
#include "access/xlog.h"
#include "pgstat.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
diff --git a/src/backend/storage/page/meson.build b/src/backend/storage/page/meson.build
index 112f00ff365..cf92a8f55f0 100644
--- a/src/backend/storage/page/meson.build
+++ b/src/backend/storage/page/meson.build
@@ -1,14 +1,5 @@
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
-checksum_backend_lib = static_library('checksum_backend_lib',
- 'checksum.c',
- dependencies: backend_build_deps,
- kwargs: internal_lib_args,
- c_args: vectorize_cflags + unroll_loops_cflags,
-)
-
-backend_link_with += checksum_backend_lib
-
backend_sources += files(
'bufpage.c',
'itemptr.c',
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 46cb2f36efa..2e0212c029c 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -29,8 +29,7 @@
#include "getopt_long.h"
#include "pg_getopt.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
static int64 files_scanned = 0;
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 91ed16acb08..f9a5ed02ee4 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -24,8 +24,7 @@
#include "common/file_perm.h"
#include "pg_upgrade.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
/*
diff --git a/src/include/storage/checksum.h b/src/include/port/checksum.h
similarity index 94%
rename from src/include/storage/checksum.h
rename to src/include/port/checksum.h
index 25d13a798d1..c2faed83ede 100644
--- a/src/include/storage/checksum.h
+++ b/src/include/port/checksum.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum.h
+ * src/include/port/checksum.h
*
*-------------------------------------------------------------------------
*/
diff --git a/src/include/storage/checksum_impl.h b/src/include/port/checksum_impl.h
similarity index 98%
rename from src/include/storage/checksum_impl.h
rename to src/include/port/checksum_impl.h
index da87d61ba52..00cb0549f24 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/port/checksum_impl.h
@@ -5,13 +5,13 @@
*
* This file exists for the benefit of external programs that may wish to
* check Postgres page checksums. They can #include this to get the code
- * referenced by storage/checksum.h. (Note: you may need to redefine
+ * referenced by port/checksum.h. (Note: you may need to redefine
* Assert() as empty to compile this successfully externally.)
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum_impl.h
+ * src/include/port/checksum_impl.h
*
*-------------------------------------------------------------------------
*/
diff --git a/src/port/Makefile b/src/port/Makefile
index 4274949dfa4..4f1f460bff2 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -39,6 +39,7 @@ OBJS = \
$(LIBOBJS) \
$(PG_CRC32C_OBJS) \
bsearch_arg.o \
+ checksum.o \
chklocale.o \
inet_net_ntop.o \
noblock.o \
@@ -90,6 +91,11 @@ pg_crc32c_armv8.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_shlib.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_srv.o: CFLAGS+=$(CFLAGS_CRC)
+# Provide special optimization flags for checksum.c
+checksum.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+checksum_shlib.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+checksum_srv.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+
#
# Shared library versions of object files
#
diff --git a/src/backend/storage/page/checksum.c b/src/port/checksum.c
similarity index 73%
rename from src/backend/storage/page/checksum.c
rename to src/port/checksum.c
index c913459b5a3..de61a46231d 100644
--- a/src/backend/storage/page/checksum.c
+++ b/src/port/checksum.c
@@ -7,16 +7,16 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * src/backend/storage/page/checksum.c
+ * src/port/checksum.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
/*
- * The actual code is in storage/checksum_impl.h. This is done so that
+ * The actual code is in port/checksum_impl.h. This is done so that
* external programs can incorporate the checksum code by #include'ing
* that file from the exported Postgres headers. (Compare our CRC code.)
*/
-#include "storage/checksum_impl.h" /* IWYU pragma: keep */
+#include "port/checksum_impl.h" /* IWYU pragma: keep */
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..d3e63bce9e7 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -104,8 +104,8 @@ replace_funcs_pos = [
['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'],
]
-pgport_cflags = {'crc': cflags_crc}
-pgport_sources_cflags = {'crc': []}
+pgport_cflags = {'crc': cflags_crc, 'checksum': vectorize_cflags + unroll_loops_cflags}
+pgport_sources_cflags = {'crc': [], 'checksum': [files('checksum.c')]}
foreach f : replace_funcs_neg
func = f.get(0)
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index c55cf6c0aac..175e491c0bc 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -24,7 +24,7 @@
#include "storage/aio_internal.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "utils/builtins.h"
--
2.43.0
[application/octet-stream] v8-0002-Add-AVX2-optimization-for-page-checksum-calculation.patch (10.7K, 3-v8-0002-Add-AVX2-optimization-for-page-checksum-calculation.patch)
download | inline diff:
From 8a33e3737360156b862fc75666630f8043f7d285 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Thu, 23 Oct 2025 16:35:22 -0700
Subject: [PATCH 1/1] Add AVX2 optimization for page checksum calculation
This patch adds runtime AVX2 detection and optimization for PostgreSQL's
page checksum algorithm while maintaining full backward compatibility.
Key changes:
- Add cross-platform AVX2 CPU detection with XSAVE/YMM register checks
- Implement function pointer dispatch pattern following PostgreSQL conventions
- Use compiler auto-vectorization with pg_attribute_target("avx2")
- Add build system support in both autotools and meson
- Maintain external program compatibility (pg_filedump, etc.)
The implementation uses the same algorithm for both default and AVX2 paths,
allowing the compiler to automatically vectorize the AVX2 version while
preserving identical results. Runtime detection ensures optimal performance
on supported hardware with graceful fallback on older systems.
Addresses reviewer feedback on configure test simplification, Windows
compatibility, and PostgreSQL coding conventions.
---
config/c-compiler.m4 | 26 ++++++
configure | 52 +++++++++++
configure.ac | 9 ++
meson.build | 30 +++++++
src/include/pg_config.h.in | 3 +
src/include/port/checksum_impl.h | 142 ++++++++++++++++++++++++++++++-
6 files changed, 261 insertions(+), 1 deletion(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..40927d56e6a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -581,6 +581,32 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_SSE42_CRC32_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# ---------------------------
+# Check if the compiler supports AVX2 target attribute.
+# This is used for optimized checksum calculations with runtime detection.
+#
+# If AVX2 target attribute is supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 target attribute support], [Ac_cachevar],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_PCLMUL_INTRINSICS
# ---------------------------
# Check if the compiler supports AVX-512 carryless multiplication
diff --git a/configure b/configure
index 22cd866147b..209849c773c 100755
--- a/configure
+++ b/configure
@@ -17562,6 +17562,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..ca7205d90ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2084,6 +2084,15 @@ else
fi
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for XSAVE intrinsics
#
PGAC_XSAVE_INTRINSICS()
diff --git a/meson.build b/meson.build
index 395416a6060..5670722944e 100644
--- a/meson.build
+++ b/meson.build
@@ -2293,6 +2293,36 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+static int avx2_test(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ return avx2_test();
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
###############################################################
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c4dc5d72bdb..987f9b5c77c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -675,6 +675,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/port/checksum_impl.h b/src/include/port/checksum_impl.h
index 00cb0549f24..0e1eef45249 100644
--- a/src/include/port/checksum_impl.h
+++ b/src/include/port/checksum_impl.h
@@ -100,8 +100,23 @@
* manually unroll the inner loop.
*/
+#include "pg_config.h"
#include "storage/bufpage.h"
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+
+#include <immintrin.h>
+
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+
+#endif
+
/* number of checksums to calculate in parallel */
#define N_SUMS 32
/* prime multiplier of FNV-1a hash */
@@ -114,6 +129,9 @@ typedef union
uint32 data[BLCKSZ / (sizeof(uint32) * N_SUMS)][N_SUMS];
} PGChecksummablePage;
+/* Forward declaration */
+static uint32 pg_checksum_block_choose(const PGChecksummablePage *page);
+
/*
* Base offsets to initialize each of the parallel FNV hashes into a
* different initial state.
@@ -129,6 +147,71 @@ static const uint32 checksumBaseOffsets[N_SUMS] = {
0x9FBF8C76, 0x15CA20BE, 0xF2CA9FD3, 0x959BD756
};
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
+/*
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Check for AVX2 support using manual CPUID detection
+ */
+static inline bool
+avx2_available(void)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+ if (!xsave_available() || !ymm_regs_available())
+ return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+#else
+ return false;
+#endif
+}
+#endif /* USE_AVX2_WITH_RUNTIME_CHECK */
+
/*
* Calculate one round of the checksum.
*/
@@ -143,7 +226,7 @@ do { \
* (at least on 4-byte boundary).
*/
static uint32
-pg_checksum_block(const PGChecksummablePage *page)
+pg_checksum_block_default(const PGChecksummablePage *page)
{
uint32 sums[N_SUMS];
uint32 result = 0;
@@ -173,6 +256,63 @@ pg_checksum_block(const PGChecksummablePage *page)
return result;
}
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+/*
+ * AVX2-optimized block checksum algorithm.
+ * Same algorithm as default, but compiled with AVX2 target for auto-vectorization.
+ */
+pg_attribute_target("avx2")
+static uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+ uint32 sums[N_SUMS];
+ uint32 result = 0;
+ uint32 i,
+ j;
+
+ /* ensure that the size is compatible with the algorithm */
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+
+ /* initialize partial checksums to their corresponding offsets */
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ /* main checksum calculation */
+ for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ /* finally add in two rounds of zeroes for additional mixing */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ /* xor fold partial checksums together */
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+#endif
+
+/* Function pointer - external linkage */
+static uint32 (*pg_checksum_block)(const PGChecksummablePage *page) = pg_checksum_block_choose;
+
+/* Choose the best available checksum implementation */
+static uint32
+pg_checksum_block_choose(const PGChecksummablePage *page)
+{
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (avx2_available())
+ {
+ pg_checksum_block = pg_checksum_block_avx2;
+ return pg_checksum_block(page);
+ }
+#endif
+ /* fallback to default implementation */
+ pg_checksum_block = pg_checksum_block_default;
+ return pg_checksum_block(page);
+}
+
/*
* Compute the checksum for a Postgres page.
*
--
2.43.0
[application/octet-stream] v8-0003-Benchmark-code-for-pg_checksum_bench-performance-tes.patch (4.8K, 4-v8-0003-Benchmark-code-for-pg_checksum_bench-performance-tes.patch)
download | inline diff:
From d8c98e0111eadd1cd698465f63b39e71bcc49985 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Thu, 23 Oct 2025 16:53:00 -0700
Subject: [PATCH 1/1] Benchmark code for pg_checksum_bench performance testing
This extension provides benchmarking functions to test and compare
the performance of different checksum implementations
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 +++++++++++++
.../pg_checksum_bench--1.0.sql | 8 +++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 34 +++++++++++++++++++
.../pg_checksum_bench.control | 4 +++
.../sql/pg_checksum_bench.sql | 17 ++++++++++
6 files changed, 87 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..e5b150e6b13
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,34 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "port/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+
+ PGChecksummablePage * pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (size_t i = 0; i < page_count * sizeof(PGChecksummablePage); i++){
+ char * byte_ptr = (char *) pages;
+ byte_ptr[i] = rand() % 256;
+ }
+
+ for (int i = 0; i < REPEATS; i++){
+ const PGChecksummablePage * test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block(test_page);
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-10-29 02:50 ` John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-10-29 02:50 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
On Fri, Oct 24, 2025 at 2:49 PM Andrew Kim <[email protected]> wrote:
> The function signatures (pg_checksum_block, pg_checksum_page) remain
> identical, and checksum_impl.h still contains the complete
> implementation that external programs can include. The runtime
> dispatch only affects internal PostgreSQL usage.
I don't quite understand the architecture here -- all
platform-specific definitions were put in the "checksum_impl.h"
header. My thinking was that checksum.c would have all that, with thin
wrappers around the functions included from that header.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-11-05 23:49 ` Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-11-05 23:49 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
Hi John,
Thank you for reviewing and bringing this up regarding checksum architecture.
On Tue, Oct 28, 2025 at 7:50 PM John Naylor <[email protected]> wrote:
>
> On Fri, Oct 24, 2025 at 2:49 PM Andrew Kim <[email protected]> wrote:
> > The function signatures (pg_checksum_block, pg_checksum_page) remain
> > identical, and checksum_impl.h still contains the complete
> > implementation that external programs can include. The runtime
> > dispatch only affects internal PostgreSQL usage.
>
> I don't quite understand the architecture here -- all
> platform-specific definitions were put in the "checksum_impl.h"
> header. My thinking was that checksum.c would have all that, with thin
> wrappers around the functions included from that header.
The v9 patch series is attached.
I've implemented the architecture as you described.
checksum_impl.h
-No platform-specific code (removed all AVX2, CPUID, intrinsics)
-External programs get a clean, portable standalone implementation
-Uses #ifndef PG_CHECKSUM_INTERNAL guard to prevent conflicts
checksum.c (full implementation for checksum):
-Includes checksum_impl.h for the basic implementation and common definitions
-Contains all platform-specific code (AVX2, CPUID detection, runtime dispatch)
-Implements thin wrapper functions that provide the public interface
-Uses #define PG_CHECKSUM_INTERNAL before including the header
>
> --
> John Naylor
> Amazon Web Services
Thanks
Andrew
Attachments:
[application/octet-stream] v9-0001-Move-checksum-functions-from-backend-storage-to-port.patch (8.8K, 2-v9-0001-Move-checksum-functions-from-backend-storage-to-port.patch)
download | inline diff:
From bc58fb3d3c5e5a0f59283912e0548ca15be16afb Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Tue, 4 Nov 2025 18:34:49 -0800
Subject: [PATCH 1/3] Move checksum functions from backend storage to port
This refactoring moves checksum implementation from src/backend/storage/page/ to src/port/
---
contrib/pageinspect/rawpage.c | 2 +-
src/backend/backup/basebackup.c | 2 +-
src/backend/storage/page/Makefile | 6 +-----
src/backend/storage/page/bufpage.c | 2 +-
src/backend/storage/page/meson.build | 9 ---------
src/bin/pg_checksums/pg_checksums.c | 3 +--
src/bin/pg_upgrade/file.c | 3 +--
src/include/{storage => port}/checksum.h | 2 +-
src/include/{storage => port}/checksum_impl.h | 4 ++--
src/port/Makefile | 6 ++++++
src/{backend/storage/page => port}/checksum.c | 8 ++++----
src/port/meson.build | 4 ++--
src/test/modules/test_aio/test_aio.c | 2 +-
13 files changed, 22 insertions(+), 31 deletions(-)
rename src/include/{storage => port}/checksum.h (94%)
rename src/include/{storage => port}/checksum_impl.h (98%)
rename src/{backend/storage/page => port}/checksum.c (73%)
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index aef442b5db3..7beb7765da9 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -23,7 +23,7 @@
#include "miscadmin.h"
#include "pageinspect.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
#include "utils/rel.h"
diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index bb7d90aa5d9..d84ced4b47c 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -39,7 +39,7 @@
#include "replication/walsender.h"
#include "replication/walsender_private.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/dsm_impl.h"
#include "storage/ipc.h"
#include "storage/reinit.h"
diff --git a/src/backend/storage/page/Makefile b/src/backend/storage/page/Makefile
index da539b113a6..788fee403f6 100644
--- a/src/backend/storage/page/Makefile
+++ b/src/backend/storage/page/Makefile
@@ -12,12 +12,8 @@ subdir = src/backend/storage/page
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = \
+OBJS = \
bufpage.o \
- checksum.o \
itemptr.o
include $(top_srcdir)/src/backend/common.mk
-
-# Provide special optimization flags for checksum.c
-checksum.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index aac6e695954..73f42dc0c49 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -18,7 +18,7 @@
#include "access/itup.h"
#include "access/xlog.h"
#include "pgstat.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
diff --git a/src/backend/storage/page/meson.build b/src/backend/storage/page/meson.build
index 112f00ff365..cf92a8f55f0 100644
--- a/src/backend/storage/page/meson.build
+++ b/src/backend/storage/page/meson.build
@@ -1,14 +1,5 @@
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
-checksum_backend_lib = static_library('checksum_backend_lib',
- 'checksum.c',
- dependencies: backend_build_deps,
- kwargs: internal_lib_args,
- c_args: vectorize_cflags + unroll_loops_cflags,
-)
-
-backend_link_with += checksum_backend_lib
-
backend_sources += files(
'bufpage.c',
'itemptr.c',
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 46cb2f36efa..2e0212c029c 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -29,8 +29,7 @@
#include "getopt_long.h"
#include "pg_getopt.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
static int64 files_scanned = 0;
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 91ed16acb08..f9a5ed02ee4 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -24,8 +24,7 @@
#include "common/file_perm.h"
#include "pg_upgrade.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
/*
diff --git a/src/include/storage/checksum.h b/src/include/port/checksum.h
similarity index 94%
rename from src/include/storage/checksum.h
rename to src/include/port/checksum.h
index 25d13a798d1..c2faed83ede 100644
--- a/src/include/storage/checksum.h
+++ b/src/include/port/checksum.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum.h
+ * src/include/port/checksum.h
*
*-------------------------------------------------------------------------
*/
diff --git a/src/include/storage/checksum_impl.h b/src/include/port/checksum_impl.h
similarity index 98%
rename from src/include/storage/checksum_impl.h
rename to src/include/port/checksum_impl.h
index da87d61ba52..00cb0549f24 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/port/checksum_impl.h
@@ -5,13 +5,13 @@
*
* This file exists for the benefit of external programs that may wish to
* check Postgres page checksums. They can #include this to get the code
- * referenced by storage/checksum.h. (Note: you may need to redefine
+ * referenced by port/checksum.h. (Note: you may need to redefine
* Assert() as empty to compile this successfully externally.)
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/storage/checksum_impl.h
+ * src/include/port/checksum_impl.h
*
*-------------------------------------------------------------------------
*/
diff --git a/src/port/Makefile b/src/port/Makefile
index 4274949dfa4..4f1f460bff2 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -39,6 +39,7 @@ OBJS = \
$(LIBOBJS) \
$(PG_CRC32C_OBJS) \
bsearch_arg.o \
+ checksum.o \
chklocale.o \
inet_net_ntop.o \
noblock.o \
@@ -90,6 +91,11 @@ pg_crc32c_armv8.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_shlib.o: CFLAGS+=$(CFLAGS_CRC)
pg_crc32c_armv8_srv.o: CFLAGS+=$(CFLAGS_CRC)
+# Provide special optimization flags for checksum.c
+checksum.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+checksum_shlib.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+checksum_srv.o: CFLAGS += ${CFLAGS_UNROLL_LOOPS} ${CFLAGS_VECTORIZE}
+
#
# Shared library versions of object files
#
diff --git a/src/backend/storage/page/checksum.c b/src/port/checksum.c
similarity index 73%
rename from src/backend/storage/page/checksum.c
rename to src/port/checksum.c
index c913459b5a3..de61a46231d 100644
--- a/src/backend/storage/page/checksum.c
+++ b/src/port/checksum.c
@@ -7,16 +7,16 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * src/backend/storage/page/checksum.c
+ * src/port/checksum.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
/*
- * The actual code is in storage/checksum_impl.h. This is done so that
+ * The actual code is in port/checksum_impl.h. This is done so that
* external programs can incorporate the checksum code by #include'ing
* that file from the exported Postgres headers. (Compare our CRC code.)
*/
-#include "storage/checksum_impl.h" /* IWYU pragma: keep */
+#include "port/checksum_impl.h" /* IWYU pragma: keep */
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..d3e63bce9e7 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -104,8 +104,8 @@ replace_funcs_pos = [
['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'],
]
-pgport_cflags = {'crc': cflags_crc}
-pgport_sources_cflags = {'crc': []}
+pgport_cflags = {'crc': cflags_crc, 'checksum': vectorize_cflags + unroll_loops_cflags}
+pgport_sources_cflags = {'crc': [], 'checksum': [files('checksum.c')]}
foreach f : replace_funcs_neg
func = f.get(0)
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index c55cf6c0aac..175e491c0bc 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -24,7 +24,7 @@
#include "storage/aio_internal.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
-#include "storage/checksum.h"
+#include "port/checksum.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "utils/builtins.h"
--
2.43.0
[application/octet-stream] v9-0002-Move-platform-specific-checksum-code-from-header-to-.patch (14.8K, 3-v9-0002-Move-platform-specific-checksum-code-from-header-to-.patch)
download | inline diff:
From f9ae422bec79b965e58382a20da14621c10d2c19 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Wed, 5 Nov 2025 00:00:20 -0800
Subject: [PATCH 1/2] Move platform-specific checksum code from header to
source
Key architectural changes:
checksum_impl.h (simplified for external programs):
- Contains only basic FNV-1a implementation
- No platform-specific code (AVX2, CPUID, intrinsics)
- External programs get portable standalone implementation
- Uses static functions (no symbol conflicts with checksum.c)
checksum.c (full implementation for PostgreSQL):
- Includes checksum_impl.h for common definitions
- Contains all platform-specific code (AVX2, CPUID detection)
- Implements runtime dispatch based on CPU features
- Provides public interfaces wrapping the basic implementation
Architecture benefits:
- Follows PostgreSQL principle: platform code belongs in .c files
- No code duplication (checksum.c includes checksum_impl.h)
- Clean separation: external programs vs internal optimization
- Maintains backward compatibility for external tools
Trade-offs:
- External programs use basic implementation only (no AVX2)
- PostgreSQL internal code gets full optimization
---
config/c-compiler.m4 | 26 ++++
configure | 52 ++++++++
configure.ac | 9 ++
meson.build | 30 +++++
src/include/pg_config.h.in | 3 +
src/include/port/checksum.h | 6 +
src/include/port/checksum_impl.h | 13 +-
src/port/checksum.c | 200 ++++++++++++++++++++++++++++++-
8 files changed, 331 insertions(+), 8 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..40927d56e6a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -581,6 +581,32 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_SSE42_CRC32_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# ---------------------------
+# Check if the compiler supports AVX2 target attribute.
+# This is used for optimized checksum calculations with runtime detection.
+#
+# If AVX2 target attribute is supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 target attribute support], [Ac_cachevar],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_PCLMUL_INTRINSICS
# ---------------------------
# Check if the compiler supports AVX-512 carryless multiplication
diff --git a/configure b/configure
index f7c24c8f576..08a04619284 100755
--- a/configure
+++ b/configure
@@ -17552,6 +17552,58 @@ $as_echo "#define HAVE_XSAVE_INTRINSICS 1" >>confdefs.h
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 support" >&5
+$as_echo_n "checking for AVX2 support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <immintrin.h>
+ #include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ #endif
+ static int avx2_test(void)
+ {
+ const char buf[sizeof(__m256i)];
+ __m256i accum = _mm256_loadu_si256((const __m256i *) buf);
+ accum = _mm256_add_epi32(accum, accum);
+ int result = _mm256_extract_epi32(accum, 0);
+ return (int) result;
+ }
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for AVX-512 popcount intrinsics
#
if test x"$host_cpu" = x"x86_64"; then
diff --git a/configure.ac b/configure.ac
index 6c802deaacb..00a701db1f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2077,6 +2077,15 @@ else
fi
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for XSAVE intrinsics
#
PGAC_XSAVE_INTRINSICS()
diff --git a/meson.build b/meson.build
index 0f61ff6a700..55b26814efc 100644
--- a/meson.build
+++ b/meson.build
@@ -2293,6 +2293,36 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+static int avx2_test(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ return avx2_test();
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
###############################################################
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index f52f14cc566..66556985a63 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -678,6 +678,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/port/checksum.h b/src/include/port/checksum.h
index c2faed83ede..531c94404f8 100644
--- a/src/include/port/checksum.h
+++ b/src/include/port/checksum.h
@@ -21,4 +21,10 @@
*/
extern uint16 pg_checksum_page(char *page, BlockNumber blkno);
+/*
+ * Choose the best available checksum implementation and compute checksum
+ * for a single block.
+ */
+extern uint32 pg_checksum_block_choose(const char *data);
+
#endif /* CHECKSUM_H */
diff --git a/src/include/port/checksum_impl.h b/src/include/port/checksum_impl.h
index 00cb0549f24..7993da92325 100644
--- a/src/include/port/checksum_impl.h
+++ b/src/include/port/checksum_impl.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* checksum_impl.h
- * Checksum implementation for data pages.
+ * Checksum implementation for data pages.
*
* This file exists for the benefit of external programs that may wish to
* check Postgres page checksums. They can #include this to get the code
@@ -173,6 +173,8 @@ pg_checksum_block(const PGChecksummablePage *page)
return result;
}
+#ifndef PG_CHECKSUM_INTERNAL
+
/*
* Compute the checksum for a Postgres page.
*
@@ -182,6 +184,9 @@ pg_checksum_block(const PGChecksummablePage *page)
* The checksum includes the block number (to detect the case where a page is
* somehow moved to a different location), the page header (excluding the
* checksum itself), and the page data.
+ *
+ * This function is only defined when included by external programs.
+ * PostgreSQL internal code uses the optimized version in checksum.c.
*/
uint16
pg_checksum_page(char *page, BlockNumber blkno)
@@ -196,8 +201,8 @@ pg_checksum_page(char *page, BlockNumber blkno)
/*
* Save pd_checksum and temporarily set it to zero, so that the checksum
* calculation isn't affected by the old checksum stored on the page.
- * Restore it after, because actually updating the checksum is NOT part of
- * the API of this function.
+ * Restore it after, because actually updating the checksum is NOT part
+ * of the API of this function.
*/
save_checksum = cpage->phdr.pd_checksum;
cpage->phdr.pd_checksum = 0;
@@ -213,3 +218,5 @@ pg_checksum_page(char *page, BlockNumber blkno)
*/
return (uint16) ((checksum % 65535) + 1);
}
+
+#endif /* !PG_CHECKSUM_INTERNAL */
diff --git a/src/port/checksum.c b/src/port/checksum.c
index de61a46231d..1f684d80db9 100644
--- a/src/port/checksum.c
+++ b/src/port/checksum.c
@@ -1,7 +1,11 @@
/*-------------------------------------------------------------------------
*
* checksum.c
- * Checksum implementation for data pages.
+ * Checksum implementation for data pages.
+ *
+ * This file provides the platform-specific optimizations (AVX2, CPUID)
+ * and runtime dispatch logic. It includes checksum_impl.h for the
+ * basic implementation and common definitions.
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -11,12 +15,198 @@
*
*-------------------------------------------------------------------------
*/
+
#include "postgres.h"
#include "port/checksum.h"
+#include "storage/bufpage.h"
+
+/* Prevent duplicate pg_checksum_page definition from checksum_impl.h */
+#define PG_CHECKSUM_INTERNAL
+
+/* Include the basic implementation and common definitions */
+#include "port/checksum_impl.h"
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+#include <immintrin.h>
+#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
+#include <cpuid.h>
+#endif
+#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
+#include <intrin.h>
+#endif
+#endif
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+
+/*
+ * Does CPUID say there's support for XSAVE instructions?
+ */
+static inline bool
+xsave_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+#if defined(HAVE__GET_CPUID)
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUID)
+ __cpuid(exx, 1);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[2] & (1 << 27)) != 0; /* osxsave */
+}
+
/*
- * The actual code is in port/checksum_impl.h. This is done so that
- * external programs can incorporate the checksum code by #include'ing
- * that file from the exported Postgres headers. (Compare our CRC code.)
+ * Does XGETBV say the YMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
*/
-#include "port/checksum_impl.h" /* IWYU pragma: keep */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+ymm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0x06) == 0x06;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Check for AVX2 support using CPUID detection
+ */
+static inline bool
+avx2_available(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+
+ if (!xsave_available() || !ymm_regs_available())
+ return false;
+
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, 7, 0);
+#else
+#error cpuid instruction not available
+#endif
+ return (exx[1] & (1 << 5)) != 0; /* avx2 */
+}
+
+/*
+ * AVX2-optimized block checksum algorithm.
+ * Same algorithm as default, but compiled with AVX2 target for auto-vectorization.
+ */
+pg_attribute_target("avx2")
+static uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+ uint32 sums[N_SUMS];
+ uint32 result = 0;
+ uint32 i,
+ j;
+
+ /* ensure that the size is compatible with the algorithm */
+ Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+
+ /* initialize partial checksums to their corresponding offsets */
+ memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+ /* main checksum calculation */
+ for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+ /* finally add in two rounds of zeroes for additional mixing */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+ /* xor fold partial checksums together */
+ for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+ return result;
+}
+#endif /* USE_AVX2_WITH_RUNTIME_CHECK */
+
+/* Function pointer for the checksum implementation */
+static uint32 (*pg_checksum_block_impl) (const PGChecksummablePage *page) = NULL;
+
+/*
+ * Initialize the checksum implementation based on available CPU features.
+ */
+static void
+pg_checksum_init(void)
+{
+ if (pg_checksum_block_impl != NULL)
+ return; /* already initialized */
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (avx2_available())
+ pg_checksum_block_impl = pg_checksum_block_avx2;
+ else
+#endif
+ pg_checksum_block_impl = pg_checksum_block;
+}
+
+/*
+ * Choose the best available checksum implementation.
+ * This follows the naming pattern of pg_crc32c_choose.
+ */
+uint32
+pg_checksum_block_choose(const char *data)
+{
+ const PGChecksummablePage *page = (const PGChecksummablePage *) data;
+
+ /* Initialize the implementation if not done already */
+ if (pg_checksum_block_impl == NULL)
+ pg_checksum_init();
+
+ return pg_checksum_block_impl(page);
+}
+
+/*
+ * Compute the checksum for a Postgres page.
+ *
+ * The page must be adequately aligned (at least on a 4-byte boundary).
+ * Beware also that the checksum field of the page is transiently zeroed.
+ *
+ * The checksum includes the block number (to detect the case where a page is
+ * somehow moved to a different location), the page header (excluding the
+ * checksum itself), and the page data.
+ */
+uint16
+pg_checksum_page(char *page, BlockNumber blkno)
+{
+ PGChecksummablePage *cpage = (PGChecksummablePage *) page;
+ uint16 save_checksum;
+ uint32 checksum;
+
+ /* We only calculate the checksum for properly-initialized pages */
+ Assert(!PageIsNew((Page) page));
+
+ /*
+ * Save pd_checksum and temporarily set it to zero, so that the checksum
+ * calculation isn't affected by the old checksum stored on the page.
+ * Restore it after, because actually updating the checksum is NOT part
+ * of the API of this function.
+ */
+ save_checksum = cpage->phdr.pd_checksum;
+ cpage->phdr.pd_checksum = 0;
+ checksum = pg_checksum_block_choose((const char *) cpage);
+ cpage->phdr.pd_checksum = save_checksum;
+
+ /* Mix in the block number to detect transposed pages */
+ checksum ^= blkno;
+
+ /*
+ * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
+ * one. That avoids checksums of zero, which seems like a good idea.
+ */
+ return (uint16) ((checksum % 65535) + 1);
+}
--
2.43.0
[application/octet-stream] v9-0003-Benchmark-code-for-postgres-checksums.patch (5.0K, 4-v9-0003-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From ddf37874e2b82849db63f2379edc6b5ba54e2665 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Wed, 5 Nov 2025 14:37:29 -0800
Subject: [PATCH 3/3] Benchmark code for postgres checksums
Add pg_checksum_bench extension for performance testing of checksum
implementations with AVX2 optimization.
Key features:
- PostgreSQL extension for benchmarking checksum performance
- Tests pg_checksum_block_choose() with runtime AVX2 dispatch
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 ++++++++++
.../pg_checksum_bench--1.0.sql | 8 ++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 42 +++++++++++++++++++
.../pg_checksum_bench.control | 4 ++
.../sql/pg_checksum_bench.sql | 17 ++++++++
6 files changed, 95 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index ed30ee7d639..fe5149aadff 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..dc20395a590
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,42 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "port/checksum.h"
+#include "port/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+ PGChecksummablePage *pages;
+ int i;
+ size_t j;
+
+ pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (j = 0; j < page_count * sizeof(PGChecksummablePage); j++)
+ {
+ char *byte_ptr = (char *) pages;
+
+ byte_ptr[j] = rand() % 256;
+ }
+
+ for (i = 0; i < REPEATS; i++)
+ {
+ const PGChecksummablePage *test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block_choose((const char *) test_page);
+
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.43.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-11-14 11:34 ` John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-11-14 11:34 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
On Thu, Nov 6, 2025 at 6:50 AM Andrew Kim <[email protected]> wrote:
> The v9 patch series is attached.
Thanks! BTW, I've set the commitfest entry to "Needs Review".
I spent some time with the v9-0001 refactoring patch, and I have one
observation that's worth sharing now:
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -29,8 +29,7 @@
#include "getopt_long.h"
#include "pg_getopt.h"
#include "storage/bufpage.h"
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
Outside the backend it is no longer required to include the
implementation header -- it just links and works correctly. That seems
like a good thing. In fact...
On Tue, Oct 21, 2025 I wrote:
> Looking at commit f04216341dd1, we have at least one example of an
> external program, pg_filedump. If we can keep this working with
> minimal fuss, it should be fine everywhere.
> https://github.com/df7cb/pg_filedump/blob/master/pg_filedump.c#L29
>
> ```
> /* checksum_impl.h uses Assert, which doesn't work outside the server */
> #undef Assert
> #define Assert(X)
>
> #include "storage/checksum.h"
> #include "storage/checksum_impl.h"
> ```
I tried building pg_filedump against the server with just the 0001
patch and it also builds fine leaving out the implementation:
diff --git a/pg_filedump.c b/pg_filedump.c
index 606a85b..0268381 100644
--- a/pg_filedump.c
+++ b/pg_filedump.c
@@ -26,12 +26,7 @@
#include <utils/pg_crc.h>
-/* checksum_impl.h uses Assert, which doesn't work outside the server */
-#undef Assert
-#define Assert(X)
-
-#include "storage/checksum.h"
-#include "storage/checksum_impl.h"
+#include "port/checksum.h"
#include "decode.h"
#include <inttypes.h>
I verified that it does in fact break when built against our master
branch without the impl.h header.
Further, if I replace the above CRC #include to point instead to our
hardware-specific API in port/pg_crc32c.h, it builds fine after
adjusting the typedef that it expects, and interprets the control file
normally:
<pg_control Contents> *********************************************
CRC: Correct
pg_control Version: 1800
Catalog Version: 202511051
...
I'll think more about this.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-11-18 03:32 ` Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-11-18 03:32 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
Hi John,
Thanks for taking the time to review the v9-0001 refactoring patch and
for setting the CF entry to Needs Review.
On Fri, Nov 14, 2025 at 3:34 AM John Naylor <[email protected]> wrote:
>
> On Thu, Nov 6, 2025 at 6:50 AM Andrew Kim <[email protected]> wrote:
> > The v9 patch series is attached.
>
> Thanks! BTW, I've set the commitfest entry to "Needs Review".
>
> I spent some time with the v9-0001 refactoring patch, and I have one
> observation that's worth sharing now:
>
> --- a/src/bin/pg_checksums/pg_checksums.c
> +++ b/src/bin/pg_checksums/pg_checksums.c
> @@ -29,8 +29,7 @@
> #include "getopt_long.h"
> #include "pg_getopt.h"
> #include "storage/bufpage.h"
> -#include "storage/checksum.h"
> -#include "storage/checksum_impl.h"
> +#include "port/checksum.h"
>
> Outside the backend it is no longer required to include the
> implementation header -- it just links and works correctly. That seems
> like a good thing. In fact...
>
> On Tue, Oct 21, 2025 I wrote:
> > Looking at commit f04216341dd1, we have at least one example of an
> > external program, pg_filedump. If we can keep this working with
> > minimal fuss, it should be fine everywhere.
>
> > https://github.com/df7cb/pg_filedump/blob/master/pg_filedump.c#L29
> >
> > ```
> > /* checksum_impl.h uses Assert, which doesn't work outside the server */
> > #undef Assert
> > #define Assert(X)
> >
> > #include "storage/checksum.h"
> > #include "storage/checksum_impl.h"
> > ```
>
> I tried building pg_filedump against the server with just the 0001
> patch and it also builds fine leaving out the implementation:
>
> diff --git a/pg_filedump.c b/pg_filedump.c
> index 606a85b..0268381 100644
> --- a/pg_filedump.c
> +++ b/pg_filedump.c
> @@ -26,12 +26,7 @@
>
> #include <utils/pg_crc.h>
>
> -/* checksum_impl.h uses Assert, which doesn't work outside the server */
> -#undef Assert
> -#define Assert(X)
> -
> -#include "storage/checksum.h"
> -#include "storage/checksum_impl.h"
> +#include "port/checksum.h"
> #include "decode.h"
> #include <inttypes.h>
>
> I verified that it does in fact break when built against our master
> branch without the impl.h header.
>
> Further, if I replace the above CRC #include to point instead to our
> hardware-specific API in port/pg_crc32c.h, it builds fine after
> adjusting the typedef that it expects, and interprets the control file
> normally:
>
> <pg_control Contents> *********************************************
>
> CRC: Correct
> pg_control Version: 1800
> Catalog Version: 202511051
> ...
>
> I'll think more about this.
>
I've double-checked everything after applying the v9 checksum patches
and updating pg_filedump accordingly.
Following your suggestion, I removed the checksum_impl.h include and
the Assert redefinition, keeping only the port/checksum.h include.
build compiles cleanly with the new architecture, and pg_filedump
functions correctly with the AVX2 optimizations.
If you agree with this approach, I'd like to prepare a patch for
upstream submission.
Please feel free to guide me on the proper process for this. Should I
submit it to the pg_filedump repository, or would you prefer to handle
the integration as part of the v9 checksum patch series?
Thanks again for your testing and guidance!
> --
> John Naylor
> Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2025-11-18 04:48 ` John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: John Naylor @ 2025-11-18 04:48 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
On Tue, Nov 18, 2025 at 10:32 AM Andrew Kim <[email protected]> wrote:
> I've double-checked everything after applying the v9 checksum patches
> and updating pg_filedump accordingly.
> Following your suggestion, I removed the checksum_impl.h include and
> the Assert redefinition, keeping only the port/checksum.h include.
> build compiles cleanly with the new architecture, and pg_filedump
> functions correctly with the AVX2 optimizations.
> If you agree with this approach, I'd like to prepare a patch for
> upstream submission.
Thanks, but there is no action required now. I mentioned some
observations, and I'm going to experiment a bit further.
Also, it's way too early to be suggesting changes to other projects,
since we haven't committed anything yet. Even things committed can
occasionally be reverted before beta 1 anyway.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2025-11-19 01:18 ` Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2025-11-19 01:18 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: [email protected]; Oleg Tselebrovskiy <[email protected]>
On Mon, Nov 17, 2025 at 8:48 PM John Naylor <[email protected]> wrote:
>
> On Tue, Nov 18, 2025 at 10:32 AM Andrew Kim <[email protected]> wrote:
>
> > I've double-checked everything after applying the v9 checksum patches
> > and updating pg_filedump accordingly.
> > Following your suggestion, I removed the checksum_impl.h include and
> > the Assert redefinition, keeping only the port/checksum.h include.
> > build compiles cleanly with the new architecture, and pg_filedump
> > functions correctly with the AVX2 optimizations.
> > If you agree with this approach, I'd like to prepare a patch for
> > upstream submission.
>
> Thanks, but there is no action required now. I mentioned some
> observations, and I'm going to experiment a bit further.
>
> Also, it's way too early to be suggesting changes to other projects,
> since we haven't committed anything yet. Even things committed can
> occasionally be reverted before beta 1 anyway.
It makes sense, I fully understand. I will standby and wait for your
next update.
-Andrew Kim
> --
> John Naylor
> Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2026-03-16 08:00 ` Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 1 reply; 36+ messages in thread
From: Andrew Kim @ 2026-03-16 08:00 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
It looks like your PostgreSQL build on Cirrus CI is failing during the
Meson configuration phase because it cannot find the libedit
libraries.
Should we add these to the pacman installation command in our CI
scripts, or is there a preferred way to handle terminal library
dependencies for the Windows Meson builds?
https://cirrus-ci.com/task/4928462311391232
[01:09:47.468] meson.build:1480:20: ERROR: C shared or static library
'libedit' not found
On Mon, Feb 9, 2026 at 12:42 AM Andrew Kim <[email protected]> wrote:
>
> Hi John, Thanks for v11.
> Adding the headercheck exception for the internal header looks good to me.
> It would be the right call to fix the CI issues.
> The current structure utilizing the semi-private header looks solid to me.
> -Andrew
>
> On Wed, Jan 21, 2026 at 3:13 AM John Naylor <[email protected]> wrote:
> >
> > Attached is v11 to fix headerscheck, per CI.
> >
> > --
> > John Naylor
> > Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
@ 2026-03-17 02:23 ` John Naylor <[email protected]>
2026-03-17 02:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 12:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
0 siblings, 2 replies; 36+ messages in thread
From: John Naylor @ 2026-03-17 02:23 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
On Mon, Mar 16, 2026 at 3:00 PM Andrew Kim <[email protected]> wrote:
>
> It looks like your PostgreSQL build on Cirrus CI is failing during the
> Meson configuration phase because it cannot find the libedit
> libraries.
> Should we add these to the pacman installation command in our CI
> scripts, or is there a preferred way to handle terminal library
> dependencies for the Windows Meson builds?
I'll leave that to the people who maintain it. Sometimes intermittent
glitches happen. And please don't top-post.
I've attached v12 which is just a rebase over the new centralized
feature detection. I also have some review:
+# Check if the compiler supports AVX2 target attribute.
+# This is used for optimized checksum calculations with runtime detection.
It could possibly be used for other things, in which case this will
get out of date. It's most reliable to grep for the symbol to see
where something is used.
Also, the first statement is not true:
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif],
With these guards, I think any compiler will pass the test, and CI
does show it passes on MSVC:
[01:09:52.888] Checking if "AVX2 support" links: YES
The consequence is that two functions get built with identical
non-AVX2 contents. Then at runtime we pick one of them, but it doesn't
matter which. This needs to test what it says it's testing.
--
John Naylor
Amazon Web Services
Attachments:
[text/x-patch] v12-0001-Benchmark-code-for-postgres-checksums.patch (4.9K, 2-v12-0001-Benchmark-code-for-postgres-checksums.patch)
download | inline diff:
From 561542289a4696de7e8e0f5635019f092714e6c8 Mon Sep 17 00:00:00 2001
From: Andrew Kim <[email protected]>
Date: Wed, 5 Nov 2025 14:37:29 -0800
Subject: [PATCH v12 1/3] Benchmark code for postgres checksums
Add pg_checksum_bench extension for performance testing of checksum
implementations with AVX2 optimization.
XXX not for commit
---
contrib/meson.build | 1 +
contrib/pg_checksum_bench/meson.build | 23 ++++++++++
.../pg_checksum_bench--1.0.sql | 8 ++++
contrib/pg_checksum_bench/pg_checksum_bench.c | 42 +++++++++++++++++++
.../pg_checksum_bench.control | 4 ++
.../sql/pg_checksum_bench.sql | 17 ++++++++
6 files changed, 95 insertions(+)
create mode 100644 contrib/pg_checksum_bench/meson.build
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.c
create mode 100644 contrib/pg_checksum_bench/pg_checksum_bench.control
create mode 100644 contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
diff --git a/contrib/meson.build b/contrib/meson.build
index 5a752eac347..9529f0b1aee 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -12,6 +12,7 @@ contrib_doc_args = {
'install_dir': contrib_doc_dir,
}
+subdir('pg_checksum_bench')
subdir('amcheck')
subdir('auth_delay')
subdir('auto_explain')
diff --git a/contrib/pg_checksum_bench/meson.build b/contrib/pg_checksum_bench/meson.build
new file mode 100644
index 00000000000..32ccd9efa0f
--- /dev/null
+++ b/contrib/pg_checksum_bench/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+pg_checksum_bench_sources = files(
+ 'pg_checksum_bench.c',
+)
+
+if host_system == 'windows'
+ pg_checksum_bench_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_checksum_bench',
+ '--FILEDESC', 'pg_checksum_bench',])
+endif
+
+pg_checksum_bench = shared_module('pg_checksum_bench',
+ pg_checksum_bench_sources,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_checksum_bench
+
+install_data(
+ 'pg_checksum_bench--1.0.sql',
+ 'pg_checksum_bench.control',
+ kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
new file mode 100644
index 00000000000..5f13cbe3c5e
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql
@@ -0,0 +1,8 @@
+/* contrib/pg_checksum_bench/pg_checksum_bench--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+-- \echo Use "CREATE EXTENSION pg_checksum_bench" to load this file. \quit
+
+CREATE FUNCTION drive_pg_checksum(page_count int)
+ RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
new file mode 100644
index 00000000000..dc20395a590
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -0,0 +1,42 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "port/checksum.h"
+#include "port/checksum_impl.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+PG_MODULE_MAGIC;
+
+#define REPEATS 1000000
+
+PG_FUNCTION_INFO_V1(drive_pg_checksum);
+Datum
+drive_pg_checksum(PG_FUNCTION_ARGS)
+{
+ int page_count = PG_GETARG_INT32(0);
+ PGChecksummablePage *pages;
+ int i;
+ size_t j;
+
+ pages = palloc(page_count * sizeof(PGChecksummablePage));
+ srand(0);
+ for (j = 0; j < page_count * sizeof(PGChecksummablePage); j++)
+ {
+ char *byte_ptr = (char *) pages;
+
+ byte_ptr[j] = rand() % 256;
+ }
+
+ for (i = 0; i < REPEATS; i++)
+ {
+ const PGChecksummablePage *test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_block_choose((const char *) test_page);
+
+ (void) result;
+ }
+
+ pfree((void *) pages);
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.control b/contrib/pg_checksum_bench/pg_checksum_bench.control
new file mode 100644
index 00000000000..4a4e2c9363c
--- /dev/null
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.control
@@ -0,0 +1,4 @@
+comment = 'pg_checksum benchmark'
+default_version = '1.0'
+module_pathname = '$libdir/pg_checksum_bench'
+relocatable = true
diff --git a/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
new file mode 100644
index 00000000000..4b347699953
--- /dev/null
+++ b/contrib/pg_checksum_bench/sql/pg_checksum_bench.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION pg_checksum_bench;
+
+SELECT drive_pg_checksum(-1);
+
+\timing on
+
+SELECT drive_pg_checksum(1);
+SELECT drive_pg_checksum(2);
+SELECT drive_pg_checksum(4);
+SELECT drive_pg_checksum(8);
+SELECT drive_pg_checksum(16);
+SELECT drive_pg_checksum(32);
+SELECT drive_pg_checksum(64);
+SELECT drive_pg_checksum(128);
+SELECT drive_pg_checksum(256);
+SELECT drive_pg_checksum(512);
+SELECT drive_pg_checksum(1024);
--
2.53.0
[text/x-patch] v12-0002-Adjust-benchmark-to-use-core-checksum.patch (1.6K, 3-v12-0002-Adjust-benchmark-to-use-core-checksum.patch)
download | inline diff:
From 556ddbb4c67b0f9b742c40ccb4ca39500de45805 Mon Sep 17 00:00:00 2001
From: John Naylor <[email protected]>
Date: Fri, 9 Jan 2026 17:07:37 +0700
Subject: [PATCH v12 2/3] Adjust benchmark to use core checksum
XXX not for commit
---
contrib/pg_checksum_bench/pg_checksum_bench.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/contrib/pg_checksum_bench/pg_checksum_bench.c b/contrib/pg_checksum_bench/pg_checksum_bench.c
index dc20395a590..61da664e723 100644
--- a/contrib/pg_checksum_bench/pg_checksum_bench.c
+++ b/contrib/pg_checksum_bench/pg_checksum_bench.c
@@ -1,7 +1,6 @@
#include "postgres.h"
#include "fmgr.h"
-#include "port/checksum.h"
-#include "port/checksum_impl.h"
+#include "storage/checksum.h"
#include <stdio.h>
#include <assert.h>
@@ -15,23 +14,23 @@ Datum
drive_pg_checksum(PG_FUNCTION_ARGS)
{
int page_count = PG_GETARG_INT32(0);
- PGChecksummablePage *pages;
+ char *pages;
int i;
size_t j;
- pages = palloc(page_count * sizeof(PGChecksummablePage));
+ pages = palloc(page_count * BLCKSZ);
srand(0);
- for (j = 0; j < page_count * sizeof(PGChecksummablePage); j++)
+ for (j = 0; j < page_count * BLCKSZ; j++)
{
- char *byte_ptr = (char *) pages;
+ char *byte_ptr = pages;
byte_ptr[j] = rand() % 256;
}
for (i = 0; i < REPEATS; i++)
{
- const PGChecksummablePage *test_page = pages + (i % page_count);
- volatile uint32 result = pg_checksum_block_choose((const char *) test_page);
+ char *test_page = pages + (i % page_count);
+ volatile uint32 result = pg_checksum_page((char *) test_page, 0);
(void) result;
}
--
2.53.0
[text/x-patch] v12-0003-Enable-autovectorizing-page-checksums-with-AVX2-.patch (13.4K, 4-v12-0003-Enable-autovectorizing-page-checksums-with-AVX2-.patch)
download | inline diff:
From a2e58990cf79dc217755431a86084e5d3ccd1e5b Mon Sep 17 00:00:00 2001
From: John Naylor <[email protected]>
Date: Mon, 2 Mar 2026 17:28:58 +0700
Subject: [PATCH v12 3/3] Enable autovectorizing page checksums with AVX2 where
available
We already rely on autovectorization for computing page checksums,
but on x86 we can get about twice the performance by annotating
pg_checksum_block() with function target attributes for AVX2,
which uses 256-bit registers.
Co-authored-by: Matthew Sterrett <[email protected]>
Co-authored-by: Andrew Kim <[email protected]>
Reviewed-by: Oleg Tselebrovskiy <[email protected]>
Discussion: https://postgr.es/m/CA%2BvA85_5GTu%2BHHniSbvvP%2B8k3%3DxZO%3DWE84NPwiKyxztqvpfZ3Q%40mail.gmail.com
Discussion: https://postgr.es/m/20250911054220.3784-1-root%40ip-172-31-36-228.ec2.internal
---
config/c-compiler.m4 | 26 +++++++++++++
configure | 46 +++++++++++++++++++++++
configure.ac | 9 +++++
meson.build | 30 +++++++++++++++
src/backend/storage/page/checksum.c | 44 +++++++++++++++++++++-
src/include/pg_config.h.in | 3 ++
src/include/port/pg_cpu.h | 3 ++
src/include/storage/checksum_block.inc.c | 42 +++++++++++++++++++++
src/include/storage/checksum_impl.h | 48 ++++++++----------------
src/port/pg_cpu_x86.c | 6 ++-
10 files changed, 222 insertions(+), 35 deletions(-)
create mode 100644 src/include/storage/checksum_block.inc.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 88333ef301d..566c62dabab 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -691,6 +691,32 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_SSE42_CRC32_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# ---------------------------
+# Check if the compiler supports AVX2 target attribute.
+# This is used for optimized checksum calculations with runtime detection.
+#
+# If AVX2 target attribute is supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 target attribute support], [Ac_cachevar],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_PCLMUL_INTRINSICS
# ---------------------------
# Check if the compiler supports AVX-512 carryless multiplication
diff --git a/configure b/configure
index 4c789bd9289..87ebeb0cd0e 100755
--- a/configure
+++ b/configure
@@ -17835,6 +17835,52 @@ $as_echo "#define HAVE__CPUIDEX 1" >>confdefs.h
fi
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 target attribute support" >&5
+$as_echo_n "checking for AVX2 target attribute support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for XSAVE intrinsics
#
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _xgetbv" >&5
diff --git a/configure.ac b/configure.ac
index 9edffe481a6..0445e1cbcff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2130,6 +2130,15 @@ else
fi
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for XSAVE intrinsics
#
PGAC_XSAVE_INTRINSICS()
diff --git a/meson.build b/meson.build
index f7a87edcc94..d57e9f89487 100644
--- a/meson.build
+++ b/meson.build
@@ -2436,6 +2436,36 @@ int main(void)
endif
+###############################################################
+# Check for the availability of AVX2 support
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+#if defined(__has_attribute) && __has_attribute (target)
+__attribute__((target("avx2")))
+#endif
+static int avx2_test(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ return avx2_test();
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
###############################################################
diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c
index 8716651c8b5..7ce51fe9d2e 100644
--- a/src/backend/storage/page/checksum.c
+++ b/src/backend/storage/page/checksum.c
@@ -13,10 +13,52 @@
*/
#include "postgres.h"
+#include "port/pg_cpu.h"
#include "storage/checksum.h"
/*
* The actual code is in storage/checksum_impl.h. This is done so that
* external programs can incorporate the checksum code by #include'ing
- * that file from the exported Postgres headers. (Compare our CRC code.)
+ * that file from the exported Postgres headers. (Compare our legacy
+ * CRC code in pg_crc.h.)
+ * The PG_CHECKSUM_INTERNAL symbol allows core to use hardware-specific
+ * coding without affecting external programs.
*/
+#define PG_CHECKSUM_INTERNAL
#include "storage/checksum_impl.h" /* IWYU pragma: keep */
+
+
+static uint32
+pg_checksum_block_fallback(const PGChecksummablePage *page)
+{
+#include "storage/checksum_block.inc.c"
+}
+
+/*
+ * AVX2-optimized block checksum algorithm.
+ */
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+pg_attribute_target("avx2")
+static uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+#include "storage/checksum_block.inc.c"
+}
+#endif /* USE_AVX2_WITH_RUNTIME_CHECK */
+
+/*
+ * Choose the best available checksum implementation.
+ */
+static uint32
+pg_checksum_choose(const PGChecksummablePage *page)
+{
+ pg_checksum_block = pg_checksum_block_fallback;
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (x86_feature_available(PG_AVX2))
+ pg_checksum_block = pg_checksum_block_avx2;
+#endif
+
+ return pg_checksum_block(page);
+}
+
+static uint32 (*pg_checksum_block) (const PGChecksummablePage *page) = pg_checksum_choose;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 79379a4d125..71f6646cd0b 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -674,6 +674,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/port/pg_cpu.h b/src/include/port/pg_cpu.h
index b93b828d3ac..c5d96bb4f47 100644
--- a/src/include/port/pg_cpu.h
+++ b/src/include/port/pg_cpu.h
@@ -24,6 +24,9 @@ typedef enum X86FeatureId
PG_SSE4_2,
PG_POPCNT,
+ /* 256-bit YMM registers */
+ PG_AVX2,
+
/* 512-bit ZMM registers */
PG_AVX512_BW,
PG_AVX512_VL,
diff --git a/src/include/storage/checksum_block.inc.c b/src/include/storage/checksum_block.inc.c
new file mode 100644
index 00000000000..743434644a4
--- /dev/null
+++ b/src/include/storage/checksum_block.inc.c
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ *
+ * checksum_block.inc.c
+ * Core algorithm for page checksums, semi private to checksum_impl.h
+ * and checksum.c.
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/storage/checksum_block.inc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* there is deliberately not an #ifndef CHECKSUM_BLOCK_INC_C here */
+
+uint32 sums[N_SUMS];
+uint32 result = 0;
+uint32 i,
+ j;
+
+/* ensure that the size is compatible with the algorithm */
+Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+
+/* initialize partial checksums to their corresponding offsets */
+memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+/* main checksum calculation */
+for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+/* finally add in two rounds of zeroes for additional mixing */
+for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+/* xor fold partial checksums together */
+for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+return result;
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 5c2dcbc63e7..49974043dc2 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -73,11 +73,10 @@
* 2e-16 false positive rate within margin of error.
*
* Vectorization of the algorithm requires 32bit x 32bit -> 32bit integer
- * multiplication instruction. As of 2013 the corresponding instruction is
- * available on x86 SSE4.1 extensions (pmulld) and ARM NEON (vmul.i32).
- * Vectorization requires a compiler to do the vectorization for us. For recent
- * GCC versions the flags -msse4.1 -funroll-loops -ftree-vectorize are enough
- * to achieve vectorization.
+ * multiplication instruction. Examples include x86 AVX2 extensions (vpmulld)
+ * and ARM NEON (vmul.i32). For simplicity we rely on the compiler to do the
+ * vectorization for us. For GCC and clang the flags -funroll-loops
+ * -ftree-vectorize are enough to achieve vectorization.
*
* The optimal amount of parallelism to use depends on CPU specific instruction
* latency, SIMD instruction width, throughput and the amount of registers
@@ -89,8 +88,9 @@
*
* The parallelism number 32 was chosen based on the fact that it is the
* largest state that fits into architecturally visible x86 SSE registers while
- * leaving some free registers for intermediate values. For future processors
- * with 256bit vector registers this will leave some performance on the table.
+ * leaving some free registers for intermediate values. For processors
+ * with 256bit vector registers this leaves some performance on the table.
+ *
* When vectorization is not available it might be beneficial to restructure
* the computation to calculate a subset of the columns at a time and perform
* multiple passes to avoid register spilling. This optimization opportunity
@@ -138,6 +138,9 @@ do { \
(checksum) = __tmp * FNV_PRIME ^ (__tmp >> 17); \
} while (0)
+/* Provide a static definition for external programs */
+#ifndef PG_CHECKSUM_INTERNAL
+
/*
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
@@ -145,34 +148,13 @@ do { \
static uint32
pg_checksum_block(const PGChecksummablePage *page)
{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
-
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
-
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
-
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
-
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
-
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
-
- return result;
+#include "storage/checksum_block.inc.c"
}
+#else
+static uint32 (*pg_checksum_block) (const PGChecksummablePage *page);
+#endif
+
/*
* Compute the checksum for a Postgres page.
*
diff --git a/src/port/pg_cpu_x86.c b/src/port/pg_cpu_x86.c
index 7575838245c..7ac4c4b3fd5 100644
--- a/src/port/pg_cpu_x86.c
+++ b/src/port/pg_cpu_x86.c
@@ -80,7 +80,7 @@ set_x86_features(void)
{
uint32 xcr0_val = 0;
- /* second cpuid call on leaf 7 to check extended AVX-512 support */
+ /* cpuid call on leaf 7 */
memset(exx, 0, 4 * sizeof(exx[0]));
@@ -95,6 +95,10 @@ set_x86_features(void)
xcr0_val = _xgetbv(0);
#endif
+ /* Are YMM registers enabled? */
+ if (mask_available(xcr0_val, XMM | YMM))
+ X86Features[PG_AVX2] = exx[1] >> 5 & 1;
+
/* Are ZMM registers enabled? */
if (mask_available(xcr0_val, XMM | YMM |
OPMASK | ZMM0_15 | ZMM16_31))
--
2.53.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2026-03-17 02:25 ` John Naylor <[email protected]>
1 sibling, 0 replies; 36+ messages in thread
From: John Naylor @ 2026-03-17 02:25 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
On Tue, Mar 17, 2026 at 9:23 AM John Naylor <[email protected]> wrote:
> I've attached v12 which is just a rebase over the new centralized
> feature detection. I also have some review:
I forgot to mention elsewhere we generated #include-able snippets of
code with the suffix ".inc.c" so I went with that rather than add
exception to headerscheck.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2026-03-30 12:01 ` John Naylor <[email protected]>
2026-03-30 15:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Ants Aasma <[email protected]>
2026-04-04 13:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
1 sibling, 2 replies; 36+ messages in thread
From: John Naylor @ 2026-03-30 12:01 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
On Tue, Mar 17, 2026 at 9:23 AM John Naylor <[email protected]> wrote:
> I've attached v12 which is just a rebase over the new centralized
> feature detection. I also have some review:
Andrew Kim let me know he is not available at this time, so since I
found only minor issues and we're close to feature freeze I took care
of them myself in the attached v13. I also further updated an outdated
comment to reflect that some compilers (for the archives: at least gcc
8.5 and up) can turn a multiplication by a constant into shifts and
adds (the FNV prime is pretty sparse in one-bits), so it's no longer
true that vector multiplication is required. That works on SSE2 and
powerpc, at least.
I don't remember the last time anyone did measurements, so I went
ahead and did that:
master: 945ms
32 AVX2: 335ms
64 AVX2: 220ms
The last one is just to verify an old code comment, and assertion in
this thread, that the choice of 32 accumulators left some performance
on the table. (Even if it weren't in diminishing returns territory, we
wouldn't consider raising this because that changes the computed
value, but if I'm updating comments anyway, I wanted to check as much
as convenient.)
I'll repeat building pg_filedump with this and if that goes well I
plan to push this week unless there are objections.
--
John Naylor
Amazon Web Services
Attachments:
[text/x-patch] v13-0001-Enable-autovectorizing-page-checksums-with-AVX2-.patch (13.6K, 2-v13-0001-Enable-autovectorizing-page-checksums-with-AVX2-.patch)
download | inline diff:
From da15aefd7269b8a342f751e2b5c2c4b9c1b0627c Mon Sep 17 00:00:00 2001
From: John Naylor <[email protected]>
Date: Mon, 2 Mar 2026 17:28:58 +0700
Subject: [PATCH v13] Enable autovectorizing page checksums with AVX2 where
available
We already rely on autovectorization for computing page checksums, but
on x86 we can get nearly three times the performance by annotating
pg_checksum_block() with a function target attribute for AVX2.
That feature set not only uses 256-bit registers, but can also use
vector multiplication rather than the vector shifts and adds available
in SSE2.
This matters most when using io_uring since in that case the checksum
computation is not done in parallel via workers.
Co-authored-by: Matthew Sterrett <[email protected]>
Co-authored-by: Andrew Kim <[email protected]>
Reviewed-by: Oleg Tselebrovskiy <[email protected]>
Discussion: https://postgr.es/m/CA%2BvA85_5GTu%2BHHniSbvvP%2B8k3%3DxZO%3DWE84NPwiKyxztqvpfZ3Q%40mail.gmail.com
Discussion: https://postgr.es/m/20250911054220.3784-1-root%40ip-172-31-36-228.ec2.internal
---
config/c-compiler.m4 | 23 +++++++++++
configure | 46 +++++++++++++++++++++
configure.ac | 9 ++++
meson.build | 28 +++++++++++++
src/backend/storage/page/checksum.c | 44 +++++++++++++++++++-
src/include/pg_config.h.in | 3 ++
src/include/port/pg_cpu.h | 3 ++
src/include/storage/checksum_block.inc.c | 42 +++++++++++++++++++
src/include/storage/checksum_impl.h | 52 ++++++++----------------
src/port/pg_cpu_x86.c | 4 ++
10 files changed, 219 insertions(+), 35 deletions(-)
create mode 100644 src/include/storage/checksum_block.inc.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 629572ee350..4d5acf8be6e 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -687,6 +687,29 @@ fi
undefine([Ac_cachevar])dnl
])# PGAC_SSE42_CRC32_INTRINSICS
+# PGAC_AVX2_SUPPORT
+# ---------------------------
+# Check if the compiler supports AVX2 as a target
+#
+# If AVX2 target attribute is supported, sets pgac_avx2_support.
+AC_DEFUN([PGAC_AVX2_SUPPORT],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_avx2_support])])dnl
+AC_CACHE_CHECK([for AVX2 target attribute support], [Ac_cachevar],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }],
+ [return avx2_test();])],
+ [Ac_cachevar=yes],
+ [Ac_cachevar=no])])
+if test x"$Ac_cachevar" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_AVX2_SUPPORT
+
# PGAC_AVX512_PCLMUL_INTRINSICS
# ---------------------------
# Check if the compiler supports AVX-512 carryless multiplication
diff --git a/configure b/configure
index 8e0e7483c1d..1ae527215c7 100755
--- a/configure
+++ b/configure
@@ -17725,6 +17725,52 @@ $as_echo "#define HAVE__CPUIDEX 1" >>confdefs.h
fi
fi
+# Check for AVX2 target and intrinsic support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVX2 target attribute support" >&5
+$as_echo_n "checking for AVX2 target attribute support... " >&6; }
+if ${pgac_cv_avx2_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #if defined(__has_attribute) && __has_attribute (target)
+ __attribute__((target("avx2")))
+ static int avx2_test(void)
+ {
+ return 0;
+ }
+ #endif
+int
+main ()
+{
+return avx2_test();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_avx2_support=yes
+else
+ pgac_cv_avx2_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_avx2_support" >&5
+$as_echo "$pgac_cv_avx2_support" >&6; }
+if test x"$pgac_cv_avx2_support" = x"yes"; then
+ pgac_avx2_support=yes
+fi
+
+ if test x"$pgac_avx2_support" = x"yes"; then
+
+$as_echo "#define USE_AVX2_WITH_RUNTIME_CHECK 1" >>confdefs.h
+
+ fi
+fi
+
# Check for XSAVE intrinsics
#
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _xgetbv" >&5
diff --git a/configure.ac b/configure.ac
index 2baac5e9da7..a43add51ca6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2129,6 +2129,15 @@ else
fi
fi
+# Check for AVX2 target support
+#
+if test x"$host_cpu" = x"x86_64"; then
+ PGAC_AVX2_SUPPORT()
+ if test x"$pgac_avx2_support" = x"yes"; then
+ AC_DEFINE(USE_AVX2_WITH_RUNTIME_CHECK, 1, [Define to 1 to use AVX2 instructions with a runtime check.])
+ fi
+fi
+
# Check for XSAVE intrinsics
#
PGAC_XSAVE_INTRINSICS()
diff --git a/meson.build b/meson.build
index ea31cbce9c0..5cf23195a6a 100644
--- a/meson.build
+++ b/meson.build
@@ -2451,6 +2451,34 @@ int main(void)
endif
+###############################################################
+# Check if the compiler supports AVX2 as a target
+###############################################################
+
+if host_cpu == 'x86_64'
+
+ prog = '''
+#include <immintrin.h>
+#include <stdint.h>
+__attribute__((target("avx2")))
+static int avx2_test(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ return avx2_test();
+}
+'''
+
+ if cc.links(prog, name: 'AVX2 support', args: test_c_args)
+ cdata.set('USE_AVX2_WITH_RUNTIME_CHECK', 1)
+ endif
+
+endif
+
+
###############################################################
# Check for the availability of AVX-512 popcount intrinsics.
###############################################################
diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c
index 8716651c8b5..7ce51fe9d2e 100644
--- a/src/backend/storage/page/checksum.c
+++ b/src/backend/storage/page/checksum.c
@@ -13,10 +13,52 @@
*/
#include "postgres.h"
+#include "port/pg_cpu.h"
#include "storage/checksum.h"
/*
* The actual code is in storage/checksum_impl.h. This is done so that
* external programs can incorporate the checksum code by #include'ing
- * that file from the exported Postgres headers. (Compare our CRC code.)
+ * that file from the exported Postgres headers. (Compare our legacy
+ * CRC code in pg_crc.h.)
+ * The PG_CHECKSUM_INTERNAL symbol allows core to use hardware-specific
+ * coding without affecting external programs.
*/
+#define PG_CHECKSUM_INTERNAL
#include "storage/checksum_impl.h" /* IWYU pragma: keep */
+
+
+static uint32
+pg_checksum_block_fallback(const PGChecksummablePage *page)
+{
+#include "storage/checksum_block.inc.c"
+}
+
+/*
+ * AVX2-optimized block checksum algorithm.
+ */
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+pg_attribute_target("avx2")
+static uint32
+pg_checksum_block_avx2(const PGChecksummablePage *page)
+{
+#include "storage/checksum_block.inc.c"
+}
+#endif /* USE_AVX2_WITH_RUNTIME_CHECK */
+
+/*
+ * Choose the best available checksum implementation.
+ */
+static uint32
+pg_checksum_choose(const PGChecksummablePage *page)
+{
+ pg_checksum_block = pg_checksum_block_fallback;
+
+#ifdef USE_AVX2_WITH_RUNTIME_CHECK
+ if (x86_feature_available(PG_AVX2))
+ pg_checksum_block = pg_checksum_block_avx2;
+#endif
+
+ return pg_checksum_block(page);
+}
+
+static uint32 (*pg_checksum_block) (const PGChecksummablePage *page) = pg_checksum_choose;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index d8d61918aff..5394a614f87 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -677,6 +677,9 @@
/* Define to 1 to use AVX-512 CRC algorithms with a runtime check. */
#undef USE_AVX512_CRC32C_WITH_RUNTIME_CHECK
+/* Define to 1 to use AVX2 instructions with a runtime check. */
+#undef USE_AVX2_WITH_RUNTIME_CHECK
+
/* Define to 1 to use AVX-512 popcount instructions with a runtime check. */
#undef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
diff --git a/src/include/port/pg_cpu.h b/src/include/port/pg_cpu.h
index b93b828d3ac..c5d96bb4f47 100644
--- a/src/include/port/pg_cpu.h
+++ b/src/include/port/pg_cpu.h
@@ -24,6 +24,9 @@ typedef enum X86FeatureId
PG_SSE4_2,
PG_POPCNT,
+ /* 256-bit YMM registers */
+ PG_AVX2,
+
/* 512-bit ZMM registers */
PG_AVX512_BW,
PG_AVX512_VL,
diff --git a/src/include/storage/checksum_block.inc.c b/src/include/storage/checksum_block.inc.c
new file mode 100644
index 00000000000..6ef8a911145
--- /dev/null
+++ b/src/include/storage/checksum_block.inc.c
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ *
+ * checksum_block.inc.c
+ * Core algorithm for page checksums, semi-private to checksum_impl.h
+ * and checksum.c.
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/storage/checksum_block.inc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* there is deliberately not an #ifndef CHECKSUM_BLOCK_INC_C here */
+
+uint32 sums[N_SUMS];
+uint32 result = 0;
+uint32 i,
+ j;
+
+/* ensure that the size is compatible with the algorithm */
+Assert(sizeof(PGChecksummablePage) == BLCKSZ);
+
+/* initialize partial checksums to their corresponding offsets */
+memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
+
+/* main checksum calculation */
+for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], page->data[i][j]);
+
+/* finally add in two rounds of zeroes for additional mixing */
+for (i = 0; i < 2; i++)
+ for (j = 0; j < N_SUMS; j++)
+ CHECKSUM_COMP(sums[j], 0);
+
+/* xor fold partial checksums together */
+for (i = 0; i < N_SUMS; i++)
+ result ^= sums[i];
+
+return result;
diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h
index 5c2dcbc63e7..28570abdda0 100644
--- a/src/include/storage/checksum_impl.h
+++ b/src/include/storage/checksum_impl.h
@@ -72,12 +72,13 @@
* random segments of page with 0x00, 0xFF and random data all show optimal
* 2e-16 false positive rate within margin of error.
*
- * Vectorization of the algorithm requires 32bit x 32bit -> 32bit integer
- * multiplication instruction. As of 2013 the corresponding instruction is
- * available on x86 SSE4.1 extensions (pmulld) and ARM NEON (vmul.i32).
- * Vectorization requires a compiler to do the vectorization for us. For recent
- * GCC versions the flags -msse4.1 -funroll-loops -ftree-vectorize are enough
- * to achieve vectorization.
+ * Vectorization of the algorithm works best with a 32bit x 32bit -> 32bit
+ * vector integer multiplication instruction, Examples include x86 AVX2
+ * extensions (vpmulld) and ARM NEON (vmul.i32). Without that, vectorization
+ * is still possible if the compiler can turn multiplication by FNV_PRIME
+ * into a sequence of vectorized shifts and adds. For simplicity we rely
+ * on the compiler to do the vectorization for us. For GCC and clang the
+ * flags -funroll-loops -ftree-vectorize are enough to achieve vectorization.
*
* The optimal amount of parallelism to use depends on CPU specific instruction
* latency, SIMD instruction width, throughput and the amount of registers
@@ -89,8 +90,9 @@
*
* The parallelism number 32 was chosen based on the fact that it is the
* largest state that fits into architecturally visible x86 SSE registers while
- * leaving some free registers for intermediate values. For future processors
- * with 256bit vector registers this will leave some performance on the table.
+ * leaving some free registers for intermediate values. For processors
+ * with 256-bit vector registers this leaves some performance on the table.
+ *
* When vectorization is not available it might be beneficial to restructure
* the computation to calculate a subset of the columns at a time and perform
* multiple passes to avoid register spilling. This optimization opportunity
@@ -138,6 +140,9 @@ do { \
(checksum) = __tmp * FNV_PRIME ^ (__tmp >> 17); \
} while (0)
+/* Provide a static definition for external programs */
+#ifndef PG_CHECKSUM_INTERNAL
+
/*
* Block checksum algorithm. The page must be adequately aligned
* (at least on 4-byte boundary).
@@ -145,34 +150,13 @@ do { \
static uint32
pg_checksum_block(const PGChecksummablePage *page)
{
- uint32 sums[N_SUMS];
- uint32 result = 0;
- uint32 i,
- j;
-
- /* ensure that the size is compatible with the algorithm */
- Assert(sizeof(PGChecksummablePage) == BLCKSZ);
-
- /* initialize partial checksums to their corresponding offsets */
- memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets));
-
- /* main checksum calculation */
- for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], page->data[i][j]);
-
- /* finally add in two rounds of zeroes for additional mixing */
- for (i = 0; i < 2; i++)
- for (j = 0; j < N_SUMS; j++)
- CHECKSUM_COMP(sums[j], 0);
-
- /* xor fold partial checksums together */
- for (i = 0; i < N_SUMS; i++)
- result ^= sums[i];
-
- return result;
+#include "storage/checksum_block.inc.c"
}
+#else
+static uint32 (*pg_checksum_block) (const PGChecksummablePage *page);
+#endif
+
/*
* Compute the checksum for a Postgres page.
*
diff --git a/src/port/pg_cpu_x86.c b/src/port/pg_cpu_x86.c
index e2ab92b09ac..f069afd1c53 100644
--- a/src/port/pg_cpu_x86.c
+++ b/src/port/pg_cpu_x86.c
@@ -121,6 +121,10 @@ set_x86_features(void)
xcr0_val = _xgetbv(0);
#endif
+ /* Are YMM registers enabled? */
+ if (mask_available(xcr0_val, XMM | YMM))
+ X86Features[PG_AVX2] = reg[EBX] >> 5 & 1;
+
/* Are ZMM registers enabled? */
if (mask_available(xcr0_val, XMM | YMM |
OPMASK | ZMM0_15 | ZMM16_31))
--
2.53.0
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 12:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2026-03-30 15:00 ` Ants Aasma <[email protected]>
2026-03-31 04:09 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
1 sibling, 1 reply; 36+ messages in thread
From: Ants Aasma @ 2026-03-30 15:00 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: Andrew Kim <[email protected]>; Oleg Tselebrovskiy <[email protected]>; [email protected]
On Mon, 30 Mar 2026 at 15:01, John Naylor <[email protected]> wrote:
> I don't remember the last time anyone did measurements, so I went
> ahead and did that:
>
> master: 945ms
> 32 AVX2: 335ms
> 64 AVX2: 220ms
I'm guessing this is on a recent Intel. Any extra width is helpful on Intel
as they doubled vpmulld latency from under us after we had settled on this
algorithm. uops.info shows that the most recent Arrow Lake-P cores bring
the latency down to 5. B Intels product lineup is so confusing that it's
hard to tell which products this core ships in. As far as I can tell not in
any Xeons yet. AMD has had 3 cycle vpmulld since Zen 3.
Out of curiosity I tried some approximate numbers on Zen 5 for differing
N_SUMS values. Numbers are ns per iteration for 10M iterations.
GCC 15.2 -O3:
n16 n32 n64 n128 n256
x86-64 620.1 482.4 493.9 543.1 584.0
x86-64-v2 188.6 125.5 121.3 183.9 196.6
x86-64-v3 185.2 101.3 63.2 60.9 101.6
x86-64-v4 182.9 86.0 53.9 35.4 30.5
native 178.2 84.7 54.0 34.5 30.9
clang 20.1 -O3:
n16 n32 n64 n128 n256
x86-64 611.7 264.0 254.7 283.9 304.0
x86-64-v2 603.7 134.0 137.9 236.1 165.8
x86-64-v3 252.1 103.2 61.9 124.0 96.9
x86-64-v4 223.9 102.1 61.4 101.7 68.9
native 203.3 91.0 54.5 35.0 40.4
FWIW I think AVX2 (x86-64-v3) is fine. On AMD the speed is close to core to
fabric bandwidth and Intel has significantly less bandwidth on server chips.
Regards,
Ants Aasma
Attachments:
[text/x-csrc] bench-checksums.c (1023B, 3-bench-checksums.c)
download | inline:
#include "postgres.h"
#include "storage/checksum_impl.h"
#include <time.h>
#undef printf
int __attribute__ ((noinline)) checksum_block(char *page, uint32 blockno)
{
return pg_checksum_page(page, blockno);
}
int main(int argc, char *argv[]) {
char *page;
uint64 i;
uint64 sum = 0;
struct timespec start;
struct timespec end;
double delta;
if (argc<3) {
printf("Usage: %s niterations nblocks\n", argv[0]);
return 1;
}
uint64 n = strtoull(argv[1], 0, 10);
uint64 b = strtoull(argv[2], 0, 10);
page = malloc(BLCKSZ*b);
for (i = 0; i < BLCKSZ*b; i++)
page[i] = (i*997) & 0xFF;
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
for (i = 0; i < n; i++)
sum += checksum_block(page + BLCKSZ*(i % b), (uint32) i);
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
delta = (double)(end.tv_sec - start.tv_sec) + (1e-9*(double) (end.tv_nsec - start.tv_nsec));
printf("%0.5fms @ %0.3f GB/s\n", delta*1000, (((double) BLCKSZ) * n)/delta/1e9);
printf(" %0.1fns per iteration\n", delta*1e9/n);
return 0;
}
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 12:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 15:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Ants Aasma <[email protected]>
@ 2026-03-31 04:09 ` John Naylor <[email protected]>
0 siblings, 0 replies; 36+ messages in thread
From: John Naylor @ 2026-03-31 04:09 UTC (permalink / raw)
To: Ants Aasma <[email protected]>; +Cc: Andrew Kim <[email protected]>; Oleg Tselebrovskiy <[email protected]>; [email protected]
On Mon, Mar 30, 2026 at 10:01 PM Ants Aasma <[email protected]> wrote:
>
> On Mon, 30 Mar 2026 at 15:01, John Naylor <[email protected]> wrote:
> > I don't remember the last time anyone did measurements, so I went
> > ahead and did that:
> >
> > master: 945ms
> > 32 AVX2: 335ms
> > 64 AVX2: 220ms
>
> I'm guessing this is on a recent Intel. Any extra width is helpful on Intel as they doubled vpmulld latency from under us after we had settled on this algorithm.
It's actually ancient and due to be replaced soon, but still several
years after the adoption of this algorithm.
> FWIW I think AVX2 (x86-64-v3) is fine.
Glad to hear it, although the patch doesn't use that build flag, so
it's not impossible there is some additional difference in the
compiler's model. Still, given the variation you found, I'll make sure
the commit message says "several time faster" so it's not specific to
my hardware.
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 12:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2026-04-04 13:25 ` John Naylor <[email protected]>
2026-04-13 08:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
1 sibling, 1 reply; 36+ messages in thread
From: John Naylor @ 2026-04-04 13:25 UTC (permalink / raw)
To: Andrew Kim <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
On Mon, Mar 30, 2026 at 7:01 PM John Naylor <[email protected]> wrote:
> I'll repeat building pg_filedump with this and if that goes well I
> plan to push this week unless there are objections.
Something change in my environment, or something, because I can't
build pg_filedump anymore, although it hasn't had any recent new
commits:
pg_config
/bin/sh: line 1: mkdir: command not found
Looks like something messed with PATH, but I don't think it was me. In
any case, very little has changed in the patch since I last built
pg_filedump successfully, so I won't worry yet.
I pushed with a couple cosmetic adjustments:
- Removed no-longer-needed #includes from configure checks
- Added a comment that we deliberately don't guard on __has_attribute
- switch things around to use #ifdef instead of #ifndef for clarity
Thanks Andrew, for picking this up again!
--
John Naylor
Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-09-24 21:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-02 05:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-17 07:15 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-21 03:30 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-10-24 07:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-10-29 02:50 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-05 23:49 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-14 11:34 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-18 03:32 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2025-11-18 04:48 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2025-11-19 01:18 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-16 08:00 ` Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
2026-03-17 02:23 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-03-30 12:01 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
2026-04-04 13:25 ` Re: Proposal for enabling auto-vectorization for checksum calculations John Naylor <[email protected]>
@ 2026-04-13 08:32 ` Andrew Kim <[email protected]>
0 siblings, 0 replies; 36+ messages in thread
From: Andrew Kim @ 2026-04-13 08:32 UTC (permalink / raw)
To: John Naylor <[email protected]>; +Cc: Oleg Tselebrovskiy <[email protected]>; [email protected]
On Sat, Apr 4, 2026 at 6:25 AM John Naylor <[email protected]> wrote:
>
> On Mon, Mar 30, 2026 at 7:01 PM John Naylor <[email protected]> wrote:
> > I'll repeat building pg_filedump with this and if that goes well I
> > plan to push this week unless there are objections.
>
> Something change in my environment, or something, because I can't
> build pg_filedump anymore, although it hasn't had any recent new
> commits:
>
> pg_config
> /bin/sh: line 1: mkdir: command not found
>
> Looks like something messed with PATH, but I don't think it was me. In
> any case, very little has changed in the patch since I last built
> pg_filedump successfully, so I won't worry yet.
>
> I pushed with a couple cosmetic adjustments:
>
> - Removed no-longer-needed #includes from configure checks
> - Added a comment that we deliberately don't guard on __has_attribute
> - switch things around to use #ifdef instead of #ifndef for clarity
>
> Thanks Andrew, for picking this up again!
Thank you for taking care of the final adjustments and pushing the
patch to master.
Thank you again for your guidance and for steering this through to the
finish line.
It was a pleasure collaborating with you on this optimization.
- Andrew
>
> --
> John Naylor
> Amazon Web Services
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
@ 2025-09-11 06:06 [email protected]
0 siblings, 0 replies; 36+ messages in thread
From: [email protected] @ 2025-09-11 06:06 UTC (permalink / raw)
To: [email protected]; +Cc: [email protected]; [email protected]
Hi John,
Thanks for the feedback. This is v5 of the patchset, updated following your comments:
- Moved the function pointer definitions out of common headers and
into src/port, consistent with existing practice.
Thanks again for the guidance.
Best regards,
Kim Andrew
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
@ 2025-09-11 06:21 [email protected]
0 siblings, 0 replies; 36+ messages in thread
From: [email protected] @ 2025-09-11 06:21 UTC (permalink / raw)
To: Matthew Sterrett <[email protected]>; +Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Hi John,
Thanks for the feedback. This is v5 of the patchset, updated following your comments:
- Moved the function pointer definitions out of common headers and
into src/port, consistent with existing practice.
Thanks again for the guidance.
Best regards,
Kim Andrew
^ permalink raw reply [nested|flat] 36+ messages in thread
* Re: Proposal for enabling auto-vectorization for checksum calculations
@ 2025-09-17 01:10 Andrew Kim <[email protected]>
0 siblings, 0 replies; 36+ messages in thread
From: Andrew Kim @ 2025-09-17 01:10 UTC (permalink / raw)
To: [email protected]; +Cc: [email protected]; Matthew Sterrett <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; Andrew Kim <[email protected]>; Andrew Kim <[email protected]>; [email protected]
> I don't know if this is related to the crashes, but it doesn't seem
> like a good idea to #include the function pointer stuff everywhere,
> that should probably go into src/port like the others.
Just a gentle reminder on this patch series — I’ve already rebased it on
the latest tip of master and addressed the earlier review comments:
* Moved the function pointer definitions into src/port as suggested.
* Rebased cleanly on the current master branch.
Could someone take another look and share any further feedback?
Thanks a lot for your time and review,
Andrew Kim
^ permalink raw reply [nested|flat] 36+ messages in thread
end of thread, other threads:[~2026-04-13 08:32 UTC | newest]
Thread overview: 36+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-04-04 22:03 Proposal for enabling auto-vectorization for checksum calculations Matthew Sterrett <[email protected]>
2025-05-07 23:57 ` Matthew Sterrett <[email protected]>
2025-05-10 11:01 ` Stepan Neretin <[email protected]>
2025-05-10 11:01 ` Stepan Neretin <[email protected]>
2025-05-19 23:54 ` Matthew Sterrett <[email protected]>
2025-05-20 14:42 ` Nazir Bilal Yavuz <[email protected]>
2025-05-22 21:54 ` Matthew Sterrett <[email protected]>
2025-06-02 12:11 ` John Naylor <[email protected]>
2025-09-11 05:42 Re: Proposal for enabling auto-vectorization for checksum calculations root <[email protected]>
2025-09-24 06:32 ` John Naylor <[email protected]>
2025-09-24 21:50 ` Andrew Kim <[email protected]>
2025-10-02 05:25 ` John Naylor <[email protected]>
2025-10-17 07:15 ` Andrew Kim <[email protected]>
2025-10-17 10:53 ` Oleg Tselebrovskiy <[email protected]>
2025-10-18 21:30 ` Andrew Kim <[email protected]>
2025-10-20 15:05 ` Oleg Tselebrovskiy <[email protected]>
2025-10-24 08:09 ` Andrew Kim <[email protected]>
2025-10-21 03:30 ` John Naylor <[email protected]>
2025-10-24 07:48 ` Andrew Kim <[email protected]>
2025-10-29 02:50 ` John Naylor <[email protected]>
2025-11-05 23:49 ` Andrew Kim <[email protected]>
2025-11-14 11:34 ` John Naylor <[email protected]>
2025-11-18 03:32 ` Andrew Kim <[email protected]>
2025-11-18 04:48 ` John Naylor <[email protected]>
2025-11-19 01:18 ` Andrew Kim <[email protected]>
2026-03-16 08:00 ` Andrew Kim <[email protected]>
2026-03-17 02:23 ` John Naylor <[email protected]>
2026-03-17 02:25 ` John Naylor <[email protected]>
2026-03-30 12:01 ` John Naylor <[email protected]>
2026-03-30 15:00 ` Ants Aasma <[email protected]>
2026-03-31 04:09 ` John Naylor <[email protected]>
2026-04-04 13:25 ` John Naylor <[email protected]>
2026-04-13 08:32 ` Andrew Kim <[email protected]>
2025-09-11 06:06 Re: Proposal for enabling auto-vectorization for checksum calculations [email protected]
2025-09-11 06:21 Re: Proposal for enabling auto-vectorization for checksum calculations [email protected]
2025-09-17 01:10 Re: Proposal for enabling auto-vectorization for checksum calculations Andrew Kim <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox