mirror of
https://github.com/postgres/postgres.git
synced 2025-12-01 12:18:01 +03:00
Add support for tracking call counts and elapsed runtime for user-defined
functions. Note that because this patch changes FmgrInfo, any external C functions you might be testing with 8.4 will need to be recompiled. Patch by Martin Pihlak, some editorialization by me (principally, removing tracking of getrusage() numbers)
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.51 2008/05/12 00:00:51 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.52 2008/05/15 00:17:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -39,6 +39,10 @@ extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_stat_get_function_time(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
|
||||
@@ -325,6 +329,39 @@ pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_TIMESTAMPTZ(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
pg_stat_get_function_calls(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid funcid = PG_GETARG_OID(0);
|
||||
PgStat_StatFuncEntry *funcentry;
|
||||
|
||||
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
||||
PG_RETURN_NULL();
|
||||
PG_RETURN_INT64(funcentry->f_numcalls);
|
||||
}
|
||||
|
||||
Datum
|
||||
pg_stat_get_function_time(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid funcid = PG_GETARG_OID(0);
|
||||
PgStat_StatFuncEntry *funcentry;
|
||||
|
||||
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
||||
PG_RETURN_NULL();
|
||||
PG_RETURN_INT64(funcentry->f_time);
|
||||
}
|
||||
|
||||
Datum
|
||||
pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid funcid = PG_GETARG_OID(0);
|
||||
PgStat_StatFuncEntry *funcentry;
|
||||
|
||||
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
||||
PG_RETURN_NULL();
|
||||
PG_RETURN_INT64(funcentry->f_time_self);
|
||||
}
|
||||
|
||||
Datum
|
||||
pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
@@ -401,7 +438,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
/*
|
||||
* Get one backend - locate by pid.
|
||||
*
|
||||
* We lookup the backend early, so we can return zero rows if it doesn't
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
$PostgreSQL: pgsql/src/backend/utils/fmgr/README,v 1.12 2008/04/21 00:26:45 tgl Exp $
|
||||
$PostgreSQL: pgsql/src/backend/utils/fmgr/README,v 1.13 2008/05/15 00:17:40 tgl Exp $
|
||||
|
||||
Function Manager
|
||||
================
|
||||
@@ -70,6 +70,7 @@ typedef struct
|
||||
short fn_nargs; /* 0..FUNC_MAX_ARGS, or -1 if variable arg count */
|
||||
bool fn_strict; /* function is "strict" (NULL in => NULL out) */
|
||||
bool fn_retset; /* function returns a set (over multiple calls) */
|
||||
unsigned char fn_stats; /* collect stats if track_functions > this */
|
||||
void *fn_extra; /* extra space for use by handler */
|
||||
MemoryContext fn_mcxt; /* memory context to store fn_extra in */
|
||||
Node *fn_expr; /* expression parse tree for call, or NULL */
|
||||
@@ -86,10 +87,11 @@ a function handler could set it to avoid making repeated lookups of its
|
||||
own when the same FmgrInfo is used repeatedly during a query.) fn_nargs
|
||||
is the number of arguments expected by the function, fn_strict is its
|
||||
strictness flag, and fn_retset shows whether it returns a set; all of
|
||||
these values come from the function's pg_proc entry. If the function is
|
||||
being called as part of a SQL expression, fn_expr will point to the
|
||||
expression parse tree for the function call; this can be used to extract
|
||||
parse-time knowledge about the actual arguments.
|
||||
these values come from the function's pg_proc entry. fn_stats is also
|
||||
set up to control whether or not to track runtime statistics for calling
|
||||
this function. If the function is being called as part of a SQL expression,
|
||||
fn_expr will point to the expression parse tree for the function call; this
|
||||
can be used to extract parse-time knowledge about the actual arguments.
|
||||
|
||||
FmgrInfo already exists in the current code, but has fewer fields. This
|
||||
change should be transparent at the source-code level.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.118 2008/05/12 00:00:52 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.119 2008/05/15 00:17:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "executor/functions.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "pgstat.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgrtab.h"
|
||||
#include "utils/guc.h"
|
||||
@@ -165,8 +166,7 @@ fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
|
||||
|
||||
/*
|
||||
* This one does the actual work. ignore_security is ordinarily false
|
||||
* but is set to true by fmgr_security_definer to avoid infinite
|
||||
* recursive lookups.
|
||||
* but is set to true by fmgr_security_definer to avoid recursion.
|
||||
*/
|
||||
static void
|
||||
fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
|
||||
@@ -197,6 +197,7 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
|
||||
finfo->fn_nargs = fbp->nargs;
|
||||
finfo->fn_strict = fbp->strict;
|
||||
finfo->fn_retset = fbp->retset;
|
||||
finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
|
||||
finfo->fn_addr = fbp->func;
|
||||
finfo->fn_oid = functionId;
|
||||
return;
|
||||
@@ -216,13 +217,23 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
|
||||
|
||||
/*
|
||||
* If it has prosecdef set, or non-null proconfig, use
|
||||
* fmgr_security_definer call handler.
|
||||
* fmgr_security_definer call handler --- unless we are being called
|
||||
* again by fmgr_security_definer.
|
||||
*
|
||||
* When using fmgr_security_definer, function stats tracking is always
|
||||
* disabled at the outer level, and instead we set the flag properly
|
||||
* in fmgr_security_definer's private flinfo and implement the tracking
|
||||
* inside fmgr_security_definer. This loses the ability to charge the
|
||||
* overhead of fmgr_security_definer to the function, but gains the
|
||||
* ability to set the track_functions GUC as a local GUC parameter of
|
||||
* an interesting function and have the right things happen.
|
||||
*/
|
||||
if (!ignore_security &&
|
||||
(procedureStruct->prosecdef ||
|
||||
!heap_attisnull(procedureTuple, Anum_pg_proc_proconfig)))
|
||||
{
|
||||
finfo->fn_addr = fmgr_security_definer;
|
||||
finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
|
||||
finfo->fn_oid = functionId;
|
||||
ReleaseSysCache(procedureTuple);
|
||||
return;
|
||||
@@ -255,18 +266,23 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
|
||||
pfree(prosrc);
|
||||
/* Should we check that nargs, strict, retset match the table? */
|
||||
finfo->fn_addr = fbp->func;
|
||||
/* note this policy is also assumed in fast path above */
|
||||
finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
|
||||
break;
|
||||
|
||||
case ClanguageId:
|
||||
fmgr_info_C_lang(functionId, finfo, procedureTuple);
|
||||
finfo->fn_stats = TRACK_FUNC_PL; /* ie, track if ALL */
|
||||
break;
|
||||
|
||||
case SQLlanguageId:
|
||||
finfo->fn_addr = fmgr_sql;
|
||||
finfo->fn_stats = TRACK_FUNC_PL; /* ie, track if ALL */
|
||||
break;
|
||||
|
||||
default:
|
||||
fmgr_info_other_lang(functionId, finfo, procedureTuple);
|
||||
finfo->fn_stats = TRACK_FUNC_OFF; /* ie, track if not OFF */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -862,6 +878,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
|
||||
Oid save_userid;
|
||||
bool save_secdefcxt;
|
||||
volatile int save_nestlevel;
|
||||
PgStat_FunctionCallUsage fcusage;
|
||||
|
||||
if (!fcinfo->flinfo->fn_extra)
|
||||
{
|
||||
@@ -934,7 +951,19 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
|
||||
{
|
||||
fcinfo->flinfo = &fcache->flinfo;
|
||||
|
||||
/* See notes in fmgr_info_cxt_security */
|
||||
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||
|
||||
result = FunctionCallInvoke(fcinfo);
|
||||
|
||||
/*
|
||||
* We could be calling either a regular or a set-returning function,
|
||||
* so we have to test to see what finalize flag to use.
|
||||
*/
|
||||
pgstat_end_function_usage(&fcusage,
|
||||
(fcinfo->resultinfo == NULL ||
|
||||
!IsA(fcinfo->resultinfo, ReturnSetInfo) ||
|
||||
((ReturnSetInfo *) fcinfo->resultinfo)->isDone != ExprMultipleResult));
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
@@ -2089,7 +2118,7 @@ float4
|
||||
DatumGetFloat4(Datum X)
|
||||
{
|
||||
union {
|
||||
int32 value;
|
||||
int32 value;
|
||||
float4 retval;
|
||||
} myunion;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.453 2008/05/12 08:35:05 mha Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.454 2008/05/15 00:17:40 tgl Exp $
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
@@ -169,7 +169,6 @@ static char *config_enum_get_options(struct config_enum *record,
|
||||
const char *prefix, const char *suffix);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Options for enum values defined in this module.
|
||||
*/
|
||||
@@ -241,6 +240,13 @@ static const struct config_enum_entry syslog_facility_options[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct config_enum_entry track_function_options[] = {
|
||||
{"none", TRACK_FUNC_OFF},
|
||||
{"pl", TRACK_FUNC_PL},
|
||||
{"all", TRACK_FUNC_ALL},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static const struct config_enum_entry xmlbinary_options[] = {
|
||||
{"base64", XMLBINARY_BASE64},
|
||||
{"hex", XMLBINARY_HEX},
|
||||
@@ -2524,6 +2530,15 @@ static struct config_enum ConfigureNamesEnum[] =
|
||||
assign_session_replication_role, NULL
|
||||
},
|
||||
|
||||
{
|
||||
{"track_functions", PGC_SUSET, STATS_COLLECTOR,
|
||||
gettext_noop("Collects function-level statistics on database activity."),
|
||||
gettext_noop("Valid values are: NONE, PL, and ALL.")
|
||||
},
|
||||
&pgstat_track_functions,
|
||||
TRACK_FUNC_OFF, track_function_options, NULL, NULL
|
||||
},
|
||||
|
||||
{
|
||||
{"wal_sync_method", PGC_SIGHUP, WAL_SETTINGS,
|
||||
gettext_noop("Selects the method used for forcing WAL updates to disk."),
|
||||
|
||||
@@ -363,6 +363,7 @@
|
||||
|
||||
#track_activities = on
|
||||
#track_counts = on
|
||||
#track_functions = none # none, pl, all
|
||||
#update_process_title = on
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user