Hi all While working on extensions I've often wanted to enable cache clobbering for a targeted piece of code, without paying the price of running it for all backends during postgres startup and any initial setup tasks that are required.
So here's a patch that, when CLOBBER_CACHE_ALWAYS or CLOBBER_CACHE_RECURSIVE are defined, adds a GUC named clobber_cache_depth . It defaults to 1 for CLOBBER_CACHE_ALWAYS or 3 for CLOBBER_CACHE_RECURSIVE to match the existing compiled-in behaviour. But with this change it's now possible to run Pg with clobber_cache_depth=0 then set it to 1 only for targeted tests. clobber_cache_depth is treated as an unknown GUC if Pg was not built with CLOBBER_CACHE_ALWAYS or CLOBBER_CACHE_RECURSIVE defined. ----- On a side note, to make things like this easier to use, I personally patch all pg_regress tests to include the following at the start of each sql input file: \set ECHO none -- Put per-test settings or overrides here \set ECHO queries then patch the expected files accordingly. That way it's easy for me to make per-test adjustments while still running the whole suite. It's not always practical to run just one targeted test with TESTS=foo. -- Craig Ringer http://www.2ndQuadrant.com/ 2ndQuadrant - PostgreSQL Solutions for the Enterprise
From 372defde443d178fb4a9c8cf4092dea7debf72ea Mon Sep 17 00:00:00 2001 From: Craig Ringer <craig.rin...@2ndquadrant.com> Date: Tue, 22 Sep 2020 09:51:00 +0800 Subject: [PATCH v1] Add runtime control over CLOBBER_CACHE_ALWAYS When CLOBBER_CACHE_ALWAYS or CLOBBER_CACHE_RECURSIVE are defined, a new GUC "clobber_cache_depth" becomes available. This allows runtime control over the behaviour of cache clobber builds in order to allow more targeted testing of new or changed features using aggressive cache clobbering. clobber_cache_depth defaults to 1 if CLOBBER_CACHE_ALWAYS is defined, and to 3 if CLOBBER_CACHE_RECURSIVE is defined. That makes it match the previous hardcoded behaviour of these macros, ensuring buildfarm members won't get upset. While we're at it, expose the macros in pg_config_manual.h --- src/backend/utils/cache/inval.c | 51 +++++++++++++++++++-------------- src/backend/utils/misc/guc.c | 15 ++++++++++ src/include/pg_config_manual.h | 28 ++++++++++++++++-- src/include/utils/inval.h | 8 ++++++ 4 files changed, 78 insertions(+), 24 deletions(-) diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 628d6f5d0c..620c9558ac 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -109,6 +109,7 @@ #include "storage/sinval.h" #include "storage/smgr.h" #include "utils/catcache.h" +#include "utils/guc.h" #include "utils/inval.h" #include "utils/memdebug.h" #include "utils/memutils.h" @@ -179,6 +180,9 @@ static SharedInvalidationMessage *SharedInvalidMessagesArray; static int numSharedInvalidMessagesArray; static int maxSharedInvalidMessagesArray; +#if CACHE_CLOBBER_ALWAYS +int clobber_cache_depth = 0; +#endif /* * Dynamically-registered callback functions. Current implementation @@ -689,35 +693,38 @@ AcceptInvalidationMessages(void) /* * Test code to force cache flushes anytime a flush could happen. * - * If used with CLOBBER_FREED_MEMORY, CLOBBER_CACHE_ALWAYS provides a + * CLOBBER_CACHE_ALWAYS (clobber_cache_depth = 1) provides a * fairly thorough test that the system contains no cache-flush hazards. * However, it also makes the system unbelievably slow --- the regression - * tests take about 100 times longer than normal. - * - * If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY. This - * slows things by at least a factor of 10000, so I wouldn't suggest - * trying to run the entire regression tests that way. It's useful to try - * a few simple tests, to make sure that cache reload isn't subject to - * internal cache-flush hazards, but after you've done a few thousand - * recursive reloads it's unlikely you'll learn more. + * tests take about 100 times longer than normal. To mitigate the + * slowdown it can be turned on and off per-backend or globally using + * the clobber_cache_depth GUC to allow targeted testing of specific + * code paths. + * + * If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY + * (set clobber_cache_depth to > 1). This slows things by at least a + * factor of 10000, so I wouldn't suggest trying to run the entire + * regression tests that way. It's useful to try a few simple tests, + * to make sure that cache reload isn't subject to internal cache-flush + * hazards, but after you've done a few thousand recursive reloads it's + * unlikely you'll learn more. + * + * You can use postgresql.conf or any other convenient means to disable + * clobbering by default then re-enable for targeted sections of tests, + * e.g you can edit a specific pg_regress test to SET + * clobber_cache_depth=1, then run the suite with: + * + * PGOPTIONS="-c clobber_cache_depth=0" make -C src/test/regress check + * + * Remember to use ALTER SYSTEM SET and reload the config if you want + * the change to apply to bgworkers, autovacuum, etc too. */ #if defined(CLOBBER_CACHE_ALWAYS) - { - static bool in_recursion = false; - - if (!in_recursion) - { - in_recursion = true; - InvalidateSystemCaches(); - in_recursion = false; - } - } -#elif defined(CLOBBER_CACHE_RECURSIVELY) + if (clobber_cache_depth > 0) { static int recursion_depth = 0; - /* Maximum depth is arbitrary depending on your threshold of pain */ - if (recursion_depth < 3) + if (recursion_depth < clobber_cache_depth) { recursion_depth++; InvalidateSystemCaches(); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 596bcb7b84..ae7d46cff0 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -99,6 +99,7 @@ #include "utils/rls.h" #include "utils/snapmgr.h" #include "utils/tzparser.h" +#include "utils/inval.h" #include "utils/varlena.h" #include "utils/xml.h" @@ -3399,7 +3400,21 @@ static struct config_int ConfigureNamesInt[] = check_huge_page_size, NULL, NULL }, +#if defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY) + /* Only available in special debug builds, see pg_config_manual.h */ + { + {"clobber_cache_depth", PGC_SUSET, DEVELOPER_OPTIONS, + gettext_noop("Runtime control over CLOBBER_CACHE_ALWAYS and CLOBBER_CACHE_RECURSIVELY", + NULL, + GUC_NOT_IN_SAMPLE + }, + &clobber_cache_depth, + DEFAULT_CLOBBER_CACHE_DEPTH, 0, 5, + NULL, NULL, NULL + }, + /* End-of-list marker */ +#endif { {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL } diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 705dc69c06..615e0833f1 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -6,8 +6,15 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * + * You can define these by editing pg_config_manual.h but it's usually + * sufficient to pass CFLAGS to configure, e.g. + * + * ./configure --enable-debug --enable-cassert CFLAGS="-DUSE_VALGRIND" + * + * The flags are persisted in Makefile.global so they will be correctly + * applied to extensions, including those built by PGXS. + * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pg_config_manual.h *------------------------------------------------------------------------ @@ -280,7 +287,8 @@ * percentage points even when not run under Valgrind. * * You should normally use MEMORY_CONTEXT_CHECKING with USE_VALGRIND; - * instrumentation of repalloc() is inferior without it. + * instrumentation of repalloc() is inferior without it. So it's defined + * automatically for USE_VALGRIND builds. */ /* #define USE_VALGRIND */ @@ -309,6 +317,22 @@ */ /* #define RANDOMIZE_ALLOCATED_MEMORY */ +/* + * For cache invalidation debugging, clobber caches whenever an invalidation is + * possible. For CLOBBER_CACHE_RECURSIVELY, do so even when already processing + * invalidations. The GUC clobber_cache_depth is only available when these + * options are defined. See inval.c for details. + * + * It's strongly recommended that you use --enable-cassert and the + * implied CLOBBER_FREED_MEMORY if you enable either of these. + */ +/* #define CLOBBER_CACHE_ALWAYS */ +/* #define CLOBBER_CACHE_RECURSIVELY */ + +#if defined(CLOBBER_CACHE_RECURSIVELY) && !defined(CLOBBER_CACHE_ALWAYS) +#define CLOBBER_CACHE_ALWAYS +#endif + /* * Define this to force all parse and plan trees to be passed through * copyObject(), to facilitate catching errors and omissions in diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h index 463888c389..ddfae7a9d6 100644 --- a/src/include/utils/inval.h +++ b/src/include/utils/inval.h @@ -18,6 +18,14 @@ #include "storage/relfilenode.h" #include "utils/relcache.h" +#ifdef CLOBBER_CACHE_ALWAYS +extern PGDLLIMPORT int clobber_cache_depth; +#ifdef CLOBBER_CACHE_RECURSIVELY +#define DEFAULT_CLOBBER_CACHE_DEPTH 3 +#else +#define DEFAULT_CLOBBER_CACHE_DEPTH 1 +#endif +#endif typedef void (*SyscacheCallbackFunction) (Datum arg, int cacheid, uint32 hashvalue); typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid); -- 2.26.2