diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index ac3e763de43..46b4ca4b0f1 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -1444,6 +1444,7 @@ bms_join(Bitmapset *a, Bitmapset *b) int bms_next_member(const Bitmapset *a, int prevbit) { + int64 currbit; int nwords; bitmapword mask; @@ -1452,13 +1453,13 @@ bms_next_member(const Bitmapset *a, int prevbit) if (a == NULL) return -2; nwords = a->nwords; - prevbit++; - mask = (~(bitmapword) 0) << BITNUM(prevbit); - for (int wordnum = WORDNUM(prevbit); wordnum < nwords; wordnum++) + currbit = (int64) prevbit + 1; + mask = (~(bitmapword) 0) << BITNUM(currbit); + for (int wordnum = WORDNUM(currbit); wordnum < nwords; wordnum++) { bitmapword w = a->words[wordnum]; - /* ignore bits before prevbit */ + /* ignore bits before currbit */ w &= mask; if (w != 0) @@ -1505,6 +1506,7 @@ int bms_prev_member(const Bitmapset *a, int prevbit) { int ushiftbits; + uint32 currbit; bitmapword mask; Assert(bms_is_valid_set(a)); @@ -1517,18 +1519,18 @@ bms_prev_member(const Bitmapset *a, int prevbit) return -2; /* Validate callers didn't give us something out of range */ - Assert(prevbit <= a->nwords * BITS_PER_BITMAPWORD); + Assert(prevbit <= (int64) a->nwords * BITS_PER_BITMAPWORD); Assert(prevbit >= -1); /* transform -1 to the highest possible bit we could have set */ if (prevbit == -1) - prevbit = a->nwords * BITS_PER_BITMAPWORD - 1; + currbit = (uint32) a->nwords * BITS_PER_BITMAPWORD - 1; else - prevbit--; + currbit = prevbit - 1; - ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(prevbit) + 1); + ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(currbit) + 1); mask = (~(bitmapword) 0) >> ushiftbits; - for (int wordnum = WORDNUM(prevbit); wordnum >= 0; wordnum--) + for (int wordnum = WORDNUM(currbit); wordnum >= 0; wordnum--) { bitmapword w = a->words[wordnum]; diff --git a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql index 6668bcef9a9..d6c0f739e13 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql +++ b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql @@ -3,6 +3,15 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION test_bitmapset" to load this file. \quit +-- Benchmark functions +CREATE FUNCTION bench_bms_next_member(text, integer) +RETURNS bigint +AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION bench_bms_prev_member(text, integer) +RETURNS bigint +AS 'MODULE_PATHNAME' LANGUAGE C; + -- Bitmapset API functions CREATE FUNCTION test_bms_make_singleton(integer) RETURNS text STRICT diff --git a/src/test/modules/test_bitmapset/test_bitmapset.c b/src/test/modules/test_bitmapset/test_bitmapset.c index 4fe22ee64d2..990347a0f22 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset.c +++ b/src/test/modules/test_bitmapset/test_bitmapset.c @@ -17,6 +17,7 @@ #include "postgres.h" #include +#include #include "catalog/pg_type.h" #include "common/pg_prng.h" #include "utils/array.h" @@ -27,8 +28,13 @@ #include "utils/builtins.h" #include "utils/timestamp.h" + PG_MODULE_MAGIC; +/* Benchmark functions */ +PG_FUNCTION_INFO_V1(bench_bms_next_member); +PG_FUNCTION_INFO_V1(bench_bms_prev_member); + /* Bitmapset API functions in order of appearance in bitmapset.c */ PG_FUNCTION_INFO_V1(test_bms_make_singleton); PG_FUNCTION_INFO_V1(test_bms_add_member); @@ -105,6 +111,73 @@ PG_FUNCTION_INFO_V1(test_random_shift_operations); #define PG_RETURN_BITMAPSET_AS_TEXT(bms) \ PG_RETURN_TEXT_P(BITMAPSET_TO_TEXT(bms)) +#define NANOSEC_PER_SEC 1000000000 + +int64 get_clock_diff(struct timespec* t1, struct timespec* t2); + +int64 +get_clock_diff(struct timespec* t1, struct timespec* t2) +{ + int64_t nanosec = (t1->tv_sec - t2->tv_sec) * NANOSEC_PER_SEC; + nanosec += (t1->tv_nsec - t2->tv_nsec); + + return nanosec; +} + +Datum +bench_bms_next_member(PG_FUNCTION_ARGS) +{ + Bitmapset* bms = PG_ARG_GETBITMAPSET(0); + int32 loops = PG_GETARG_INT32(1); + + struct timespec start, end; + int64 nanoseconds; + int64 counter = 0; + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + + for (int i = 0; i < loops; i++) + { + int m = -1; + while ((m = bms_next_member(bms, m)) >= 0) + { + counter++; + } + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + nanoseconds = get_clock_diff(&end, &start); + + PG_RETURN_INT64(nanoseconds); +} + +Datum +bench_bms_prev_member(PG_FUNCTION_ARGS) +{ + Bitmapset* bms = PG_ARG_GETBITMAPSET(0); + int32 loops = PG_GETARG_INT32(1); + + struct timespec start, end; + int64 nanoseconds; + int64 counter = 0; + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + + for (int i = 0; i < loops; i++) + { + int m = -1; + while ((m = bms_prev_member(bms, m)) >= 0) + { + counter++; + } + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + nanoseconds = get_clock_diff(&end, &start); + + PG_RETURN_INT64(nanoseconds); +} + /* * Individual test functions for each bitmapset API function *