LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat_function.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 93.2 % 59 55 4 55
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 7 7 7
Baseline: 16@8cea358b128 Branches: 68.8 % 16 11 5 11
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 93.2 % 59 55 4 55
Function coverage date bins:
(240..) days: 100.0 % 7 7 7
Branch coverage date bins:
(240..) days: 68.8 % 16 11 5 11

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* -------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pgstat_function.c
                                  4                 :                :  *    Implementation of function statistics.
                                  5                 :                :  *
                                  6                 :                :  * This file contains the implementation of function 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                 :                :  * Copyright (c) 2001-2024, PostgreSQL Global Development Group
                                 12                 :                :  *
                                 13                 :                :  * IDENTIFICATION
                                 14                 :                :  *    src/backend/utils/activity/pgstat_function.c
                                 15                 :                :  * -------------------------------------------------------------------------
                                 16                 :                :  */
                                 17                 :                : 
                                 18                 :                : #include "postgres.h"
                                 19                 :                : 
                                 20                 :                : #include "fmgr.h"
                                 21                 :                : #include "utils/inval.h"
                                 22                 :                : #include "utils/pgstat_internal.h"
                                 23                 :                : #include "utils/syscache.h"
                                 24                 :                : 
                                 25                 :                : 
                                 26                 :                : /* ----------
                                 27                 :                :  * GUC parameters
                                 28                 :                :  * ----------
                                 29                 :                :  */
                                 30                 :                : int         pgstat_track_functions = TRACK_FUNC_OFF;
                                 31                 :                : 
                                 32                 :                : 
                                 33                 :                : /*
                                 34                 :                :  * Total time charged to functions so far in the current backend.
                                 35                 :                :  * We use this to help separate "self" and "other" time charges.
                                 36                 :                :  * (We assume this initializes to zero.)
                                 37                 :                :  */
                                 38                 :                : static instr_time total_func_time;
                                 39                 :                : 
                                 40                 :                : 
                                 41                 :                : /*
                                 42                 :                :  * Ensure that stats are dropped if transaction aborts.
                                 43                 :                :  */
                                 44                 :                : void
  739 andres@anarazel.de         45                 :CBC        7283 : pgstat_create_function(Oid proid)
                                 46                 :                : {
                                 47                 :           7283 :     pgstat_create_transactional(PGSTAT_KIND_FUNCTION,
                                 48                 :                :                                 MyDatabaseId,
                                 49                 :                :                                 proid);
                                 50                 :           7283 : }
                                 51                 :                : 
                                 52                 :                : /*
                                 53                 :                :  * Ensure that stats are dropped if transaction commits.
                                 54                 :                :  *
                                 55                 :                :  * NB: This is only reliable because pgstat_init_function_usage() does some
                                 56                 :                :  * extra work. If other places start emitting function stats they likely need
                                 57                 :                :  * similar logic.
                                 58                 :                :  */
                                 59                 :                : void
                                 60                 :           3221 : pgstat_drop_function(Oid proid)
                                 61                 :                : {
                                 62                 :           3221 :     pgstat_drop_transactional(PGSTAT_KIND_FUNCTION,
                                 63                 :                :                               MyDatabaseId,
                                 64                 :                :                               proid);
                                 65                 :           3221 : }
                                 66                 :                : 
                                 67                 :                : /*
                                 68                 :                :  * Initialize function call usage data.
                                 69                 :                :  * Called by the executor before invoking a function.
                                 70                 :                :  */
                                 71                 :                : void
  755                            72                 :        9231013 : pgstat_init_function_usage(FunctionCallInfo fcinfo,
                                 73                 :                :                            PgStat_FunctionCallUsage *fcu)
                                 74                 :                : {
                                 75                 :                :     PgStat_EntryRef *entry_ref;
                                 76                 :                :     PgStat_FunctionCounts *pending;
                                 77                 :                :     bool        created_entry;
                                 78                 :                : 
                                 79         [ +  + ]:        9231013 :     if (pgstat_track_functions <= fcinfo->flinfo->fn_stats)
                                 80                 :                :     {
                                 81                 :                :         /* stats not wanted */
                                 82                 :        9230906 :         fcu->fs = NULL;
                                 83                 :        9230906 :         return;
                                 84                 :                :     }
                                 85                 :                : 
  739                            86                 :            107 :     entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_FUNCTION,
                                 87                 :                :                                           MyDatabaseId,
                                 88                 :            107 :                                           fcinfo->flinfo->fn_oid,
                                 89                 :                :                                           &created_entry);
                                 90                 :                : 
                                 91                 :                :     /*
                                 92                 :                :      * If no shared entry already exists, check if the function has been
                                 93                 :                :      * deleted concurrently. This can go unnoticed until here because
                                 94                 :                :      * executing a statement that just calls a function, does not trigger
                                 95                 :                :      * cache invalidation processing. The reason we care about this case is
                                 96                 :                :      * that otherwise we could create a new stats entry for an already dropped
                                 97                 :                :      * function (for relations etc this is not possible because emitting stats
                                 98                 :                :      * requires a lock for the relation to already have been acquired).
                                 99                 :                :      *
                                100                 :                :      * It's somewhat ugly to have a behavioral difference based on
                                101                 :                :      * track_functions being enabled/disabled. But it seems acceptable, given
                                102                 :                :      * that there's already behavioral differences depending on whether the
                                103                 :                :      * function is the caches etc.
                                104                 :                :      *
                                105                 :                :      * For correctness it'd be sufficient to set ->dropped to true. However,
                                106                 :                :      * the accepted invalidation will commonly cause "low level" failures in
                                107                 :                :      * PL code, with an OID in the error message. Making this harder to
                                108                 :                :      * test...
                                109                 :                :      */
                                110         [ +  + ]:            107 :     if (created_entry)
                                111                 :                :     {
                                112                 :             48 :         AcceptInvalidationMessages();
                                113         [ -  + ]:             48 :         if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid)))
                                114                 :                :         {
  739 andres@anarazel.de        115                 :UBC           0 :             pgstat_drop_entry(PGSTAT_KIND_FUNCTION, MyDatabaseId,
                                116                 :              0 :                               fcinfo->flinfo->fn_oid);
                                117         [ #  # ]:              0 :             ereport(ERROR, errcode(ERRCODE_UNDEFINED_FUNCTION),
                                118                 :                :                     errmsg("function call to dropped function"));
                                119                 :                :         }
                                120                 :                :     }
                                121                 :                : 
  739 andres@anarazel.de        122                 :CBC         107 :     pending = entry_ref->pending;
                                123                 :                : 
  395 michael@paquier.xyz       124                 :            107 :     fcu->fs = pending;
                                125                 :                : 
                                126                 :                :     /* save stats for this function, later used to compensate for recursion */
  387                           127                 :            107 :     fcu->save_f_total_time = pending->total_time;
                                128                 :                : 
                                129                 :                :     /* save current backend-wide total time */
  755 andres@anarazel.de        130                 :            107 :     fcu->save_total = total_func_time;
                                131                 :                : 
                                132                 :                :     /* get clock time as of function start */
  387 michael@paquier.xyz       133                 :            107 :     INSTR_TIME_SET_CURRENT(fcu->start);
                                134                 :                : }
                                135                 :                : 
                                136                 :                : /*
                                137                 :                :  * Calculate function call usage and update stat counters.
                                138                 :                :  * Called by the executor after invoking a function.
                                139                 :                :  *
                                140                 :                :  * In the case of a set-returning function that runs in value-per-call mode,
                                141                 :                :  * we will see multiple pgstat_init_function_usage/pgstat_end_function_usage
                                142                 :                :  * calls for what the user considers a single call of the function.  The
                                143                 :                :  * finalize flag should be TRUE on the last call.
                                144                 :                :  */
                                145                 :                : void
  755 andres@anarazel.de        146                 :        9227016 : pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
                                147                 :                : {
                                148                 :        9227016 :     PgStat_FunctionCounts *fs = fcu->fs;
                                149                 :                :     instr_time  total;
                                150                 :                :     instr_time  others;
                                151                 :                :     instr_time  self;
                                152                 :                : 
                                153                 :                :     /* stats not wanted? */
                                154         [ +  + ]:        9227016 :     if (fs == NULL)
                                155                 :        9226909 :         return;
                                156                 :                : 
                                157                 :                :     /* total elapsed time in this function call */
  387 michael@paquier.xyz       158                 :            107 :     INSTR_TIME_SET_CURRENT(total);
                                159                 :            107 :     INSTR_TIME_SUBTRACT(total, fcu->start);
                                160                 :                : 
                                161                 :                :     /* self usage: elapsed minus anything already charged to other calls */
                                162                 :            107 :     others = total_func_time;
                                163                 :            107 :     INSTR_TIME_SUBTRACT(others, fcu->save_total);
                                164                 :            107 :     self = total;
                                165                 :            107 :     INSTR_TIME_SUBTRACT(self, others);
                                166                 :                : 
                                167                 :                :     /* update backend-wide total time */
                                168                 :            107 :     INSTR_TIME_ADD(total_func_time, self);
                                169                 :                : 
                                170                 :                :     /*
                                171                 :                :      * Compute the new total_time as the total elapsed time added to the
                                172                 :                :      * pre-call value of total_time.  This is necessary to avoid
                                173                 :                :      * double-counting any time taken by recursive calls of myself.  (We do
                                174                 :                :      * not need any similar kluge for self time, since that already excludes
                                175                 :                :      * any recursive calls.)
                                176                 :                :      */
                                177                 :            107 :     INSTR_TIME_ADD(total, fcu->save_f_total_time);
                                178                 :                : 
                                179                 :                :     /* update counters in function stats table */
  755 andres@anarazel.de        180         [ +  - ]:            107 :     if (finalize)
  387 michael@paquier.xyz       181                 :            107 :         fs->numcalls++;
                                182                 :            107 :     fs->total_time = total;
                                183                 :            107 :     INSTR_TIME_ADD(fs->self_time, self);
                                184                 :                : }
                                185                 :                : 
                                186                 :                : /*
                                187                 :                :  * Flush out pending stats for the entry
                                188                 :                :  *
                                189                 :                :  * If nowait is true, this function returns false if lock could not
                                190                 :                :  * immediately acquired, otherwise true is returned.
                                191                 :                :  */
                                192                 :                : bool
  739 andres@anarazel.de        193                 :             69 : pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
                                194                 :                : {
                                195                 :                :     PgStat_FunctionCounts *localent;
                                196                 :                :     PgStatShared_Function *shfuncent;
                                197                 :                : 
  395 michael@paquier.xyz       198                 :             69 :     localent = (PgStat_FunctionCounts *) entry_ref->pending;
  739 andres@anarazel.de        199                 :             69 :     shfuncent = (PgStatShared_Function *) entry_ref->shared_stats;
                                200                 :                : 
                                201                 :                :     /* localent always has non-zero content */
                                202                 :                : 
                                203         [ -  + ]:             69 :     if (!pgstat_lock_entry(entry_ref, nowait))
  739 andres@anarazel.de        204                 :UBC           0 :         return false;
                                205                 :                : 
  387 michael@paquier.xyz       206                 :CBC          69 :     shfuncent->stats.numcalls += localent->numcalls;
                                207                 :             69 :     shfuncent->stats.total_time +=
                                208                 :             69 :         INSTR_TIME_GET_MICROSEC(localent->total_time);
                                209                 :             69 :     shfuncent->stats.self_time +=
                                210                 :             69 :         INSTR_TIME_GET_MICROSEC(localent->self_time);
                                211                 :                : 
  739 andres@anarazel.de        212                 :             69 :     pgstat_unlock_entry(entry_ref);
                                213                 :                : 
                                214                 :             69 :     return true;
                                215                 :                : }
                                216                 :                : 
                                217                 :                : /*
                                218                 :                :  * find any existing PgStat_FunctionCounts entry for specified function
                                219                 :                :  *
                                220                 :                :  * If no entry, return NULL, don't create a new one
                                221                 :                :  */
                                222                 :                : PgStat_FunctionCounts *
  755                           223                 :             12 : find_funcstat_entry(Oid func_id)
                                224                 :                : {
                                225                 :                :     PgStat_EntryRef *entry_ref;
                                226                 :                : 
  739                           227                 :             12 :     entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_FUNCTION, MyDatabaseId, func_id);
                                228                 :                : 
                                229         [ +  + ]:             12 :     if (entry_ref)
                                230                 :              9 :         return entry_ref->pending;
                                231                 :              3 :     return NULL;
                                232                 :                : }
                                233                 :                : 
                                234                 :                : /*
                                235                 :                :  * Support function for the SQL-callable pgstat* functions. Returns
                                236                 :                :  * the collected statistics for one function or NULL.
                                237                 :                :  */
                                238                 :                : PgStat_StatFuncEntry *
                                239                 :            293 : pgstat_fetch_stat_funcentry(Oid func_id)
                                240                 :                : {
                                241                 :            293 :     return (PgStat_StatFuncEntry *)
                                242                 :            293 :         pgstat_fetch_entry(PGSTAT_KIND_FUNCTION, MyDatabaseId, func_id);
                                243                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622