On Thu, Sep 09, 2021 at 01:19:14PM +0900, Michael Paquier wrote: > I broke that again, so rebased as v9 attached.
Well. -- Michael
From 09b1f5a5e0e88a6d84bfc2f8a1bc410e21fb3775 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Thu, 9 Sep 2021 13:10:24 +0900 Subject: [PATCH v9 1/2] Introduce huge_pages_required GUC. This runtime-computed GUC shows the number of huge pages required for the server's main shared memory area. --- src/include/storage/pg_shmem.h | 1 + src/backend/port/sysv_shmem.c | 16 +++++++++++----- src/backend/port/win32_shmem.c | 14 ++++++++++++++ src/backend/storage/ipc/ipci.c | 14 ++++++++++++++ src/backend/utils/misc/guc.c | 12 ++++++++++++ doc/src/sgml/config.sgml | 21 +++++++++++++++++++++ 6 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h index 059df1b72c..518eb86065 100644 --- a/src/include/storage/pg_shmem.h +++ b/src/include/storage/pg_shmem.h @@ -87,5 +87,6 @@ extern PGShmemHeader *PGSharedMemoryCreate(Size size, PGShmemHeader **shim); extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); extern void PGSharedMemoryDetach(void); +extern void GetHugePageSize(Size *hugepagesize, int *mmap_flags); #endif /* PG_SHMEM_H */ diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 9de96edf6a..125e2d47ec 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -456,8 +456,6 @@ PGSharedMemoryAttach(IpcMemoryId shmId, return shmStat.shm_nattch == 0 ? SHMSTATE_UNATTACHED : SHMSTATE_ATTACHED; } -#ifdef MAP_HUGETLB - /* * Identify the huge page size to use, and compute the related mmap flags. * @@ -476,11 +474,19 @@ PGSharedMemoryAttach(IpcMemoryId shmId, * such as increasing shared_buffers to absorb the extra space. * * Returns the (real, assumed or config provided) page size into *hugepagesize, - * and the hugepage-related mmap flags to use into *mmap_flags. + * and the hugepage-related mmap flags to use into *mmap_flags. If huge pages + * is not supported, *hugepagesize and *mmap_flags will be set to 0. */ -static void +void GetHugePageSize(Size *hugepagesize, int *mmap_flags) { +#ifndef MAP_HUGETLB + + *hugepagesize = 0; + *mmap_flags = 0; + +#else + Size default_hugepagesize = 0; /* @@ -553,9 +559,9 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags) *mmap_flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT; } #endif -} #endif /* MAP_HUGETLB */ +} /* * Creates an anonymous mmap()ed shared memory segment. diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c index d7a71992d8..90de2ab4e1 100644 --- a/src/backend/port/win32_shmem.c +++ b/src/backend/port/win32_shmem.c @@ -605,3 +605,17 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild) return true; } + +/* + * This function is provided for consistency with sysv_shmem.c and does not + * provide any useful information for Windows. To obtain the large page size, + * use GetLargePageMinimum() instead. + * + * This always sets *hugepagesize and *mmap_flags to 0. + */ +void +GetHugePageSize(Size *hugepagesize, int *mmap_flags) +{ + *hugepagesize = 0; + *mmap_flags = 0; +} diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 13f3926ff6..91490653cf 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -326,6 +326,9 @@ InitializeShmemGUCs(void) char buf[64]; Size size_b; Size size_mb; + Size hp_size; + Size hp_required; + int unused; /* * Calculate the shared memory size and round up to the nearest megabyte. @@ -334,4 +337,15 @@ InitializeShmemGUCs(void) size_mb = add_size(size_b, (1024 * 1024) - 1) / (1024 * 1024); sprintf(buf, "%zu", size_mb); SetConfigOption("shared_memory_size", buf, PGC_INTERNAL, PGC_S_OVERRIDE); + + /* + * Calculate the number of huge pages required. + */ + GetHugePageSize(&hp_size, &unused); + if (hp_size != 0) + { + hp_required = (size_b / hp_size) + 1; + sprintf(buf, "%zu", hp_required); + SetConfigOption("huge_pages_required", buf, PGC_INTERNAL, PGC_S_OVERRIDE); + } } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index fd4ca83be1..8edfd07340 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -665,6 +665,7 @@ static int max_identifier_length; static int block_size; static int segment_size; static int shared_memory_size_mb; +static int huge_pages_required; static int wal_block_size; static bool data_checksums; static bool integer_datetimes; @@ -2224,6 +2225,17 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"huge_pages_required", PGC_INTERNAL, PRESET_OPTIONS, + gettext_noop("Shows the number of huge pages needed for the main shared memory area."), + gettext_noop("-1 indicates that the value could not be determined."), + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + }, + &huge_pages_required, + -1, -1, INT_MAX, + NULL, NULL, NULL + }, + { /* This is PGC_SUSET to prevent hiding from log_lock_waits. */ {"deadlock_timeout", PGC_SUSET, LOCK_MANAGEMENT, diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ef0e2a7746..b27d8aff15 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -10101,6 +10101,27 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' </listitem> </varlistentry> + <varlistentry id="guc-huge-pages-required" xreflabel="huge_pages_required"> + <term><varname>huge_pages_required</varname> (<type>integer</type>) + <indexterm> + <primary><varname>huge_pages_required</varname> configuration parameter</primary> + </indexterm> + </term> + <listitem> + <para> + Reports the number of huge pages that are required for the main + shared memory area based on the specified + <xref linkend="guc-huge-page-size"/>. If huge pages are not supported, + this will be <literal>-1</literal>. + </para> + <para> + This setting is supported only on Linux. It is always set to + <literal>-1</literal> on other platforms. For more details about using + huge pages on Linux, see <xref linkend="linux-huge-pages"/>. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-integer-datetimes" xreflabel="integer_datetimes"> <term><varname>integer_datetimes</varname> (<type>boolean</type>) <indexterm> -- 2.33.0
From f4763273a7f4649d4c50699b590c0b4b8077cb95 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Thu, 9 Sep 2021 13:10:38 +0900 Subject: [PATCH v9 2/2] Provide useful values for 'postgres -C' with runtime-computed GUCs. The -C option is handled before a small subset of GUCs that are computed at runtime are initialized. Unfortunately, we cannot move this handling to after they are initialized without disallowing 'postgres -C' on a running server. One notable reason for this is that loadable libraries' _PG_init() functions are called before all runtime-computed GUCs are initialized, and this is not guaranteed to be safe to do on running servers. In order to provide useful values for 'postgres -C' for runtime- computed GUCs, this change adds a new section for handling just these GUCs just before shared memory is initialized. While users won't be able to use -C for runtime-computed GUCs on running servers, providing a useful value with this restriction seems better than not providing a useful value at all. --- src/include/utils/guc.h | 6 ++++ src/backend/postmaster/postmaster.c | 50 +++++++++++++++++++++++++---- src/backend/utils/misc/guc.c | 10 +++--- doc/src/sgml/ref/postgres-ref.sgml | 12 +++++-- doc/src/sgml/runtime.sgml | 33 +++++++------------ 5 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index a7c3a4958e..aa18d304ac 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -229,6 +229,12 @@ typedef enum #define GUC_EXPLAIN 0x100000 /* include in explain */ +/* + * GUC_RUNTIME_COMPUTED is intended for runtime-computed GUCs that are only + * available via 'postgres -C' if the server is not running. + */ +#define GUC_RUNTIME_COMPUTED 0x200000 + #define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index b2fe420c3c..f601b9e5d1 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -896,15 +896,31 @@ PostmasterMain(int argc, char *argv[]) if (output_config_variable != NULL) { /* - * "-C guc" was specified, so print GUC's value and exit. No extra - * permission check is needed because the user is reading inside the - * data dir. + * If this is a runtime-computed GUC, it hasn't yet been initialized, + * and the present value is not useful. However, this is a convenient + * place to print the value for most GUCs because it is safe to run + * postmaster startup to this point even if the server is already + * running. For the handful of runtime-computed GUCs that we can't + * provide meaningful values for yet, we wait until later in postmaster + * startup to print the value. We won't be able to use -C on running + * servers for those GUCs, but otherwise this option is unusable for + * them. */ - const char *config_val = GetConfigOption(output_config_variable, - false, false); + int flags = GetConfigOptionFlags(output_config_variable, true); - puts(config_val ? config_val : ""); - ExitPostmaster(0); + if ((flags & GUC_RUNTIME_COMPUTED) == 0) + { + /* + * "-C guc" was specified, so print GUC's value and exit. No extra + * permission check is needed because the user is reading inside + * the data dir. + */ + const char *config_val = GetConfigOption(output_config_variable, + false, false); + + puts(config_val ? config_val : ""); + ExitPostmaster(0); + } } /* Verify that DataDir looks reasonable */ @@ -1033,6 +1049,26 @@ PostmasterMain(int argc, char *argv[]) */ InitializeShmemGUCs(); + /* + * If -C was specified with a runtime-computed GUC, we held off printing + * the value earlier, as the GUC was not yet initialized. We handle -C for + * most GUCs before we lock the data directory so that the option may be + * used on a running server. However, a handful of GUCs are runtime- + * computed and do not have meaningful values until after locking the data + * directory, and we cannot safely calculate their values earlier on a + * running server. At this point, such GUCs should be properly + * initialized, and we haven't yet set up shared memory, so this is a good + * time to handle the -C option for these special GUCs. + */ + if (output_config_variable != NULL) + { + const char *config_val = GetConfigOption(output_config_variable, + false, false); + + puts(config_val ? config_val : ""); + ExitPostmaster(0); + } + /* * Set up shared memory and semaphores. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8edfd07340..50e60b270b 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1984,7 +1984,7 @@ static struct config_bool ConfigureNamesBool[] = {"data_checksums", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows whether data checksums are turned on for this cluster."), NULL, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &data_checksums, false, @@ -2229,7 +2229,7 @@ static struct config_int ConfigureNamesInt[] = {"huge_pages_required", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the number of huge pages needed for the main shared memory area."), gettext_noop("-1 indicates that the value could not be determined."), - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &huge_pages_required, -1, -1, INT_MAX, @@ -2354,7 +2354,7 @@ static struct config_int ConfigureNamesInt[] = {"shared_memory_size", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the size of the server's main shared memory area (rounded up to the nearest MB)."), NULL, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB | GUC_RUNTIME_COMPUTED }, &shared_memory_size_mb, 0, 0, INT_MAX, @@ -2419,7 +2419,7 @@ static struct config_int ConfigureNamesInt[] = "in the form accepted by the chmod and umask system " "calls. (To use the customary octal format the number " "must start with a 0 (zero).)"), - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &data_directory_mode, 0700, 0000, 0777, @@ -3243,7 +3243,7 @@ static struct config_int ConfigureNamesInt[] = {"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the size of write ahead log segments."), NULL, - GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &wal_segment_size, DEFAULT_XLOG_SEG_SIZE, diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres-ref.sgml index 4aaa7abe1a..89cc3cdb4e 100644 --- a/doc/src/sgml/ref/postgres-ref.sgml +++ b/doc/src/sgml/ref/postgres-ref.sgml @@ -133,13 +133,21 @@ PostgreSQL documentation <listitem> <para> Prints the value of the named run-time parameter, and exits. - (See the <option>-c</option> option above for details.) This can - be used on a running server, and returns values from + (See the <option>-c</option> option above for details.) This + returns values from <filename>postgresql.conf</filename>, modified by any parameters supplied in this invocation. It does not reflect parameters supplied when the cluster was started. </para> + <para> + This can be used on a running server for most parameters. However, + the server must be shut down for some runtime-computed parameters + (e.g., <xref linkend="guc-huge-pages-required"/>, + <xref linkend="guc-shared-memory-size"/>, and + <xref linkend="guc-wal-segment-size"/>). + </para> + <para> This option is meant for other programs that interact with a server instance, such as <xref linkend="app-pg-ctl"/>, to query configuration diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index f1cbc1d9e9..d955639900 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1442,32 +1442,21 @@ export PG_OOM_ADJUST_VALUE=0 with <varname>CONFIG_HUGETLBFS=y</varname> and <varname>CONFIG_HUGETLB_PAGE=y</varname>. You will also have to configure the operating system to provide enough huge pages of the desired size. - To estimate the number of huge pages needed, start - <productname>PostgreSQL</productname> without huge pages enabled and check - the postmaster's anonymous shared memory segment size, as well as the - system's default and supported huge page sizes, using the - <filename>/proc</filename> and <filename>/sys</filename> file systems. - This might look like: + To estimate the number of huge pages needed, use the + <command>postgres</command> command to see the value of + <xref linkend="guc-huge-pages-required"/>. This might look like: <programlisting> -$ <userinput>head -1 $PGDATA/postmaster.pid</userinput> -4170 -$ <userinput>pmap 4170 | awk '/rw-s/ && /zero/ {print $2}'</userinput> -6490428K -$ <userinput>grep ^Hugepagesize /proc/meminfo</userinput> -Hugepagesize: 2048 kB -$ <userinput>ls /sys/kernel/mm/hugepages</userinput> -hugepages-1048576kB hugepages-2048kB +$ <userinput>postgres -D $PGDATA -C huge_pages_required</userinput> +3170 </programlisting> - In this example the default is 2MB, but you can also explicitly request - either 2MB or 1GB with <xref linkend="guc-huge-page-size"/>. + Note that you can explicitly request either 2MB or 1GB huge pages with + <xref linkend="guc-huge-page-size"/>. - Assuming <literal>2MB</literal> huge pages, - <literal>6490428</literal> / <literal>2048</literal> gives approximately - <literal>3169.154</literal>, so in this example we need at - least <literal>3170</literal> huge pages. A larger setting would be - appropriate if other programs on the machine also need huge pages. - We can set this with: + While we need at least <literal>3170</literal> huge pages in this + example, a larger setting would be appropriate if other programs on + the machine also need huge pages. We can allocate the huge pages + with: <programlisting> # <userinput>sysctl -w vm.nr_hugepages=3170</userinput> </programlisting> -- 2.33.0
signature.asc
Description: PGP signature