Introduce GUC shared_memory_size_in_huge_pages
authorMichael Paquier
Tue, 21 Sep 2021 01:31:58 +0000 (10:31 +0900)
committerMichael Paquier
Tue, 21 Sep 2021 01:31:58 +0000 (10:31 +0900)
This runtime-computed GUC shows the number of huge pages required
for the server's main shared memory area, taking advantage of the
work done in 0c39c29 and 0bd305e.  This is useful for users to estimate
the amount of huge pages required for a server as it becomes possible to
do an estimation without having to start the server and potentially
allocate a large chunk of shared memory.

The number of huge pages is calculated based on the existing GUC
huge_page_size if set, or by using the system's default by looking at
/proc/meminfo on Linux.  There is nothing new here as this commit reuses
the existing calculation methods, and just exposes this information
directly to the user.  The routine calculating the huge page size is
refactored to limit the number of files with platform-specific flags.

This new GUC's name was the most popular choice based on the discussion
done.  This is only supported on Linux.

I have taken the time to test the change on Linux, Windows and MacOS,
though for the last two ones large pages are not supported.  The first
one calculates correctly the number of pages depending on the existing
GUC huge_page_size or the system's default.

Thanks to Andres Freund, Robert Haas, Kyotaro Horiguchi, Tom Lane,
Justin Pryzby (and anybody forgotten here) for the discussion.

Author: Nathan Bossart
Discussion: https://postgr.es/m/F2772387-CE0F-46BF-B5F1-CC55516EB885@amazon.com

doc/src/sgml/config.sgml
doc/src/sgml/ref/postgres-ref.sgml
doc/src/sgml/runtime.sgml
src/backend/port/sysv_shmem.c
src/backend/port/win32_shmem.c
src/backend/storage/ipc/ipci.c
src/backend/utils/misc/guc.c
src/include/storage/pg_shmem.h

index ef0e2a77462c83f0c0b5babd3eed10e5fb871b4b..0a8e35c59f46bcf17c6d0e5141675e118a5dad27 100644 (file)
@@ -10289,6 +10289,27 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
       
      
 
+     
+      shared_memory_size_in_huge_pages (integer)
+      
+       shared_memory_size_in_huge_pages configuration parameter
+      
+      
+      
+       
+        Reports the number of huge pages that are needed for the main shared
+        memory area based on the specified .
+        If huge pages are not supported, this will be -1.
+       
+       
+        This setting is supported only on Linux.  It
+        is always set to -1 on other platforms.  For more
+        details about using huge pages on Linux, see
+        .
+       
+      
+     
+
      
       ssl_library (string)
       
index f72c3b04e421b34686af42a5b6bb71cd2cdd39a4..55a3f6c69d1f489271b5924f4afb171e3999b392 100644 (file)
@@ -143,7 +143,8 @@ PostgreSQL documentation
        
         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.,  and
+        (e.g., ,
+        , and
         ).
        
 
index f1cbc1d9e922b43b7d674d25c4e49f20d16f15d5..d74d1ed7afadfc06e64c71288824aaebf38dc7ed 100644 (file)
@@ -1442,17 +1442,14 @@ export PG_OOM_ADJUST_VALUE=0
     with CONFIG_HUGETLBFS=y and
     CONFIG_HUGETLB_PAGE=y. 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
-    PostgreSQL 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
-    /proc and /sys file systems.
+    To determine the number of huge pages needed, use the
+    postgres command to see the value of
+    .  Note that the
+    server must be shut down to view this runtime-computed parameter.
     This might look like:
 
-$ head -1 $PGDATA/postmaster.pid
-4170
-$ pmap 4170 | awk '/rw-s/ && /zero/ {print $2}'
-6490428K
+$ postgres -D $PGDATA -C shared_memory_size_in_huge_pages
+3170
 $ grep ^Hugepagesize /proc/meminfo
 Hugepagesize:       2048 kB
 $ ls /sys/kernel/mm/hugepages
@@ -1460,13 +1457,13 @@ hugepages-1048576kB  hugepages-2048kB
 
 
      In this example the default is 2MB, but you can also explicitly request
-     either 2MB or 1GB with .
+     either 2MB or 1GB with  to adapt
+     the number of pages calculated by
+     shared_memory_size_in_huge_pages.
 
-     Assuming 2MB huge pages,
-     6490428 / 2048 gives approximately
-     3169.154, so in this example we need at
-     least 3170 huge pages.  A larger setting would be
-     appropriate if other programs on the machine also need huge pages.
+     While we need at least 3170 huge pages in this example,
+     a larger setting would be appropriate if other programs on the machine
+     also need huge pages.
      We can set this with:
 
 # sysctl -w vm.nr_hugepages=3170
index 9de96edf6ad43cfd057403e5b9720053b9960f62..cd385c4df650df53688ee74eb18823d6d42116d7 100644 (file)
@@ -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.
  *
