1/* -------------------------------------------------------------------------
4 * Implementation of function statistics.
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
11 * Copyright (c) 2001-2025, PostgreSQL Global Development Group
14 * src/backend/utils/activity/pgstat_function.c
15 * -------------------------------------------------------------------------
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.)
42 * Ensure that stats are dropped if transaction aborts.
53 * Ensure that stats are dropped if transaction commits.
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
68 * Initialize function call usage data.
69 * Called by the executor before invoking a function.
79 if (pgstat_track_functions <= fcinfo->flinfo->fn_stats)
81 /* stats not wanted */
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).
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.
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
118 errmsg(
"function call to dropped function"));
126 /* save stats for this function, later used to compensate for recursion */
129 /* save current backend-wide total time */
132 /* get clock time as of function start */
137 * Calculate function call usage and update stat counters.
138 * Called by the executor after invoking a function.
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.
153 /* stats not wanted? */
157 /* total elapsed time in this function call */
161 /* self usage: elapsed minus anything already charged to other calls */
167 /* update backend-wide total time */
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.)
179 /* update counters in function stats table */
187 * Flush out pending stats for the entry
189 * If nowait is true and the lock could not be immediately acquired, returns
190 * false without flushing the entry. Otherwise returns true.
201 /* localent always has non-zero content */
218 * find any existing PgStat_FunctionCounts entry for specified function
220 * If no entry, return NULL, don't create a new one
235 * Support function for the SQL-callable pgstat* functions. Returns
236 * the collected statistics for one function or NULL.
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define INSTR_TIME_SET_CURRENT(t)
#define INSTR_TIME_ADD(x, y)
#define INSTR_TIME_SUBTRACT(x, y)
#define INSTR_TIME_GET_MICROSEC(t)
void AcceptInvalidationMessages(void)
PgStat_EntryRef * pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *created_entry)
PgStat_EntryRef * pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
void pgstat_drop_function(Oid proid)
PgStat_StatFuncEntry * pgstat_fetch_stat_funcentry(Oid func_id)
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
int pgstat_track_functions
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
void pgstat_create_function(Oid proid)
static instr_time total_func_time
bool pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
PgStat_FunctionCounts * find_funcstat_entry(Oid func_id)
#define PGSTAT_KIND_FUNCTION
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
static Datum ObjectIdGetDatum(Oid X)
PgStat_StatFuncEntry stats
PgStatShared_Common * shared_stats
PgStat_FunctionCounts * fs
instr_time save_f_total_time
PgStat_Counter total_time
#define SearchSysCacheExists1(cacheId, key1)