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 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 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 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 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 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 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 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 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

* Re: Optimize LISTEN/NOTIFY
@ 2026-01-07 20:29 Tom Lane <[email protected]>
  0 siblings, 0 replies; 43+ messages in thread

From: Tom Lane @ 2026-01-07 20:29 UTC (permalink / raw)
  To: Joel Jacobson <[email protected]>; +Cc: Chao Li <[email protected]>; pgsql-hackers

"Joel Jacobson" <[email protected]> writes:
> I've reworked the staging mechanism for LISTEN/UNLISTEN. The new design
> tracks LISTEN state at three levels:
> * pendingListenChannels: per-transaction pending changes
> * listenChannelsHash: per-backend committed state cache
> * channelHash: cluster-wide shared state

I spent some time looking through this version.

> The main benefit is that pendingListenChannels is now a hash table
> instead of a simple List.  In the old design, LISTEN foo; UNLISTEN foo;
> LISTEN foo would create three list entries that all had to be processed
> at commit.  The new design collapses this to one hash entry storing the
> final state, which we just apply at commit.

That seems a little weird: surely such usage is not something we need
to optimize.  Maybe it can be justified because it makes the code
simpler, but that's not immediately obvious to me.

I found the terminology pretty confusing, in particular there's too
little cognitive distance between "channel hash table" and "local
listen channels hash table" and "pending listen channels hash table".
I think you could improve matters by renaming, perhaps along the
lines of
	channelHash -> globalChannelTable
	listenChannelsHash -> localChannelTable
	pendingListenChannels -> pendingListenActions

... and I just noticed that there's yet a fourth data structure
that's described as a "channel hash table", namely
pendingNotifies->channelSet.  That's another name that could be
better, maybe uniqueChannelNames?

I noted while looking at code coverage results that AtAbort_Notify
seems almost entirely unreached, and soon realized that that's because
none of it runs unless we are cleaning up a transaction that fails
after Exec_ListenPreCommit has created pendingListenChannels.
That's obviously extremely difficult to reach in a test, so it's a bit
sad that we have that big chunk of unreachable code, especially when
the coverage elsewhere in this file is pretty stellar.  I wonder if
there is a way to merge that chunk with the code in AtCommit_Notify
that also has to scan pendingListenChannels, so as to reduce the
amount of untested code.  Also, the comments for AtAbort_Notify
don't really make it clear that there's nothing to do unless we're
reverting an almost-committed transaction.

Speaking of AtCommit_Notify:

            entry = dshash_find(channelHash, &key, true);
            if (entry == NULL)
                continue;

How can it be okay to just silently "continue" here?  Certainly
this case should be unreachable, but that doesn't make it okay
to silently ignore the failure if one were to occur.  Given
that this is post-commit processing, probably we can do no
better than

            if (entry == NULL)
                elog(PANIC, "could not find channel hash entry when expected");

Also, a bit further down:

                        /* UNLISTEN being committed: remove from channelHash */
                        entry->numListeners--;
                        if (i < entry->numListeners)
                            memmove(&listeners[i], &listeners[i + 1],
                                    sizeof(ListenerEntry) * (entry->numListeners - i));

                        /* Remove from local cache */
                        (void) hash_search(listenChannelsHash, pending->channel,
                                           HASH_REMOVE, NULL);

                        if (entry->numListeners == 0)
                        {
                            dsa_free(channelDSA, entry->listenersArray);
                            dshash_delete_entry(channelHash, entry);
                            entry = NULL;
                        }

This seems like a weird order of operations: why didn't you finish
dealing with the channelHash entry before dealing with
listenChannelsHash?

The separation between (for example) Exec_ListenPreCommit
and Exec_ListenPreCommitStage is extremely nonobvious;
readers will wonder why you didn't fold them into one routine.
I see that you did that because Exec_ListenPreCommit falls
out early if amRegisteredListener, but that doesn't make it
less confusing.  I wonder if it'd help to rename
Exec_ListenPreCommit to something that better reflects what
it actually does, say BecomeRegisteredListener.  The new
function's name is not good either.  I think what's bugging me
about it is that you're using "stage" as a verb, but English
does not put the verb at the end of the sentence, so readers
will think "stage" means "a step of the process" and then
wonder why you couldn't be clearer about which step.
Maybe better, "PrepareTableEntriesForListen"?  Similar
comments apply to the other xxxStage functions.

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 43+ messages in thread


end of thread, other threads:[~2026-01-07 20:29 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 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 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 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 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 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 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 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]>
2026-01-07 20:29 Re: Optimize LISTEN/NOTIFY Tom Lane <[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