@@ -475,13 +473,19 @@ PGSharedMemoryAttach(IpcMemoryId shmId,
  * hugepage sizes, we might want to think about more invasive strategies,
  * 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.
+ * Returns the (real, assumed or config provided) page size into
+ * *hugepagesize, and the hugepage-related mmap flags to use into
+ * *mmap_flags if requested by the caller.  If huge pages are not supported,
+ * *hugepagesize and *mmap_flags are set to 0.
  */
-static void
+void
 GetHugePageSize(Size *hugepagesize, int *mmap_flags)
 {
+#ifdef MAP_HUGETLB
+
    Size        default_hugepagesize = 0;
+   Size        hugepagesize_local = 0;
+   int         mmap_flags_local = 0;
 
    /*
     * System-dependent code to find out the default huge page size.
@@ -519,12 +523,12 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
    if (huge_page_size != 0)
    {
        /* If huge page size is requested explicitly, use that. */
-       *hugepagesize = (Size) huge_page_size * 1024;
+       hugepagesize_local = (Size) huge_page_size * 1024;
    }
    else if (default_hugepagesize != 0)
    {
        /* Otherwise use the system default, if we have it. */
-       *hugepagesize = default_hugepagesize;
+       hugepagesize_local = default_hugepagesize;
    }
    else
    {
@@ -536,26 +540,39 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
         * writing, there are no reports of any non-Linux systems being picky
         * about that.
         */
-       *hugepagesize = 2 * 1024 * 1024;
+       hugepagesize_local = 2 * 1024 * 1024;
    }
 
-   *mmap_flags = MAP_HUGETLB;
+   mmap_flags_local = MAP_HUGETLB;
 
    /*
     * On recent enough Linux, also include the explicit page size, if
     * necessary.
     */
 #if defined(MAP_HUGE_MASK) && defined(MAP_HUGE_SHIFT)
-   if (*hugepagesize != default_hugepagesize)
+   if (hugepagesize_local != default_hugepagesize)
    {
-       int         shift = pg_ceil_log2_64(*hugepagesize);
+       int         shift = pg_ceil_log2_64(hugepagesize_local);
 
-       *mmap_flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
+       mmap_flags_local |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
    }
 #endif
-}
+
+   /* assign the results found */
+   if (mmap_flags)
+       *mmap_flags = mmap_flags_local;
+   if (hugepagesize)
+       *hugepagesize = hugepagesize_local;
+
+#else
+
+   if (hugepagesize)
+       *hugepagesize = 0;
+   if (mmap_flags)
+       *mmap_flags = 0;
 
 #endif                         /* MAP_HUGETLB */
+}
 
 /*
  * Creates an anonymous mmap()ed shared memory segment.
index d7a71992d81a2a06d69c989501c183aaec1a633b..64fde8de8f002dc7d0fa604e6a05416a31eec01b 100644 (file)
@@ -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.
+ */
+void
+GetHugePageSize(Size *hugepagesize, int *mmap_flags)
+{
+   if (hugepagesize)
+       *hugepagesize = 0;
+   if (mmap_flags)
+       *mmap_flags = 0;
+}
index 13f3926ff67e237dbf52244eaa15a4b5d39fe401..9fa3e0631e61d1402f9c8ecf33cb9be58605ff5c 100644 (file)
@@ -326,6 +326,7 @@ InitializeShmemGUCs(void)
    char        buf[64];
    Size        size_b;
    Size        size_mb;
+   Size        hp_size;
 
    /*
     * Calculate the shared memory size and round up to the nearest megabyte.
@@ -334,4 +335,17 @@ 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, NULL);
+   if (hp_size != 0)
+   {
+       Size        hp_required;
+
+       hp_required = add_size(size_b / hp_size, 1);
+       sprintf(buf, "%zu", hp_required);
+       SetConfigOption("shared_memory_size_in_huge_pages", buf, PGC_INTERNAL, PGC_S_OVERRIDE);
+   }
 }
index a6e4fcc24edc5ddbbbef34b514c9878fbdc746ae..d2ce4a845065787934c2196bde74884eb19dc5de 100644 (file)
@@ -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 shared_memory_size_in_huge_pages;
 static int wal_block_size;
 static bool data_checksums;
 static bool integer_datetimes;
@@ -2349,6 +2350,17 @@ static struct config_int ConfigureNamesInt[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"shared_memory_size_in_huge_pages", 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_RUNTIME_COMPUTED
+       },
+       &shared_memory_size_in_huge_pages,
+       -1, -1, INT_MAX,
+       NULL, NULL, NULL
+   },
+
    {
        {"temp_buffers", PGC_USERSET, RESOURCES_MEM,
            gettext_noop("Sets the maximum number of temporary buffers used by each session."),
index 059df1b72c23f9545561ca5e1482999b40c62c36..518eb860657b280c3ed1b326aa02149fdc54b7f2 100644 (file)
@@ -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 */