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-2022, 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  */
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  */
44 void
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  */
59 void
61 {
64  proid);
65 }
66 
67 /*
68  * Initialize function call usage data.
69  * Called by the executor before invoking a function.
70  */
71 void
74 {
75  PgStat_EntryRef *entry_ref;
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  {
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->f_counts;
125 
126  /* save stats for this function, later used to compensate for recursion */
127  fcu->save_f_total_time = pending->f_counts.f_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  */
145 void
147 {
148  PgStat_FunctionCounts *fs = fcu->fs;
149  instr_time f_total;
150  instr_time f_others;
151  instr_time f_self;
152 
153  /* stats not wanted? */
154  if (fs == NULL)
155  return;
156 
157  /* total elapsed time in this function call */
158  INSTR_TIME_SET_CURRENT(f_total);
159  INSTR_TIME_SUBTRACT(f_total, fcu->f_start);
160 
161  /* self usage: elapsed minus anything already charged to other calls */
162  f_others = total_func_time;
163  INSTR_TIME_SUBTRACT(f_others, fcu->save_total);
164  f_self = f_total;
165  INSTR_TIME_SUBTRACT(f_self, f_others);
166 
167  /* update backend-wide total time */
169 
170  /*
171  * Compute the new f_total_time as the total elapsed time added to the
172  * pre-call value of f_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  INSTR_TIME_ADD(f_total, fcu->save_f_total_time);
178 
179  /* update counters in function stats table */
180  if (finalize)
181  fs->f_numcalls++;
182  fs->f_total_time = f_total;
183  INSTR_TIME_ADD(fs->f_self_time, f_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
194 {
195  PgStat_BackendFunctionEntry *localent;
196  PgStatShared_Function *shfuncent;
197 
198  localent = (PgStat_BackendFunctionEntry *) 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.f_numcalls += localent->f_counts.f_numcalls;
207  shfuncent->stats.f_total_time +=
209  shfuncent->stats.f_self_time +=
211 
212  pgstat_unlock_entry(entry_ref);
213 
214  return true;
215 }
216 
217 /*
218  * find any existing PgStat_BackendFunctionEntry 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:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
Oid MyDatabaseId
Definition: globals.c:89
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:158
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
void AcceptInvalidationMessages(void)
Definition: inval.c:746
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:779
PgStat_EntryRef * pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid, bool *created_entry)
Definition: pgstat.c:1053
PgStat_EntryRef * pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:1091
@ PGSTAT_KIND_FUNCTION
Definition: pgstat.h:43
@ TRACK_FUNC_OFF
Definition: pgstat.h:62
void pgstat_drop_function(Oid proid)
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
int pgstat_track_functions
PgStat_StatFuncEntry * pgstat_fetch_stat_funcentry(Oid func_id)
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_BackendFunctionEntry * find_funcstat_entry(Oid func_id)
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:583
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:838
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
Definition: pgstat_shmem.c:571
void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:366
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:388
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo * flinfo
Definition: fmgr.h:87
PgStat_StatFuncEntry stats
PgStat_FunctionCounts f_counts
Definition: pgstat.h:119
PgStatShared_Common * shared_stats
instr_time save_total
Definition: pgstat.h:133
PgStat_FunctionCounts * fs
Definition: pgstat.h:129
instr_time f_start
Definition: pgstat.h:135
instr_time save_f_total_time
Definition: pgstat.h:131
instr_time f_total_time
Definition: pgstat.h:109
PgStat_Counter f_numcalls
Definition: pgstat.h:108
instr_time f_self_time
Definition: pgstat.h:110
PgStat_Counter f_self_time
Definition: pgstat.h:319
PgStat_Counter f_total_time
Definition: pgstat.h:318
PgStat_Counter f_numcalls
Definition: pgstat.h:316
@ PROCOID
Definition: syscache.h:79
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:188