LCOV - code coverage report
Current view: top level - src/port - pg_numa.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 33.3 % 6 2
Test Date: 2026-03-03 10:15:07 Functions: 33.3 % 3 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_numa.c
       4              :  *      Basic NUMA portability routines
       5              :  *
       6              :  *
       7              :  * Copyright (c) 2025-2026, PostgreSQL Global Development Group
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/port/pg_numa.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "c.h"
      17              : #include <unistd.h>
      18              : 
      19              : #include "miscadmin.h"
      20              : #include "port/pg_numa.h"
      21              : 
      22              : /*
      23              :  * At this point we provide support only for Linux thanks to libnuma, but in
      24              :  * future support for other platforms e.g. Win32 or FreeBSD might be possible
      25              :  * too. For Win32 NUMA APIs see
      26              :  * https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support
      27              :  */
      28              : #ifdef USE_LIBNUMA
      29              : 
      30              : #include <numa.h>
      31              : #include <numaif.h>
      32              : 
      33              : /*
      34              :  * numa_move_pages() chunk size, has to be <= 16 to work around a kernel bug
      35              :  * in do_pages_stat() (chunked by DO_PAGES_STAT_CHUNK_NR). By using the same
      36              :  * chunk size, we make it work even on unfixed kernels.
      37              :  *
      38              :  * 64-bit system are not affected by the bug, and so use much larger chunks.
      39              :  */
      40              : #if SIZEOF_SIZE_T == 4
      41              : #define NUMA_QUERY_CHUNK_SIZE 16
      42              : #else
      43              : #define NUMA_QUERY_CHUNK_SIZE 1024
      44              : #endif
      45              : 
      46              : /* libnuma requires initialization as per numa(3) on Linux */
      47              : int
      48              : pg_numa_init(void)
      49              : {
      50              :     int         r;
      51              : 
      52              :     /*
      53              :      * XXX libnuma versions before 2.0.19 don't handle EPERM by disabling
      54              :      * NUMA, which then leads to unexpected failures later. This affects
      55              :      * containers that disable get_mempolicy by a seccomp profile.
      56              :      */
      57              :     if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && (errno == EPERM))
      58              :         r = -1;
      59              :     else
      60              :         r = numa_available();
      61              : 
      62              :     return r;
      63              : }
      64              : 
      65              : /*
      66              :  * We use move_pages(2) syscall here - instead of get_mempolicy(2) - as the
      67              :  * first one allows us to batch and query about many memory pages in one single
      68              :  * giant system call that is way faster.
      69              :  *
      70              :  * We call numa_move_pages() for smaller chunks of the whole array. The first
      71              :  * reason is to work around a kernel bug, but also to allow interrupting the
      72              :  * query between the calls (for many pointers processing the whole array can
      73              :  * take a lot of time).
      74              :  */
      75              : int
      76              : pg_numa_query_pages(int pid, unsigned long count, void **pages, int *status)
      77              : {
      78              :     unsigned long next = 0;
      79              :     int         ret = 0;
      80              : 
      81              :     /*
      82              :      * Chunk pointers passed to numa_move_pages to NUMA_QUERY_CHUNK_SIZE
      83              :      * items, to work around a kernel bug in do_pages_stat().
      84              :      */
      85              :     while (next < count)
      86              :     {
      87              :         unsigned long count_chunk = Min(count - next,
      88              :                                         NUMA_QUERY_CHUNK_SIZE);
      89              : 
      90              : #ifndef FRONTEND
      91              :         CHECK_FOR_INTERRUPTS();
      92              : #endif
      93              : 
      94              :         /*
      95              :          * Bail out if any of the chunks errors out (ret<0). We ignore (ret>0)
      96              :          * which is used to return number of nonmigrated pages, but we're not
      97              :          * migrating any pages here.
      98              :          */
      99              :         ret = numa_move_pages(pid, count_chunk, &pages[next], NULL, &status[next], 0);
     100              :         if (ret < 0)
     101              :         {
     102              :             /* plain error, return as is */
     103              :             return ret;
     104              :         }
     105              : 
     106              :         next += count_chunk;
     107              :     }
     108              : 
     109              :     /* should have consumed the input array exactly */
     110              :     Assert(next == count);
     111              : 
     112              :     return 0;
     113              : }
     114              : 
     115              : int
     116              : pg_numa_get_max_node(void)
     117              : {
     118              :     return numa_max_node();
     119              : }
     120              : 
     121              : #else
     122              : 
     123              : /* Empty wrappers */
     124              : int
     125            7 : pg_numa_init(void)
     126              : {
     127              :     /* We state that NUMA is not available */
     128            7 :     return -1;
     129              : }
     130              : 
     131              : int
     132            0 : pg_numa_query_pages(int pid, unsigned long count, void **pages, int *status)
     133              : {
     134            0 :     return 0;
     135              : }
     136              : 
     137              : int
     138            0 : pg_numa_get_max_node(void)
     139              : {
     140            0 :     return 0;
     141              : }
     142              : 
     143              : #endif
        

Generated by: LCOV version 2.0-1