LCOV - code coverage report
Current view: top level - src/backend/executor - instrument.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 90.0 % 160 144
Test Date: 2026-01-26 10:56:24 Functions: 92.9 % 14 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 53.4 % 58 31

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * instrument.c
       4                 :             :  *       functions for instrumentation of plan execution
       5                 :             :  *
       6                 :             :  *
       7                 :             :  * Copyright (c) 2001-2026, PostgreSQL Global Development Group
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/backend/executor/instrument.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : #include "postgres.h"
      15                 :             : 
      16                 :             : #include <unistd.h>
      17                 :             : 
      18                 :             : #include "executor/instrument.h"
      19                 :             : 
      20                 :             : BufferUsage pgBufferUsage;
      21                 :             : static BufferUsage save_pgBufferUsage;
      22                 :             : WalUsage        pgWalUsage;
      23                 :             : static WalUsage save_pgWalUsage;
      24                 :             : 
      25                 :             : static void BufferUsageAdd(BufferUsage *dst, const BufferUsage *add);
      26                 :             : static void WalUsageAdd(WalUsage *dst, WalUsage *add);
      27                 :             : 
      28                 :             : 
      29                 :             : /* Allocate new instrumentation structure(s) */
      30                 :             : Instrumentation *
      31                 :        1710 : InstrAlloc(int n, int instrument_options, bool async_mode)
      32                 :             : {
      33                 :        1710 :         Instrumentation *instr;
      34                 :             : 
      35                 :             :         /* initialize all fields to zeroes, then modify as needed */
      36                 :        1710 :         instr = palloc0(n * sizeof(Instrumentation));
      37         [ +  + ]:        1710 :         if (instrument_options & (INSTRUMENT_BUFFERS | INSTRUMENT_TIMER | INSTRUMENT_WAL))
      38                 :             :         {
      39                 :         898 :                 bool            need_buffers = (instrument_options & INSTRUMENT_BUFFERS) != 0;
      40                 :         898 :                 bool            need_wal = (instrument_options & INSTRUMENT_WAL) != 0;
      41                 :         898 :                 bool            need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
      42                 :         898 :                 int                     i;
      43                 :             : 
      44         [ +  + ]:        1796 :                 for (i = 0; i < n; i++)
      45                 :             :                 {
      46                 :         898 :                         instr[i].need_bufusage = need_buffers;
      47                 :         898 :                         instr[i].need_walusage = need_wal;
      48                 :         898 :                         instr[i].need_timer = need_timer;
      49                 :         898 :                         instr[i].async_mode = async_mode;
      50                 :         898 :                 }
      51                 :         898 :         }
      52                 :             : 
      53                 :        3420 :         return instr;
      54                 :        1710 : }
      55                 :             : 
      56                 :             : /* Initialize a pre-allocated instrumentation structure. */
      57                 :             : void
      58                 :         280 : InstrInit(Instrumentation *instr, int instrument_options)
      59                 :             : {
      60                 :         280 :         memset(instr, 0, sizeof(Instrumentation));
      61                 :         280 :         instr->need_bufusage = (instrument_options & INSTRUMENT_BUFFERS) != 0;
      62                 :         280 :         instr->need_walusage = (instrument_options & INSTRUMENT_WAL) != 0;
      63                 :         280 :         instr->need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
      64                 :         280 : }
      65                 :             : 
      66                 :             : /* Entry to a plan node */
      67                 :             : void
      68                 :     2253523 : InstrStartNode(Instrumentation *instr)
      69                 :             : {
      70   [ +  +  +  -  :     2253523 :         if (instr->need_timer &&
                   #  # ]
      71                 :     1779459 :                 !INSTR_TIME_SET_CURRENT_LAZY(instr->starttime))
      72   [ #  #  #  # ]:           0 :                 elog(ERROR, "InstrStartNode called twice in a row");
      73                 :             : 
      74                 :             :         /* save buffer usage totals at node entry, if needed */
      75         [ +  + ]:     2253523 :         if (instr->need_bufusage)
      76                 :     1766897 :                 instr->bufusage_start = pgBufferUsage;
      77                 :             : 
      78         [ +  - ]:     2253523 :         if (instr->need_walusage)
      79                 :           0 :                 instr->walusage_start = pgWalUsage;
      80                 :     2253523 : }
      81                 :             : 
      82                 :             : /* Exit from a plan node */
      83                 :             : void
      84                 :     2253521 : InstrStopNode(Instrumentation *instr, double nTuples)
      85                 :             : {
      86                 :     2253521 :         double          save_tuplecount = instr->tuplecount;
      87                 :     2253521 :         instr_time      endtime;
      88                 :             : 
      89                 :             :         /* count the returned tuples */
      90                 :     2253521 :         instr->tuplecount += nTuples;
      91                 :             : 
      92                 :             :         /* let's update the time only if the timer was requested */
      93         [ +  + ]:     2253521 :         if (instr->need_timer)
      94                 :             :         {
      95         [ +  - ]:     1779459 :                 if (INSTR_TIME_IS_ZERO(instr->starttime))
      96   [ #  #  #  # ]:           0 :                         elog(ERROR, "InstrStopNode called without start");
      97                 :             : 
      98                 :     1779459 :                 INSTR_TIME_SET_CURRENT(endtime);
      99                 :     1779459 :                 INSTR_TIME_ACCUM_DIFF(instr->counter, endtime, instr->starttime);
     100                 :             : 
     101                 :     1779459 :                 INSTR_TIME_SET_ZERO(instr->starttime);
     102                 :     1779459 :         }
     103                 :             : 
     104                 :             :         /* Add delta of buffer usage since entry to node's totals */
     105         [ +  + ]:     2253521 :         if (instr->need_bufusage)
     106                 :     3533794 :                 BufferUsageAccumDiff(&instr->bufusage,
     107                 :     1766897 :                                                          &pgBufferUsage, &instr->bufusage_start);
     108                 :             : 
     109         [ +  - ]:     2253521 :         if (instr->need_walusage)
     110                 :           0 :                 WalUsageAccumDiff(&instr->walusage,
     111                 :           0 :                                                   &pgWalUsage, &instr->walusage_start);
     112                 :             : 
     113                 :             :         /* Is this the first tuple of this cycle? */
     114         [ +  + ]:     2253521 :         if (!instr->running)
     115                 :             :         {
     116                 :        8508 :                 instr->running = true;
     117                 :        8508 :                 instr->firsttuple = instr->counter;
     118                 :        8508 :         }
     119                 :             :         else
     120                 :             :         {
     121                 :             :                 /*
     122                 :             :                  * In async mode, if the plan node hadn't emitted any tuples before,
     123                 :             :                  * this might be the first tuple
     124                 :             :                  */
     125   [ -  +  #  # ]:     2245013 :                 if (instr->async_mode && save_tuplecount < 1.0)
     126                 :           0 :                         instr->firsttuple = instr->counter;
     127                 :             :         }
     128                 :     2253521 : }
     129                 :             : 
     130                 :             : /* Update tuple count */
     131                 :             : void
     132                 :           0 : InstrUpdateTupleCount(Instrumentation *instr, double nTuples)
     133                 :             : {
     134                 :             :         /* count the returned tuples */
     135                 :           0 :         instr->tuplecount += nTuples;
     136                 :           0 : }
     137                 :             : 
     138                 :             : /* Finish a run cycle for a plan node */
     139                 :             : void
     140                 :        8851 : InstrEndLoop(Instrumentation *instr)
     141                 :             : {
     142                 :             :         /* Skip if nothing has happened, or already shut down */
     143         [ +  + ]:        8851 :         if (!instr->running)
     144                 :         343 :                 return;
     145                 :             : 
     146         [ +  - ]:        8508 :         if (!INSTR_TIME_IS_ZERO(instr->starttime))
     147   [ #  #  #  # ]:           0 :                 elog(ERROR, "InstrEndLoop called on running node");
     148                 :             : 
     149                 :             :         /* Accumulate per-cycle statistics into totals */
     150                 :        8508 :         INSTR_TIME_ADD(instr->startup, instr->firsttuple);
     151                 :        8508 :         INSTR_TIME_ADD(instr->total, instr->counter);
     152                 :        8508 :         instr->ntuples += instr->tuplecount;
     153                 :        8508 :         instr->nloops += 1;
     154                 :             : 
     155                 :             :         /* Reset for next cycle (if any) */
     156                 :        8508 :         instr->running = false;
     157                 :        8508 :         INSTR_TIME_SET_ZERO(instr->starttime);
     158                 :        8508 :         INSTR_TIME_SET_ZERO(instr->counter);
     159                 :        8508 :         INSTR_TIME_SET_ZERO(instr->firsttuple);
     160                 :        8508 :         instr->tuplecount = 0;
     161                 :        8851 : }
     162                 :             : 
     163                 :             : /* aggregate instrumentation information */
     164                 :             : void
     165                 :         676 : InstrAggNode(Instrumentation *dst, Instrumentation *add)
     166                 :             : {
     167   [ +  +  +  - ]:         676 :         if (!dst->running && add->running)
     168                 :             :         {
     169                 :           0 :                 dst->running = true;
     170                 :           0 :                 dst->firsttuple = add->firsttuple;
     171                 :           0 :         }
     172   [ +  +  -  +  :         676 :         else if (dst->running && add->running &&
                   #  # ]
     173                 :           0 :                          INSTR_TIME_LT(dst->firsttuple, add->firsttuple))
     174                 :           0 :                 dst->firsttuple = add->firsttuple;
     175                 :             : 
     176                 :         676 :         INSTR_TIME_ADD(dst->counter, add->counter);
     177                 :             : 
     178                 :         676 :         dst->tuplecount += add->tuplecount;
     179                 :         676 :         INSTR_TIME_ADD(dst->startup, add->startup);
     180                 :         676 :         INSTR_TIME_ADD(dst->total, add->total);
     181                 :         676 :         dst->ntuples += add->ntuples;
     182                 :         676 :         dst->ntuples2 += add->ntuples2;
     183                 :         676 :         dst->nloops += add->nloops;
     184                 :         676 :         dst->nfiltered1 += add->nfiltered1;
     185                 :         676 :         dst->nfiltered2 += add->nfiltered2;
     186                 :             : 
     187                 :             :         /* Add delta of buffer usage since entry to node's totals */
     188         [ +  + ]:         676 :         if (dst->need_bufusage)
     189                 :         318 :                 BufferUsageAdd(&dst->bufusage, &add->bufusage);
     190                 :             : 
     191         [ +  - ]:         676 :         if (dst->need_walusage)
     192                 :           0 :                 WalUsageAdd(&dst->walusage, &add->walusage);
     193                 :         676 : }
     194                 :             : 
     195                 :             : /* note current values during parallel executor startup */
     196                 :             : void
     197                 :         477 : InstrStartParallelQuery(void)
     198                 :             : {
     199                 :         477 :         save_pgBufferUsage = pgBufferUsage;
     200                 :         477 :         save_pgWalUsage = pgWalUsage;
     201                 :         477 : }
     202                 :             : 
     203                 :             : /* report usage after parallel executor shutdown */
     204                 :             : void
     205                 :         475 : InstrEndParallelQuery(BufferUsage *bufusage, WalUsage *walusage)
     206                 :             : {
     207                 :         475 :         memset(bufusage, 0, sizeof(BufferUsage));
     208                 :         475 :         BufferUsageAccumDiff(bufusage, &pgBufferUsage, &save_pgBufferUsage);
     209                 :         475 :         memset(walusage, 0, sizeof(WalUsage));
     210                 :         475 :         WalUsageAccumDiff(walusage, &pgWalUsage, &save_pgWalUsage);
     211                 :         475 : }
     212                 :             : 
     213                 :             : /* accumulate work done by workers in leader's stats */
     214                 :             : void
     215                 :         475 : InstrAccumParallelQuery(BufferUsage *bufusage, WalUsage *walusage)
     216                 :             : {
     217                 :         475 :         BufferUsageAdd(&pgBufferUsage, bufusage);
     218                 :         475 :         WalUsageAdd(&pgWalUsage, walusage);
     219                 :         475 : }
     220                 :             : 
     221                 :             : /* dst += add */
     222                 :             : static void
     223                 :         793 : BufferUsageAdd(BufferUsage *dst, const BufferUsage *add)
     224                 :             : {
     225                 :         793 :         dst->shared_blks_hit += add->shared_blks_hit;
     226                 :         793 :         dst->shared_blks_read += add->shared_blks_read;
     227                 :         793 :         dst->shared_blks_dirtied += add->shared_blks_dirtied;
     228                 :         793 :         dst->shared_blks_written += add->shared_blks_written;
     229                 :         793 :         dst->local_blks_hit += add->local_blks_hit;
     230                 :         793 :         dst->local_blks_read += add->local_blks_read;
     231                 :         793 :         dst->local_blks_dirtied += add->local_blks_dirtied;
     232                 :         793 :         dst->local_blks_written += add->local_blks_written;
     233                 :         793 :         dst->temp_blks_read += add->temp_blks_read;
     234                 :         793 :         dst->temp_blks_written += add->temp_blks_written;
     235                 :         793 :         INSTR_TIME_ADD(dst->shared_blk_read_time, add->shared_blk_read_time);
     236                 :         793 :         INSTR_TIME_ADD(dst->shared_blk_write_time, add->shared_blk_write_time);
     237                 :         793 :         INSTR_TIME_ADD(dst->local_blk_read_time, add->local_blk_read_time);
     238                 :         793 :         INSTR_TIME_ADD(dst->local_blk_write_time, add->local_blk_write_time);
     239                 :         793 :         INSTR_TIME_ADD(dst->temp_blk_read_time, add->temp_blk_read_time);
     240                 :         793 :         INSTR_TIME_ADD(dst->temp_blk_write_time, add->temp_blk_write_time);
     241                 :         793 : }
     242                 :             : 
     243                 :             : /* dst += add - sub */
     244                 :             : void
     245                 :     1767811 : BufferUsageAccumDiff(BufferUsage *dst,
     246                 :             :                                          const BufferUsage *add,
     247                 :             :                                          const BufferUsage *sub)
     248                 :             : {
     249                 :     1767811 :         dst->shared_blks_hit += add->shared_blks_hit - sub->shared_blks_hit;
     250                 :     1767811 :         dst->shared_blks_read += add->shared_blks_read - sub->shared_blks_read;
     251                 :     1767811 :         dst->shared_blks_dirtied += add->shared_blks_dirtied - sub->shared_blks_dirtied;
     252                 :     1767811 :         dst->shared_blks_written += add->shared_blks_written - sub->shared_blks_written;
     253                 :     1767811 :         dst->local_blks_hit += add->local_blks_hit - sub->local_blks_hit;
     254                 :     1767811 :         dst->local_blks_read += add->local_blks_read - sub->local_blks_read;
     255                 :     1767811 :         dst->local_blks_dirtied += add->local_blks_dirtied - sub->local_blks_dirtied;
     256                 :     1767811 :         dst->local_blks_written += add->local_blks_written - sub->local_blks_written;
     257                 :     1767811 :         dst->temp_blks_read += add->temp_blks_read - sub->temp_blks_read;
     258                 :     1767811 :         dst->temp_blks_written += add->temp_blks_written - sub->temp_blks_written;
     259                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->shared_blk_read_time,
     260                 :             :                                                   add->shared_blk_read_time, sub->shared_blk_read_time);
     261                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->shared_blk_write_time,
     262                 :             :                                                   add->shared_blk_write_time, sub->shared_blk_write_time);
     263                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->local_blk_read_time,
     264                 :             :                                                   add->local_blk_read_time, sub->local_blk_read_time);
     265                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->local_blk_write_time,
     266                 :             :                                                   add->local_blk_write_time, sub->local_blk_write_time);
     267                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->temp_blk_read_time,
     268                 :             :                                                   add->temp_blk_read_time, sub->temp_blk_read_time);
     269                 :     1767811 :         INSTR_TIME_ACCUM_DIFF(dst->temp_blk_write_time,
     270                 :             :                                                   add->temp_blk_write_time, sub->temp_blk_write_time);
     271                 :     1767811 : }
     272                 :             : 
     273                 :             : /* helper functions for WAL usage accumulation */
     274                 :             : static void
     275                 :         475 : WalUsageAdd(WalUsage *dst, WalUsage *add)
     276                 :             : {
     277                 :         475 :         dst->wal_bytes += add->wal_bytes;
     278                 :         475 :         dst->wal_records += add->wal_records;
     279                 :         475 :         dst->wal_fpi += add->wal_fpi;
     280                 :         475 :         dst->wal_fpi_bytes += add->wal_fpi_bytes;
     281                 :         475 :         dst->wal_buffers_full += add->wal_buffers_full;
     282                 :         475 : }
     283                 :             : 
     284                 :             : void
     285                 :        1150 : WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
     286                 :             : {
     287                 :        1150 :         dst->wal_bytes += add->wal_bytes - sub->wal_bytes;
     288                 :        1150 :         dst->wal_records += add->wal_records - sub->wal_records;
     289                 :        1150 :         dst->wal_fpi += add->wal_fpi - sub->wal_fpi;
     290                 :        1150 :         dst->wal_fpi_bytes += add->wal_fpi_bytes - sub->wal_fpi_bytes;
     291                 :        1150 :         dst->wal_buffers_full += add->wal_buffers_full - sub->wal_buffers_full;
     292                 :        1150 : }
        

Generated by: LCOV version 2.3.2-1