public inbox for [email protected]help / color / mirror / Atom feed
[PATCH v2 1/1] resownerbench 43+ messages / 2 participants [nested] [flat]
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..18c54e13fc9 --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000), + (0, 5, 2000000), + (0, 10, 1000000), + (0, 60, 100000), + (0, 70, 100000), + (0, 100, 100000), + (0, 1000, 10000), + (0, 10000, 1000), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000), + (9, 100, 100000), + (9, 1000, 10000), + (9, 10000, 1000), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000), + (65, 100, 100000), + (65, 1000, 10000), + (65, 10000, 1000) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------1104342304EC6341F5D7C60C-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* [PATCH v2 1/1] resownerbench @ 2020-11-11 22:40 Heikki Linnakangas <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Heikki Linnakangas @ 2020-11-11 22:40 UTC (permalink / raw) --- contrib/resownerbench/Makefile | 17 ++ contrib/resownerbench/resownerbench--1.0.sql | 14 ++ contrib/resownerbench/resownerbench.c | 154 +++++++++++++++++++ contrib/resownerbench/resownerbench.control | 6 + contrib/resownerbench/snaptest.sql | 37 +++++ 5 files changed, 228 insertions(+) create mode 100644 contrib/resownerbench/Makefile create mode 100644 contrib/resownerbench/resownerbench--1.0.sql create mode 100644 contrib/resownerbench/resownerbench.c create mode 100644 contrib/resownerbench/resownerbench.control create mode 100644 contrib/resownerbench/snaptest.sql diff --git a/contrib/resownerbench/Makefile b/contrib/resownerbench/Makefile new file mode 100644 index 00000000000..9b0e1cfee1a --- /dev/null +++ b/contrib/resownerbench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = resownerbench +OBJS = resownerbench.o + +EXTENSION = resownerbench +DATA = resownerbench--1.0.sql +PGFILEDESC = "resownerbench - benchmark for ResourceOwners" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/resownerbench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/resownerbench/resownerbench--1.0.sql b/contrib/resownerbench/resownerbench--1.0.sql new file mode 100644 index 00000000000..d29182f5982 --- /dev/null +++ b/contrib/resownerbench/resownerbench--1.0.sql @@ -0,0 +1,14 @@ +/* contrib/resownerbench/resownerbench--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION resownerbench" to load this file. \quit + +CREATE FUNCTION snapshotbench_lifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_lifo' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION snapshotbench_fifo(numkeep int, numsnaps int, numiters int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'snapshotbench_fifo' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/resownerbench/resownerbench.c b/contrib/resownerbench/resownerbench.c new file mode 100644 index 00000000000..acfb6c39199 --- /dev/null +++ b/contrib/resownerbench/resownerbench.c @@ -0,0 +1,154 @@ +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/snapmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(snapshotbench_lifo); +PG_FUNCTION_INFO_V1(snapshotbench_fifo); + +/* + * ResourceOwner Performance test, using RegisterSnapshot(). + * + * This takes three parameters: numkeep, numsnaps, numiters. + * + * First, we register 'numkeep' snapshots. They are kept registed + * until the end of the test. Then, we repeatedly register and + * unregister 'numsnaps - numkeep' additional snapshots, repeating + * 'numiters' times. All the register/unregister calls are made in + * LIFO order. + * + * Returns the time spent, in milliseconds. + * + * The idea is to test the performance of ResourceOwnerRemember() + * and ReourceOwnerForget() operations, under different regimes. + * + * In the old implementation, if 'numsnaps' is small enough, all + * the entries fit in the resource owner's small array (it can + * hold 64 entries). + * + * In the new implementation, the array is much smaller, only 8 + * entries, but it's used together with the hash table so that + * we stay in the "array regime" as long as 'numsnaps - numkeep' + * is smaller than 8 entries. + * + * 'numiters' can be adjusted to adjust the overall runtime to be + * suitable long. + */ +Datum +snapshotbench_lifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + while (numregistered > numkeep) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + } + + while (numregistered > 0) + { + numregistered--; + UnregisterSnapshot(rs[numregistered]); + } + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; + + +/* + * Same, but do the register/unregister operations in + * FIFO order. + */ +Datum +snapshotbench_fifo(PG_FUNCTION_ARGS) +{ + int numkeep = PG_GETARG_INT32(0); + int numsnaps = PG_GETARG_INT32(1); + int numiters = PG_GETARG_INT32(2); + int i, + j; + instr_time start, + duration; + Snapshot lsnap; + Snapshot *rs; + int numregistered = 0; + + rs = palloc(Max(numsnaps, numkeep) * sizeof(Snapshot)); + + lsnap = GetLatestSnapshot(); + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + + while (numregistered < numkeep) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (i = 0 ; i < numiters; i++) + { + while (numregistered < numsnaps) + { + rs[numregistered] = RegisterSnapshot(lsnap); + numregistered++; + } + + for (j = numkeep; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + } + + for (j = 0; j < numregistered; j++) + UnregisterSnapshot(rs[j]); + numregistered = numkeep; + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(duration)); +}; diff --git a/contrib/resownerbench/resownerbench.control b/contrib/resownerbench/resownerbench.control new file mode 100644 index 00000000000..ada88b8eed8 --- /dev/null +++ b/contrib/resownerbench/resownerbench.control @@ -0,0 +1,6 @@ +# resownerbench + +comment = 'benchmark for ResourceOwners' +default_version = '1.0' +module_pathname = '$libdir/resownerbench' +relocatable = true diff --git a/contrib/resownerbench/snaptest.sql b/contrib/resownerbench/snaptest.sql new file mode 100644 index 00000000000..e3c0a9710ee --- /dev/null +++ b/contrib/resownerbench/snaptest.sql @@ -0,0 +1,37 @@ +-- +-- Performance test RegisterSnapshot/UnregisterSnapshot. +-- +select numkeep, numsnaps, + -- numiters, + -- round(lifo_time_ms) as lifo_total_time_ms, + -- round(fifo_time_ms) as fifo_total_time_ms, + round((lifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as lifo_time_ns, + round((fifo_time_ms::numeric / (numkeep + (numsnaps - numkeep) * numiters)) * 1000000, 1) as fifo_time_ns +from +(values (0, 1, 10000000 * 10), + (0, 5, 2000000 * 10), + (0, 10, 1000000 * 10), + (0, 60, 100000 * 10), + (0, 70, 100000 * 10), + (0, 100, 100000 * 10), + (0, 1000, 10000 * 10), + (0, 10000, 1000 * 10), + +-- These tests keep 9 snapshots registered across the iterations. That +-- exceeds the size of the little array in the patch, so this exercises +-- the hash lookups. Without the patch, these still fit in the array +-- (it's 64 entries without the patch) + (9, 10, 10000000 * 10), + (9, 100, 100000 * 10), + (9, 1000, 10000 * 10), + (9, 10000, 1000 * 10), + +-- These exceed the 64 entry array even without the patch, so these fall +-- in the hash table regime with and without the patch. + (65, 70, 1000000 * 10), + (65, 100, 100000 * 10), + (65, 1000, 10000 * 10), + (65, 10000, 1000 * 10) +) AS params (numkeep, numsnaps, numiters), +lateral snapshotbench_lifo(numkeep, numsnaps, numiters) as lifo_time_ms, +lateral snapshotbench_fifo(numkeep, numsnaps, numiters) as fifo_time_ms; -- 2.29.2 --------------F30A5443A5D524A5CBC51AE7-- ^ permalink raw reply [nested|flat] 43+ messages in thread
* Cleaning up threading code @ 2023-06-10 02:23 Thomas Munro <[email protected]> 0 siblings, 0 replies; 43+ messages in thread From: Thomas Munro @ 2023-06-10 02:23 UTC (permalink / raw) To: pgsql-hackers Hi, This message is not about inventing backend threads, but I was reminded to post this by some thought-provoking hallway track discussion of that large topic at PGCon, mostly with Heikki. 1. We should completely remove --disable-thread-safety and the various !defined(ENABLE_THREAD_SAFETY) code paths. There are no computers that need it, it's not being tested, and support was already dropped/hardcoded in meson.build. Here is a mostly mechanical patch to finish that job, originally posted in one of the big 'historical baggage' threads -- I just didn't get around to committing in time for 16. Also a couple of related tiny cleanups for port/thread.c, which is by now completely bogus. 2. I don't like the way we have to deal with POSIX vs Windows at every site where we use threads, and each place has a different style of wrappers. I considered a few different approaches to cleaning this up: * provide centralised and thorough pthread emulation for Windows; I don't like this, I don't even like all of pthreads and there are many details to get lost in * adopt C11 <threads.h>; unfortunately it is too early, so you'd need to write/borrow replacements for at least 3 of our 11 target systems * invent our own mini-abstraction for a carefully controlled subset of stuff Here is an attempt at that last thing. Since I don't really like making up new names for things, I just used all the C11 names but with pg_ in front, and declared it all in "port/pg_threads.h" (actually I tried to write C11 replacements and then noped out and added the pg_ prefixes). I suppose the idea is that it and the prefixes might eventually go away. Note: here I am talking only about very basic operations like create, exit, join, explicit thread locals -- the stuff that we actually use today in frontend code. I'm not talking about other stuff like C11 atomics, memory models, and the thread_local storage class, which are all very good and interesting topics for another day. One mystery still eludes me on Windows: while trying to fix the ancient bug that ECPG leaks memory on Windows, because it doesn't call thread-local destructors, I discovered that if you use FlsAlloc instead of TlsAlloc you can pass in a destructor (that's "fibre-local", but we're not using fibres so it's works out the same as thread local AFAICT). It seems to crash in strange ways if you uncomment the line FlsAlloc(destructor). Maybe it calls the destructor even for NULL value? Or maybe it suffers from some kind of Windowsian multiple-heaps-active problem. I noticed that some other attempts at implementing tss on Windows use TlsAlloc but do their own bookkeeping of destructors and run them at thread exit, which I was hoping to avoid, but ... Before I spend time fixing that issue or seeking Windowsian help... do you think this direction is an improvement? Attachments: [text/x-patch] 0001-Remove-obsolete-comments-and-code-from-fe-auth.c.patch (1.3K, ../../CA+hUKGLtmexrpMtxBRLCVePqV_dtWG-ZsEbyPrYc+NBB2TkNsw@mail.gmail.com/2-0001-Remove-obsolete-comments-and-code-from-fe-auth.c.patch) download | inline diff: From 4d0d568fba15543070e7b7e501e1748ae6aab821 Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> Date: Fri, 9 Jun 2023 13:56:21 +1200 Subject: [PATCH 1/5] Remove obsolete comments and code from fe-auth.c. We don't use getpwuid() anymore (see commit e757cdd6), so we don't need locking around pg_get_user_name(). --- src/interfaces/libpq/fe-auth.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 88fd0f3d80..b65333268f 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -1179,15 +1179,6 @@ pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage) char pwdbuf[BUFSIZ]; #endif - /* - * Some users are using configure --enable-thread-safety-force, so we - * might as well do the locking within our library to protect getpwuid(). - * In fact, application developers can use getpwuid() in their application - * if they use the locking call we provide, or install their own locking - * function using PQregisterThreadLock(). - */ - pglock_thread(); - #ifdef WIN32 if (GetUserName(username, &namesize)) name = username; @@ -1209,8 +1200,6 @@ pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage) libpq_append_error(errorMessage, "out of memory"); } - pgunlock_thread(); - return result; } -- 2.39.2 [text/x-patch] 0002-Rename-port-thread.c-to-port-user.c.patch (2.7K, ../../CA+hUKGLtmexrpMtxBRLCVePqV_dtWG-ZsEbyPrYc+NBB2TkNsw@mail.gmail.com/3-0002-Rename-port-thread.c-to-port-user.c.patch) download | inline diff: From 6991b8cea31833359bb56c7cfa880507a5b314a7 Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> Date: Sat, 10 Jun 2023 12:26:04 +1200 Subject: [PATCH 2/5] Rename port/thread.c to port/user.c. Historically this module dealt with non-threadsafe system interfaces for user name and home directory lookup, but now it's just wrapper code. Arguably the Windows variants of this logic could be moved in here too, to justify its presence under port, but for now, just tidy up obsolete references to threads. --- src/port/Makefile | 6 +----- src/port/meson.build | 2 +- src/port/{thread.c => user.c} | 13 +++---------- 3 files changed, 5 insertions(+), 16 deletions(-) rename src/port/{thread.c => user.c} (88%) diff --git a/src/port/Makefile b/src/port/Makefile index 711f59e32b..f205c2c9c5 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -59,7 +59,7 @@ OBJS = \ snprintf.o \ strerror.o \ tar.o \ - thread.o + user.o # libpgport.a, libpgport_shlib.a, and libpgport_srv.a contain the same files # foo.o, foo_shlib.o, and foo_srv.o are all built from foo.c @@ -84,10 +84,6 @@ libpgport.a: $(OBJS) rm -f $@ $(AR) $(AROPT) $@ $^ -# thread.o and thread_shlib.o need PTHREAD_CFLAGS (but thread_srv.o does not) -thread.o: CFLAGS+=$(PTHREAD_CFLAGS) -thread_shlib.o: CFLAGS+=$(PTHREAD_CFLAGS) - # all versions of pg_crc32c_sse42.o need CFLAGS_CRC pg_crc32c_sse42.o: CFLAGS+=$(CFLAGS_CRC) pg_crc32c_sse42_shlib.o: CFLAGS+=$(CFLAGS_CRC) diff --git a/src/port/meson.build b/src/port/meson.build index 24416b9bfc..9d0cd93c43 100644 --- a/src/port/meson.build +++ b/src/port/meson.build @@ -20,7 +20,7 @@ pgport_sources = [ 'snprintf.c', 'strerror.c', 'tar.c', - 'thread.c', + 'user.c', ] if host_system == 'windows' diff --git a/src/port/thread.c b/src/port/user.c similarity index 88% rename from src/port/thread.c rename to src/port/user.c index 375c89b297..d278684fe2 100644 --- a/src/port/thread.c +++ b/src/port/user.c @@ -1,13 +1,12 @@ /*------------------------------------------------------------------------- * - * thread.c + * user.c * - * Prototypes and macros around system calls, used to help make - * threaded libraries reentrant and safe to use from threaded applications. + * Wrapper functions for user and home directory lookup. * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * - * src/port/thread.c + * src/port/user.c * *------------------------------------------------------------------------- */ @@ -16,12 +15,6 @@ #include <pwd.h> - -/* - * Historically, the code in this module had to deal with operating systems - * that lacked getpwuid_r(). - */ - #ifndef WIN32 /* -- 2.39.2 [text/x-patch] 0003-Remove-disable-thread-safety.patch (59.4K, ../../CA+hUKGLtmexrpMtxBRLCVePqV_dtWG-ZsEbyPrYc+NBB2TkNsw@mail.gmail.com/4-0003-Remove-disable-thread-safety.patch) download | inline diff: From 394bc4cbb9ae881de9b0c2442d1392352adc3229 Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> Date: Fri, 9 Jun 2023 14:07:26 +1200 Subject: [PATCH 3/5] Remove --disable-thread-safety. All supported computers have either POSIX or Windows threads, and we no longer have any automated testing of --disable-thread-safety. --- configure | 56 ++------------- configure.ac | 28 ++------ doc/src/sgml/installation.sgml | 13 ---- meson.build | 11 --- src/Makefile.global.in | 1 - src/bin/pgbench/pgbench.c | 22 +----- src/include/pg_config.h.in | 4 -- src/interfaces/ecpg/ecpglib/connect.c | 40 ----------- src/interfaces/ecpg/ecpglib/descriptor.c | 10 --- src/interfaces/ecpg/ecpglib/ecpglib_extern.h | 2 - src/interfaces/ecpg/ecpglib/execute.c | 2 - src/interfaces/ecpg/ecpglib/memory.c | 7 -- src/interfaces/ecpg/ecpglib/misc.c | 47 ------------ .../ecpg/include/ecpg-pthread-win32.h | 3 - src/interfaces/ecpg/include/ecpg_config.h.in | 4 -- src/interfaces/ecpg/include/ecpglib.h | 2 - src/interfaces/ecpg/include/meson.build | 1 - .../ecpg/test/expected/thread-alloc.c | 43 +++++------ .../ecpg/test/expected/thread-descriptor.c | 22 +++--- .../ecpg/test/expected/thread-prep.c | 71 ++++++++----------- .../ecpg/test/expected/thread-thread.c | 63 +++++++--------- .../test/expected/thread-thread_implicit.c | 63 +++++++--------- src/interfaces/ecpg/test/thread/alloc.pgc | 9 --- .../ecpg/test/thread/descriptor.pgc | 8 +-- src/interfaces/ecpg/test/thread/prep.pgc | 9 --- src/interfaces/ecpg/test/thread/thread.pgc | 9 --- .../ecpg/test/thread/thread_implicit.pgc | 9 --- src/interfaces/libpq/Makefile | 5 +- src/interfaces/libpq/fe-connect.c | 4 -- src/interfaces/libpq/fe-exec.c | 4 -- src/interfaces/libpq/fe-print.c | 13 +--- src/interfaces/libpq/fe-secure-openssl.c | 17 +---- src/interfaces/libpq/fe-secure.c | 26 +------ src/interfaces/libpq/legacy-pqsignal.c | 4 +- src/interfaces/libpq/libpq-int.h | 9 +-- src/makefiles/meson.build | 1 - src/tools/msvc/Solution.pm | 3 +- src/tools/msvc/ecpg_regression.proj | 2 +- 38 files changed, 133 insertions(+), 514 deletions(-) diff --git a/configure b/configure index 1b415142d1..85ed3f853a 100755 --- a/configure +++ b/configure @@ -722,7 +722,6 @@ with_tcl ICU_LIBS ICU_CFLAGS with_icu -enable_thread_safety INCLUDES autodepend PKG_CONFIG_LIBDIR @@ -848,7 +847,6 @@ with_CC with_llvm enable_depend enable_cassert -enable_thread_safety with_icu with_tcl with_tclconfig @@ -1536,7 +1534,6 @@ Optional Features: --enable-tap-tests enable TAP tests (requires Perl and IPC::Run) --enable-depend turn on automatic dependency tracking --enable-cassert enable assertion checks (for debugging) - --disable-thread-safety disable thread-safety in client libraries --disable-largefile omit support for large files Optional Packages: @@ -8338,43 +8335,6 @@ $as_echo "$as_me: WARNING: *** Library directory $dir does not exist." >&2;} done IFS=$ac_save_IFS -# -# Enable thread-safe client libraries -# -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking allow thread-safe client libraries" >&5 -$as_echo_n "checking allow thread-safe client libraries... " >&6; } - - -# Check whether --enable-thread-safety was given. -if test "${enable_thread_safety+set}" = set; then : - enableval=$enable_thread_safety; - case $enableval in - yes) - : - ;; - no) - : - ;; - *) - as_fn_error $? "no argument expected for --enable-thread-safety option" "$LINENO" 5 - ;; - esac - -else - enable_thread_safety=yes - -fi - - -if test "$enable_thread_safety" = yes; then - -$as_echo "#define ENABLE_THREAD_SAFETY 1" >>confdefs.h - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_thread_safety" >&5 -$as_echo "$enable_thread_safety" >&6; } - - # # ICU # @@ -11065,7 +11025,7 @@ fi done -if test "$enable_thread_safety" = yes -a "$PORTNAME" != "win32"; then : +if test "$PORTNAME" != "win32"; then : # then @@ -11724,7 +11684,7 @@ if test "x$ac_cv_header_pthread_h" = xyes; then : else as_fn_error $? " -pthread.h not found; use --disable-thread-safety to disable thread safety" "$LINENO" 5 +pthread.h not found" "$LINENO" 5 fi @@ -12408,8 +12368,7 @@ if test "$ac_res" != no; then : fi -if test "$enable_thread_safety" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_barrier_wait" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_barrier_wait" >&5 $as_echo_n "checking for library containing pthread_barrier_wait... " >&6; } if ${ac_cv_search_pthread_barrier_wait+:} false; then : $as_echo_n "(cached) " >&6 @@ -12465,7 +12424,6 @@ if test "$ac_res" != no; then : fi -fi if test "$with_readline" = yes; then @@ -13352,7 +13310,7 @@ else thread_safe_libldap=no fi - if test "$enable_thread_safety" = yes -a "$thread_safe_libldap" = no; then + if test "$thread_safe_libldap" = no; then # Use ldap_r for FE if available, else assume ldap is thread-safe. # On some platforms ldap_r fails to link without PTHREAD_LIBS. LIBS="$_LIBS" @@ -13398,8 +13356,6 @@ else LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS" fi - else - LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_bind in -lwldap32" >&5 @@ -16385,8 +16341,7 @@ fi -if test "$enable_thread_safety" = yes; then - ac_fn_c_check_func "$LINENO" "pthread_barrier_wait" "ac_cv_func_pthread_barrier_wait" +ac_fn_c_check_func "$LINENO" "pthread_barrier_wait" "ac_cv_func_pthread_barrier_wait" if test "x$ac_cv_func_pthread_barrier_wait" = xyes; then : $as_echo "#define HAVE_PTHREAD_BARRIER_WAIT 1" >>confdefs.h @@ -16400,7 +16355,6 @@ esac fi -fi if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then # Cygwin and (apparently, based on test results) Mingw both diff --git a/configure.ac b/configure.ac index 09558ada0f..9077f597d5 100644 --- a/configure.ac +++ b/configure.ac @@ -837,18 +837,6 @@ for dir in $LIBRARY_DIRS $SRCH_LIB; do done IFS=$ac_save_IFS -# -# Enable thread-safe client libraries -# -AC_MSG_CHECKING([allow thread-safe client libraries]) -PGAC_ARG_BOOL(enable, thread-safety, yes, [disable thread-safety in client libraries]) -if test "$enable_thread_safety" = yes; then - AC_DEFINE([ENABLE_THREAD_SAFETY], 1, - [Define to 1 to build client libraries as thread-safe code. (--enable-thread-safety)]) -fi -AC_MSG_RESULT([$enable_thread_safety]) -AC_SUBST(enable_thread_safety) - # # ICU # @@ -1244,7 +1232,7 @@ dnl note: We have to use AS_IF here rather than plain if. The AC_CHECK_HEADER dnl invocation below is the first one in the script, and autoconf generates dnl additional code for that, which must not be inside the if-block. AS_IF dnl knows how to do that. -AS_IF([test "$enable_thread_safety" = yes -a "$PORTNAME" != "win32"], +AS_IF([test "$PORTNAME" != "win32"], [ # then AX_PTHREAD # set thread flags @@ -1259,7 +1247,7 @@ CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$LIBS $PTHREAD_LIBS" AC_CHECK_HEADER(pthread.h, [], [AC_MSG_ERROR([ -pthread.h not found; use --disable-thread-safety to disable thread safety])]) +pthread.h not found])]) AC_CHECK_FUNCS([strerror_r]) @@ -1306,9 +1294,7 @@ AC_SEARCH_LIBS(shmget, cygipc) # *BSD: AC_SEARCH_LIBS(backtrace_symbols, execinfo) -if test "$enable_thread_safety" = yes; then - AC_SEARCH_LIBS(pthread_barrier_wait, pthread) -fi +AC_SEARCH_LIBS(pthread_barrier_wait, pthread) if test "$with_readline" = yes; then PGAC_CHECK_READLINE @@ -1436,7 +1422,7 @@ if test "$with_ldap" = yes ; then AC_CHECK_FUNC([ldap_verify_credentials], [thread_safe_libldap=yes], [thread_safe_libldap=no]) - if test "$enable_thread_safety" = yes -a "$thread_safe_libldap" = no; then + if test "$thread_safe_libldap" = no; then # Use ldap_r for FE if available, else assume ldap is thread-safe. # On some platforms ldap_r fails to link without PTHREAD_LIBS. LIBS="$_LIBS" @@ -1444,8 +1430,6 @@ if test "$with_ldap" = yes ; then [LDAP_LIBS_FE="-lldap_r $EXTRA_LDAP_LIBS"], [LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS"], [$PTHREAD_CFLAGS $PTHREAD_LIBS $EXTRA_LDAP_LIBS]) - else - LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS" fi else AC_CHECK_LIB(wldap32, ldap_bind, [], [AC_MSG_ERROR([library 'wldap32' is required for LDAP])]) @@ -1860,9 +1844,7 @@ AC_REPLACE_FUNCS(m4_normalize([ strnlen ])) -if test "$enable_thread_safety" = yes; then - AC_REPLACE_FUNCS(pthread_barrier_wait) -fi +AC_REPLACE_FUNCS(pthread_barrier_wait) if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then # Cygwin and (apparently, based on test results) Mingw both diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index 75dc81a0a9..5be927db26 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -1306,19 +1306,6 @@ build-postgresql: </listitem> </varlistentry> - <varlistentry id="configure-option-disable-thread-safety"> - <term><option>--disable-thread-safety</option></term> - <listitem> - <para> - Disable the thread-safety of client libraries. This prevents - concurrent threads in <application>libpq</application> and - <application>ECPG</application> programs from safely controlling - their private connection handles. Use this only on platforms - with deficient threading support. - </para> - </listitem> - </varlistentry> - </variablelist> </sect3> diff --git a/meson.build b/meson.build index 16b2e86646..a4f3da351a 100644 --- a/meson.build +++ b/meson.build @@ -2519,17 +2519,6 @@ cdata.set_quoted('PG_VERSION_STR', ) - -############################################################### -# Threading -############################################################### - -# XXX: About to rely on thread safety in the autoconf build, so not worth -# implementing a fallback. -cdata.set('ENABLE_THREAD_SAFETY', 1) - - - ############################################################### # NLS / Gettext ############################################################### diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 974b1dfef9..df9f721a41 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -202,7 +202,6 @@ enable_debug = @enable_debug@ enable_dtrace = @enable_dtrace@ enable_coverage = @enable_coverage@ enable_tap_tests = @enable_tap_tests@ -enable_thread_safety = @enable_thread_safety@ python_includespec = @python_includespec@ python_libdir = @python_libdir@ diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 1d1670d4c2..683fc5860f 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -137,7 +137,7 @@ typedef struct socket_set EnterSynchronizationBarrier((barrier), \ SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) #define THREAD_BARRIER_DESTROY(barrier) -#elif defined(ENABLE_THREAD_SAFETY) +#else /* Use POSIX threads */ #include "port/pg_pthread.h" #define THREAD_T pthread_t @@ -153,16 +153,6 @@ typedef struct socket_set pthread_barrier_init((barrier), NULL, (n)) #define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier)) #define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier)) -#else -/* No threads implementation, use none (-j 1) */ -#define THREAD_T void * -#define THREAD_FUNC_RETURN_TYPE void * -#define THREAD_FUNC_RETURN return NULL -#define THREAD_FUNC_CC -#define THREAD_BARRIER_T int -#define THREAD_BARRIER_INIT(barrier, n) (*(barrier) = 0) -#define THREAD_BARRIER_WAIT(barrier) -#define THREAD_BARRIER_DESTROY(barrier) #endif @@ -6749,10 +6739,6 @@ main(int argc, char **argv) { exit(1); } -#ifndef ENABLE_THREAD_SAFETY - if (nthreads != 1) - pg_fatal("threads are not supported on this platform; use -j1"); -#endif /* !ENABLE_THREAD_SAFETY */ break; case 'l': benchmarking_option_set = true; @@ -7236,7 +7222,6 @@ main(int argc, char **argv) if (errno != 0) pg_fatal("could not initialize barrier: %m"); -#ifdef ENABLE_THREAD_SAFETY /* start all threads but thread 0 which is executed directly later */ for (i = 1; i < nthreads; i++) { @@ -7248,9 +7233,6 @@ main(int argc, char **argv) if (errno != 0) pg_fatal("could not create thread: %m"); } -#else - Assert(nthreads == 1); -#endif /* ENABLE_THREAD_SAFETY */ /* compute when to stop */ threads[0].create_time = pg_time_now(); @@ -7268,10 +7250,8 @@ main(int argc, char **argv) { TState *thread = &threads[i]; -#ifdef ENABLE_THREAD_SAFETY if (i > 0) THREAD_JOIN(thread->thread); -#endif /* ENABLE_THREAD_SAFETY */ for (int j = 0; j < thread->nstate; j++) if (thread->state[j].state != CSTATE_FINISHED) diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 6d572c3820..18e90fd842 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -51,10 +51,6 @@ /* Define to 1 if you want National Language Support. (--enable-nls) */ #undef ENABLE_NLS -/* Define to 1 to build client libraries as thread-safe code. - (--enable-thread-safety) */ -#undef ENABLE_THREAD_SAFETY - /* Define to 1 if you have the `append_history' function. */ #undef HAVE_APPEND_HISTORY diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index db0bae1fe0..8afb1f0a26 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -14,15 +14,12 @@ locale_t ecpg_clocale = (locale_t) 0; #endif -#ifdef ENABLE_THREAD_SAFETY static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t actual_connection_key; static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT; -#endif static struct connection *actual_connection = NULL; static struct connection *all_connections = NULL; -#ifdef ENABLE_THREAD_SAFETY static void ecpg_actual_connection_init(void) { @@ -34,7 +31,6 @@ ecpg_pthreads_init(void) { pthread_once(&actual_connection_key_once, ecpg_actual_connection_init); } -#endif static struct connection * ecpg_get_connection_nr(const char *connection_name) @@ -43,7 +39,6 @@ ecpg_get_connection_nr(const char *connection_name) if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0)) { -#ifdef ENABLE_THREAD_SAFETY ecpg_pthreads_init(); /* ensure actual_connection_key is valid */ ret = pthread_getspecific(actual_connection_key); @@ -56,9 +51,6 @@ ecpg_get_connection_nr(const char *connection_name) if (ret == NULL) /* no TSD connection, going for global */ ret = actual_connection; -#else - ret = actual_connection; -#endif } else { @@ -82,7 +74,6 @@ ecpg_get_connection(const char *connection_name) if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0)) { -#ifdef ENABLE_THREAD_SAFETY ecpg_pthreads_init(); /* ensure actual_connection_key is valid */ ret = pthread_getspecific(actual_connection_key); @@ -95,21 +86,14 @@ ecpg_get_connection(const char *connection_name) if (ret == NULL) /* no TSD connection here either, using global */ ret = actual_connection; -#else - ret = actual_connection; -#endif } else { -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&connections_mutex); -#endif ret = ecpg_get_connection_nr(connection_name); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif } return ret; @@ -143,10 +127,8 @@ ecpg_finish(struct connection *act) con->next = act->next; } -#ifdef ENABLE_THREAD_SAFETY if (pthread_getspecific(actual_connection_key) == act) pthread_setspecific(actual_connection_key, all_connections); -#endif if (actual_connection == act) actual_connection = all_connections; @@ -212,11 +194,7 @@ ECPGsetconn(int lineno, const char *connection_name) if (!ecpg_init(con, connection_name, lineno)) return false; -#ifdef ENABLE_THREAD_SAFETY pthread_setspecific(actual_connection_key, con); -#else - actual_connection = con; -#endif return true; } @@ -326,9 +304,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p if (dbname == NULL && connection_name == NULL) connection_name = "DEFAULT"; -#if ENABLE_THREAD_SAFETY ecpg_pthreads_init(); -#endif /* check if the identifier is unique */ if (ecpg_get_connection(connection_name)) @@ -505,9 +481,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p } /* add connection to our list */ -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&connections_mutex); -#endif /* * ... but first, make certain we have created ecpg_clocale. Rely on @@ -519,9 +493,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); if (!ecpg_clocale) { -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL); if (host) @@ -558,9 +530,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p this->next = all_connections; all_connections = this; -#ifdef ENABLE_THREAD_SAFETY pthread_setspecific(actual_connection_key, all_connections); -#endif actual_connection = all_connections; ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n", @@ -678,9 +648,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_log("ECPGconnect: %s", errmsg); ecpg_finish(this); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db); if (realname) @@ -692,9 +660,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p if (realname) ecpg_free(realname); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif this->autocommit = autocommit; @@ -716,9 +682,7 @@ ECPGdisconnect(int lineno, const char *connection_name) return false; } -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&connections_mutex); -#endif if (strcmp(connection_name, "ALL") == 0) { @@ -737,18 +701,14 @@ ECPGdisconnect(int lineno, const char *connection_name) if (!ecpg_init(con, connection_name, lineno)) { -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif return false; } else ecpg_finish(con); } -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); -#endif return true; } diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index 883a210a81..ad279e245c 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -19,7 +19,6 @@ static void descriptor_free(struct descriptor *desc); /* We manage descriptors separately for each thread. */ -#ifdef ENABLE_THREAD_SAFETY static pthread_key_t descriptor_key; static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT; @@ -49,12 +48,6 @@ set_descriptors(struct descriptor *value) { pthread_setspecific(descriptor_key, value); } -#else -static struct descriptor *all_descriptors = NULL; - -#define get_descriptors() (all_descriptors) -#define set_descriptors(value) do { all_descriptors = (value); } while(0) -#endif /* old internal convenience function that might go away later */ static PGresult * @@ -782,8 +775,6 @@ ECPGdeallocate_desc(int line, const char *name) return false; } -#ifdef ENABLE_THREAD_SAFETY - /* Deallocate all descriptors in the list */ static void descriptor_deallocate_all(struct descriptor *list) @@ -796,7 +787,6 @@ descriptor_deallocate_all(struct descriptor *list) list = next; } } -#endif /* ENABLE_THREAD_SAFETY */ bool ECPGallocate_desc(int line, const char *name) diff --git a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h index 8b8f081f27..01b4309a71 100644 --- a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h +++ b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h @@ -169,9 +169,7 @@ bool ecpg_get_data(const PGresult *, int, int, int, enum ECPGttype type, enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool); -#ifdef ENABLE_THREAD_SAFETY void ecpg_pthreads_init(void); -#endif struct connection *ecpg_get_connection(const char *connection_name); char *ecpg_alloc(long size, int lineno); char *ecpg_auto_alloc(long size, int lineno); diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 93926fd4fb..04d0b40c53 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1961,9 +1961,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, return false; } -#ifdef ENABLE_THREAD_SAFETY ecpg_pthreads_init(); -#endif con = ecpg_get_connection(connection_name); diff --git a/src/interfaces/ecpg/ecpglib/memory.c b/src/interfaces/ecpg/ecpglib/memory.c index bd81251054..a83637ac75 100644 --- a/src/interfaces/ecpg/ecpglib/memory.c +++ b/src/interfaces/ecpg/ecpglib/memory.c @@ -68,7 +68,6 @@ struct auto_mem struct auto_mem *next; }; -#ifdef ENABLE_THREAD_SAFETY static pthread_key_t auto_mem_key; static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT; @@ -97,12 +96,6 @@ set_auto_allocs(struct auto_mem *am) { pthread_setspecific(auto_mem_key, am); } -#else -static struct auto_mem *auto_allocs = NULL; - -#define get_auto_allocs() (auto_allocs) -#define set_auto_allocs(am) do { auto_allocs = (am); } while(0) -#endif char * ecpg_auto_alloc(long size, int lineno) diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index 7f75e18733..2b78caeaf5 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -55,42 +55,11 @@ static struct sqlca_t sqlca_init = } }; -#ifdef ENABLE_THREAD_SAFETY static pthread_key_t sqlca_key; static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT; -#else -static struct sqlca_t sqlca = -{ - { - 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' ' - }, - sizeof(struct sqlca_t), - 0, - { - 0, - { - 0 - } - }, - { - 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' ' - }, - { - 0, 0, 0, 0, 0, 0 - }, - { - 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - '0', '0', '0', '0', '0' - } -}; -#endif -#ifdef ENABLE_THREAD_SAFETY static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif static int simple_debug = 0; static FILE *debugstream = NULL; @@ -123,7 +92,6 @@ ecpg_init(const struct connection *con, const char *connection_name, const int l return true; } -#ifdef ENABLE_THREAD_SAFETY static void ecpg_sqlca_key_destructor(void *arg) { @@ -135,12 +103,10 @@ ecpg_sqlca_key_init(void) { pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor); } -#endif struct sqlca_t * ECPGget_sqlca(void) { -#ifdef ENABLE_THREAD_SAFETY struct sqlca_t *sqlca; pthread_once(&sqlca_key_once, ecpg_sqlca_key_init); @@ -155,9 +121,6 @@ ECPGget_sqlca(void) pthread_setspecific(sqlca_key, sqlca); } return sqlca; -#else - return &sqlca; -#endif } bool @@ -240,9 +203,7 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction) void ECPGdebug(int n, FILE *dbgs) { -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&debug_init_mutex); -#endif if (n > 100) { @@ -256,9 +217,7 @@ ECPGdebug(int n, FILE *dbgs) ecpg_log("ECPGdebug: set to %d\n", simple_debug); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&debug_init_mutex); -#endif } void @@ -290,9 +249,7 @@ ecpg_log(const char *format,...) else snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&debug_mutex); -#endif va_start(ap, format); vfprintf(debugstream, fmt, ap); @@ -307,9 +264,7 @@ ecpg_log(const char *format,...) fflush(debugstream); -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&debug_mutex); -#endif free(fmt); } @@ -451,7 +406,6 @@ ECPGis_noind_null(enum ECPGttype type, const void *ptr) } #ifdef WIN32 -#ifdef ENABLE_THREAD_SAFETY void win32_pthread_mutex(volatile pthread_mutex_t *mutex) @@ -482,7 +436,6 @@ win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void)) pthread_mutex_unlock(&win32_pthread_once_lock); } } -#endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ #ifdef ENABLE_NLS diff --git a/src/interfaces/ecpg/include/ecpg-pthread-win32.h b/src/interfaces/ecpg/include/ecpg-pthread-win32.h index 33c897b633..8252a17809 100644 --- a/src/interfaces/ecpg/include/ecpg-pthread-win32.h +++ b/src/interfaces/ecpg/include/ecpg-pthread-win32.h @@ -5,8 +5,6 @@ #ifndef _ECPG_PTHREAD_WIN32_H #define _ECPG_PTHREAD_WIN32_H -#ifdef ENABLE_THREAD_SAFETY - #ifndef WIN32 #include <pthread.h> @@ -53,6 +51,5 @@ void win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void)); win32_pthread_once((once), (fn)); \ } while(0) #endif /* WIN32 */ -#endif /* ENABLE_THREAD_SAFETY */ #endif /* _ECPG_PTHREAD_WIN32_H */ diff --git a/src/interfaces/ecpg/include/ecpg_config.h.in b/src/interfaces/ecpg/include/ecpg_config.h.in index cbd24f11a0..6d01608a49 100644 --- a/src/interfaces/ecpg/include/ecpg_config.h.in +++ b/src/interfaces/ecpg/include/ecpg_config.h.in @@ -1,7 +1,3 @@ -/* Define to 1 to build client libraries as thread-safe code. - * (--enable-thread-safety) */ -#undef ENABLE_THREAD_SAFETY - /* Define to 1 if the system has the type `int64'. */ #undef HAVE_INT64 diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index 21a2134483..771761ffe4 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -98,9 +98,7 @@ void *ECPGget_var(int number); /* dynamic result allocation */ void ECPGfree_auto_mem(void); -#ifdef ENABLE_THREAD_SAFETY void ecpg_pthreads_init(void); -#endif #ifdef __cplusplus } diff --git a/src/interfaces/ecpg/include/meson.build b/src/interfaces/ecpg/include/meson.build index 2278f0d305..543e48fd6e 100644 --- a/src/interfaces/ecpg/include/meson.build +++ b/src/interfaces/ecpg/include/meson.build @@ -3,7 +3,6 @@ ecpg_inc = include_directories('.') ecpg_conf_keys = [ - 'ENABLE_THREAD_SAFETY', 'HAVE_INT64', 'HAVE_LONG_INT_64', 'HAVE_LONG_LONG_INT_64', diff --git a/src/interfaces/ecpg/test/expected/thread-alloc.c b/src/interfaces/ecpg/test/expected/thread-alloc.c index 37ef44ed94..3b31d27fd3 100644 --- a/src/interfaces/ecpg/test/expected/thread-alloc.c +++ b/src/interfaces/ecpg/test/expected/thread-alloc.c @@ -11,14 +11,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -101,7 +93,7 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 26 "alloc.pgc" +#line 18 "alloc.pgc" #line 1 "regression.h" @@ -111,14 +103,14 @@ struct sqlca_t *ECPGget_sqlca(void); -#line 27 "alloc.pgc" +#line 19 "alloc.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 29 "alloc.pgc" +#line 21 "alloc.pgc" /* exec sql whenever not found sqlprint ; */ -#line 30 "alloc.pgc" +#line 22 "alloc.pgc" #ifdef WIN32 @@ -134,54 +126,54 @@ static void* fn(void* arg) -#line 41 "alloc.pgc" +#line 33 "alloc.pgc" int value ; -#line 42 "alloc.pgc" +#line 34 "alloc.pgc" char name [ 100 ] ; -#line 43 "alloc.pgc" +#line 35 "alloc.pgc" char ** r = NULL ; /* exec sql end declare section */ -#line 44 "alloc.pgc" +#line 36 "alloc.pgc" value = (intptr_t) arg; sprintf(name, "Connection: %d", value); { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); -#line 49 "alloc.pgc" +#line 41 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 49 "alloc.pgc" +#line 41 "alloc.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 50 "alloc.pgc" +#line 42 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 50 "alloc.pgc" +#line 42 "alloc.pgc" for (i = 1; i <= REPEATS; ++i) { { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select relname from pg_class where relname = 'pg_class'", ECPGt_EOIT, ECPGt_char,&(r),(long)0,(long)0,(1)*sizeof(char), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); -#line 53 "alloc.pgc" +#line 45 "alloc.pgc" if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint(); -#line 53 "alloc.pgc" +#line 45 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 53 "alloc.pgc" +#line 45 "alloc.pgc" free(r); r = NULL; } { ECPGdisconnect(__LINE__, name); -#line 57 "alloc.pgc" +#line 49 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 57 "alloc.pgc" +#line 49 "alloc.pgc" return 0; @@ -215,4 +207,3 @@ int main () return 0; } -#endif diff --git a/src/interfaces/ecpg/test/expected/thread-descriptor.c b/src/interfaces/ecpg/test/expected/thread-descriptor.c index f56cc25ab0..e34f4708d1 100644 --- a/src/interfaces/ecpg/test/expected/thread-descriptor.c +++ b/src/interfaces/ecpg/test/expected/thread-descriptor.c @@ -7,7 +7,6 @@ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) #line 1 "descriptor.pgc" -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -16,7 +15,6 @@ #else #include <pthread.h> #endif -#endif #include <stdio.h> #define THREADS 16 @@ -91,16 +89,16 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 16 "descriptor.pgc" +#line 14 "descriptor.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 17 "descriptor.pgc" +#line 15 "descriptor.pgc" /* exec sql whenever not found sqlprint ; */ -#line 18 "descriptor.pgc" +#line 16 "descriptor.pgc" -#if defined(ENABLE_THREAD_SAFETY) && defined(WIN32) +#if defined(WIN32) static unsigned __stdcall fn(void* arg) #else static void* fn(void* arg) @@ -111,16 +109,16 @@ static void* fn(void* arg) for (i = 1; i <= REPEATS; ++i) { ECPGallocate_desc(__LINE__, "mydesc"); -#line 30 "descriptor.pgc" +#line 28 "descriptor.pgc" if (sqlca.sqlcode < 0) sqlprint(); -#line 30 "descriptor.pgc" +#line 28 "descriptor.pgc" ECPGdeallocate_desc(__LINE__, "mydesc"); -#line 31 "descriptor.pgc" +#line 29 "descriptor.pgc" if (sqlca.sqlcode < 0) sqlprint(); -#line 31 "descriptor.pgc" +#line 29 "descriptor.pgc" } @@ -129,7 +127,6 @@ if (sqlca.sqlcode < 0) sqlprint(); int main () { -#ifdef ENABLE_THREAD_SAFETY int i; #ifdef WIN32 HANDLE threads[THREADS]; @@ -153,9 +150,6 @@ int main () for (i = 0; i < THREADS; ++i) pthread_join(threads[i], NULL); #endif -#else - fn(NULL); -#endif return 0; } diff --git a/src/interfaces/ecpg/test/expected/thread-prep.c b/src/interfaces/ecpg/test/expected/thread-prep.c index 7cdf2505d3..052e27b634 100644 --- a/src/interfaces/ecpg/test/expected/thread-prep.c +++ b/src/interfaces/ecpg/test/expected/thread-prep.c @@ -11,14 +11,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -101,7 +93,7 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 26 "prep.pgc" +#line 18 "prep.pgc" #line 1 "regression.h" @@ -111,14 +103,14 @@ struct sqlca_t *ECPGget_sqlca(void); -#line 27 "prep.pgc" +#line 19 "prep.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 29 "prep.pgc" +#line 21 "prep.pgc" /* exec sql whenever not found sqlprint ; */ -#line 30 "prep.pgc" +#line 22 "prep.pgc" #ifdef WIN32 @@ -134,64 +126,64 @@ static void* fn(void* arg) -#line 41 "prep.pgc" +#line 33 "prep.pgc" int value ; -#line 42 "prep.pgc" +#line 34 "prep.pgc" char name [ 100 ] ; -#line 43 "prep.pgc" +#line 35 "prep.pgc" char query [ 256 ] = "INSERT INTO T VALUES ( ? )" ; /* exec sql end declare section */ -#line 44 "prep.pgc" +#line 36 "prep.pgc" value = (intptr_t) arg; sprintf(name, "Connection: %d", value); { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); -#line 49 "prep.pgc" +#line 41 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 49 "prep.pgc" +#line 41 "prep.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 50 "prep.pgc" +#line 42 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 50 "prep.pgc" +#line 42 "prep.pgc" for (i = 1; i <= REPEATS; ++i) { { ECPGprepare(__LINE__, NULL, 0, "i", query); -#line 53 "prep.pgc" +#line 45 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 53 "prep.pgc" +#line 45 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "i", ECPGt_int,&(value),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 54 "prep.pgc" +#line 46 "prep.pgc" if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint(); -#line 54 "prep.pgc" +#line 46 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 54 "prep.pgc" +#line 46 "prep.pgc" } { ECPGdeallocate(__LINE__, 0, NULL, "i"); -#line 56 "prep.pgc" +#line 48 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 56 "prep.pgc" +#line 48 "prep.pgc" { ECPGdisconnect(__LINE__, name); -#line 57 "prep.pgc" +#line 49 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 57 "prep.pgc" +#line 49 "prep.pgc" return 0; @@ -207,34 +199,34 @@ int main () #endif { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); -#line 71 "prep.pgc" +#line 63 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 71 "prep.pgc" +#line 63 "prep.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 72 "prep.pgc" +#line 64 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 72 "prep.pgc" +#line 64 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table if exists T", ECPGt_EOIT, ECPGt_EORT); -#line 73 "prep.pgc" +#line 65 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 73 "prep.pgc" +#line 65 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table T ( i int )", ECPGt_EOIT, ECPGt_EORT); -#line 74 "prep.pgc" +#line 66 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 74 "prep.pgc" +#line 66 "prep.pgc" { ECPGdisconnect(__LINE__, "CURRENT"); -#line 75 "prep.pgc" +#line 67 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 75 "prep.pgc" +#line 67 "prep.pgc" #ifdef WIN32 @@ -256,4 +248,3 @@ if (sqlca.sqlcode < 0) sqlprint();} return 0; } -#endif diff --git a/src/interfaces/ecpg/test/expected/thread-thread.c b/src/interfaces/ecpg/test/expected/thread-thread.c index 0e75c47fab..95faa223c2 100644 --- a/src/interfaces/ecpg/test/expected/thread-thread.c +++ b/src/interfaces/ecpg/test/expected/thread-thread.c @@ -15,14 +15,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifndef WIN32 #include <pthread.h> #else @@ -38,7 +30,7 @@ main(void) -#line 24 "thread.pgc" +#line 16 "thread.pgc" void *test_thread(void *arg); @@ -57,10 +49,10 @@ int main() /* exec sql begin declare section */ -#line 40 "thread.pgc" +#line 32 "thread.pgc" int l_rows ; /* exec sql end declare section */ -#line 41 "thread.pgc" +#line 33 "thread.pgc" /* Do not switch on debug output for regression tests. The threads get executed in @@ -69,22 +61,22 @@ int main() /* setup test_thread table */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 48 "thread.pgc" +#line 40 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);} -#line 49 "thread.pgc" +#line 41 "thread.pgc" /* DROP might fail */ { ECPGtrans(__LINE__, NULL, "commit");} -#line 50 "thread.pgc" +#line 42 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);} -#line 55 "thread.pgc" +#line 47 "thread.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 56 "thread.pgc" +#line 48 "thread.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 57 "thread.pgc" +#line 49 "thread.pgc" /* create, and start, threads */ @@ -116,18 +108,18 @@ int main() /* and check results */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 87 "thread.pgc" +#line 79 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} -#line 88 "thread.pgc" +#line 80 "thread.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 89 "thread.pgc" +#line 81 "thread.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 90 "thread.pgc" +#line 82 "thread.pgc" if( l_rows == (nthreads * iterations) ) printf("Success.\n"); @@ -145,13 +137,13 @@ void *test_thread(void *arg) -#line 104 "thread.pgc" +#line 96 "thread.pgc" int l_i ; -#line 105 "thread.pgc" +#line 97 "thread.pgc" char l_connection [ 128 ] ; /* exec sql end declare section */ -#line 106 "thread.pgc" +#line 98 "thread.pgc" /* build up connection name, and connect to database */ @@ -161,13 +153,13 @@ void *test_thread(void *arg) _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum); #endif /* exec sql whenever sqlerror sqlprint ; */ -#line 114 "thread.pgc" +#line 106 "thread.pgc" { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); -#line 115 "thread.pgc" +#line 107 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 115 "thread.pgc" +#line 107 "thread.pgc" if( sqlca.sqlcode != 0 ) { @@ -175,10 +167,10 @@ if (sqlca.sqlcode < 0) sqlprint();} return NULL; } { ECPGtrans(__LINE__, l_connection, "begin"); -#line 121 "thread.pgc" +#line 113 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 121 "thread.pgc" +#line 113 "thread.pgc" /* insert into test_thread table */ @@ -189,10 +181,10 @@ if (sqlca.sqlcode < 0) sqlprint();} ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 126 "thread.pgc" +#line 118 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 126 "thread.pgc" +#line 118 "thread.pgc" if( sqlca.sqlcode != 0 ) printf("%s: ERROR: insert failed!\n", l_connection); @@ -200,17 +192,16 @@ if (sqlca.sqlcode < 0) sqlprint();} /* all done */ { ECPGtrans(__LINE__, l_connection, "commit"); -#line 132 "thread.pgc" +#line 124 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 132 "thread.pgc" +#line 124 "thread.pgc" { ECPGdisconnect(__LINE__, l_connection); -#line 133 "thread.pgc" +#line 125 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 133 "thread.pgc" +#line 125 "thread.pgc" return NULL; } -#endif /* ENABLE_THREAD_SAFETY */ diff --git a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c index 0df2794530..7ac0297a23 100644 --- a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c +++ b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c @@ -15,14 +15,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifndef WIN32 #include <pthread.h> #else @@ -38,7 +30,7 @@ main(void) -#line 24 "thread_implicit.pgc" +#line 16 "thread_implicit.pgc" void *test_thread(void *arg); @@ -57,10 +49,10 @@ int main() /* exec sql begin declare section */ -#line 40 "thread_implicit.pgc" +#line 32 "thread_implicit.pgc" int l_rows ; /* exec sql end declare section */ -#line 41 "thread_implicit.pgc" +#line 33 "thread_implicit.pgc" /* Do not switch on debug output for regression tests. The threads get executed in @@ -69,22 +61,22 @@ int main() /* setup test_thread table */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 48 "thread_implicit.pgc" +#line 40 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);} -#line 49 "thread_implicit.pgc" +#line 41 "thread_implicit.pgc" /* DROP might fail */ { ECPGtrans(__LINE__, NULL, "commit");} -#line 50 "thread_implicit.pgc" +#line 42 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);} -#line 55 "thread_implicit.pgc" +#line 47 "thread_implicit.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 56 "thread_implicit.pgc" +#line 48 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 57 "thread_implicit.pgc" +#line 49 "thread_implicit.pgc" /* create, and start, threads */ @@ -116,18 +108,18 @@ int main() /* and check results */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 87 "thread_implicit.pgc" +#line 79 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} -#line 88 "thread_implicit.pgc" +#line 80 "thread_implicit.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 89 "thread_implicit.pgc" +#line 81 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 90 "thread_implicit.pgc" +#line 82 "thread_implicit.pgc" if( l_rows == (nthreads * iterations) ) printf("Success.\n"); @@ -145,13 +137,13 @@ void *test_thread(void *arg) -#line 104 "thread_implicit.pgc" +#line 96 "thread_implicit.pgc" int l_i ; -#line 105 "thread_implicit.pgc" +#line 97 "thread_implicit.pgc" char l_connection [ 128 ] ; /* exec sql end declare section */ -#line 106 "thread_implicit.pgc" +#line 98 "thread_implicit.pgc" /* build up connection name, and connect to database */ @@ -161,13 +153,13 @@ void *test_thread(void *arg) _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum); #endif /* exec sql whenever sqlerror sqlprint ; */ -#line 114 "thread_implicit.pgc" +#line 106 "thread_implicit.pgc" { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); -#line 115 "thread_implicit.pgc" +#line 107 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 115 "thread_implicit.pgc" +#line 107 "thread_implicit.pgc" if( sqlca.sqlcode != 0 ) { @@ -175,10 +167,10 @@ if (sqlca.sqlcode < 0) sqlprint();} return NULL; } { ECPGtrans(__LINE__, NULL, "begin"); -#line 121 "thread_implicit.pgc" +#line 113 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 121 "thread_implicit.pgc" +#line 113 "thread_implicit.pgc" /* insert into test_thread table */ @@ -189,10 +181,10 @@ if (sqlca.sqlcode < 0) sqlprint();} ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 126 "thread_implicit.pgc" +#line 118 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 126 "thread_implicit.pgc" +#line 118 "thread_implicit.pgc" if( sqlca.sqlcode != 0 ) printf("%s: ERROR: insert failed!\n", l_connection); @@ -200,17 +192,16 @@ if (sqlca.sqlcode < 0) sqlprint();} /* all done */ { ECPGtrans(__LINE__, NULL, "commit"); -#line 132 "thread_implicit.pgc" +#line 124 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 132 "thread_implicit.pgc" +#line 124 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, l_connection); -#line 133 "thread_implicit.pgc" +#line 125 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 133 "thread_implicit.pgc" +#line 125 "thread_implicit.pgc" return NULL; } -#endif /* ENABLE_THREAD_SAFETY */ diff --git a/src/interfaces/ecpg/test/thread/alloc.pgc b/src/interfaces/ecpg/test/thread/alloc.pgc index c0021a737e..d3d35493bf 100644 --- a/src/interfaces/ecpg/test/thread/alloc.pgc +++ b/src/interfaces/ecpg/test/thread/alloc.pgc @@ -2,14 +2,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -87,4 +79,3 @@ int main () return 0; } -#endif diff --git a/src/interfaces/ecpg/test/thread/descriptor.pgc b/src/interfaces/ecpg/test/thread/descriptor.pgc index 76a7a5dff5..30bce7c87b 100644 --- a/src/interfaces/ecpg/test/thread/descriptor.pgc +++ b/src/interfaces/ecpg/test/thread/descriptor.pgc @@ -1,4 +1,3 @@ -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -7,7 +6,6 @@ #else #include <pthread.h> #endif -#endif #include <stdio.h> #define THREADS 16 @@ -17,7 +15,7 @@ EXEC SQL include sqlca; EXEC SQL whenever sqlerror sqlprint; EXEC SQL whenever not found sqlprint; -#if defined(ENABLE_THREAD_SAFETY) && defined(WIN32) +#if defined(WIN32) static unsigned __stdcall fn(void* arg) #else static void* fn(void* arg) @@ -36,7 +34,6 @@ static void* fn(void* arg) int main () { -#ifdef ENABLE_THREAD_SAFETY int i; #ifdef WIN32 HANDLE threads[THREADS]; @@ -60,9 +57,6 @@ int main () for (i = 0; i < THREADS; ++i) pthread_join(threads[i], NULL); #endif -#else - fn(NULL); -#endif return 0; } diff --git a/src/interfaces/ecpg/test/thread/prep.pgc b/src/interfaces/ecpg/test/thread/prep.pgc index d7ecfd4855..f61b31ce10 100644 --- a/src/interfaces/ecpg/test/thread/prep.pgc +++ b/src/interfaces/ecpg/test/thread/prep.pgc @@ -2,14 +2,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -93,4 +85,3 @@ int main () return 0; } -#endif diff --git a/src/interfaces/ecpg/test/thread/thread.pgc b/src/interfaces/ecpg/test/thread/thread.pgc index e7d8c00af6..b9b9ebb441 100644 --- a/src/interfaces/ecpg/test/thread/thread.pgc +++ b/src/interfaces/ecpg/test/thread/thread.pgc @@ -6,14 +6,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifndef WIN32 #include <pthread.h> #else @@ -133,4 +125,3 @@ void *test_thread(void *arg) EXEC SQL DISCONNECT :l_connection; return NULL; } -#endif /* ENABLE_THREAD_SAFETY */ diff --git a/src/interfaces/ecpg/test/thread/thread_implicit.pgc b/src/interfaces/ecpg/test/thread/thread_implicit.pgc index b4cae7e1ae..ff9b12a943 100644 --- a/src/interfaces/ecpg/test/thread/thread_implicit.pgc +++ b/src/interfaces/ecpg/test/thread/thread_implicit.pgc @@ -6,14 +6,6 @@ #include <stdlib.h> #include "ecpg_config.h" -#ifndef ENABLE_THREAD_SAFETY -int -main(void) -{ - printf("No threading enabled.\n"); - return 0; -} -#else #ifndef WIN32 #include <pthread.h> #else @@ -133,4 +125,3 @@ void *test_thread(void *arg) EXEC SQL DISCONNECT :l_connection; return NULL; } -#endif /* ENABLE_THREAD_SAFETY */ diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 0919d8f32f..46653682b0 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -69,11 +69,8 @@ endif ifeq ($(PORTNAME), win32) OBJS += \ + pthread-win32.o \ win32.o - -ifeq ($(enable_thread_safety), yes) -OBJS += pthread-win32.o -endif endif diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index a8584d2c68..837c5321aa 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -52,13 +52,11 @@ #include <netinet/tcp.h> #endif -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include <pthread.h> #endif -#endif #ifdef USE_LDAP #ifdef WIN32 @@ -7784,7 +7782,6 @@ pqGetHomeDirectory(char *buf, int bufsize) static void default_threadlock(int acquire) { -#ifdef ENABLE_THREAD_SAFETY #ifndef WIN32 static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER; #else @@ -7813,7 +7810,6 @@ default_threadlock(int acquire) if (pthread_mutex_unlock(&singlethread_lock)) Assert(false); } -#endif } pgthreadlock_t diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 14d706efd5..39d10f0eb3 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -3824,11 +3824,7 @@ PQisnonblocking(const PGconn *conn) int PQisthreadsafe(void) { -#ifdef ENABLE_THREAD_SAFETY return true; -#else - return false; -#endif } diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index 40620b47e9..8af15032be 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -88,14 +88,11 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) bool usePipe = false; char *pagerenv; -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) +#if !defined(WIN32) sigset_t osigset; bool sigpipe_masked = false; bool sigpipe_pending; #endif -#if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) - pqsigfunc oldsigpipehandler = NULL; -#endif #ifdef TIOCGWINSZ struct winsize screen_size; @@ -186,12 +183,8 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) { usePipe = true; #ifndef WIN32 -#ifdef ENABLE_THREAD_SAFETY if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0) sigpipe_masked = true; -#else - oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); -#endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ } else @@ -324,13 +317,9 @@ exit: #else pclose(fout); -#ifdef ENABLE_THREAD_SAFETY /* we can't easily verify if EPIPE occurred, so say it did */ if (sigpipe_masked) pq_reset_sigpipe(&osigset, sigpipe_pending, true); -#else - pqsignal(SIGPIPE, oldsigpipehandler); -#endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ } } diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 390c888c96..4976d963a2 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -44,13 +44,11 @@ #include <sys/stat.h> -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include <pthread.h> #endif -#endif /* * These SSL-related #includes must come after all system-provided headers. @@ -91,7 +89,6 @@ static bool pq_init_crypto_lib = true; static bool ssl_lib_initialized = false; -#ifdef ENABLE_THREAD_SAFETY static long crypto_open_connections = 0; #ifndef WIN32 @@ -100,7 +97,6 @@ static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t ssl_config_mutex = NULL; static long win32_ssl_create_mutex = 0; #endif -#endif /* ENABLE_THREAD_SAFETY */ static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL; static int ssl_protocol_version_to_openssl(const char *protocol); @@ -112,15 +108,12 @@ static int ssl_protocol_version_to_openssl(const char *protocol); void pgtls_init_library(bool do_ssl, int do_crypto) { -#ifdef ENABLE_THREAD_SAFETY - /* * Disallow changing the flags while we have open connections, else we'd * get completely confused. */ if (crypto_open_connections != 0) return; -#endif pq_init_ssl_lib = do_ssl; pq_init_crypto_lib = do_crypto; @@ -720,7 +713,7 @@ pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn, return rc; } -#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) +#if defined(HAVE_CRYPTO_LOCK) /* * Callback functions for OpenSSL internal locking. (OpenSSL 1.1.0 * does its own locking, and doesn't need these anymore. The @@ -761,7 +754,7 @@ pq_lockingcallback(int mode, int n, const char *file, int line) Assert(false); } } -#endif /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */ +#endif /* HAVE_CRYPTO_LOCK */ /* * Initialize SSL library. @@ -776,7 +769,6 @@ pq_lockingcallback(int mode, int n, const char *file, int line) int pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) { -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 /* Also see similar code in fe-connect.c, default_threadlock() */ if (ssl_config_mutex == NULL) @@ -842,7 +834,6 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) } } #endif /* HAVE_CRYPTO_LOCK */ -#endif /* ENABLE_THREAD_SAFETY */ if (!ssl_lib_initialized && do_ssl) { @@ -859,9 +850,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) ssl_lib_initialized = true; } -#ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&ssl_config_mutex); -#endif return 0; } @@ -880,7 +869,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) static void destroy_ssl_system(void) { -#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) +#if defined(HAVE_CRYPTO_LOCK) /* Mutex is created in pgtls_init() */ if (pthread_mutex_lock(&ssl_config_mutex)) return; diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 8069e38142..bd72a87bbb 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -35,13 +35,11 @@ #include <sys/stat.h> -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include <pthread.h> #endif -#endif #include "fe-auth.h" #include "libpq-fe.h" @@ -56,8 +54,6 @@ #define SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag) -#ifdef ENABLE_THREAD_SAFETY - struct sigpipe_info { sigset_t oldsigmask; @@ -90,24 +86,6 @@ struct sigpipe_info pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \ (spinfo).got_epipe); \ } while (0) -#else /* !ENABLE_THREAD_SAFETY */ - -#define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL - -#define DISABLE_SIGPIPE(conn, spinfo, failaction) \ - do { \ - if (!SIGPIPE_MASKED(conn)) \ - spinfo = pqsignal(SIGPIPE, SIG_IGN); \ - } while (0) - -#define REMEMBER_EPIPE(spinfo, cond) - -#define RESTORE_SIGPIPE(conn, spinfo) \ - do { \ - if (!SIGPIPE_MASKED(conn)) \ - pqsignal(SIGPIPE, spinfo); \ - } while (0) -#endif /* ENABLE_THREAD_SAFETY */ #else /* WIN32 */ #define DECLARE_SIGPIPE_INFO(spinfo) @@ -524,7 +502,7 @@ PQgssEncInUse(PGconn *conn) #endif /* ENABLE_GSS */ -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) +#if !defined(WIN32) /* * Block SIGPIPE for this thread. This prevents send()/write() from exiting @@ -608,4 +586,4 @@ pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe) SOCK_ERRNO_SET(save_errno); } -#endif /* ENABLE_THREAD_SAFETY && !WIN32 */ +#endif /* !WIN32 */ diff --git a/src/interfaces/libpq/legacy-pqsignal.c b/src/interfaces/libpq/legacy-pqsignal.c index 790ab5a18c..97baa86a27 100644 --- a/src/interfaces/libpq/legacy-pqsignal.c +++ b/src/interfaces/libpq/legacy-pqsignal.c @@ -28,9 +28,7 @@ * with the semantics it had in 9.2; in particular, this has different * behavior for SIGALRM than the version in src/port/pqsignal.c. * - * libpq itself uses this only for SIGPIPE (and even then, only in - * non-ENABLE_THREAD_SAFETY builds), so the incompatibility isn't - * troublesome for internal references. + * libpq itself does not use this. */ pqsigfunc pqsignal(int signo, pqsigfunc func) diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 0045f83cbf..10f20c1175 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -31,14 +31,12 @@ #include <sys/time.h> #endif -#ifdef ENABLE_THREAD_SAFETY #ifdef WIN32 #include "pthread-win32.h" #else #include <pthread.h> #endif #include <signal.h> -#endif /* include stuff common to fe and be */ #include "libpq/pqcomm.h" @@ -681,15 +679,10 @@ extern int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len); extern bool pqGetHomeDirectory(char *buf, int bufsize); -#ifdef ENABLE_THREAD_SAFETY extern pgthreadlock_t pg_g_threadlock; #define pglock_thread() pg_g_threadlock(true) #define pgunlock_thread() pg_g_threadlock(false) -#else -#define pglock_thread() ((void) 0) -#define pgunlock_thread() ((void) 0) -#endif /* === in fe-exec.c === */ @@ -765,7 +758,7 @@ extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len); extern ssize_t pqsecure_raw_read(PGconn *, void *ptr, size_t len); extern ssize_t pqsecure_raw_write(PGconn *, const void *ptr, size_t len); -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) +#if !defined(WIN32) extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending); extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe); diff --git a/src/makefiles/meson.build b/src/makefiles/meson.build index 13045cbd6e..be946f7b38 100644 --- a/src/makefiles/meson.build +++ b/src/makefiles/meson.build @@ -52,7 +52,6 @@ pgxs_kv = { 'abs_top_builddir': meson.build_root(), 'abs_top_srcdir': meson.source_root(), - 'enable_thread_safety': 'yes', 'enable_rpath': get_option('rpath') ? 'yes' : 'no', 'enable_nls': libintl.found() ? 'yes' : 'no', 'enable_tap_tests': tap_tests_enabled ? 'yes' : 'no', diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index b6d31c3583..2f484d89fa 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -219,7 +219,6 @@ sub GenerateFiles DLSUFFIX => '".dll"', ENABLE_GSS => $self->{options}->{gss} ? 1 : undef, ENABLE_NLS => $self->{options}->{nls} ? 1 : undef, - ENABLE_THREAD_SAFETY => 1, HAVE_APPEND_HISTORY => undef, HAVE_ASN1_STRING_GET0_DATA => undef, HAVE_ATOMICS => 1, @@ -1199,7 +1198,7 @@ sub GetFakeConfigure { my $self = shift; - my $cfg = '--enable-thread-safety'; + my $cfg = ''; $cfg .= ' --enable-cassert' if ($self->{options}->{asserts}); $cfg .= ' --enable-nls' if ($self->{options}->{nls}); $cfg .= ' --enable-tap-tests' if ($self->{options}->{tap_tests}); diff --git a/src/tools/msvc/ecpg_regression.proj b/src/tools/msvc/ecpg_regression.proj index ec2760b1f6..0ec60a275e 100644 --- a/src/tools/msvc/ecpg_regression.proj +++ b/src/tools/msvc/ecpg_regression.proj @@ -54,7 +54,7 @@ <!-- Run ECPG and the Visual C++ compiler on the files. Don't bother with dependency check between the steps --> <Exec WorkingDirectory="%(Pgc.RelativeDir)" Command="$(OUTDIR)ecpg\ecpg -I ../../include --regression $(ECPGPARAM) -o %(Pgc.Filename).c %(Pgc.Filename).pgc" /> - <Exec WorkingDirectory="%(Pgc.RelativeDir)" Command="cl /nologo %(Pgc.FileName).c /TC /MD$(DEBUGLIB) /DENABLE_THREAD_SAFETY /DWIN32 /I. /I..\..\include /I..\..\..\libpq /I..\..\..\..\include /link /defaultlib:$(OUTDIR)libecpg\libecpg.lib /defaultlib:$(OUTDIR)libecpg_compat\libecpg_compat.lib /defaultlib:$(OUTDIR)libpgtypes\libpgtypes.lib" /> + <Exec WorkingDirectory="%(Pgc.RelativeDir)" Command="cl /nologo %(Pgc.FileName).c /TC /MD$(DEBUGLIB) /DWIN32 /I. /I..\..\include /I..\..\..\libpq /I..\..\..\..\include /link /defaultlib:$(OUTDIR)libecpg\libecpg.lib /defaultlib:$(OUTDIR)libecpg_compat\libecpg_compat.lib /defaultlib:$(OUTDIR)libpgtypes\libpgtypes.lib" /> </Target> <!-- Clean up all output files --> -- 2.39.2 [text/x-patch] 0004-Add-port-pg_threads.h-for-a-common-threading-API.patch (10.1K, ../../CA+hUKGLtmexrpMtxBRLCVePqV_dtWG-ZsEbyPrYc+NBB2TkNsw@mail.gmail.com/5-0004-Add-port-pg_threads.h-for-a-common-threading-API.patch) download | inline diff: From ca74df4ff11ce0fd1e51786eccaeca810921fc6d Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> Date: Sat, 10 Jun 2023 09:14:07 +1200 Subject: [PATCH 4/5] Add port/pg_threads.h for a common threading API. Loosely based on C11's <threads.h>, but with pg_ prefixes, this will allow us to clean up many places that have to cope with POSIX and Windows threads. --- src/include/port/pg_threads.h | 252 +++++++++++++++++++++++++++++++ src/port/Makefile | 1 + src/port/meson.build | 1 + src/port/pg_threads.c | 117 ++++++++++++++ src/tools/pgindent/typedefs.list | 7 + 5 files changed, 378 insertions(+) create mode 100644 src/include/port/pg_threads.h create mode 100644 src/port/pg_threads.c diff --git a/src/include/port/pg_threads.h b/src/include/port/pg_threads.h new file mode 100644 index 0000000000..1706709994 --- /dev/null +++ b/src/include/port/pg_threads.h @@ -0,0 +1,252 @@ +/* + * A multi-threading API abstraction loosely based on the C11 standard's + * <threads.h> header. The identifiers have a pg_ prefix. Perhaps one day + * we'll use standard C threads directly, and we'll drop the prefixes. + * + * Exceptions: + * - pg_thrd_barrier_t is not based on C11 + */ + +#ifndef PG_THREADS_H +#define PG_THREADS_H + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <processthreadsapi.h> +#include <fibersapi.h> +#include <synchapi.h> +#else +#include <errno.h> +#include "port/pg_pthread.h" +#endif + +#include <stdint.h> + +#ifdef WIN32 +typedef HANDLE pg_thrd_t; +typedef CRITICAL_SECTION pg_mtx_t; +typedef CONDITION_VARIABLE pg_cnd_t; +typedef SYNCHRONIZATION_BARRIER pg_thrd_barrier_t; +typedef DWORD pg_tss_t; +typedef INIT_ONCE pg_once_flag; +#define PG_ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT +#else +typedef pthread_t pg_thrd_t; +typedef pthread_mutex_t pg_mtx_t; +typedef pthread_cond_t pg_cnd_t; +typedef pthread_barrier_t pg_thrd_barrier_t; +typedef pthread_key_t pg_tss_t; +typedef pthread_once_t pg_once_flag; +#define PG_ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#endif + +typedef int (*pg_thrd_start_t) (void *); +typedef void (*pg_tss_dtor_t) (void *); +typedef void (*pg_call_once_function_t) (void); + +enum +{ + pg_thrd_success = 0, + pg_thrd_nomem = 1, + pg_thrd_timedout = 2, + pg_thrd_busy = 3, + pg_thrd_error = 4 +}; + +enum +{ + pg_mtx_plain = 0 +}; + +extern int pg_thrd_create(pg_thrd_t *thread, pg_thrd_start_t function, void *argument); +extern int pg_thrd_join(pg_thrd_t thread, int *result); +extern void pg_thrd_exit(int result); + +#ifndef WIN32 +static inline int +pg_thrd_maperror(int error) +{ + if (error == 0) + return pg_thrd_success; + if (error == ENOMEM) + return pg_thrd_nomem; + return pg_thrd_error; +} +#endif + +#ifdef WIN32 +BOOL pg_call_once_trampoline(pg_once_flag *flag, void *parameter, void **context); +#endif + +static inline void +pg_call_once(pg_once_flag *flag, pg_call_once_function_t function) +{ +#ifdef WIN32 + InitOnceExecuteOnce(flag, pg_call_once_trampoline, (void *) function, NULL); +#else + pthread_once(flag, function); +#endif +} + +static inline int +pg_thrd_equal(pg_thrd_t lhs, pg_thrd_t rhs) +{ +#ifdef WIN32 + return lhs == rhs; +#else + return pthread_equal(lhs, rhs); +#endif +} + +static inline int +pg_tss_create(pg_tss_t *key, pg_tss_dtor_t destructor) +{ +#ifdef WIN32 + //*key = FlsAlloc(destructor); + *key = FlsAlloc(NULL); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_key_create(key, destructor)); +#endif +} + +static inline void * +pg_tss_get(pg_tss_t key) +{ +#ifdef WIN32 + return FlsGetValue(key); +#else + return pthread_getspecific(key); +#endif +} + +static inline int +pg_tss_set(pg_tss_t key, void *value) +{ +#ifdef WIN32 + return FlsSetValue(key, value) ? pg_thrd_success : pg_thrd_error; +#else + return pg_thrd_maperror(pthread_setspecific(key, value)); +#endif +} + +static inline int +pg_mtx_init(pg_mtx_t *mutex, int type) +{ +#ifdef WIN32 + InitializeCriticalSection(mutex); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_mutex_init(mutex, NULL)); +#endif +} + +static inline int +pg_mtx_lock(pg_mtx_t *mutex) +{ +#ifdef WIN32 + EnterCriticalSection(mutex); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_mutex_lock(mutex)); +#endif +} + +static inline int +pg_mtx_unlock(pg_mtx_t *mutex) +{ +#ifdef WIN32 + LeaveCriticalSection(mutex); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_mutex_unlock(mutex)); +#endif +} + +static inline int +pg_mtx_destroy(pg_mtx_t *mutex) +{ +#ifdef WIN32 + DeleteCriticalSection(mutex); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_mutex_destroy(mutex)); +#endif +} + +static inline int +pg_cnd_init(pg_cnd_t *condvar) +{ +#ifdef WIN32 + InitializeConditionVariable(condvar); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_cond_init(condvar, NULL)); +#endif +} + +static inline int +pg_cnd_broadcast(pg_cnd_t *condvar) +{ +#ifdef WIN32 + WakeAllConditionVariable(condvar); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_cond_broadcast(condvar)); +#endif +} + +static inline int +pg_cnd_wait(pg_cnd_t *condvar, pg_mtx_t *mutex) +{ +#ifdef WIN32 + SleepConditionVariableCS(condvar, mutex, INFINITE); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_cond_wait(condvar, mutex)); +#endif +} + +static inline int +pg_cnd_destroy(pg_cnd_t *condvar) +{ +#ifdef WIN32 + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_cond_destroy(condvar)); +#endif +} + +static inline int +pg_thrd_barrier_init(pg_thrd_barrier_t *barrier, int count) +{ +#ifdef WIN32 + return InitializeSynchronizationBarrier(barrier, count, 0) ? pg_thrd_success : pg_thrd_error; +#else + return pg_thrd_maperror(pthread_barrier_init(barrier, NULL, count)); +#endif +} + +static inline int +pg_thrd_barrier_wait(pg_thrd_barrier_t *barrier) +{ +#ifdef WIN32 + EnterSynchronizationBarrier(barrier, SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY); + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_barrier_wait(barrier)); +#endif +} + +static inline int +pg_thrd_barrier_destroy(pg_thrd_barrier_t *barrier) +{ +#ifdef WIN32 + return pg_thrd_success; +#else + return pg_thrd_maperror(pthread_barrier_destroy(barrier)); +#endif +} + +#endif diff --git a/src/port/Makefile b/src/port/Makefile index f205c2c9c5..6e9ec3b35f 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -47,6 +47,7 @@ OBJS = \ path.o \ pg_bitutils.o \ pg_strong_random.o \ + pg_threads.o \ pgcheckdir.o \ pgmkdirp.o \ pgsleep.o \ diff --git a/src/port/meson.build b/src/port/meson.build index 9d0cd93c43..3d2277d151 100644 --- a/src/port/meson.build +++ b/src/port/meson.build @@ -8,6 +8,7 @@ pgport_sources = [ 'path.c', 'pg_bitutils.c', 'pg_strong_random.c', + 'pg_threads.c', 'pgcheckdir.c', 'pgmkdirp.c', 'pgsleep.c', diff --git a/src/port/pg_threads.c b/src/port/pg_threads.c new file mode 100644 index 0000000000..ded62b669d --- /dev/null +++ b/src/port/pg_threads.c @@ -0,0 +1,117 @@ +#include "c.h" +#include "port/pg_threads.h" + +#include <errno.h> +#include <stdlib.h> + +/* + * There are small differences between the function types in C11, POSIX (return + * type) and Windows (return type signedness, calling convention). The + * int return value will survive casting to/from void * and DWORD respectively, + * but we still need a small trampoline function to deal with the different + * function pointer type. + */ +typedef struct pg_thrd_thunk +{ + pg_thrd_start_t function; + void *argument; +} pg_thrd_thunk; + +#ifdef WIN32 +BOOL +pg_call_once_trampoline(pg_once_flag *flag, void *parameter, void **context) +{ + pg_call_once_function_t function = (pg_call_once_function_t) parameter; + + function(); + return TRUE; +} +#endif + +#ifdef WIN32 +static DWORD __stdcall +pg_thrd_trampoline(void *vthunk) +#else +static void * +pg_thrd_trampoline(void *vthunk) +#endif +{ + pg_thrd_thunk *thunk = (pg_thrd_thunk *) vthunk; + void *argument = thunk->argument; + pg_thrd_start_t function = thunk->function; + int result; + + free(vthunk); + + result = function(argument); + +#ifdef WIN32 + return (DWORD) result; +#else + return (void *) (intptr_t) result; +#endif +} + +int +pg_thrd_create(pg_thrd_t *thread, pg_thrd_start_t function, void *argument) +{ + pg_thrd_thunk *thunk; + + thunk = malloc(sizeof(*thunk)); + if (thunk == NULL) + return pg_thrd_nomem; + thunk->function = function; + thunk->argument = argument; + +#ifdef WIN32 + *thread = CreateThread(NULL, 0, pg_thrd_trampoline, thunk, 0, 0); + if (*thread != NULL) + return pg_thrd_success; +#else + if (pthread_create(thread, NULL, pg_thrd_trampoline, thunk) == 0) + return pg_thrd_success; +#endif + + free(thunk); + return pg_thrd_error; +} + +int +pg_thrd_join(pg_thrd_t thread, int *result) +{ +#ifdef WIN32 + DWORD dword_result; + + if (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0) + { + if (result) + { + if (!GetExitCodeThread(thread, &dword_result)) + return pg_thrd_error; + *result = (int) dword_result; + } + CloseHandle(thread); + return pg_thrd_success; + } +#else + void *void_star_result; + + if (pthread_join(thread, &void_star_result) == 0) + { + if (result) + *result = (int) (intptr_t) void_star_result; + return pg_thrd_success; + } +#endif + return pg_thrd_error; +} + +void +pg_thrd_exit(int result) +{ +#ifdef WIN32 + ExitThread((DWORD) result); +#else + pthread_exit((void *) (intptr_t) result); +#endif +} diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 260854747b..b4a22e678f 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3515,6 +3515,7 @@ pg_be_sasl_mech pg_checksum_context pg_checksum_raw_context pg_checksum_type +pg_cnd_t pg_compress_algorithm pg_compress_specification pg_conn_host @@ -3540,7 +3541,9 @@ pg_local_to_utf_combined pg_locale_t pg_mb_radix_tree pg_md5_ctx +pg_mtx_t pg_on_exit_callback +pg_once_flag pg_prng_state pg_re_flags pg_saslprep_rc @@ -3551,8 +3554,12 @@ pg_sha384_ctx pg_sha512_ctx pg_snapshot pg_stack_base_t +pg_thrd_t +pg_thrd_thunk +pg_thrd_barrier_t pg_time_t pg_time_usec_t +pg_tss_t pg_tz pg_tz_cache pg_tzenum -- 2.39.2 [text/x-patch] 0005-Replace-various-ad-hoc-abstractions-with-pg_threads..patch (62.9K, ../../CA+hUKGLtmexrpMtxBRLCVePqV_dtWG-ZsEbyPrYc+NBB2TkNsw@mail.gmail.com/6-0005-Replace-various-ad-hoc-abstractions-with-pg_threads..patch) download | inline diff: From 2e1281762b56bb6e62f71124611505e5e29e5627 Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> Date: Fri, 9 Jun 2023 13:27:42 +1200 Subject: [PATCH 5/5] Replace various ad hoc abstractions with pg_threads.h. Several places had their own macros and functions to abstract POSIX and Windows threading APIs. Use the new centralized API instead. --- src/bin/pgbench/pgbench.c | 67 +++---------- src/interfaces/ecpg/ecpglib/connect.c | 43 ++++---- src/interfaces/ecpg/ecpglib/descriptor.c | 14 +-- src/interfaces/ecpg/ecpglib/memory.c | 14 +-- src/interfaces/ecpg/ecpglib/misc.c | 68 ++++--------- src/interfaces/ecpg/ecpglib/sqlda.c | 1 - .../ecpg/include/ecpg-pthread-win32.h | 55 ----------- src/interfaces/ecpg/include/ecpg_config.h.in | 3 + src/interfaces/ecpg/include/meson.build | 1 + .../ecpg/test/expected/thread-alloc.c | 73 +++++--------- .../ecpg/test/expected/thread-descriptor.c | 52 +++------- .../ecpg/test/expected/thread-prep.c | 99 +++++++------------ .../ecpg/test/expected/thread-thread.c | 92 +++++++---------- .../test/expected/thread-thread_implicit.c | 92 +++++++---------- src/interfaces/ecpg/test/thread/alloc.pgc | 39 +------- .../ecpg/test/thread/descriptor.pgc | 38 +------ src/interfaces/ecpg/test/thread/prep.pgc | 37 +------ src/interfaces/ecpg/test/thread/thread.pgc | 38 ++----- .../ecpg/test/thread/thread_implicit.pgc | 38 ++----- src/interfaces/libpq/Makefile | 1 - src/interfaces/libpq/fe-connect.c | 39 +++----- src/interfaces/libpq/fe-secure-openssl.c | 63 +++++------- src/interfaces/libpq/fe-secure.c | 4 +- src/interfaces/libpq/libpq-int.h | 5 - src/interfaces/libpq/meson.build | 4 +- src/interfaces/libpq/pthread-win32.c | 60 ----------- src/port/pthread-win32.h | 22 ----- src/tools/pginclude/cpluspluscheck | 1 - src/tools/pginclude/headerscheck | 1 - 29 files changed, 285 insertions(+), 779 deletions(-) delete mode 100644 src/interfaces/ecpg/include/ecpg-pthread-win32.h delete mode 100644 src/interfaces/libpq/pthread-win32.c delete mode 100644 src/port/pthread-win32.h diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 683fc5860f..57e3b5fb46 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -66,6 +66,7 @@ #include "libpq-fe.h" #include "pgbench.h" #include "port/pg_bitutils.h" +#include "port/pg_threads.h" #include "portability/instr_time.h" /* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */ @@ -113,49 +114,6 @@ typedef struct socket_set #endif /* POLL_USING_SELECT */ -/* - * Multi-platform thread implementations - */ - -#ifdef WIN32 -/* Use Windows threads */ -#include <windows.h> -#define GETERRNO() (_dosmaperr(GetLastError()), errno) -#define THREAD_T HANDLE -#define THREAD_FUNC_RETURN_TYPE unsigned -#define THREAD_FUNC_RETURN return 0 -#define THREAD_FUNC_CC __stdcall -#define THREAD_CREATE(handle, function, arg) \ - ((*(handle) = (HANDLE) _beginthreadex(NULL, 0, (function), (arg), 0, NULL)) == 0 ? errno : 0) -#define THREAD_JOIN(handle) \ - (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 ? \ - GETERRNO() : CloseHandle(handle) ? 0 : GETERRNO()) -#define THREAD_BARRIER_T SYNCHRONIZATION_BARRIER -#define THREAD_BARRIER_INIT(barrier, n) \ - (InitializeSynchronizationBarrier((barrier), (n), 0) ? 0 : GETERRNO()) -#define THREAD_BARRIER_WAIT(barrier) \ - EnterSynchronizationBarrier((barrier), \ - SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) -#define THREAD_BARRIER_DESTROY(barrier) -#else -/* Use POSIX threads */ -#include "port/pg_pthread.h" -#define THREAD_T pthread_t -#define THREAD_FUNC_RETURN_TYPE void * -#define THREAD_FUNC_RETURN return NULL -#define THREAD_FUNC_CC -#define THREAD_CREATE(handle, function, arg) \ - pthread_create((handle), NULL, (function), (arg)) -#define THREAD_JOIN(handle) \ - pthread_join((handle), NULL) -#define THREAD_BARRIER_T pthread_barrier_t -#define THREAD_BARRIER_INIT(barrier, n) \ - pthread_barrier_init((barrier), NULL, (n)) -#define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier)) -#define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier)) -#endif - - /******************************************************************** * some configurable parameters */ @@ -477,7 +435,7 @@ typedef enum TStatus static pg_prng_state base_random_sequence; /* Synchronization barrier for start and connection */ -static THREAD_BARRIER_T barrier; +static pg_thrd_barrier_t barrier; /* * Connection state machine states. @@ -644,7 +602,7 @@ typedef struct typedef struct { int tid; /* thread id */ - THREAD_T thread; /* thread handle */ + pg_thrd_t thread; /* thread handle */ CState *state; /* array of CState */ int nstate; /* length of state[] */ @@ -825,7 +783,7 @@ static void doLog(TState *thread, CState *st, static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg); static void addScript(const ParsedScript *script); -static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg); +static int threadRun(void *arg); static void finishCon(CState *st); static void setalarm(int seconds); static socket_set *alloc_socket_set(int count); @@ -7218,7 +7176,7 @@ main(int argc, char **argv) if (duration > 0) setalarm(duration); - errno = THREAD_BARRIER_INIT(&barrier, nthreads); + errno = pg_thrd_barrier_init(&barrier, nthreads); if (errno != 0) pg_fatal("could not initialize barrier: %m"); @@ -7228,7 +7186,7 @@ main(int argc, char **argv) TState *thread = &threads[i]; thread->create_time = pg_time_now(); - errno = THREAD_CREATE(&thread->thread, threadRun, thread); + errno = pg_thrd_create(&thread->thread, threadRun, thread); if (errno != 0) pg_fatal("could not create thread: %m"); @@ -7251,7 +7209,7 @@ main(int argc, char **argv) TState *thread = &threads[i]; if (i > 0) - THREAD_JOIN(thread->thread); + pg_thrd_join(thread->thread, NULL); for (int j = 0; j < thread->nstate; j++) if (thread->state[j].state != CSTATE_FINISHED) @@ -7291,7 +7249,7 @@ main(int argc, char **argv) printResults(&stats, pg_time_now() - bench_start, conn_total_duration, bench_start - start_time, latency_late); - THREAD_BARRIER_DESTROY(&barrier); + pg_thrd_barrier_destroy(&barrier); if (exit_code != 0) pg_log_error("Run was aborted; the above results are incomplete."); @@ -7299,7 +7257,7 @@ main(int argc, char **argv) return exit_code; } -static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC +static int threadRun(void *arg) { TState *thread = (TState *) arg; @@ -7336,7 +7294,7 @@ threadRun(void *arg) state[i].state = CSTATE_CHOOSE_SCRIPT; /* READY */ - THREAD_BARRIER_WAIT(&barrier); + pg_thrd_barrier_wait(&barrier); thread_start = pg_time_now(); thread->started_time = thread_start; @@ -7360,7 +7318,7 @@ threadRun(void *arg) } /* GO */ - THREAD_BARRIER_WAIT(&barrier); + pg_thrd_barrier_wait(&barrier); start = pg_time_now(); thread->bench_start = start; @@ -7572,7 +7530,8 @@ done: thread->logfile = NULL; } free_socket_set(sockets); - THREAD_FUNC_RETURN; + + return 0; } static void diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index 8afb1f0a26..61ca9a0829 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -2,8 +2,8 @@ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" +#include "port/pg_threads.h" -#include "ecpg-pthread-win32.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" @@ -14,22 +14,23 @@ locale_t ecpg_clocale = (locale_t) 0; #endif -static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_key_t actual_connection_key; -static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT; +static pg_mtx_t connections_mutex; +static pg_tss_t actual_connection_key; +static pg_once_flag actual_connection_key_once = PG_ONCE_FLAG_INIT; static struct connection *actual_connection = NULL; static struct connection *all_connections = NULL; static void ecpg_actual_connection_init(void) { - pthread_key_create(&actual_connection_key, NULL); + pg_mtx_init(&connections_mutex, pg_mtx_plain); + pg_tss_create(&actual_connection_key, NULL); } void ecpg_pthreads_init(void) { - pthread_once(&actual_connection_key_once, ecpg_actual_connection_init); + pg_call_once(&actual_connection_key_once, ecpg_actual_connection_init); } static struct connection * @@ -41,7 +42,7 @@ ecpg_get_connection_nr(const char *connection_name) { ecpg_pthreads_init(); /* ensure actual_connection_key is valid */ - ret = pthread_getspecific(actual_connection_key); + ret = pg_tss_get(actual_connection_key); /* * if no connection in TSD for this thread, get the global default @@ -76,7 +77,7 @@ ecpg_get_connection(const char *connection_name) { ecpg_pthreads_init(); /* ensure actual_connection_key is valid */ - ret = pthread_getspecific(actual_connection_key); + ret = pg_tss_get(actual_connection_key); /* * if no connection in TSD for this thread, get the global default @@ -89,11 +90,11 @@ ecpg_get_connection(const char *connection_name) } else { - pthread_mutex_lock(&connections_mutex); + pg_mtx_lock(&connections_mutex); ret = ecpg_get_connection_nr(connection_name); - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); } return ret; @@ -127,8 +128,8 @@ ecpg_finish(struct connection *act) con->next = act->next; } - if (pthread_getspecific(actual_connection_key) == act) - pthread_setspecific(actual_connection_key, all_connections); + if (pg_tss_get(actual_connection_key) == act) + pg_tss_set(actual_connection_key, all_connections); if (actual_connection == act) actual_connection = all_connections; @@ -194,7 +195,7 @@ ECPGsetconn(int lineno, const char *connection_name) if (!ecpg_init(con, connection_name, lineno)) return false; - pthread_setspecific(actual_connection_key, con); + pg_tss_set(actual_connection_key, con); return true; } @@ -481,7 +482,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p } /* add connection to our list */ - pthread_mutex_lock(&connections_mutex); + pg_mtx_lock(&connections_mutex); /* * ... but first, make certain we have created ecpg_clocale. Rely on @@ -493,7 +494,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); if (!ecpg_clocale) { - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL); if (host) @@ -530,7 +531,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p this->next = all_connections; all_connections = this; - pthread_setspecific(actual_connection_key, all_connections); + pg_tss_set(actual_connection_key, all_connections); actual_connection = all_connections; ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n", @@ -648,7 +649,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_log("ECPGconnect: %s", errmsg); ecpg_finish(this); - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db); if (realname) @@ -660,7 +661,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p if (realname) ecpg_free(realname); - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); this->autocommit = autocommit; @@ -682,7 +683,7 @@ ECPGdisconnect(int lineno, const char *connection_name) return false; } - pthread_mutex_lock(&connections_mutex); + pg_mtx_lock(&connections_mutex); if (strcmp(connection_name, "ALL") == 0) { @@ -701,14 +702,14 @@ ECPGdisconnect(int lineno, const char *connection_name) if (!ecpg_init(con, connection_name, lineno)) { - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); return false; } else ecpg_finish(con); } - pthread_mutex_unlock(&connections_mutex); + pg_mtx_unlock(&connections_mutex); return true; } diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index ad279e245c..b57e065672 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -7,11 +7,11 @@ #include "postgres_fe.h" #include "catalog/pg_type_d.h" -#include "ecpg-pthread-win32.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" #include "ecpgtype.h" +#include "port/pg_threads.h" #include "sql3types.h" #include "sqlca.h" #include "sqlda.h" @@ -19,8 +19,8 @@ static void descriptor_free(struct descriptor *desc); /* We manage descriptors separately for each thread. */ -static pthread_key_t descriptor_key; -static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT; +static pg_tss_t descriptor_key; +static pg_once_flag descriptor_once = PG_ONCE_FLAG_INIT; static void descriptor_deallocate_all(struct descriptor *list); @@ -33,20 +33,20 @@ descriptor_destructor(void *arg) static void descriptor_key_init(void) { - pthread_key_create(&descriptor_key, descriptor_destructor); + pg_tss_create(&descriptor_key, descriptor_destructor); } static struct descriptor * get_descriptors(void) { - pthread_once(&descriptor_once, descriptor_key_init); - return (struct descriptor *) pthread_getspecific(descriptor_key); + pg_call_once(&descriptor_once, descriptor_key_init); + return (struct descriptor *) pg_tss_get(descriptor_key); } static void set_descriptors(struct descriptor *value) { - pthread_setspecific(descriptor_key, value); + pg_tss_set(descriptor_key, value); } /* old internal convenience function that might go away later */ diff --git a/src/interfaces/ecpg/ecpglib/memory.c b/src/interfaces/ecpg/ecpglib/memory.c index a83637ac75..985f05087d 100644 --- a/src/interfaces/ecpg/ecpglib/memory.c +++ b/src/interfaces/ecpg/ecpglib/memory.c @@ -3,11 +3,11 @@ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" -#include "ecpg-pthread-win32.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" #include "ecpgtype.h" +#include "port/pg_threads.h" void ecpg_free(void *ptr) @@ -68,8 +68,8 @@ struct auto_mem struct auto_mem *next; }; -static pthread_key_t auto_mem_key; -static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT; +static pg_tss_t auto_mem_key; +static pg_once_flag auto_mem_once = PG_ONCE_FLAG_INIT; static void auto_mem_destructor(void *arg) @@ -81,20 +81,20 @@ auto_mem_destructor(void *arg) static void auto_mem_key_init(void) { - pthread_key_create(&auto_mem_key, auto_mem_destructor); + pg_tss_create(&auto_mem_key, auto_mem_destructor); } static struct auto_mem * get_auto_allocs(void) { - pthread_once(&auto_mem_once, auto_mem_key_init); - return (struct auto_mem *) pthread_getspecific(auto_mem_key); + pg_call_once(&auto_mem_once, auto_mem_key_init); + return (struct auto_mem *) pg_tss_get(auto_mem_key); } static void set_auto_allocs(struct auto_mem *am) { - pthread_setspecific(auto_mem_key, am); + pg_tss_set(auto_mem_key, am); } char * diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index 2b78caeaf5..b3d997e749 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -6,7 +6,6 @@ #include <limits.h> #include <unistd.h> -#include "ecpg-pthread-win32.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" @@ -16,6 +15,7 @@ #include "pgtypes_interval.h" #include "pgtypes_numeric.h" #include "pgtypes_timestamp.h" +#include "port/pg_threads.h" #include "sqlca.h" #ifndef LONG_LONG_MIN @@ -55,11 +55,10 @@ static struct sqlca_t sqlca_init = } }; -static pthread_key_t sqlca_key; -static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT; - -static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER; +static pg_tss_t sqlca_key; +static pg_once_flag ecpg_once = PG_ONCE_FLAG_INIT; +static pg_mtx_t debug_mutex; +static pg_mtx_t debug_init_mutex; static int simple_debug = 0; static FILE *debugstream = NULL; @@ -99,9 +98,11 @@ ecpg_sqlca_key_destructor(void *arg) } static void -ecpg_sqlca_key_init(void) +ecpg_init_once(void) { - pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor); + pg_tss_create(&sqlca_key, ecpg_sqlca_key_destructor); + pg_mtx_init(&debug_mutex, pg_mtx_plain); + pg_mtx_init(&debug_init_mutex, pg_mtx_plain); } struct sqlca_t * @@ -109,16 +110,16 @@ ECPGget_sqlca(void) { struct sqlca_t *sqlca; - pthread_once(&sqlca_key_once, ecpg_sqlca_key_init); + pg_call_once(&ecpg_once, ecpg_init_once); - sqlca = pthread_getspecific(sqlca_key); + sqlca = pg_tss_get(sqlca_key); if (sqlca == NULL) { sqlca = malloc(sizeof(struct sqlca_t)); if (sqlca == NULL) return NULL; ecpg_init_sqlca(sqlca); - pthread_setspecific(sqlca_key, sqlca); + pg_tss_set(sqlca_key, sqlca); } return sqlca; } @@ -203,7 +204,9 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction) void ECPGdebug(int n, FILE *dbgs) { - pthread_mutex_lock(&debug_init_mutex); + pg_call_once(&ecpg_once, ecpg_init_once); + + pg_mtx_lock(&debug_init_mutex); if (n > 100) { @@ -217,7 +220,7 @@ ECPGdebug(int n, FILE *dbgs) ecpg_log("ECPGdebug: set to %d\n", simple_debug); - pthread_mutex_unlock(&debug_init_mutex); + pg_mtx_unlock(&debug_init_mutex); } void @@ -249,7 +252,9 @@ ecpg_log(const char *format,...) else snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format); - pthread_mutex_lock(&debug_mutex); + pg_call_once(&ecpg_once, ecpg_init_once); + + pg_mtx_lock(&debug_mutex); va_start(ap, format); vfprintf(debugstream, fmt, ap); @@ -264,7 +269,7 @@ ecpg_log(const char *format,...) fflush(debugstream); - pthread_mutex_unlock(&debug_mutex); + pg_mtx_unlock(&debug_mutex); free(fmt); } @@ -405,39 +410,6 @@ ECPGis_noind_null(enum ECPGttype type, const void *ptr) return false; } -#ifdef WIN32 - -void -win32_pthread_mutex(volatile pthread_mutex_t *mutex) -{ - if (mutex->handle == NULL) - { - while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1) - Sleep(0); - if (mutex->handle == NULL) - mutex->handle = CreateMutex(NULL, FALSE, NULL); - InterlockedExchange((LONG *) &mutex->initlock, 0); - } -} - -static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER; - -void -win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void)) -{ - if (!*once) - { - pthread_mutex_lock(&win32_pthread_once_lock); - if (!*once) - { - fn(); - *once = true; - } - pthread_mutex_unlock(&win32_pthread_once_lock); - } -} -#endif /* WIN32 */ - #ifdef ENABLE_NLS char * diff --git a/src/interfaces/ecpg/ecpglib/sqlda.c b/src/interfaces/ecpg/ecpglib/sqlda.c index 081e32666f..7231cc4a6f 100644 --- a/src/interfaces/ecpg/ecpglib/sqlda.c +++ b/src/interfaces/ecpg/ecpglib/sqlda.c @@ -11,7 +11,6 @@ #include "catalog/pg_type_d.h" #include "decimal.h" -#include "ecpg-pthread-win32.h" #include "ecpgerrno.h" #include "ecpglib.h" #include "ecpglib_extern.h" diff --git a/src/interfaces/ecpg/include/ecpg-pthread-win32.h b/src/interfaces/ecpg/include/ecpg-pthread-win32.h deleted file mode 100644 index 8252a17809..0000000000 --- a/src/interfaces/ecpg/include/ecpg-pthread-win32.h +++ /dev/null @@ -1,55 +0,0 @@ -/* src/interfaces/ecpg/include/ecpg-pthread-win32.h */ -/* - * pthread mapping macros for win32 native thread implementation - */ -#ifndef _ECPG_PTHREAD_WIN32_H -#define _ECPG_PTHREAD_WIN32_H - -#ifndef WIN32 - -#include <pthread.h> -#else - -typedef struct pthread_mutex_t -{ - HANDLE handle; - LONG initlock; -} pthread_mutex_t; - -typedef DWORD pthread_key_t; -typedef bool pthread_once_t; - -#define PTHREAD_MUTEX_INITIALIZER { NULL, 0 } -#define PTHREAD_ONCE_INIT false - -void win32_pthread_mutex(volatile pthread_mutex_t *mutex); -void win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void)); - -#define pthread_mutex_lock(mutex) \ - do { \ - if ((mutex)->handle == NULL) \ - win32_pthread_mutex((mutex)); \ - WaitForSingleObject((mutex)->handle, INFINITE); \ - } while(0) - -#define pthread_mutex_unlock(mutex) \ - ReleaseMutex((mutex)->handle) - -#define pthread_getspecific(key) \ - TlsGetValue((key)) - -#define pthread_setspecific(key, value) \ - TlsSetValue((key), (value)) - -/* FIXME: destructor is never called in Win32. */ -#define pthread_key_create(key, destructor) \ - do { *(key) = TlsAlloc(); ((void)(destructor)); } while(0) - -#define pthread_once(once, fn) \ - do { \ - if (!*(once)) \ - win32_pthread_once((once), (fn)); \ - } while(0) -#endif /* WIN32 */ - -#endif /* _ECPG_PTHREAD_WIN32_H */ diff --git a/src/interfaces/ecpg/include/ecpg_config.h.in b/src/interfaces/ecpg/include/ecpg_config.h.in index 6d01608a49..e693c9074f 100644 --- a/src/interfaces/ecpg/include/ecpg_config.h.in +++ b/src/interfaces/ecpg/include/ecpg_config.h.in @@ -10,5 +10,8 @@ /* Define to 1 if `long long int' works and is 64 bits. */ #undef HAVE_LONG_LONG_INT_64 +/* Define to 1 if you have the `pthread_barrier_wait' function. */ +#undef HAVE_PTHREAD_BARRIER_WAIT + /* Define to 1 to use <stdbool.h> to define type bool. */ #undef PG_USE_STDBOOL diff --git a/src/interfaces/ecpg/include/meson.build b/src/interfaces/ecpg/include/meson.build index 543e48fd6e..2e93efde98 100644 --- a/src/interfaces/ecpg/include/meson.build +++ b/src/interfaces/ecpg/include/meson.build @@ -6,6 +6,7 @@ ecpg_conf_keys = [ 'HAVE_INT64', 'HAVE_LONG_INT_64', 'HAVE_LONG_LONG_INT_64', + 'HAVE_PTHREAD_BARRIER_WAIT', 'PG_USE_STDBOOL', ] diff --git a/src/interfaces/ecpg/test/expected/thread-alloc.c b/src/interfaces/ecpg/test/expected/thread-alloc.c index 3b31d27fd3..97ed928ef1 100644 --- a/src/interfaces/ecpg/test/expected/thread-alloc.c +++ b/src/interfaces/ecpg/test/expected/thread-alloc.c @@ -10,16 +10,7 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif -#include <stdio.h> +#include "port/pg_threads.h" #define THREADS 16 #define REPEATS 50 @@ -93,7 +84,7 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 18 "alloc.pgc" +#line 9 "alloc.pgc" #line 1 "regression.h" @@ -103,21 +94,17 @@ struct sqlca_t *ECPGget_sqlca(void); -#line 19 "alloc.pgc" +#line 10 "alloc.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 21 "alloc.pgc" +#line 12 "alloc.pgc" /* exec sql whenever not found sqlprint ; */ -#line 22 "alloc.pgc" +#line 13 "alloc.pgc" -#ifdef WIN32 -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; @@ -126,54 +113,54 @@ static void* fn(void* arg) -#line 33 "alloc.pgc" +#line 20 "alloc.pgc" int value ; -#line 34 "alloc.pgc" +#line 21 "alloc.pgc" char name [ 100 ] ; -#line 35 "alloc.pgc" +#line 22 "alloc.pgc" char ** r = NULL ; /* exec sql end declare section */ -#line 36 "alloc.pgc" +#line 23 "alloc.pgc" value = (intptr_t) arg; sprintf(name, "Connection: %d", value); { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); -#line 41 "alloc.pgc" +#line 28 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 41 "alloc.pgc" +#line 28 "alloc.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 42 "alloc.pgc" +#line 29 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 42 "alloc.pgc" +#line 29 "alloc.pgc" for (i = 1; i <= REPEATS; ++i) { { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select relname from pg_class where relname = 'pg_class'", ECPGt_EOIT, ECPGt_char,&(r),(long)0,(long)0,(1)*sizeof(char), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); -#line 45 "alloc.pgc" +#line 32 "alloc.pgc" if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint(); -#line 45 "alloc.pgc" +#line 32 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 45 "alloc.pgc" +#line 32 "alloc.pgc" free(r); r = NULL; } { ECPGdisconnect(__LINE__, name); -#line 49 "alloc.pgc" +#line 36 "alloc.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 49 "alloc.pgc" +#line 36 "alloc.pgc" return 0; @@ -182,28 +169,12 @@ if (sqlca.sqlcode < 0) sqlprint();} int main () { intptr_t i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif - -#ifdef WIN32 - for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id); - } + pg_thrd_t threads[THREADS]; - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else + pg_thrd_create(&threads[i], fn, (void *) i); for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, (void *) i); - for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/expected/thread-descriptor.c b/src/interfaces/ecpg/test/expected/thread-descriptor.c index e34f4708d1..50cdbf1b2f 100644 --- a/src/interfaces/ecpg/test/expected/thread-descriptor.c +++ b/src/interfaces/ecpg/test/expected/thread-descriptor.c @@ -7,15 +7,7 @@ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) #line 1 "descriptor.pgc" -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif -#include <stdio.h> +#include "port/pg_threads.h" #define THREADS 16 #define REPEATS 50000 @@ -89,36 +81,32 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 14 "descriptor.pgc" +#line 6 "descriptor.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 15 "descriptor.pgc" +#line 7 "descriptor.pgc" /* exec sql whenever not found sqlprint ; */ -#line 16 "descriptor.pgc" +#line 8 "descriptor.pgc" -#if defined(WIN32) -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; for (i = 1; i <= REPEATS; ++i) { ECPGallocate_desc(__LINE__, "mydesc"); -#line 28 "descriptor.pgc" +#line 16 "descriptor.pgc" if (sqlca.sqlcode < 0) sqlprint(); -#line 28 "descriptor.pgc" +#line 16 "descriptor.pgc" ECPGdeallocate_desc(__LINE__, "mydesc"); -#line 29 "descriptor.pgc" +#line 17 "descriptor.pgc" if (sqlca.sqlcode < 0) sqlprint(); -#line 29 "descriptor.pgc" +#line 17 "descriptor.pgc" } @@ -128,28 +116,12 @@ if (sqlca.sqlcode < 0) sqlprint(); int main () { int i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif - -#ifdef WIN32 - for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, NULL, 0, &id); - } + pg_thrd_t threads[THREADS]; - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); - for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, NULL); + pg_thrd_create(&threads[i], fn, NULL); for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/expected/thread-prep.c b/src/interfaces/ecpg/test/expected/thread-prep.c index 052e27b634..c5b60d18cb 100644 --- a/src/interfaces/ecpg/test/expected/thread-prep.c +++ b/src/interfaces/ecpg/test/expected/thread-prep.c @@ -10,15 +10,8 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" +#include "port/pg_threads.h" -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif #include <stdio.h> #define THREADS 16 @@ -93,7 +86,7 @@ struct sqlca_t *ECPGget_sqlca(void); #endif -#line 18 "prep.pgc" +#line 11 "prep.pgc" #line 1 "regression.h" @@ -103,21 +96,17 @@ struct sqlca_t *ECPGget_sqlca(void); -#line 19 "prep.pgc" +#line 12 "prep.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 21 "prep.pgc" +#line 14 "prep.pgc" /* exec sql whenever not found sqlprint ; */ -#line 22 "prep.pgc" +#line 15 "prep.pgc" -#ifdef WIN32 -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; @@ -126,64 +115,64 @@ static void* fn(void* arg) -#line 33 "prep.pgc" +#line 22 "prep.pgc" int value ; -#line 34 "prep.pgc" +#line 23 "prep.pgc" char name [ 100 ] ; -#line 35 "prep.pgc" +#line 24 "prep.pgc" char query [ 256 ] = "INSERT INTO T VALUES ( ? )" ; /* exec sql end declare section */ -#line 36 "prep.pgc" +#line 25 "prep.pgc" value = (intptr_t) arg; sprintf(name, "Connection: %d", value); { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); -#line 41 "prep.pgc" +#line 30 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 41 "prep.pgc" +#line 30 "prep.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 42 "prep.pgc" +#line 31 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 42 "prep.pgc" +#line 31 "prep.pgc" for (i = 1; i <= REPEATS; ++i) { { ECPGprepare(__LINE__, NULL, 0, "i", query); -#line 45 "prep.pgc" +#line 34 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 45 "prep.pgc" +#line 34 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "i", ECPGt_int,&(value),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 46 "prep.pgc" +#line 35 "prep.pgc" if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint(); -#line 46 "prep.pgc" +#line 35 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 46 "prep.pgc" +#line 35 "prep.pgc" } { ECPGdeallocate(__LINE__, 0, NULL, "i"); -#line 48 "prep.pgc" +#line 37 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 48 "prep.pgc" +#line 37 "prep.pgc" { ECPGdisconnect(__LINE__, name); -#line 49 "prep.pgc" +#line 38 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 49 "prep.pgc" +#line 38 "prep.pgc" return 0; @@ -192,59 +181,43 @@ if (sqlca.sqlcode < 0) sqlprint();} int main () { intptr_t i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif + pg_thrd_t threads[THREADS]; { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); -#line 63 "prep.pgc" +#line 48 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 63 "prep.pgc" +#line 48 "prep.pgc" { ECPGsetcommit(__LINE__, "on", NULL); -#line 64 "prep.pgc" +#line 49 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 64 "prep.pgc" +#line 49 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table if exists T", ECPGt_EOIT, ECPGt_EORT); -#line 65 "prep.pgc" +#line 50 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 65 "prep.pgc" +#line 50 "prep.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table T ( i int )", ECPGt_EOIT, ECPGt_EORT); -#line 66 "prep.pgc" +#line 51 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 66 "prep.pgc" +#line 51 "prep.pgc" { ECPGdisconnect(__LINE__, "CURRENT"); -#line 67 "prep.pgc" +#line 52 "prep.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 67 "prep.pgc" +#line 52 "prep.pgc" -#ifdef WIN32 for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id); - } - - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); + pg_thrd_create(&threads[i], fn, (void *) i); for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else - for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, (void *) i); - for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/expected/thread-thread.c b/src/interfaces/ecpg/test/expected/thread-thread.c index 95faa223c2..03c7169995 100644 --- a/src/interfaces/ecpg/test/expected/thread-thread.c +++ b/src/interfaces/ecpg/test/expected/thread-thread.c @@ -14,13 +14,7 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifndef WIN32 -#include <pthread.h> -#else -#include <windows.h> -#include <locale.h> -#endif +#include "port/pg_threads.h" #line 1 "regression.h" @@ -30,29 +24,25 @@ -#line 16 "thread.pgc" +#line 10 "thread.pgc" -void *test_thread(void *arg); +int test_thread(void *arg); int nthreads = 10; int iterations = 20; int main() { -#ifndef WIN32 - pthread_t *threads; -#else - HANDLE *threads; -#endif + pg_thrd_t *threads; intptr_t n; /* exec sql begin declare section */ -#line 32 "thread.pgc" +#line 22 "thread.pgc" int l_rows ; /* exec sql end declare section */ -#line 33 "thread.pgc" +#line 23 "thread.pgc" /* Do not switch on debug output for regression tests. The threads get executed in @@ -61,22 +51,22 @@ int main() /* setup test_thread table */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 40 "thread.pgc" +#line 30 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);} -#line 41 "thread.pgc" +#line 31 "thread.pgc" /* DROP might fail */ { ECPGtrans(__LINE__, NULL, "commit");} -#line 42 "thread.pgc" +#line 32 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);} -#line 47 "thread.pgc" +#line 37 "thread.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 48 "thread.pgc" +#line 38 "thread.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 49 "thread.pgc" +#line 39 "thread.pgc" /* create, and start, threads */ @@ -87,39 +77,27 @@ int main() return 1; } for( n = 0; n < nthreads; n++ ) - { -#ifndef WIN32 - pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1)); -#else - threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n + 1), 0, NULL); -#endif - } + pg_thrd_create(&threads[n], test_thread, (void *) (n + 1)); /* wait for thread completion */ -#ifndef WIN32 for( n = 0; n < nthreads; n++ ) - { - pthread_join(threads[n], NULL); - } -#else - WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE); -#endif + pg_thrd_join(threads[n], NULL); free(threads); /* and check results */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 79 "thread.pgc" +#line 57 "thread.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} -#line 80 "thread.pgc" +#line 58 "thread.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 81 "thread.pgc" +#line 59 "thread.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 82 "thread.pgc" +#line 60 "thread.pgc" if( l_rows == (nthreads * iterations) ) printf("Success.\n"); @@ -129,7 +107,7 @@ int main() return 0; } -void *test_thread(void *arg) +int test_thread(void *arg) { long threadnum = (intptr_t) arg; @@ -137,13 +115,13 @@ void *test_thread(void *arg) -#line 96 "thread.pgc" +#line 74 "thread.pgc" int l_i ; -#line 97 "thread.pgc" +#line 75 "thread.pgc" char l_connection [ 128 ] ; /* exec sql end declare section */ -#line 98 "thread.pgc" +#line 76 "thread.pgc" /* build up connection name, and connect to database */ @@ -153,24 +131,24 @@ void *test_thread(void *arg) _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum); #endif /* exec sql whenever sqlerror sqlprint ; */ -#line 106 "thread.pgc" +#line 84 "thread.pgc" { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); -#line 107 "thread.pgc" +#line 85 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 107 "thread.pgc" +#line 85 "thread.pgc" if( sqlca.sqlcode != 0 ) { printf("%s: ERROR: cannot connect to database!\n", l_connection); - return NULL; + return 0; } { ECPGtrans(__LINE__, l_connection, "begin"); -#line 113 "thread.pgc" +#line 91 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 113 "thread.pgc" +#line 91 "thread.pgc" /* insert into test_thread table */ @@ -181,10 +159,10 @@ if (sqlca.sqlcode < 0) sqlprint();} ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 118 "thread.pgc" +#line 96 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 118 "thread.pgc" +#line 96 "thread.pgc" if( sqlca.sqlcode != 0 ) printf("%s: ERROR: insert failed!\n", l_connection); @@ -192,16 +170,16 @@ if (sqlca.sqlcode < 0) sqlprint();} /* all done */ { ECPGtrans(__LINE__, l_connection, "commit"); -#line 124 "thread.pgc" +#line 102 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 124 "thread.pgc" +#line 102 "thread.pgc" { ECPGdisconnect(__LINE__, l_connection); -#line 125 "thread.pgc" +#line 103 "thread.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 125 "thread.pgc" +#line 103 "thread.pgc" - return NULL; + return 0; } diff --git a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c index 7ac0297a23..c859012f50 100644 --- a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c +++ b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c @@ -14,13 +14,7 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifndef WIN32 -#include <pthread.h> -#else -#include <windows.h> -#include <locale.h> -#endif +#include "port/pg_threads.h" #line 1 "regression.h" @@ -30,29 +24,25 @@ -#line 16 "thread_implicit.pgc" +#line 10 "thread_implicit.pgc" -void *test_thread(void *arg); +int test_thread(void *arg); int nthreads = 10; int iterations = 20; int main() { -#ifndef WIN32 - pthread_t *threads; -#else - HANDLE *threads; -#endif + pg_thrd_t *threads; intptr_t n; /* exec sql begin declare section */ -#line 32 "thread_implicit.pgc" +#line 22 "thread_implicit.pgc" int l_rows ; /* exec sql end declare section */ -#line 33 "thread_implicit.pgc" +#line 23 "thread_implicit.pgc" /* Do not switch on debug output for regression tests. The threads get executed in @@ -61,22 +51,22 @@ int main() /* setup test_thread table */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 40 "thread_implicit.pgc" +#line 30 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);} -#line 41 "thread_implicit.pgc" +#line 31 "thread_implicit.pgc" /* DROP might fail */ { ECPGtrans(__LINE__, NULL, "commit");} -#line 42 "thread_implicit.pgc" +#line 32 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);} -#line 47 "thread_implicit.pgc" +#line 37 "thread_implicit.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 48 "thread_implicit.pgc" +#line 38 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 49 "thread_implicit.pgc" +#line 39 "thread_implicit.pgc" /* create, and start, threads */ @@ -87,39 +77,27 @@ int main() return 1; } for( n = 0; n < nthreads; n++ ) - { -#ifndef WIN32 - pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1)); -#else - threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n+1), 0, NULL); -#endif - } + pg_thrd_create(&threads[n], test_thread, (void *) (n + 1)); /* wait for thread completion */ -#ifndef WIN32 for( n = 0; n < nthreads; n++ ) - { - pthread_join(threads[n], NULL); - } -#else - WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE); -#endif + pg_thrd_join(threads[n], NULL); free(threads); /* and check results */ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); } -#line 79 "thread_implicit.pgc" +#line 57 "thread_implicit.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} -#line 80 "thread_implicit.pgc" +#line 58 "thread_implicit.pgc" { ECPGtrans(__LINE__, NULL, "commit");} -#line 81 "thread_implicit.pgc" +#line 59 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, "CURRENT");} -#line 82 "thread_implicit.pgc" +#line 60 "thread_implicit.pgc" if( l_rows == (nthreads * iterations) ) printf("Success.\n"); @@ -129,7 +107,7 @@ int main() return 0; } -void *test_thread(void *arg) +int test_thread(void *arg) { long threadnum = (intptr_t) arg; @@ -137,13 +115,13 @@ void *test_thread(void *arg) -#line 96 "thread_implicit.pgc" +#line 74 "thread_implicit.pgc" int l_i ; -#line 97 "thread_implicit.pgc" +#line 75 "thread_implicit.pgc" char l_connection [ 128 ] ; /* exec sql end declare section */ -#line 98 "thread_implicit.pgc" +#line 76 "thread_implicit.pgc" /* build up connection name, and connect to database */ @@ -153,24 +131,24 @@ void *test_thread(void *arg) _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum); #endif /* exec sql whenever sqlerror sqlprint ; */ -#line 106 "thread_implicit.pgc" +#line 84 "thread_implicit.pgc" { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); -#line 107 "thread_implicit.pgc" +#line 85 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 107 "thread_implicit.pgc" +#line 85 "thread_implicit.pgc" if( sqlca.sqlcode != 0 ) { printf("%s: ERROR: cannot connect to database!\n", l_connection); - return NULL; + return 0; } { ECPGtrans(__LINE__, NULL, "begin"); -#line 113 "thread_implicit.pgc" +#line 91 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 113 "thread_implicit.pgc" +#line 91 "thread_implicit.pgc" /* insert into test_thread table */ @@ -181,10 +159,10 @@ if (sqlca.sqlcode < 0) sqlprint();} ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); -#line 118 "thread_implicit.pgc" +#line 96 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 118 "thread_implicit.pgc" +#line 96 "thread_implicit.pgc" if( sqlca.sqlcode != 0 ) printf("%s: ERROR: insert failed!\n", l_connection); @@ -192,16 +170,16 @@ if (sqlca.sqlcode < 0) sqlprint();} /* all done */ { ECPGtrans(__LINE__, NULL, "commit"); -#line 124 "thread_implicit.pgc" +#line 102 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 124 "thread_implicit.pgc" +#line 102 "thread_implicit.pgc" { ECPGdisconnect(__LINE__, l_connection); -#line 125 "thread_implicit.pgc" +#line 103 "thread_implicit.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 125 "thread_implicit.pgc" +#line 103 "thread_implicit.pgc" - return NULL; + return 0; } diff --git a/src/interfaces/ecpg/test/thread/alloc.pgc b/src/interfaces/ecpg/test/thread/alloc.pgc index d3d35493bf..248a29447c 100644 --- a/src/interfaces/ecpg/test/thread/alloc.pgc +++ b/src/interfaces/ecpg/test/thread/alloc.pgc @@ -1,16 +1,7 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif -#include <stdio.h> +#include "port/pg_threads.h" #define THREADS 16 #define REPEATS 50 @@ -21,11 +12,7 @@ exec sql include ../regression; exec sql whenever sqlerror sqlprint; exec sql whenever not found sqlprint; -#ifdef WIN32 -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; @@ -54,28 +41,12 @@ static void* fn(void* arg) int main () { intptr_t i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif - -#ifdef WIN32 - for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id); - } + pg_thrd_t threads[THREADS]; - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); - for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, (void *) i); + pg_thrd_create(&threads[i], fn, (void *) i); for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/thread/descriptor.pgc b/src/interfaces/ecpg/test/thread/descriptor.pgc index 30bce7c87b..faa9a0a656 100644 --- a/src/interfaces/ecpg/test/thread/descriptor.pgc +++ b/src/interfaces/ecpg/test/thread/descriptor.pgc @@ -1,12 +1,4 @@ -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif -#include <stdio.h> +#include "port/pg_threads.h" #define THREADS 16 #define REPEATS 50000 @@ -15,11 +7,7 @@ EXEC SQL include sqlca; EXEC SQL whenever sqlerror sqlprint; EXEC SQL whenever not found sqlprint; -#if defined(WIN32) -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; @@ -35,28 +23,12 @@ static void* fn(void* arg) int main () { int i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif + pg_thrd_t threads[THREADS]; -#ifdef WIN32 for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, NULL, 0, &id); - } - - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); - for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else - for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, NULL); + pg_thrd_create(&threads[i], fn, NULL); for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/thread/prep.pgc b/src/interfaces/ecpg/test/thread/prep.pgc index f61b31ce10..f5a875cc28 100644 --- a/src/interfaces/ecpg/test/thread/prep.pgc +++ b/src/interfaces/ecpg/test/thread/prep.pgc @@ -1,15 +1,8 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" +#include "port/pg_threads.h" -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <process.h> -#include <locale.h> -#else -#include <pthread.h> -#endif #include <stdio.h> #define THREADS 16 @@ -21,11 +14,7 @@ exec sql include ../regression; exec sql whenever sqlerror sqlprint; exec sql whenever not found sqlprint; -#ifdef WIN32 -static unsigned __stdcall fn(void* arg) -#else -static void* fn(void* arg) -#endif +static int fn(void* arg) { int i; @@ -54,11 +43,7 @@ static void* fn(void* arg) int main () { intptr_t i; -#ifdef WIN32 - HANDLE threads[THREADS]; -#else - pthread_t threads[THREADS]; -#endif + pg_thrd_t threads[THREADS]; EXEC SQL CONNECT TO REGRESSDB1; EXEC SQL SET AUTOCOMMIT TO ON; @@ -66,22 +51,10 @@ int main () EXEC SQL CREATE TABLE T ( i int ); EXEC SQL DISCONNECT; -#ifdef WIN32 for (i = 0; i < THREADS; ++i) - { - unsigned id; - threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id); - } - - WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE); - for (i = 0; i < THREADS; ++i) - CloseHandle(threads[i]); -#else - for (i = 0; i < THREADS; ++i) - pthread_create(&threads[i], NULL, fn, (void *) i); + pg_thrd_create(&threads[i], fn, (void *) i); for (i = 0; i < THREADS; ++i) - pthread_join(threads[i], NULL); -#endif + pg_thrd_join(threads[i], NULL); return 0; } diff --git a/src/interfaces/ecpg/test/thread/thread.pgc b/src/interfaces/ecpg/test/thread/thread.pgc index b9b9ebb441..bc967b9da8 100644 --- a/src/interfaces/ecpg/test/thread/thread.pgc +++ b/src/interfaces/ecpg/test/thread/thread.pgc @@ -5,28 +5,18 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifndef WIN32 -#include <pthread.h> -#else -#include <windows.h> -#include <locale.h> -#endif +#include "port/pg_threads.h" exec sql include ../regression; -void *test_thread(void *arg); +int test_thread(void *arg); int nthreads = 10; int iterations = 20; int main() { -#ifndef WIN32 - pthread_t *threads; -#else - HANDLE *threads; -#endif + pg_thrd_t *threads; intptr_t n; EXEC SQL BEGIN DECLARE SECTION; int l_rows; @@ -56,23 +46,11 @@ int main() return 1; } for( n = 0; n < nthreads; n++ ) - { -#ifndef WIN32 - pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1)); -#else - threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n + 1), 0, NULL); -#endif - } + pg_thrd_create(&threads[n], test_thread, (void *) (n + 1)); /* wait for thread completion */ -#ifndef WIN32 for( n = 0; n < nthreads; n++ ) - { - pthread_join(threads[n], NULL); - } -#else - WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE); -#endif + pg_thrd_join(threads[n], NULL); free(threads); /* and check results */ @@ -88,7 +66,7 @@ int main() return 0; } -void *test_thread(void *arg) +int test_thread(void *arg) { long threadnum = (intptr_t) arg; @@ -108,7 +86,7 @@ void *test_thread(void *arg) if( sqlca.sqlcode != 0 ) { printf("%s: ERROR: cannot connect to database!\n", l_connection); - return NULL; + return 0; } EXEC SQL AT :l_connection BEGIN; @@ -123,5 +101,5 @@ void *test_thread(void *arg) /* all done */ EXEC SQL AT :l_connection COMMIT; EXEC SQL DISCONNECT :l_connection; - return NULL; + return 0; } diff --git a/src/interfaces/ecpg/test/thread/thread_implicit.pgc b/src/interfaces/ecpg/test/thread/thread_implicit.pgc index ff9b12a943..7a793dc7f8 100644 --- a/src/interfaces/ecpg/test/thread/thread_implicit.pgc +++ b/src/interfaces/ecpg/test/thread/thread_implicit.pgc @@ -5,28 +5,18 @@ #include <stdint.h> #include <stdlib.h> #include "ecpg_config.h" - -#ifndef WIN32 -#include <pthread.h> -#else -#include <windows.h> -#include <locale.h> -#endif +#include "port/pg_threads.h" exec sql include ../regression; -void *test_thread(void *arg); +int test_thread(void *arg); int nthreads = 10; int iterations = 20; int main() { -#ifndef WIN32 - pthread_t *threads; -#else - HANDLE *threads; -#endif + pg_thrd_t *threads; intptr_t n; EXEC SQL BEGIN DECLARE SECTION; int l_rows; @@ -56,23 +46,11 @@ int main() return 1; } for( n = 0; n < nthreads; n++ ) - { -#ifndef WIN32 - pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1)); -#else - threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n+1), 0, NULL); -#endif - } + pg_thrd_create(&threads[n], test_thread, (void *) (n + 1)); /* wait for thread completion */ -#ifndef WIN32 for( n = 0; n < nthreads; n++ ) - { - pthread_join(threads[n], NULL); - } -#else - WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE); -#endif + pg_thrd_join(threads[n], NULL); free(threads); /* and check results */ @@ -88,7 +66,7 @@ int main() return 0; } -void *test_thread(void *arg) +int test_thread(void *arg) { long threadnum = (intptr_t) arg; @@ -108,7 +86,7 @@ void *test_thread(void *arg) if( sqlca.sqlcode != 0 ) { printf("%s: ERROR: cannot connect to database!\n", l_connection); - return NULL; + return 0; } EXEC SQL BEGIN; @@ -123,5 +101,5 @@ void *test_thread(void *arg) /* all done */ EXEC SQL COMMIT; EXEC SQL DISCONNECT :l_connection; - return NULL; + return 0; } diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 46653682b0..62269ddbf4 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -69,7 +69,6 @@ endif ifeq ($(PORTNAME), win32) OBJS += \ - pthread-win32.o \ win32.o endif diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 837c5321aa..7806f67879 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -32,6 +32,7 @@ #include "mb/pg_wchar.h" #include "pg_config_paths.h" #include "port/pg_bswap.h" +#include "port/pg_threads.h" #ifdef WIN32 #include "win32.h" @@ -52,12 +53,6 @@ #include <netinet/tcp.h> #endif -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include <pthread.h> -#endif - #ifdef USE_LDAP #ifdef WIN32 #include <winldap.h> @@ -7779,35 +7774,29 @@ pqGetHomeDirectory(char *buf, int bufsize) * the field. */ +static pg_mtx_t singlethread_lock; + +static void +singlethread_lock_init(void) +{ + pg_mtx_init(&singlethread_lock, pg_mtx_plain); +} + static void default_threadlock(int acquire) { -#ifndef WIN32 - static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER; -#else - static pthread_mutex_t singlethread_lock = NULL; - static long mutex_initlock = 0; + static pg_once_flag singlethread_lock_once = PG_ONCE_FLAG_INIT; + + pg_call_once(&singlethread_lock_once, singlethread_lock_init); - if (singlethread_lock == NULL) - { - while (InterlockedExchange(&mutex_initlock, 1) == 1) - /* loop, another thread own the lock */ ; - if (singlethread_lock == NULL) - { - if (pthread_mutex_init(&singlethread_lock, NULL)) - Assert(false); - } - InterlockedExchange(&mutex_initlock, 0); - } -#endif if (acquire) { - if (pthread_mutex_lock(&singlethread_lock)) + if (pg_mtx_lock(&singlethread_lock) != pg_thrd_success) Assert(false); } else { - if (pthread_mutex_unlock(&singlethread_lock)) + if (pg_mtx_unlock(&singlethread_lock) != pg_thrd_success) Assert(false); } } diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 4976d963a2..dcbab932ee 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -30,6 +30,7 @@ #include "fe-auth.h" #include "fe-secure-common.h" #include "libpq-int.h" +#include "port/pg_threads.h" #ifdef WIN32 #include "win32.h" @@ -44,12 +45,6 @@ #include <sys/stat.h> -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include <pthread.h> -#endif - /* * These SSL-related #includes must come after all system-provided headers. * This ensures that OpenSSL can take care of conflicts with Windows' @@ -91,12 +86,8 @@ static bool ssl_lib_initialized = false; static long crypto_open_connections = 0; -#ifndef WIN32 -static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; -#else -static pthread_mutex_t ssl_config_mutex = NULL; -static long win32_ssl_create_mutex = 0; -#endif +static pg_mtx_t ssl_config_mutex; +static pg_once_flag ssl_config_mutex_once = PG_ONCE_FLAG_INIT; static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL; static int ssl_protocol_version_to_openssl(const char *protocol); @@ -726,14 +717,14 @@ static unsigned long pq_threadidcallback(void) { /* - * This is not standards-compliant. pthread_self() returns pthread_t, and + * This is not standards-compliant. thrd_currnt() returns thrd_t, and * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires * it, so we have to do it. */ - return (unsigned long) pthread_self(); + return (unsigned long) thrd_current(); } -static pthread_mutex_t *pq_lockarray; +static pg_mtx_t *pq_lockarray; static void pq_lockingcallback(int mode, int n, const char *file, int line) @@ -745,17 +736,23 @@ pq_lockingcallback(int mode, int n, const char *file, int line) */ if (mode & CRYPTO_LOCK) { - if (pthread_mutex_lock(&pq_lockarray[n])) + if (pg_mtx_lock(&pq_lockarray[n]) != pg_thrd_success) Assert(false); } else { - if (pthread_mutex_unlock(&pq_lockarray[n])) + if (pg_mtx_unlock(&pq_lockarray[n]) != pg_thrd_success) Assert(false); } } #endif /* HAVE_CRYPTO_LOCK */ +static void +ssl_config_mutex_init(void) +{ + pg_mtx_init(&ssl_config_mutex, pg_mtx_plain); +} + /* * Initialize SSL library. * @@ -769,21 +766,9 @@ pq_lockingcallback(int mode, int n, const char *file, int line) int pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) { -#ifdef WIN32 - /* Also see similar code in fe-connect.c, default_threadlock() */ - if (ssl_config_mutex == NULL) - { - while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1) - /* loop, another thread own the lock */ ; - if (ssl_config_mutex == NULL) - { - if (pthread_mutex_init(&ssl_config_mutex, NULL)) - return -1; - } - InterlockedExchange(&win32_ssl_create_mutex, 0); - } -#endif - if (pthread_mutex_lock(&ssl_config_mutex)) + pg_call_once(&ssl_config_mutex_once, ssl_config_mutex_init); + + if (pg_mtx_lock(&ssl_config_mutex) != pg_thrd_success) return -1; #ifdef HAVE_CRYPTO_LOCK @@ -797,19 +782,19 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) { int i; - pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); + pq_lockarray = malloc(sizeof(pg_mtx_t) * CRYPTO_num_locks()); if (!pq_lockarray) { - pthread_mutex_unlock(&ssl_config_mutex); + pg_mtx_unlock(&ssl_config_mutex); return -1; } for (i = 0; i < CRYPTO_num_locks(); i++) { - if (pthread_mutex_init(&pq_lockarray[i], NULL)) + if (pg_mtx_init(&pq_lockarray[i], NULL) != pg_thrd_success) { free(pq_lockarray); pq_lockarray = NULL; - pthread_mutex_unlock(&ssl_config_mutex); + pg_mtx_unlock(&ssl_config_mutex); return -1; } } @@ -850,7 +835,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) ssl_lib_initialized = true; } - pthread_mutex_unlock(&ssl_config_mutex); + pg_mtx_unlock(&ssl_config_mutex); return 0; } @@ -871,7 +856,7 @@ destroy_ssl_system(void) { #if defined(HAVE_CRYPTO_LOCK) /* Mutex is created in pgtls_init() */ - if (pthread_mutex_lock(&ssl_config_mutex)) + if (pg_mtx_lock(&ssl_config_mutex) != pg_thrd_success) return; if (pq_init_crypto_lib && crypto_open_connections > 0) @@ -897,7 +882,7 @@ destroy_ssl_system(void) */ } - pthread_mutex_unlock(&ssl_config_mutex); + pg_mtx_unlock(&ssl_config_mutex); #endif } diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index bd72a87bbb..804b5e30aa 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -35,9 +35,7 @@ #include <sys/stat.h> -#ifdef WIN32 -#include "pthread-win32.h" -#else +#ifndef WIN32 #include <pthread.h> #endif diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 10f20c1175..870db73841 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -31,11 +31,6 @@ #include <sys/time.h> #endif -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include <pthread.h> -#endif #include <signal.h> /* include stuff common to fe and be */ diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build index 80e6a15adf..6aa0276209 100644 --- a/src/interfaces/libpq/meson.build +++ b/src/interfaces/libpq/meson.build @@ -21,7 +21,7 @@ libpq_sources = files( libpq_so_sources = [] # for shared lib, in addition to the above if host_system == 'windows' - libpq_sources += files('pthread-win32.c', 'win32.c') + libpq_sources += files('win32.c') libpq_so_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ '--NAME', 'libpq', '--FILEDESC', 'PostgreSQL Access Library',]) @@ -43,7 +43,7 @@ export_file = custom_target('libpq.exports', kwargs: gen_export_kwargs, ) -# port needs to be in include path due to pthread-win32.h +# XXX why do we need this? libpq_inc = include_directories('.', '../../port') libpq_c_args = ['-DSO_MAJOR_VERSION=5'] diff --git a/src/interfaces/libpq/pthread-win32.c b/src/interfaces/libpq/pthread-win32.c deleted file mode 100644 index 8e65637387..0000000000 --- a/src/interfaces/libpq/pthread-win32.c +++ /dev/null @@ -1,60 +0,0 @@ -/*------------------------------------------------------------------------- -* -* pthread-win32.c -* partial pthread implementation for win32 -* -* Copyright (c) 2004-2023, PostgreSQL Global Development Group -* IDENTIFICATION -* src/interfaces/libpq/pthread-win32.c -* -*------------------------------------------------------------------------- -*/ - -#include "postgres_fe.h" - -#include "pthread-win32.h" - -DWORD -pthread_self(void) -{ - return GetCurrentThreadId(); -} - -void -pthread_setspecific(pthread_key_t key, void *val) -{ -} - -void * -pthread_getspecific(pthread_key_t key) -{ - return NULL; -} - -int -pthread_mutex_init(pthread_mutex_t *mp, void *attr) -{ - *mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION)); - if (!*mp) - return 1; - InitializeCriticalSection(*mp); - return 0; -} - -int -pthread_mutex_lock(pthread_mutex_t *mp) -{ - if (!*mp) - return 1; - EnterCriticalSection(*mp); - return 0; -} - -int -pthread_mutex_unlock(pthread_mutex_t *mp) -{ - if (!*mp) - return 1; - LeaveCriticalSection(*mp); - return 0; -} diff --git a/src/port/pthread-win32.h b/src/port/pthread-win32.h deleted file mode 100644 index 97ccc17a12..0000000000 --- a/src/port/pthread-win32.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * src/port/pthread-win32.h - */ -#ifndef __PTHREAD_H -#define __PTHREAD_H - -typedef ULONG pthread_key_t; -typedef CRITICAL_SECTION *pthread_mutex_t; -typedef int pthread_once_t; - -DWORD pthread_self(void); - -void pthread_setspecific(pthread_key_t, void *); -void *pthread_getspecific(pthread_key_t); - -int pthread_mutex_init(pthread_mutex_t *, void *attr); -int pthread_mutex_lock(pthread_mutex_t *); - -/* blocking */ -int pthread_mutex_unlock(pthread_mutex_t *); - -#endif diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck index 4e09c4686b..121c7a2684 100755 --- a/src/tools/pginclude/cpluspluscheck +++ b/src/tools/pginclude/cpluspluscheck @@ -79,7 +79,6 @@ do test "$f" = src/include/port/win32_msvc/dirent.h && continue test "$f" = src/include/port/win32_msvc/utime.h && continue test "$f" = src/include/port/win32ntdll.h && continue - test "$f" = src/port/pthread-win32.h && continue # Likewise, these files are platform-specific, and the one # relevant to our platform will be included by atomics.h. diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck index 8dee1b5670..b42467dfc6 100755 --- a/src/tools/pginclude/headerscheck +++ b/src/tools/pginclude/headerscheck @@ -74,7 +74,6 @@ do test "$f" = src/include/port/win32_msvc/dirent.h && continue test "$f" = src/include/port/win32_msvc/utime.h && continue test "$f" = src/include/port/win32ntdll.h && continue - test "$f" = src/port/pthread-win32.h && continue # Likewise, these files are platform-specific, and the one # relevant to our platform will be included by atomics.h. -- 2.39.2 ^ permalink raw reply [nested|flat] 43+ messages in thread
end of thread, other threads:[~2023-06-10 02:23 UTC | newest] Thread overview: 43+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2020-11-11 22:40 [PATCH v2 1/1] resownerbench Heikki Linnakangas <[email protected]> 2023-06-10 02:23 Cleaning up threading code Thomas Munro <[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