PostgreSQL Source Code git master
pgstat_function.c
Go to the documentation of this file.
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-2025, 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"
23#include "utils/syscache.h"
24
25
26/* ----------
27 * GUC parameters
28 * ----------
29 */
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 */
39
40
41/*
42 * Ensure that stats are dropped if transaction aborts.
43 */
44void
46{
49 proid);
50}
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 */
59void
61{
64 proid);
65}
66
67/*
68 * Initialize function call usage data.
69 * Called by the executor before invoking a function.
70 */
71void
74{
75 PgStat_EntryRef *entry_ref;
76 PgStat_FunctionCounts *pending;
77 bool created_entry;
78
79 if (pgstat_track_functions <= fcinfo->flinfo->fn_stats)
80 {
81 /* stats not wanted */
82 fcu->fs = NULL;
83 return;
84 }
85
88 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 if (created_entry)
111 {
113 if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid)))
114 {
116 fcinfo->flinfo->fn_oid);
117 ereport(ERROR, errcode(ERRCODE_UNDEFINED_FUNCTION),
118 errmsg("function call to dropped function"));
119 }
120 }
121
122 pending = entry_ref->pending;
123
124 fcu->fs = pending;
125
126 /* save stats for this function, later used to compensate for recursion */
127 fcu->save_f_total_time = pending->total_time;
128
129 /* save current backend-wide total time */
131
132 /* get clock time as of function 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 */
145void
147{
148 PgStat_FunctionCounts *fs = fcu->fs;
149 instr_time total;
150 instr_time others;
151 instr_time self;
152
153 /* stats not wanted? */
154 if (fs == NULL)
155 return;
156
157 /* total elapsed time in this function call */
159 INSTR_TIME_SUBTRACT(total, fcu->start);
160
161 /* self usage: elapsed minus anything already charged to other calls */
162 others = total_func_time;
163 INSTR_TIME_SUBTRACT(others, fcu->save_total);
164 self = total;
165 INSTR_TIME_SUBTRACT(self, others);
166
167 /* update backend-wide total time */
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 */
178
179 /* update counters in function stats table */
180 if (finalize)
181 fs->numcalls++;
182 fs->total_time = total;
183 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 */
192bool
194{
195 PgStat_FunctionCounts *localent;
196 PgStatShared_Function *shfuncent;
197
198 localent = (PgStat_FunctionCounts *) entry_ref->pending;
199 shfuncent = (PgStatShared_Function *) entry_ref->shared_stats;
200
201 /* localent always has non-zero content */
202
203 if (!pgstat_lock_entry(entry_ref, nowait))
204 return false;
205
206 shfuncent->stats.numcalls += localent->numcalls;
207 shfuncent->stats.total_time +=
209 shfuncent->stats.self_time +=
211
212 pgstat_unlock_entry(entry_ref);
213
214 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 */
224{
225 PgStat_EntryRef *entry_ref;
226
228
229 if (entry_ref)
230 return entry_ref->pending;
231 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 */
240{
241 return (PgStat_StatFuncEntry *)
243}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Oid MyDatabaseId
Definition: globals.c:93
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:178
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:194
void AcceptInvalidationMessages(void)
Definition: inval.c:863
PgStat_EntryRef * pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *created_entry)
Definition: pgstat.c:1294
PgStat_EntryRef * pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat.c:1332
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat.c:960
@ TRACK_FUNC_OFF
Definition: pgstat.h:40
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
Definition: pgstat_kind.h:29
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat_shmem.c:953
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:675
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
Definition: pgstat_shmem.c:647
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat_xact.c:384
void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat_xact.c:361
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:32
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo * flinfo
Definition: fmgr.h:87
PgStat_StatFuncEntry stats
PgStatShared_Common * shared_stats
instr_time save_total
Definition: pgstat.h:99
PgStat_FunctionCounts * fs
Definition: pgstat.h:95
instr_time save_f_total_time
Definition: pgstat.h:97
PgStat_Counter numcalls
Definition: pgstat.h:83
instr_time total_time
Definition: pgstat.h:84
instr_time self_time
Definition: pgstat.h:85
PgStat_Counter self_time
Definition: pgstat.h:398
PgStat_Counter numcalls
Definition: pgstat.h:395
PgStat_Counter total_time
Definition: pgstat.h:397
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100