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

Generated by: LCOV version 2.5.0-beta