LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat_backend.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 93.1 % 116 108 8 108
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 12 12 12
Baseline: lcov-20250906-005545-baseline Branches: 67.9 % 81 55 26 55
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 93.1 % 116 108 8 108
Function coverage date bins:
(30,360] days: 100.0 % 12 12 12
Branch coverage date bins:
(30,360] days: 67.9 % 81 55 26 55

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* -------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pgstat_backend.c
                                  4                 :                :  *    Implementation of backend statistics.
                                  5                 :                :  *
                                  6                 :                :  * This file contains the implementation of backend statistics.  It is kept
                                  7                 :                :  * separate from pgstat.c to enforce the line between the statistics access /
                                  8                 :                :  * storage implementation and the details about individual types of
                                  9                 :                :  * statistics.
                                 10                 :                :  *
                                 11                 :                :  * This statistics kind uses a proc number as object ID for the hash table
                                 12                 :                :  * of pgstats.  Entries are created each time a process is spawned, and are
                                 13                 :                :  * dropped when the process exits.  These are not written to the pgstats file
                                 14                 :                :  * on disk.  Pending statistics are managed without direct interactions with
                                 15                 :                :  * PgStat_EntryRef->pending, relying on PendingBackendStats instead so as it
                                 16                 :                :  * is possible to report data within critical sections.
                                 17                 :                :  *
                                 18                 :                :  * Copyright (c) 2001-2025, PostgreSQL Global Development Group
                                 19                 :                :  *
                                 20                 :                :  * IDENTIFICATION
                                 21                 :                :  *    src/backend/utils/activity/pgstat_backend.c
                                 22                 :                :  * -------------------------------------------------------------------------
                                 23                 :                :  */
                                 24                 :                : 
                                 25                 :                : #include "postgres.h"
                                 26                 :                : 
                                 27                 :                : #include "access/xlog.h"
                                 28                 :                : #include "storage/bufmgr.h"
                                 29                 :                : #include "storage/proc.h"
                                 30                 :                : #include "storage/procarray.h"
                                 31                 :                : #include "utils/memutils.h"
                                 32                 :                : #include "utils/pgstat_internal.h"
                                 33                 :                : 
                                 34                 :                : /*
                                 35                 :                :  * Backend statistics counts waiting to be flushed out. These counters may be
                                 36                 :                :  * reported within critical sections so we use static memory in order to avoid
                                 37                 :                :  * memory allocation.
                                 38                 :                :  */
                                 39                 :                : static PgStat_BackendPending PendingBackendStats;
                                 40                 :                : static bool backend_has_iostats = false;
                                 41                 :                : 
                                 42                 :                : /*
                                 43                 :                :  * WAL usage counters saved from pgWalUsage at the previous call to
                                 44                 :                :  * pgstat_flush_backend().  This is used to calculate how much WAL usage
                                 45                 :                :  * happens between pgstat_flush_backend() calls, by subtracting the
                                 46                 :                :  * previous counters from the current ones.
                                 47                 :                :  */
                                 48                 :                : static WalUsage prevBackendWalUsage;
                                 49                 :                : 
                                 50                 :                : /*
                                 51                 :                :  * Utility routines to report I/O stats for backends, kept here to avoid
                                 52                 :                :  * exposing PendingBackendStats to the outside world.
                                 53                 :                :  */
                                 54                 :                : void
  228 michael@paquier.xyz        55                 :CBC           3 : pgstat_count_backend_io_op_time(IOObject io_object, IOContext io_context,
                                 56                 :                :                                 IOOp io_op, instr_time io_time)
                                 57                 :                : {
  192                            58   [ -  +  -  - ]:              3 :     Assert(track_io_timing || track_wal_io_timing);
                                 59                 :                : 
  228                            60         [ -  + ]:              3 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
  228 michael@paquier.xyz        61                 :UBC           0 :         return;
                                 62                 :                : 
  228 michael@paquier.xyz        63         [ -  + ]:CBC           3 :     Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, io_op));
                                 64                 :                : 
                                 65                 :              3 :     INSTR_TIME_ADD(PendingBackendStats.pending_io.pending_times[io_object][io_context][io_op],
                                 66                 :                :                    io_time);
                                 67                 :                : 
  171                            68                 :              3 :     backend_has_iostats = true;
   40                            69                 :              3 :     pgstat_report_fixed = true;
                                 70                 :                : }
                                 71                 :                : 
                                 72                 :                : void
  228                            73                 :       62329751 : pgstat_count_backend_io_op(IOObject io_object, IOContext io_context,
                                 74                 :                :                            IOOp io_op, uint32 cnt, uint64 bytes)
                                 75                 :                : {
                                 76         [ +  + ]:       62329751 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
                                 77                 :        7255993 :         return;
                                 78                 :                : 
                                 79         [ -  + ]:       55073758 :     Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, io_op));
                                 80                 :                : 
                                 81                 :       55073758 :     PendingBackendStats.pending_io.counts[io_object][io_context][io_op] += cnt;
                                 82                 :       55073758 :     PendingBackendStats.pending_io.bytes[io_object][io_context][io_op] += bytes;
                                 83                 :                : 
  171                            84                 :       55073758 :     backend_has_iostats = true;
   40                            85                 :       55073758 :     pgstat_report_fixed = true;
                                 86                 :                : }
                                 87                 :                : 
                                 88                 :                : /*
                                 89                 :                :  * Returns statistics of a backend by proc number.
                                 90                 :                :  */
                                 91                 :                : PgStat_Backend *
  261                            92                 :             27 : pgstat_fetch_stat_backend(ProcNumber procNumber)
                                 93                 :                : {
                                 94                 :                :     PgStat_Backend *backend_entry;
                                 95                 :                : 
                                 96                 :             27 :     backend_entry = (PgStat_Backend *) pgstat_fetch_entry(PGSTAT_KIND_BACKEND,
                                 97                 :                :                                                           InvalidOid, procNumber);
                                 98                 :                : 
                                 99                 :             27 :     return backend_entry;
                                100                 :                : }
                                101                 :                : 
                                102                 :                : /*
                                103                 :                :  * Returns statistics of a backend by pid.
                                104                 :                :  *
                                105                 :                :  * This routine includes sanity checks to ensure that the backend exists and
                                106                 :                :  * is running.  "bktype" can be optionally defined to return the BackendType
                                107                 :                :  * of the backend whose statistics are returned.
                                108                 :                :  */
                                109                 :                : PgStat_Backend *
  190                           110                 :             33 : pgstat_fetch_stat_backend_by_pid(int pid, BackendType *bktype)
                                111                 :                : {
                                112                 :                :     PGPROC     *proc;
                                113                 :                :     PgBackendStatus *beentry;
                                114                 :                :     ProcNumber  procNumber;
                                115                 :                :     PgStat_Backend *backend_stats;
                                116                 :                : 
                                117                 :             33 :     proc = BackendPidGetProc(pid);
                                118         [ +  + ]:             33 :     if (bktype)
                                119                 :             27 :         *bktype = B_INVALID;
                                120                 :                : 
                                121                 :                :     /* this could be an auxiliary process */
  187                           122         [ +  + ]:             33 :     if (!proc)
                                123                 :              6 :         proc = AuxiliaryPidGetProc(pid);
                                124                 :                : 
  190                           125         [ +  + ]:             33 :     if (!proc)
                                126                 :              3 :         return NULL;
                                127                 :                : 
                                128                 :             30 :     procNumber = GetNumberFromPGProc(proc);
                                129                 :                : 
                                130                 :             30 :     beentry = pgstat_get_beentry_by_proc_number(procNumber);
                                131         [ -  + ]:             30 :     if (!beentry)
  190 michael@paquier.xyz       132                 :UBC           0 :         return NULL;
                                133                 :                : 
                                134                 :                :     /* check if the backend type tracks statistics */
  187 michael@paquier.xyz       135         [ +  + ]:CBC          30 :     if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
                                136                 :              3 :         return NULL;
                                137                 :                : 
                                138                 :                :     /* if PID does not match, leave */
  190                           139         [ -  + ]:             27 :     if (beentry->st_procpid != pid)
  190 michael@paquier.xyz       140                 :UBC           0 :         return NULL;
                                141                 :                : 
  190 michael@paquier.xyz       142         [ +  + ]:CBC          27 :     if (bktype)
                                143                 :             21 :         *bktype = beentry->st_backendType;
                                144                 :                : 
                                145                 :                :     /*
                                146                 :                :      * Retrieve the entry.  Note that "beentry" may be freed depending on the
                                147                 :                :      * value of stats_fetch_consistency, so do not access it from this point.
                                148                 :                :      */
  152                           149                 :             27 :     backend_stats = pgstat_fetch_stat_backend(procNumber);
                                150         [ -  + ]:             27 :     if (!backend_stats)
                                151                 :                :     {
  152 michael@paquier.xyz       152         [ #  # ]:UBC           0 :         if (bktype)
                                153                 :              0 :             *bktype = B_INVALID;
                                154                 :              0 :         return NULL;
                                155                 :                :     }
                                156                 :                : 
  190 michael@paquier.xyz       157                 :CBC          27 :     return backend_stats;
                                158                 :                : }
                                159                 :                : 
                                160                 :                : /*
                                161                 :                :  * Flush out locally pending backend IO statistics.  Locking is managed
                                162                 :                :  * by the caller.
                                163                 :                :  */
                                164                 :                : static void
  239                           165                 :          42740 : pgstat_flush_backend_entry_io(PgStat_EntryRef *entry_ref)
                                166                 :                : {
                                167                 :                :     PgStatShared_Backend *shbackendent;
                                168                 :                :     PgStat_BktypeIO *bktype_shstats;
                                169                 :                :     PgStat_PendingIO pending_io;
                                170                 :                : 
                                171                 :                :     /*
                                172                 :                :      * This function can be called even if nothing at all has happened for IO
                                173                 :                :      * statistics.  In this case, avoid unnecessarily modifying the stats
                                174                 :                :      * entry.
                                175                 :                :      */
  171                           176         [ +  + ]:          42740 :     if (!backend_has_iostats)
  228                           177                 :            176 :         return;
                                178                 :                : 
  239                           179                 :          42564 :     shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
                                180                 :          42564 :     bktype_shstats = &shbackendent->stats.io_stats;
  228                           181                 :          42564 :     pending_io = PendingBackendStats.pending_io;
                                182                 :                : 
  261                           183         [ +  + ]:         170256 :     for (int io_object = 0; io_object < IOOBJECT_NUM_TYPES; io_object++)
                                184                 :                :     {
                                185         [ +  + ]:         766152 :         for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
                                186                 :                :         {
                                187         [ +  + ]:        5746140 :             for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
                                188                 :                :             {
                                189                 :                :                 instr_time  time;
                                190                 :                : 
                                191                 :        5107680 :                 bktype_shstats->counts[io_object][io_context][io_op] +=
  228                           192                 :        5107680 :                     pending_io.counts[io_object][io_context][io_op];
  235                           193                 :        5107680 :                 bktype_shstats->bytes[io_object][io_context][io_op] +=
  228                           194                 :        5107680 :                     pending_io.bytes[io_object][io_context][io_op];
                                195                 :        5107680 :                 time = pending_io.pending_times[io_object][io_context][io_op];
                                196                 :                : 
  261                           197                 :        5107680 :                 bktype_shstats->times[io_object][io_context][io_op] +=
                                198                 :        5107680 :                     INSTR_TIME_GET_MICROSEC(time);
                                199                 :                :             }
                                200                 :                :         }
                                201                 :                :     }
                                202                 :                : 
                                203                 :                :     /*
                                204                 :                :      * Clear out the statistics buffer, so it can be re-used.
                                205                 :                :      */
  228                           206   [ +  -  +  -  :          42564 :     MemSet(&PendingBackendStats.pending_io, 0, sizeof(PgStat_PendingIO));
                                     +  -  -  +  -  
                                                 - ]
                                207                 :                : 
  171                           208                 :          42564 :     backend_has_iostats = false;
                                209                 :                : }
                                210                 :                : 
                                211                 :                : /*
                                212                 :                :  * To determine whether WAL usage happened.
                                213                 :                :  */
                                214                 :                : static inline bool
  179                           215                 :          55435 : pgstat_backend_wal_have_pending(void)
                                216                 :                : {
                                217                 :          55435 :     return (pgWalUsage.wal_records != prevBackendWalUsage.wal_records);
                                218                 :                : }
                                219                 :                : 
                                220                 :                : /*
                                221                 :                :  * Flush out locally pending backend WAL statistics.  Locking is managed
                                222                 :                :  * by the caller.
                                223                 :                :  */
                                224                 :                : static void
                                225                 :          16703 : pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref)
                                226                 :                : {
                                227                 :                :     PgStatShared_Backend *shbackendent;
                                228                 :                :     PgStat_WalCounters *bktype_shstats;
                                229                 :          16703 :     WalUsage    wal_usage_diff = {0};
                                230                 :                : 
                                231                 :                :     /*
                                232                 :                :      * This function can be called even if nothing at all has happened for WAL
                                233                 :                :      * statistics.  In this case, avoid unnecessarily modifying the stats
                                234                 :                :      * entry.
                                235                 :                :      */
                                236         [ +  + ]:          16703 :     if (!pgstat_backend_wal_have_pending())
                                237                 :           8160 :         return;
                                238                 :                : 
                                239                 :           8543 :     shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
                                240                 :           8543 :     bktype_shstats = &shbackendent->stats.wal_counters;
                                241                 :                : 
                                242                 :                :     /*
                                243                 :                :      * Calculate how much WAL usage counters were increased by subtracting the
                                244                 :                :      * previous counters from the current ones.
                                245                 :                :      */
                                246                 :           8543 :     WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevBackendWalUsage);
                                247                 :                : 
                                248                 :                : #define WALSTAT_ACC(fld, var_to_add) \
                                249                 :                :     (bktype_shstats->fld += var_to_add.fld)
                                250                 :           8543 :     WALSTAT_ACC(wal_buffers_full, wal_usage_diff);
                                251                 :           8543 :     WALSTAT_ACC(wal_records, wal_usage_diff);
                                252                 :           8543 :     WALSTAT_ACC(wal_fpi, wal_usage_diff);
                                253                 :           8543 :     WALSTAT_ACC(wal_bytes, wal_usage_diff);
                                254                 :                : #undef WALSTAT_ACC
                                255                 :                : 
                                256                 :                :     /*
                                257                 :                :      * Save the current counters for the subsequent calculation of WAL usage.
                                258                 :                :      */
                                259                 :           8543 :     prevBackendWalUsage = pgWalUsage;
                                260                 :                : }
                                261                 :                : 
                                262                 :                : /*
                                263                 :                :  * Flush out locally pending backend statistics
                                264                 :                :  *
                                265                 :                :  * "flags" parameter controls which statistics to flush.  Returns true
                                266                 :                :  * if some statistics could not be flushed due to lock contention.
                                267                 :                :  */
                                268                 :                : bool
  228                           269                 :         103799 : pgstat_flush_backend(bool nowait, bits32 flags)
                                270                 :                : {
                                271                 :                :     PgStat_EntryRef *entry_ref;
  179                           272                 :         103799 :     bool        has_pending_data = false;
                                273                 :                : 
  239                           274         [ +  + ]:         103799 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
                                275                 :          32244 :         return false;
                                276                 :                : 
                                277                 :                :     /* Some IO data pending? */
  171                           278   [ +  +  +  + ]:          71555 :     if ((flags & PGSTAT_BACKEND_FLUSH_IO) && backend_has_iostats)
  179                           279                 :          42564 :         has_pending_data = true;
                                280                 :                : 
                                281                 :                :     /* Some WAL data pending? */
                                282   [ +  +  +  + ]:         110287 :     if ((flags & PGSTAT_BACKEND_FLUSH_WAL) &&
                                283                 :          38732 :         pgstat_backend_wal_have_pending())
                                284                 :           8543 :         has_pending_data = true;
                                285                 :                : 
                                286         [ +  + ]:          71555 :     if (!has_pending_data)
  239                           287                 :          28815 :         return false;
                                288                 :                : 
  228                           289                 :          42740 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid,
                                290                 :                :                                             MyProcNumber, nowait);
                                291         [ -  + ]:          42740 :     if (!entry_ref)
  228 michael@paquier.xyz       292                 :UBC           0 :         return true;
                                293                 :                : 
                                294                 :                :     /* Flush requested statistics */
  239 michael@paquier.xyz       295         [ +  - ]:CBC       42740 :     if (flags & PGSTAT_BACKEND_FLUSH_IO)
                                296                 :          42740 :         pgstat_flush_backend_entry_io(entry_ref);
                                297                 :                : 
  179                           298         [ +  + ]:          42740 :     if (flags & PGSTAT_BACKEND_FLUSH_WAL)
                                299                 :          16703 :         pgstat_flush_backend_entry_wal(entry_ref);
                                300                 :                : 
  261                           301                 :          42740 :     pgstat_unlock_entry(entry_ref);
                                302                 :                : 
  228                           303                 :          42740 :     return false;
                                304                 :                : }
                                305                 :                : 
                                306                 :                : /*
                                307                 :                :  * Callback to flush out locally pending backend statistics.
                                308                 :                :  *
                                309                 :                :  * If some stats could not be flushed due to lock contention, return true.
                                310                 :                :  */
                                311                 :                : bool
                                312                 :          30995 : pgstat_backend_flush_cb(bool nowait)
                                313                 :                : {
                                314                 :          30995 :     return pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_ALL);
                                315                 :                : }
                                316                 :                : 
                                317                 :                : /*
                                318                 :                :  * Create backend statistics entry for proc number.
                                319                 :                :  */
                                320                 :                : void
  261                           321                 :          14887 : pgstat_create_backend(ProcNumber procnum)
                                322                 :                : {
                                323                 :                :     PgStat_EntryRef *entry_ref;
                                324                 :                :     PgStatShared_Backend *shstatent;
                                325                 :                : 
  228                           326                 :          14887 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid,
                                327                 :                :                                             MyProcNumber, false);
  261                           328                 :          14887 :     shstatent = (PgStatShared_Backend *) entry_ref->shared_stats;
                                329                 :                : 
                                330                 :                :     /*
                                331                 :                :      * NB: need to accept that there might be stats from an older backend,
                                332                 :                :      * e.g. if we previously used this proc number.
                                333                 :                :      */
                                334                 :          14887 :     memset(&shstatent->stats, 0, sizeof(shstatent->stats));
  228                           335                 :          14887 :     pgstat_unlock_entry(entry_ref);
                                336                 :                : 
                                337   [ +  -  +  -  :          14887 :     MemSet(&PendingBackendStats, 0, sizeof(PgStat_BackendPending));
                                     +  -  -  +  -  
                                                 - ]
  171                           338                 :          14887 :     backend_has_iostats = false;
                                339                 :                : 
                                340                 :                :     /*
                                341                 :                :      * Initialize prevBackendWalUsage with pgWalUsage so that
                                342                 :                :      * pgstat_backend_flush_cb() can calculate how much pgWalUsage counters
                                343                 :                :      * are increased by subtracting prevBackendWalUsage from pgWalUsage.
                                344                 :                :      */
  179                           345                 :          14887 :     prevBackendWalUsage = pgWalUsage;
  261                           346                 :          14887 : }
                                347                 :                : 
                                348                 :                : /*
                                349                 :                :  * Backend statistics are not collected for all BackendTypes.
                                350                 :                :  *
                                351                 :                :  * The following BackendTypes do not participate in the backend stats
                                352                 :                :  * subsystem:
                                353                 :                :  * - The same and for the same reasons as in pgstat_tracks_io_bktype().
                                354                 :                :  * - B_BG_WRITER, B_CHECKPOINTER, B_STARTUP and B_AUTOVAC_LAUNCHER because their
                                355                 :                :  * I/O stats are already visible in pg_stat_io and there is only one of those.
                                356                 :                :  *
                                357                 :                :  * Function returns true if BackendType participates in the backend stats
                                358                 :                :  * subsystem and false if it does not.
                                359                 :                :  *
                                360                 :                :  * When adding a new BackendType, also consider adding relevant restrictions to
                                361                 :                :  * pgstat_tracks_io_object() and pgstat_tracks_io_op().
                                362                 :                :  */
                                363                 :                : bool
                                364                 :       62452094 : pgstat_tracks_backend_bktype(BackendType bktype)
                                365                 :                : {
                                366                 :                :     /*
                                367                 :                :      * List every type so that new backend types trigger a warning about
                                368                 :                :      * needing to adjust this switch.
                                369                 :                :      */
                                370      [ +  +  - ]:       62452094 :     switch (bktype)
                                371                 :                :     {
                                372                 :        7291861 :         case B_INVALID:
                                373                 :                :         case B_AUTOVAC_LAUNCHER:
                                374                 :                :         case B_DEAD_END_BACKEND:
                                375                 :                :         case B_ARCHIVER:
                                376                 :                :         case B_LOGGER:
                                377                 :                :         case B_BG_WRITER:
                                378                 :                :         case B_CHECKPOINTER:
                                379                 :                :         case B_IO_WORKER:
                                380                 :                :         case B_STARTUP:
                                381                 :        7291861 :             return false;
                                382                 :                : 
                                383                 :       55160233 :         case B_AUTOVAC_WORKER:
                                384                 :                :         case B_BACKEND:
                                385                 :                :         case B_BG_WORKER:
                                386                 :                :         case B_STANDALONE_BACKEND:
                                387                 :                :         case B_SLOTSYNC_WORKER:
                                388                 :                :         case B_WAL_RECEIVER:
                                389                 :                :         case B_WAL_SENDER:
                                390                 :                :         case B_WAL_SUMMARIZER:
                                391                 :                :         case B_WAL_WRITER:
                                392                 :       55160233 :             return true;
                                393                 :                :     }
                                394                 :                : 
  261 michael@paquier.xyz       395                 :UBC           0 :     return false;
                                396                 :                : }
                                397                 :                : 
                                398                 :                : void
  261 michael@paquier.xyz       399                 :CBC           3 : pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
                                400                 :                : {
                                401                 :              3 :     ((PgStatShared_Backend *) header)->stats.stat_reset_timestamp = ts;
                                402                 :              3 : }
        

Generated by: LCOV version 2.4-beta