LCOV - code coverage report
Current view: top level - src/backend/utils/activity - pgstat_backend.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 59 63 93.7 %
Date: 2025-02-22 07:14:56 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          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 "storage/bufmgr.h"
      28             : #include "utils/memutils.h"
      29             : #include "utils/pgstat_internal.h"
      30             : 
      31             : /*
      32             :  * Backend statistics counts waiting to be flushed out. These counters may be
      33             :  * reported within critical sections so we use static memory in order to avoid
      34             :  * memory allocation.
      35             :  */
      36             : static PgStat_BackendPending PendingBackendStats;
      37             : 
      38             : /*
      39             :  * Utility routines to report I/O stats for backends, kept here to avoid
      40             :  * exposing PendingBackendStats to the outside world.
      41             :  */
      42             : void
      43           2 : pgstat_count_backend_io_op_time(IOObject io_object, IOContext io_context,
      44             :                                 IOOp io_op, instr_time io_time)
      45             : {
      46             :     Assert(track_io_timing);
      47             : 
      48           2 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
      49           0 :         return;
      50             : 
      51             :     Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, io_op));
      52             : 
      53           2 :     INSTR_TIME_ADD(PendingBackendStats.pending_io.pending_times[io_object][io_context][io_op],
      54             :                    io_time);
      55             : }
      56             : 
      57             : void
      58   122683264 : pgstat_count_backend_io_op(IOObject io_object, IOContext io_context,
      59             :                            IOOp io_op, uint32 cnt, uint64 bytes)
      60             : {
      61   122683264 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
      62    14084360 :         return;
      63             : 
      64             :     Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, io_op));
      65             : 
      66   108598904 :     PendingBackendStats.pending_io.counts[io_object][io_context][io_op] += cnt;
      67   108598904 :     PendingBackendStats.pending_io.bytes[io_object][io_context][io_op] += bytes;
      68             : }
      69             : 
      70             : /*
      71             :  * Returns statistics of a backend by proc number.
      72             :  */
      73             : PgStat_Backend *
      74          42 : pgstat_fetch_stat_backend(ProcNumber procNumber)
      75             : {
      76             :     PgStat_Backend *backend_entry;
      77             : 
      78          42 :     backend_entry = (PgStat_Backend *) pgstat_fetch_entry(PGSTAT_KIND_BACKEND,
      79             :                                                           InvalidOid, procNumber);
      80             : 
      81          42 :     return backend_entry;
      82             : }
      83             : 
      84             : /*
      85             :  * Flush out locally pending backend IO statistics.  Locking is managed
      86             :  * by the caller.
      87             :  */
      88             : static void
      89      164134 : pgstat_flush_backend_entry_io(PgStat_EntryRef *entry_ref)
      90             : {
      91             :     PgStatShared_Backend *shbackendent;
      92             :     PgStat_BktypeIO *bktype_shstats;
      93             :     PgStat_PendingIO pending_io;
      94             : 
      95             :     /*
      96             :      * This function can be called even if nothing at all has happened for IO
      97             :      * statistics.  In this case, avoid unnecessarily modifying the stats
      98             :      * entry.
      99             :      */
     100      164134 :     if (pg_memory_is_all_zeros(&PendingBackendStats.pending_io,
     101             :                                sizeof(struct PgStat_PendingIO)))
     102           0 :         return;
     103             : 
     104      164134 :     shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
     105      164134 :     bktype_shstats = &shbackendent->stats.io_stats;
     106      164134 :     pending_io = PendingBackendStats.pending_io;
     107             : 
     108      656536 :     for (int io_object = 0; io_object < IOOBJECT_NUM_TYPES; io_object++)
     109             :     {
     110     2954412 :         for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
     111             :         {
     112    22158090 :             for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
     113             :             {
     114             :                 instr_time  time;
     115             : 
     116    19696080 :                 bktype_shstats->counts[io_object][io_context][io_op] +=
     117    19696080 :                     pending_io.counts[io_object][io_context][io_op];
     118    19696080 :                 bktype_shstats->bytes[io_object][io_context][io_op] +=
     119    19696080 :                     pending_io.bytes[io_object][io_context][io_op];
     120    19696080 :                 time = pending_io.pending_times[io_object][io_context][io_op];
     121             : 
     122    19696080 :                 bktype_shstats->times[io_object][io_context][io_op] +=
     123    19696080 :                     INSTR_TIME_GET_MICROSEC(time);
     124             :             }
     125             :         }
     126             :     }
     127             : 
     128             :     /*
     129             :      * Clear out the statistics buffer, so it can be re-used.
     130             :      */
     131      164134 :     MemSet(&PendingBackendStats.pending_io, 0, sizeof(PgStat_PendingIO));
     132             : }
     133             : 
     134             : /*
     135             :  * Flush out locally pending backend statistics
     136             :  *
     137             :  * "flags" parameter controls which statistics to flush.  Returns true
     138             :  * if some statistics could not be flushed due to lock contention.
     139             :  */
     140             : bool
     141      192322 : pgstat_flush_backend(bool nowait, bits32 flags)
     142             : {
     143             :     PgStat_EntryRef *entry_ref;
     144             : 
     145      192322 :     if (!pgstat_tracks_backend_bktype(MyBackendType))
     146        3716 :         return false;
     147             : 
     148      188606 :     if (pg_memory_is_all_zeros(&PendingBackendStats,
     149             :                                sizeof(struct PgStat_BackendPending)))
     150       24472 :         return false;
     151             : 
     152      164134 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid,
     153             :                                             MyProcNumber, nowait);
     154      164134 :     if (!entry_ref)
     155           0 :         return true;
     156             : 
     157             :     /* Flush requested statistics */
     158      164134 :     if (flags & PGSTAT_BACKEND_FLUSH_IO)
     159      164134 :         pgstat_flush_backend_entry_io(entry_ref);
     160             : 
     161      164134 :     pgstat_unlock_entry(entry_ref);
     162             : 
     163      164134 :     return false;
     164             : }
     165             : 
     166             : /*
     167             :  * Check if there are any backend stats waiting for flush.
     168             :  */
     169             : bool
     170       13270 : pgstat_backend_have_pending_cb(void)
     171             : {
     172       13270 :     return (!pg_memory_is_all_zeros(&PendingBackendStats,
     173       13270 :                                     sizeof(struct PgStat_BackendPending)));
     174             : }
     175             : 
     176             : /*
     177             :  * Callback to flush out locally pending backend statistics.
     178             :  *
     179             :  * If some stats could not be flushed due to lock contention, return true.
     180             :  */
     181             : bool
     182       60954 : pgstat_backend_flush_cb(bool nowait)
     183             : {
     184       60954 :     return pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_ALL);
     185             : }
     186             : 
     187             : /*
     188             :  * Create backend statistics entry for proc number.
     189             :  */
     190             : void
     191       30732 : pgstat_create_backend(ProcNumber procnum)
     192             : {
     193             :     PgStat_EntryRef *entry_ref;
     194             :     PgStatShared_Backend *shstatent;
     195             : 
     196       30732 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid,
     197             :                                             MyProcNumber, false);
     198       30732 :     shstatent = (PgStatShared_Backend *) entry_ref->shared_stats;
     199             : 
     200             :     /*
     201             :      * NB: need to accept that there might be stats from an older backend,
     202             :      * e.g. if we previously used this proc number.
     203             :      */
     204       30732 :     memset(&shstatent->stats, 0, sizeof(shstatent->stats));
     205       30732 :     pgstat_unlock_entry(entry_ref);
     206             : 
     207       30732 :     MemSet(&PendingBackendStats, 0, sizeof(PgStat_BackendPending));
     208       30732 : }
     209             : 
     210             : /*
     211             :  * Backend statistics are not collected for all BackendTypes.
     212             :  *
     213             :  * The following BackendTypes do not participate in the backend stats
     214             :  * subsystem:
     215             :  * - The same and for the same reasons as in pgstat_tracks_io_bktype().
     216             :  * - B_BG_WRITER, B_CHECKPOINTER, B_STARTUP and B_AUTOVAC_LAUNCHER because their
     217             :  * I/O stats are already visible in pg_stat_io and there is only one of those.
     218             :  *
     219             :  * Function returns true if BackendType participates in the backend stats
     220             :  * subsystem and false if it does not.
     221             :  *
     222             :  * When adding a new BackendType, also consider adding relevant restrictions to
     223             :  * pgstat_tracks_io_object() and pgstat_tracks_io_op().
     224             :  */
     225             : bool
     226   122910334 : pgstat_tracks_backend_bktype(BackendType bktype)
     227             : {
     228             :     /*
     229             :      * List every type so that new backend types trigger a warning about
     230             :      * needing to adjust this switch.
     231             :      */
     232   122910334 :     switch (bktype)
     233             :     {
     234    14092090 :         case B_INVALID:
     235             :         case B_AUTOVAC_LAUNCHER:
     236             :         case B_DEAD_END_BACKEND:
     237             :         case B_ARCHIVER:
     238             :         case B_LOGGER:
     239             :         case B_BG_WRITER:
     240             :         case B_CHECKPOINTER:
     241             :         case B_STARTUP:
     242    14092090 :             return false;
     243             : 
     244   108818244 :         case B_AUTOVAC_WORKER:
     245             :         case B_BACKEND:
     246             :         case B_BG_WORKER:
     247             :         case B_STANDALONE_BACKEND:
     248             :         case B_SLOTSYNC_WORKER:
     249             :         case B_WAL_RECEIVER:
     250             :         case B_WAL_SENDER:
     251             :         case B_WAL_SUMMARIZER:
     252             :         case B_WAL_WRITER:
     253   108818244 :             return true;
     254             :     }
     255             : 
     256           0 :     return false;
     257             : }
     258             : 
     259             : void
     260           6 : pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
     261             : {
     262           6 :     ((PgStatShared_Backend *) header)->stats.stat_reset_timestamp = ts;
     263           6 : }

Generated by: LCOV version 1.14