Generate pg_stat_get_xact*() functions with Macros

Started by Drouvot, Bertrandabout 3 years ago24 messages
#1Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
1 attachment(s)

Hi hackers,

Please find attached a patch proposal to $SUBJECT.

This is the same kind of work that has been done in 83a1a1b566 and 8018ffbf58 but this time for the
pg_stat_get_xact*() functions (as suggested by Andres in [1]/messages/by-id/20230105002733.ealhzubjaiqis6ua@awork3.anarazel.de).

The function names remain the same, but some fields have to be renamed.

While at it, I also took the opportunity to create the macros for pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time() and pg_stat_get_function_total_time(), pg_stat_get_function_self_time()
(even if the same code pattern is only repeated two 2 times).

Now that this patch renames some fields, I think that, for consistency, those ones should be renamed too (aka remove the f_ and t_ prefixes):

PgStat_FunctionCounts.f_numcalls
PgStat_StatFuncEntry.f_numcalls
PgStat_TableCounts.t_truncdropped
PgStat_TableCounts.t_delta_live_tuples
PgStat_TableCounts.t_delta_dead_tuples
PgStat_TableCounts.t_changed_tuples

But I think it would be better to do it in a follow-up patch (once this one get committed).

[1]: /messages/by-id/20230105002733.ealhzubjaiqis6ua@awork3.anarazel.de

Looking forward to your feedback,

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-generate-pg_stat_get_xact-functions-with-macros.patchtext/plain; charset=UTF-8; name=v1-0001-generate-pg_stat_get_xact-functions-with-macros.patchDownload
diff --git a/src/backend/utils/activity/pgstat_function.c b/src/backend/utils/activity/pgstat_function.c
index 6139a27fee..77af8541e0 100644
--- a/src/backend/utils/activity/pgstat_function.c
+++ b/src/backend/utils/activity/pgstat_function.c
@@ -124,7 +124,7 @@ pgstat_init_function_usage(FunctionCallInfo fcinfo,
 	fcu->fs = &pending->f_counts;
 
 	/* save stats for this function, later used to compensate for recursion */
-	fcu->save_f_total_time = pending->f_counts.f_total_time;
+	fcu->save_total_time = pending->f_counts.total_time;
 
 	/* save current backend-wide total time */
 	fcu->save_total = total_func_time;
@@ -168,19 +168,19 @@ pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
 	INSTR_TIME_ADD(total_func_time, f_self);
 
 	/*
-	 * Compute the new f_total_time as the total elapsed time added to the
-	 * pre-call value of f_total_time.  This is necessary to avoid
+	 * Compute the new total_time as the total elapsed time added to the
+	 * pre-call value of total_time.  This is necessary to avoid
 	 * double-counting any time taken by recursive calls of myself.  (We do
 	 * not need any similar kluge for self time, since that already excludes
 	 * any recursive calls.)
 	 */
-	INSTR_TIME_ADD(f_total, fcu->save_f_total_time);
+	INSTR_TIME_ADD(f_total, fcu->save_total_time);
 
 	/* update counters in function stats table */
 	if (finalize)
 		fs->f_numcalls++;
-	fs->f_total_time = f_total;
-	INSTR_TIME_ADD(fs->f_self_time, f_self);
+	fs->total_time = f_total;
+	INSTR_TIME_ADD(fs->self_time, f_self);
 }
 
 /*
@@ -204,10 +204,10 @@ pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 		return false;
 
 	shfuncent->stats.f_numcalls += localent->f_counts.f_numcalls;
-	shfuncent->stats.f_total_time +=
-		INSTR_TIME_GET_MICROSEC(localent->f_counts.f_total_time);
-	shfuncent->stats.f_self_time +=
-		INSTR_TIME_GET_MICROSEC(localent->f_counts.f_self_time);
+	shfuncent->stats.total_time +=
+		INSTR_TIME_GET_MICROSEC(localent->f_counts.total_time);
+	shfuncent->stats.self_time +=
+		INSTR_TIME_GET_MICROSEC(localent->f_counts.self_time);
 
 	pgstat_unlock_entry(entry_ref);
 
diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index 1730425de1..625cd2a96f 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -371,9 +371,9 @@ pgstat_count_heap_update(Relation rel, bool hot)
 		ensure_tabstat_xact_level(pgstat_info);
 		pgstat_info->trans->tuples_updated++;
 
-		/* t_tuples_hot_updated is nontransactional, so just advance it */
+		/* tuples_hot_updated is nontransactional, so just advance it */
 		if (hot)
-			pgstat_info->t_counts.t_tuples_hot_updated++;
+			pgstat_info->t_counts.tuples_hot_updated++;
 	}
 }
 
@@ -501,9 +501,9 @@ AtEOXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit)
 		if (!isCommit)
 			restore_truncdrop_counters(trans);
 		/* count attempted actions regardless of commit/abort */
-		tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted;
-		tabstat->t_counts.t_tuples_updated += trans->tuples_updated;
-		tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted;
+		tabstat->t_counts.tuples_inserted += trans->tuples_inserted;
+		tabstat->t_counts.tuples_updated += trans->tuples_updated;
+		tabstat->t_counts.tuples_deleted += trans->tuples_deleted;
 		if (isCommit)
 		{
 			tabstat->t_counts.t_truncdropped = trans->truncdropped;
@@ -607,9 +607,9 @@ AtEOSubXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit, in
 			/* first restore values obliterated by truncate/drop */
 			restore_truncdrop_counters(trans);
 			/* count attempted actions regardless of commit/abort */
-			tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted;
-			tabstat->t_counts.t_tuples_updated += trans->tuples_updated;
-			tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted;
+			tabstat->t_counts.tuples_inserted += trans->tuples_inserted;
+			tabstat->t_counts.tuples_updated += trans->tuples_updated;
+			tabstat->t_counts.tuples_deleted += trans->tuples_deleted;
 			/* inserted tuples are dead, deleted tuples are unaffected */
 			tabstat->t_counts.t_delta_dead_tuples +=
 				trans->tuples_inserted + trans->tuples_updated;
@@ -691,9 +691,9 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info,
 	pgstat_info = pgstat_prep_relation_pending(rec->t_id, rec->t_shared);
 
 	/* Same math as in AtEOXact_PgStat, commit case */
-	pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted;
-	pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated;
-	pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted;
+	pgstat_info->t_counts.tuples_inserted += rec->tuples_inserted;
+	pgstat_info->t_counts.tuples_updated += rec->tuples_updated;
+	pgstat_info->t_counts.tuples_deleted += rec->tuples_deleted;
 	pgstat_info->t_counts.t_truncdropped = rec->t_truncdropped;
 	if (rec->t_truncdropped)
 	{
@@ -733,9 +733,9 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info,
 		rec->tuples_updated = rec->updated_pre_truncdrop;
 		rec->tuples_deleted = rec->deleted_pre_truncdrop;
 	}
-	pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted;
-	pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated;
-	pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted;
+	pgstat_info->t_counts.tuples_inserted += rec->tuples_inserted;
+	pgstat_info->t_counts.tuples_updated += rec->tuples_updated;
+	pgstat_info->t_counts.tuples_deleted += rec->tuples_deleted;
 	pgstat_info->t_counts.t_delta_dead_tuples +=
 		rec->tuples_inserted + rec->tuples_updated;
 }
@@ -779,19 +779,19 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 	/* add the values to the shared entry. */
 	tabentry = &shtabstats->stats;
 
-	tabentry->numscans += lstats->t_counts.t_numscans;
-	if (lstats->t_counts.t_numscans)
+	tabentry->numscans += lstats->t_counts.numscans;
+	if (lstats->t_counts.numscans)
 	{
 		TimestampTz t = GetCurrentTransactionStopTimestamp();
 		if (t > tabentry->lastscan)
 			tabentry->lastscan = t;
 	}
-	tabentry->tuples_returned += lstats->t_counts.t_tuples_returned;
-	tabentry->tuples_fetched += lstats->t_counts.t_tuples_fetched;
-	tabentry->tuples_inserted += lstats->t_counts.t_tuples_inserted;
-	tabentry->tuples_updated += lstats->t_counts.t_tuples_updated;
-	tabentry->tuples_deleted += lstats->t_counts.t_tuples_deleted;
-	tabentry->tuples_hot_updated += lstats->t_counts.t_tuples_hot_updated;
+	tabentry->tuples_returned += lstats->t_counts.tuples_returned;
+	tabentry->tuples_fetched += lstats->t_counts.tuples_fetched;
+	tabentry->tuples_inserted += lstats->t_counts.tuples_inserted;
+	tabentry->tuples_updated += lstats->t_counts.tuples_updated;
+	tabentry->tuples_deleted += lstats->t_counts.tuples_deleted;
+	tabentry->tuples_hot_updated += lstats->t_counts.tuples_hot_updated;
 
 	/*
 	 * If table was truncated/dropped, first reset the live/dead counters.
@@ -806,9 +806,9 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 	tabentry->live_tuples += lstats->t_counts.t_delta_live_tuples;
 	tabentry->dead_tuples += lstats->t_counts.t_delta_dead_tuples;
 	tabentry->mod_since_analyze += lstats->t_counts.t_changed_tuples;
-	tabentry->ins_since_vacuum += lstats->t_counts.t_tuples_inserted;
-	tabentry->blocks_fetched += lstats->t_counts.t_blocks_fetched;
-	tabentry->blocks_hit += lstats->t_counts.t_blocks_hit;
+	tabentry->ins_since_vacuum += lstats->t_counts.tuples_inserted;
+	tabentry->blocks_fetched += lstats->t_counts.blocks_fetched;
+	tabentry->blocks_hit += lstats->t_counts.blocks_hit;
 
 	/* Clamp live_tuples in case of negative delta_live_tuples */
 	tabentry->live_tuples = Max(tabentry->live_tuples, 0);
@@ -819,13 +819,13 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 
 	/* The entry was successfully flushed, add the same to database stats */
 	dbentry = pgstat_prep_database_pending(dboid);
-	dbentry->tuples_returned += lstats->t_counts.t_tuples_returned;
-	dbentry->tuples_fetched += lstats->t_counts.t_tuples_fetched;
-	dbentry->tuples_inserted += lstats->t_counts.t_tuples_inserted;
-	dbentry->tuples_updated += lstats->t_counts.t_tuples_updated;
-	dbentry->tuples_deleted += lstats->t_counts.t_tuples_deleted;
-	dbentry->blocks_fetched += lstats->t_counts.t_blocks_fetched;
-	dbentry->blocks_hit += lstats->t_counts.t_blocks_hit;
+	dbentry->tuples_returned += lstats->t_counts.tuples_returned;
+	dbentry->tuples_fetched += lstats->t_counts.tuples_fetched;
+	dbentry->tuples_inserted += lstats->t_counts.tuples_inserted;
+	dbentry->tuples_updated += lstats->t_counts.tuples_updated;
+	dbentry->tuples_deleted += lstats->t_counts.tuples_deleted;
+	dbentry->blocks_fetched += lstats->t_counts.blocks_fetched;
+	dbentry->blocks_hit += lstats->t_counts.blocks_hit;
 
 	return true;
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6cddd74aa7..27bb928db4 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -148,29 +148,24 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(funcentry->f_numcalls);
 }
 
-Datum
-pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
-
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
+#define PG_STAT_GET_FUNCENTRY_FLOAT8(stat)							\
+Datum																\
+CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)				\
+{																	\
+	Oid			funcid = PG_GETARG_OID(0);							\
+	PgStat_StatFuncEntry *funcentry;								\
+																	\
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)	\
+		PG_RETURN_NULL();											\
+	/* convert counter from microsec to millisec for display */		\
+	PG_RETURN_FLOAT8(((double) funcentry->stat) / 1000.0);			\
 }
 
-Datum
-pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
+/* pg_stat_get_function_total_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8(total_time)
 
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0);
-}
+/* pg_stat_get_function_self_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8(self_time)
 
 Datum
 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
@@ -1345,158 +1340,70 @@ pg_stat_get_slru(PG_FUNCTION_ARGS)
 	return (Datum) 0;
 }
 
-Datum
-pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_numscans);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_tuples_returned);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_tuples_fetched);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-	PgStat_TableXactStatus *trans;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-	{
-		result = tabentry->t_counts.t_tuples_inserted;
-		/* live subtransactions' counts aren't in t_tuples_inserted yet */
-		for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
-			result += trans->tuples_inserted;
-	}
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-	PgStat_TableXactStatus *trans;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-	{
-		result = tabentry->t_counts.t_tuples_updated;
-		/* live subtransactions' counts aren't in t_tuples_updated yet */
-		for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
-			result += trans->tuples_updated;
-	}
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-	PgStat_TableXactStatus *trans;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-	{
-		result = tabentry->t_counts.t_tuples_deleted;
-		/* live subtransactions' counts aren't in t_tuples_deleted yet */
-		for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
-			result += trans->tuples_deleted;
-	}
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_blocks_fetched);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->t_counts.t_blocks_hit);
-
-	PG_RETURN_INT64(result);
-}
+#define PG_STAT_GET_XACT_RELENTRY_INT64(stat)				\
+Datum														\
+CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS)			\
+{															\
+	Oid         relid = PG_GETARG_OID(0);					\
+	int64       result;										\
+	PgStat_TableStatus *tabentry;							\
+															\
+	if ((tabentry = find_tabstat_entry(relid)) == NULL)		\
+		result = 0;											\
+	else													\
+		result = (int64) (tabentry->t_counts.stat);			\
+															\
+	PG_RETURN_INT64(result);								\
+}
+
+/* pg_stat_get_xact_numscans */
+PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
+
+/* pg_stat_get_xact_tuples_returned */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
+
+/* pg_stat_get_xact_tuples_fetched */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
+
+/* pg_stat_get_xact_tuples_hot_updated */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
+
+/* pg_stat_get_xact_blocks_fetched */
+PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
+
+/* pg_stat_get_xact_blocks_hit */
+PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
+
+#define PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(stat)					\
+Datum																		\
+CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS)							\
+{																			\
+	Oid         relid = PG_GETARG_OID(0);									\
+	int64       result;														\
+	PgStat_TableStatus *tabentry;											\
+	PgStat_TableXactStatus *trans;											\
+																			\
+	if ((tabentry = find_tabstat_entry(relid)) == NULL)						\
+		result = 0;															\
+	else																	\
+	{																		\
+		result = tabentry->t_counts.stat;									\
+		/* live subtransactions' counts aren't in the stat yet */			\
+		for (trans = tabentry->trans; trans != NULL; trans = trans->upper)	\
+			result += trans->stat;											\
+	}																		\
+																			\
+	PG_RETURN_INT64(result);												\
+}
+
+/* pg_stat_get_xact_tuples_inserted */
+PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(tuples_inserted)
+
+/* pg_stat_get_xact_tuples_updated */
+PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(tuples_updated)
+
+/* pg_stat_get_xact_tuples_deleted */
+PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(tuples_deleted)
 
 Datum
 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
@@ -1509,28 +1416,23 @@ pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
 }
 
-Datum
-pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_BackendFunctionEntry *funcentry;
-
-	if ((funcentry = find_funcstat_entry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
+#define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8(stat)								\
+Datum																		\
+CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS)				\
+{																			\
+	Oid			funcid = PG_GETARG_OID(0);									\
+	PgStat_BackendFunctionEntry *funcentry;									\
+																			\
+	if ((funcentry = find_funcstat_entry(funcid)) == NULL)					\
+		PG_RETURN_NULL();													\
+	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.stat));	\
 }
 
-Datum
-pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_BackendFunctionEntry *funcentry;
-
-	if ((funcentry = find_funcstat_entry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
-}
+/* pg_stat_get_xact_function_total_time */
+PG_STAT_GET_XACT_FUNCENTRY_FLOAT8(total_time)
 
+/* pg_stat_get_xact_function_self_time */
+PG_STAT_GET_XACT_FUNCENTRY_FLOAT8(self_time)
 
 /* Get the timestamp of the current statistics snapshot */
 Datum
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index d3e965d744..d26d0d8324 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -106,8 +106,8 @@ typedef int64 PgStat_Counter;
 typedef struct PgStat_FunctionCounts
 {
 	PgStat_Counter f_numcalls;
-	instr_time	f_total_time;
-	instr_time	f_self_time;
+	instr_time	total_time;
+	instr_time	self_time;
 } PgStat_FunctionCounts;
 
 /* ----------
@@ -128,7 +128,7 @@ typedef struct PgStat_FunctionCallUsage
 	/* NULL means we are not tracking the current function call */
 	PgStat_FunctionCounts *fs;
 	/* Total time previously charged to function, as of function start */
-	instr_time	save_f_total_time;
+	instr_time	save_total_time;
 	/* Backend-wide total time as of function start */
 	instr_time	save_total;
 	/* system clock as of function start */
@@ -167,23 +167,23 @@ typedef struct PgStat_BackendSubEntry
  */
 typedef struct PgStat_TableCounts
 {
-	PgStat_Counter t_numscans;
+	PgStat_Counter numscans;
 
-	PgStat_Counter t_tuples_returned;
-	PgStat_Counter t_tuples_fetched;
+	PgStat_Counter tuples_returned;
+	PgStat_Counter tuples_fetched;
 
-	PgStat_Counter t_tuples_inserted;
-	PgStat_Counter t_tuples_updated;
-	PgStat_Counter t_tuples_deleted;
-	PgStat_Counter t_tuples_hot_updated;
+	PgStat_Counter tuples_inserted;
+	PgStat_Counter tuples_updated;
+	PgStat_Counter tuples_deleted;
+	PgStat_Counter tuples_hot_updated;
 	bool		t_truncdropped;
 
 	PgStat_Counter t_delta_live_tuples;
 	PgStat_Counter t_delta_dead_tuples;
 	PgStat_Counter t_changed_tuples;
 
-	PgStat_Counter t_blocks_fetched;
-	PgStat_Counter t_blocks_hit;
+	PgStat_Counter blocks_fetched;
+	PgStat_Counter blocks_hit;
 } PgStat_TableCounts;
 
 /* ----------
@@ -315,8 +315,8 @@ typedef struct PgStat_StatFuncEntry
 {
 	PgStat_Counter f_numcalls;
 
-	PgStat_Counter f_total_time;	/* times in microseconds */
-	PgStat_Counter f_self_time;
+	PgStat_Counter total_time;	/* times in microseconds */
+	PgStat_Counter self_time;
 } PgStat_StatFuncEntry;
 
 typedef struct PgStat_StatReplSlotEntry
@@ -525,37 +525,37 @@ extern void pgstat_report_analyze(Relation rel,
 #define pgstat_count_heap_scan(rel)									\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_numscans++;				\
+			(rel)->pgstat_info->t_counts.numscans++;				\
 	} while (0)
 #define pgstat_count_heap_getnext(rel)								\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_tuples_returned++;		\
+			(rel)->pgstat_info->t_counts.tuples_returned++;			\
 	} while (0)
 #define pgstat_count_heap_fetch(rel)								\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_tuples_fetched++;		\
+			(rel)->pgstat_info->t_counts.tuples_fetched++;			\
 	} while (0)
 #define pgstat_count_index_scan(rel)								\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_numscans++;				\
+			(rel)->pgstat_info->t_counts.numscans++;				\
 	} while (0)
 #define pgstat_count_index_tuples(rel, n)							\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_tuples_returned += (n);	\
+			(rel)->pgstat_info->t_counts.tuples_returned += (n);	\
 	} while (0)
 #define pgstat_count_buffer_read(rel)								\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_blocks_fetched++;		\
+			(rel)->pgstat_info->t_counts.blocks_fetched++;			\
 	} while (0)
 #define pgstat_count_buffer_hit(rel)								\
 	do {															\
 		if (pgstat_should_count_relation(rel))						\
-			(rel)->pgstat_info->t_counts.t_blocks_hit++;			\
+			(rel)->pgstat_info->t_counts.blocks_hit++;				\
 	} while (0)
 
 extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
#2Corey Huinker
corey.huinker@gmail.com
In reply to: Drouvot, Bertrand (#1)
Re: Generate pg_stat_get_xact*() functions with Macros

On Thu, Jan 5, 2023 at 8:50 AM Drouvot, Bertrand <
bertranddrouvot.pg@gmail.com> wrote:

Hi hackers,

Please find attached a patch proposal to $SUBJECT.

This is the same kind of work that has been done in 83a1a1b566 and
8018ffbf58 but this time for the
pg_stat_get_xact*() functions (as suggested by Andres in [1]).

The function names remain the same, but some fields have to be renamed.

While at it, I also took the opportunity to create the macros for
pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time() and
pg_stat_get_function_total_time(), pg_stat_get_function_self_time()
(even if the same code pattern is only repeated two 2 times).

Now that this patch renames some fields, I think that, for consistency,
those ones should be renamed too (aka remove the f_ and t_ prefixes):

PgStat_FunctionCounts.f_numcalls
PgStat_StatFuncEntry.f_numcalls
PgStat_TableCounts.t_truncdropped
PgStat_TableCounts.t_delta_live_tuples
PgStat_TableCounts.t_delta_dead_tuples
PgStat_TableCounts.t_changed_tuples

But I think it would be better to do it in a follow-up patch (once this
one get committed).

[1]:
/messages/by-id/20230105002733.ealhzubjaiqis6ua@awork3.anarazel.de

Looking forward to your feedback,

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

I like code cleanups like this. It makes sense, it results in less code,
and anyone doing a `git grep pg_stat_get_live_tuples` will quickly find the
macro definition.

Unsurprisingly, it passes `make check-world`.

So I think it's good to go as-is.

It does get me wondering, however, if we reordered the three typedefs to
group like-typed registers together, we could make them an array with the
names becoming defined constant index values (or keeping them via a union),
then the typedefs effectively become:

typedef struct PgStat_FunctionCallUsage
{
PgStat_FunctionCounts *fs;
instr_time time_counters[3];
} PgStat_FunctionCallUsage;

typedef struct PgStat_BackendSubEntry
{
PgStat_Counter counters[2];
} PgStat_BackendSubEntry;

typedef struct PgStat_TableCounts
{
bool t_truncdropped;
PgStat_Counter counters[12];
} PgStat_TableCounts;

Then we'd only have 3 actual C functions:

pg_stat_get_xact_counter(oid, int)
pg_stat_get_xact_subtrans_counter(oid, int)
pg_stat_get_xact_function_time_counter(oid, int)

and then the existing functions become SQL standard function body calls,
something like this:

CREATE OR REPLACE FUNCTION pg_stat_get_xact_numscans(oid)
RETURNS bigint
LANGUAGE sql
STABLE PARALLEL RESTRICTED COST 1
RETURN pg_stat_get_xact_counter($1, 0);

CREATE OR REPLACE FUNCTION pg_stat_get_xact_tuples_returned(oid)
RETURNS bigint
LANGUAGE sql
STABLE PARALLEL RESTRICTED COST 1
RETURN pg_stat_get_xact_counter($1, 1);

The most obvious drawback to this approach is that the C functions would
need to do runtime bounds checking on the index parameter, and the amount
of memory footprint saved by going from 17 short functions to 3 is not
enough to make any real difference. So I think your approach is better, but
I wanted to throw this idea out there.

#3Andres Freund
andres@anarazel.de
In reply to: Corey Huinker (#2)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 2023-01-05 15:19:54 -0500, Corey Huinker wrote:

It does get me wondering, however, if we reordered the three typedefs to
group like-typed registers together, we could make them an array with the
names becoming defined constant index values (or keeping them via a union),
then the typedefs effectively become:

I think that'd make it substantially enough harder to work with the
datastructures that I don't want to go there.

The "more fundamental" approach would be to switch to using a table-returning
function for accessing these stat values. When just accessing a single counter
or two, the current approach avoids the overhead of having to construct a
tuple. But after that the overhead of having to fetch the stats data (i.e. a
hash table lookup, potentially some locking) multiple times takes over.

Unfortunately there's currently no way to dynamically switch between those
behaviours.

Greetings,

Andres Freund

#4Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Corey Huinker (#2)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 1/5/23 9:19 PM, Corey Huinker wrote:

I like code cleanups like this. It makes sense, it results in less code, and anyone doing a `git grep pg_stat_get_live_tuples` will quickly find the macro definition.

Unsurprisingly, it passes `make check-world`.

So I think it's good to go as-is.

Thanks for the review!

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#5Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Andres Freund (#3)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 1/6/23 12:21 AM, Andres Freund wrote:

Hi,

On 2023-01-05 15:19:54 -0500, Corey Huinker wrote:

It does get me wondering, however, if we reordered the three typedefs to
group like-typed registers together, we could make them an array with the
names becoming defined constant index values (or keeping them via a union),
then the typedefs effectively become:

I think that'd make it substantially enough harder to work with the
datastructures that I don't want to go there.

Yeah, I think that's a good idea from a "coding style" point of view but harder to work with.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#6Andres Freund
andres@anarazel.de
In reply to: Drouvot, Bertrand (#1)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

Michael, CCing you because of the point about PG_STAT_GET_DBENTRY_FLOAT8
below.

On 2023-01-05 14:48:39 +0100, Drouvot, Bertrand wrote:

While at it, I also took the opportunity to create the macros for pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time() and pg_stat_get_function_total_time(), pg_stat_get_function_self_time()
(even if the same code pattern is only repeated two 2 times).

I'd split that up into a separate commit.

Now that this patch renames some fields

I don't mind renaming the fields - the prefixes really don't provide anything
useful. But it's not clear why this is related to this patch? You could just
include the f_ prefix in the macro, no?

, I think that, for consistency, those ones should be renamed too (aka remove the f_ and t_ prefixes):

PgStat_FunctionCounts.f_numcalls
PgStat_StatFuncEntry.f_numcalls
PgStat_TableCounts.t_truncdropped
PgStat_TableCounts.t_delta_live_tuples
PgStat_TableCounts.t_delta_dead_tuples
PgStat_TableCounts.t_changed_tuples

Yea, without that the result is profoundly weird.

But I think it would be better to do it in a follow-up patch (once this one get committed).

I don't mind committing it in a separate commit, but I think it should be done
at least immediately following the other commit. I.e. developed together.

I probably would go the other way, and rename all of them first. That'd make
this commit a lot more focused, and the renaming commit purely mechanical.

Probably should remove PgStat_BackendFunctionEntry. PgStat_TableStatus has
reason to exist, but that's not true for PgStat_BackendFunctionEntry.

@@ -168,19 +168,19 @@ pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
INSTR_TIME_ADD(total_func_time, f_self);

/*
-	 * Compute the new f_total_time as the total elapsed time added to the
-	 * pre-call value of f_total_time.  This is necessary to avoid
+	 * Compute the new total_time as the total elapsed time added to the
+	 * pre-call value of total_time.  This is necessary to avoid
* double-counting any time taken by recursive calls of myself.  (We do
* not need any similar kluge for self time, since that already excludes
* any recursive calls.)
*/
-	INSTR_TIME_ADD(f_total, fcu->save_f_total_time);
+	INSTR_TIME_ADD(f_total, fcu->save_total_time);
/* update counters in function stats table */
if (finalize)
fs->f_numcalls++;
-	fs->f_total_time = f_total;
-	INSTR_TIME_ADD(fs->f_self_time, f_self);
+	fs->total_time = f_total;
+	INSTR_TIME_ADD(fs->self_time, f_self);
}

I'd also rename f_self etc.

@@ -148,29 +148,24 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
PG_RETURN_INT64(funcentry->f_numcalls);
}

-Datum
-pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
-
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
+#define PG_STAT_GET_FUNCENTRY_FLOAT8(stat)							\
+Datum																\
+CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)				\
+{																	\
+	Oid			funcid = PG_GETARG_OID(0);							\
+	PgStat_StatFuncEntry *funcentry;								\
+																	\
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)	\
+		PG_RETURN_NULL();											\
+	/* convert counter from microsec to millisec for display */		\
+	PG_RETURN_FLOAT8(((double) funcentry->stat) / 1000.0);			\
}

Hm. Given the conversion with / 1000, is PG_STAT_GET_FUNCENTRY_FLOAT8 an
accurate name? Maybe PG_STAT_GET_FUNCENTRY_FLOAT8_MS?

I now see that PG_STAT_GET_DBENTRY_FLOAT8 already exists, defined the same
way. But the name fields misleading enough that I'd be inclined to rename it?

+#define PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(stat) \

How about PG_STAT_GET_XACT_PLUS_SUBTRANS_INT64?

Although I suspect this actually hints at an architectural thing that could be
fixed better: Perhaps we should replace find_tabstat_entry() with a version
returning a fully "reconciled" PgStat_StatTabEntry? It feels quite wrong to
have that intimitate knowledge of the subtransaction stuff in pgstatfuncs.c
and about how the different counts get combined.

I think that'd allow us to move the definition of PgStat_TableStatus to
PgStat_TableXactStatus, PgStat_TableCounts to pgstat_internal.h. Which feels a
heck of a lot cleaner.

Greetings,

Andres Freund

#7Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Andres Freund (#6)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 1/11/23 11:59 PM, Andres Freund wrote:

Hi,

Michael, CCing you because of the point about PG_STAT_GET_DBENTRY_FLOAT8
below.

On 2023-01-05 14:48:39 +0100, Drouvot, Bertrand wrote:

While at it, I also took the opportunity to create the macros for pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time() and pg_stat_get_function_total_time(), pg_stat_get_function_self_time()
(even if the same code pattern is only repeated two 2 times).

I'd split that up into a separate commit.

Thanks for looking at it! Makes sense, will do.

Now that this patch renames some fields

I don't mind renaming the fields - the prefixes really don't provide anything
useful. But it's not clear why this is related to this patch? You could just
include the f_ prefix in the macro, no?

Right, but the idea is to take the same approach that the one used in 8018ffbf58 (where placing the prefixes in the macro
would have been possible too).

, I think that, for consistency, those ones should be renamed too (aka remove the f_ and t_ prefixes):

PgStat_FunctionCounts.f_numcalls
PgStat_StatFuncEntry.f_numcalls
PgStat_TableCounts.t_truncdropped
PgStat_TableCounts.t_delta_live_tuples
PgStat_TableCounts.t_delta_dead_tuples
PgStat_TableCounts.t_changed_tuples

Yea, without that the result is profoundly weird.

But I think it would be better to do it in a follow-up patch (once this one get committed).

I don't mind committing it in a separate commit, but I think it should be done
at least immediately following the other commit. I.e. developed together.

I probably would go the other way, and rename all of them first. That'd make
this commit a lot more focused, and the renaming commit purely mechanical.

Yeah, makes sense. Let's proceed that way. I'll provide the "rename" patch.

Probably should remove PgStat_BackendFunctionEntry.

I think that would be a 3rd patch, agree?

@@ -168,19 +168,19 @@ pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
INSTR_TIME_ADD(total_func_time, f_self);

/*
-	 * Compute the new f_total_time as the total elapsed time added to the
-	 * pre-call value of f_total_time.  This is necessary to avoid
+	 * Compute the new total_time as the total elapsed time added to the
+	 * pre-call value of total_time.  This is necessary to avoid
* double-counting any time taken by recursive calls of myself.  (We do
* not need any similar kluge for self time, since that already excludes
* any recursive calls.)
*/
-	INSTR_TIME_ADD(f_total, fcu->save_f_total_time);
+	INSTR_TIME_ADD(f_total, fcu->save_total_time);
/* update counters in function stats table */
if (finalize)
fs->f_numcalls++;
-	fs->f_total_time = f_total;
-	INSTR_TIME_ADD(fs->f_self_time, f_self);
+	fs->total_time = f_total;
+	INSTR_TIME_ADD(fs->self_time, f_self);
}

I'd also rename f_self etc.

Makes sense, will do.

@@ -148,29 +148,24 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
PG_RETURN_INT64(funcentry->f_numcalls);
}

-Datum
-pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
-
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
+#define PG_STAT_GET_FUNCENTRY_FLOAT8(stat)							\
+Datum																\
+CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)				\
+{																	\
+	Oid			funcid = PG_GETARG_OID(0);							\
+	PgStat_StatFuncEntry *funcentry;								\
+																	\
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)	\
+		PG_RETURN_NULL();											\
+	/* convert counter from microsec to millisec for display */		\
+	PG_RETURN_FLOAT8(((double) funcentry->stat) / 1000.0);			\
}

Hm. Given the conversion with / 1000, is PG_STAT_GET_FUNCENTRY_FLOAT8 an
accurate name? Maybe PG_STAT_GET_FUNCENTRY_FLOAT8_MS?

I now see that PG_STAT_GET_DBENTRY_FLOAT8 already exists, defined the same
way. But the name fields misleading enough that I'd be inclined to rename it?

PG_STAT_GET_FUNCENTRY_FLOAT8_MS looks good by me. Waiting on what we'll decide for
the existing PG_STAT_GET_DBENTRY_FLOAT8 (so that I can align for the PG_STAT_GET_FUNCENTRY_FLOAT8).

+#define PG_STAT_GET_XACT_WITH_SUBTRANS_RELENTRY_INT64(stat) \

How about PG_STAT_GET_XACT_PLUS_SUBTRANS_INT64?

Sounds, better, thanks!

Although I suspect this actually hints at an architectural thing that could be
fixed better: Perhaps we should replace find_tabstat_entry() with a version
returning a fully "reconciled" PgStat_StatTabEntry? It feels quite wrong to
have that intimitate knowledge of the subtransaction stuff in pgstatfuncs.c
and about how the different counts get combined.

I think that'd allow us to move the definition of PgStat_TableStatus to
PgStat_TableXactStatus, PgStat_TableCounts to pgstat_internal.h. Which feels a
heck of a lot cleaner.

Yeah, I think that would be for a 4th patch, agree?

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#8Andres Freund
andres@anarazel.de
In reply to: Drouvot, Bertrand (#7)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 2023-01-12 08:38:57 +0100, Drouvot, Bertrand wrote:

On 1/11/23 11:59 PM, Andres Freund wrote:

Now that this patch renames some fields

I don't mind renaming the fields - the prefixes really don't provide anything
useful. But it's not clear why this is related to this patch? You could just
include the f_ prefix in the macro, no?

Right, but the idea is to take the same approach that the one used in 8018ffbf58 (where placing the prefixes in the macro
would have been possible too).

I'm not super happy about that patch tbh.

Probably should remove PgStat_BackendFunctionEntry.

I think that would be a 3rd patch, agree?

Yep.

I now see that PG_STAT_GET_DBENTRY_FLOAT8 already exists, defined the same
way. But the name fields misleading enough that I'd be inclined to rename it?

PG_STAT_GET_FUNCENTRY_FLOAT8_MS looks good by me. Waiting on what we'll decide for
the existing PG_STAT_GET_DBENTRY_FLOAT8 (so that I can align for the PG_STAT_GET_FUNCENTRY_FLOAT8).

+1

Although I suspect this actually hints at an architectural thing that could be
fixed better: Perhaps we should replace find_tabstat_entry() with a version
returning a fully "reconciled" PgStat_StatTabEntry? It feels quite wrong to
have that intimitate knowledge of the subtransaction stuff in pgstatfuncs.c
and about how the different counts get combined.

I think that'd allow us to move the definition of PgStat_TableStatus to
PgStat_TableXactStatus, PgStat_TableCounts to pgstat_internal.h. Which feels a
heck of a lot cleaner.

Yeah, I think that would be for a 4th patch, agree?

Yea. I am of multiple minds about the ordering. I can see benefits on fixing
the architectural issue before reducing duplication in the accessor with a
macro. The reason is that if we addressed the architectural issue, the
difference between the xact and non-xact version will be very minimal, and
could even be generated by the same macro.

Greetings,

Andres Freund

#9Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Andres Freund (#8)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 1/12/23 7:24 PM, Andres Freund wrote:

Hi,

On 2023-01-12 08:38:57 +0100, Drouvot, Bertrand wrote:

On 1/11/23 11:59 PM, Andres Freund wrote:

Now that this patch renames some fields

I don't mind renaming the fields - the prefixes really don't provide anything
useful. But it's not clear why this is related to this patch? You could just
include the f_ prefix in the macro, no?

Right, but the idea is to take the same approach that the one used in 8018ffbf58 (where placing the prefixes in the macro
would have been possible too).

I'm not super happy about that patch tbh.

Probably should remove PgStat_BackendFunctionEntry.

I think that would be a 3rd patch, agree?

Yep.

I now see that PG_STAT_GET_DBENTRY_FLOAT8 already exists, defined the same
way. But the name fields misleading enough that I'd be inclined to rename it?

PG_STAT_GET_FUNCENTRY_FLOAT8_MS looks good by me. Waiting on what we'll decide for
the existing PG_STAT_GET_DBENTRY_FLOAT8 (so that I can align for the PG_STAT_GET_FUNCENTRY_FLOAT8).

+1

Although I suspect this actually hints at an architectural thing that could be
fixed better: Perhaps we should replace find_tabstat_entry() with a version
returning a fully "reconciled" PgStat_StatTabEntry? It feels quite wrong to
have that intimitate knowledge of the subtransaction stuff in pgstatfuncs.c
and about how the different counts get combined.

I think that'd allow us to move the definition of PgStat_TableStatus to
PgStat_TableXactStatus, PgStat_TableCounts to pgstat_internal.h. Which feels a
heck of a lot cleaner.

Yeah, I think that would be for a 4th patch, agree?

Yea. I am of multiple minds about the ordering. I can see benefits on fixing
the architectural issue before reducing duplication in the accessor with a
macro. The reason is that if we addressed the architectural issue, the
difference between the xact and non-xact version will be very minimal, and
could even be generated by the same macro.

Yeah, I do agree and I'm in favor of this ordering:

1) replace find_tabstat_entry() with a version returning a fully "reconciled" PgStat_StatTabEntry
2) remove prefixes
3) Introduce the new macros

And it looks to me that removing PgStat_BackendFunctionEntry can be done independently

I'll first look at 1).

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#10Andres Freund
andres@anarazel.de
In reply to: Drouvot, Bertrand (#9)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 2023-01-13 10:36:49 +0100, Drouvot, Bertrand wrote:

Although I suspect this actually hints at an architectural thing that could be
fixed better: Perhaps we should replace find_tabstat_entry() with a version
returning a fully "reconciled" PgStat_StatTabEntry? It feels quite wrong to
have that intimitate knowledge of the subtransaction stuff in pgstatfuncs.c
and about how the different counts get combined.

I think that'd allow us to move the definition of PgStat_TableStatus to
PgStat_TableXactStatus, PgStat_TableCounts to pgstat_internal.h. Which feels a
heck of a lot cleaner.

Yeah, I think that would be for a 4th patch, agree?

Yea. I am of multiple minds about the ordering. I can see benefits on fixing
the architectural issue before reducing duplication in the accessor with a
macro. The reason is that if we addressed the architectural issue, the
difference between the xact and non-xact version will be very minimal, and
could even be generated by the same macro.

Yeah, I do agree and I'm in favor of this ordering:

1) replace find_tabstat_entry() with a version returning a fully "reconciled" PgStat_StatTabEntry
2) remove prefixes
3) Introduce the new macros

I'll first look at 1).

Makes sense.

And it looks to me that removing PgStat_BackendFunctionEntry can be done independently

It's imo the function version of 1), just a bit simpler to implement due to
the much simpler reconciliation. It could be done together with it, or
separately.

Greetings,

Andres Freund

#11Gregory Stark (as CFM)
stark.cfm@gmail.com
In reply to: Andres Freund (#10)
Re: Generate pg_stat_get_xact*() functions with Macros

Looks like you have a path forward on this and it's not ready to
commit yet? In which case I'll mark it Waiting on Author?

On Fri, 13 Jan 2023 at 13:38, Andres Freund <andres@anarazel.de> wrote:

On 2023-01-13 10:36:49 +0100, Drouvot, Bertrand wrote:

I'll first look at 1).

Makes sense.

And it looks to me that removing PgStat_BackendFunctionEntry can be done independently

It's imo the function version of 1), just a bit simpler to implement due to
the much simpler reconciliation. It could be done together with it, or
separately.

--
Gregory Stark
As Commitfest Manager

#12Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Gregory Stark (as CFM) (#11)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 3/1/23 8:54 PM, Gregory Stark (as CFM) wrote:

Looks like you have a path forward on this and it's not ready to
commit yet? In which case I'll mark it Waiting on Author?

Yeah, there is some dependencies around this one.

[1]: /messages/by-id/f572abe7-a1bb-e13b-48c7-2ca150546822@gmail.com
Current one depends of [2]/messages/by-id/b9e1f543-ee93-8168-d530-d961708ad9d3@gmail.com, [3]/messages/by-id/11d531fe-52fc-c6ea-7e8e-62f1b6ec626e@gmail.com and [4]/messages/by-id/9142f62a-a422-145c-bde0-b5bc498a4ada@gmail.com

Waiting on Author is then the right state, thanks for having moved it to that state.

[1]: /messages/by-id/f572abe7-a1bb-e13b-48c7-2ca150546822@gmail.com
[2]: /messages/by-id/b9e1f543-ee93-8168-d530-d961708ad9d3@gmail.com
[3]: /messages/by-id/11d531fe-52fc-c6ea-7e8e-62f1b6ec626e@gmail.com
[4]: /messages/by-id/9142f62a-a422-145c-bde0-b5bc498a4ada@gmail.com

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#13Michael Paquier
michael@paquier.xyz
In reply to: Drouvot, Bertrand (#12)
Re: Generate pg_stat_get_xact*() functions with Macros

On Thu, Mar 02, 2023 at 08:39:14AM +0100, Drouvot, Bertrand wrote:

Yeah, there is some dependencies around this one.

[1]: depends on it
Current one depends of [2], [3] and [4]

Waiting on Author is then the right state, thanks for having moved it to that state.

[1]: /messages/by-id/f572abe7-a1bb-e13b-48c7-2ca150546822@gmail.com
[2]: /messages/by-id/b9e1f543-ee93-8168-d530-d961708ad9d3@gmail.com
[3]: /messages/by-id/11d531fe-52fc-c6ea-7e8e-62f1b6ec626e@gmail.com
[4]: /messages/by-id/9142f62a-a422-145c-bde0-b5bc498a4ada@gmail.com

[3]: and [4] have been applied. [2] is more sensitive than it looks, and [1] for the split of index and table stats can feed on the one of this thread.
and [1] for the split of index and table stats can feed on the one of
this thread.

Roma wasn't built in one day, and from what I can see you can still do
some progress with the refactoring of pgstatfuncs.c with what's
already on HEAD. So how about handling doing that first as much as we
can based on the state of HEAD? That looks like 50~60% (?) of the
original goal to switch pgstatfuncs.c to use more macros to generate
the definition of all these SQL functions.
--
Michael

#14Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Michael Paquier (#13)
1 attachment(s)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 3/24/23 1:04 AM, Michael Paquier wrote:

On Thu, Mar 02, 2023 at 08:39:14AM +0100, Drouvot, Bertrand wrote:

Yeah, there is some dependencies around this one.

[1]: depends on it
Current one depends of [2], [3] and [4]

Waiting on Author is then the right state, thanks for having moved it to that state.

[1]: /messages/by-id/f572abe7-a1bb-e13b-48c7-2ca150546822@gmail.com
[2]: /messages/by-id/b9e1f543-ee93-8168-d530-d961708ad9d3@gmail.com
[3]: /messages/by-id/11d531fe-52fc-c6ea-7e8e-62f1b6ec626e@gmail.com
[4]: /messages/by-id/9142f62a-a422-145c-bde0-b5bc498a4ada@gmail.com

[3] and [4] have been applied.

Thanks for your help on this!

[2] is more sensitive than it looks,
and [1] for the split of index and table stats can feed on the one of
this thread.

Roma wasn't built in one day, and from what I can see you can still do
some progress with the refactoring of pgstatfuncs.c with what's
already on HEAD. So how about handling doing that first as much as we
can based on the state of HEAD? That looks like 50~60% (?) of the
original goal to switch pgstatfuncs.c to use more macros to generate
the definition of all these SQL functions.

I think that's a good idea, so please find enclosed V2 which as compare to V1:

- Does not include the refactoring for pg_stat_get_xact_tuples_inserted(), pg_stat_get_xact_tuples_updated()
and pg_stat_get_xact_tuples_deleted() (as they depend of [2] mentioned above)

- Does not include the refactoring for pg_stat_get_xact_function_total_time(), pg_stat_get_xact_function_self_time(),
pg_stat_get_function_total_time() and pg_stat_get_function_self_time(). I think they can be done in a dedicated commit once
we agree on the renaming for PG_STAT_GET_DBENTRY_FLOAT8 (see Andres's comment up-thread) so that the new macros can match the future agreement.

- Does include the refactoring of the new pg_stat_get_xact_tuples_newpage_updated() function (added in ae4fdde135)

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-generate-pg_stat_get_xact-functions-with-macros.patchtext/plain; charset=UTF-8; name=v2-0001-generate-pg_stat_get_xact-functions-with-macros.patchDownload
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index c7ba86b3dc..e1dd1e0ad3 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1498,50 +1498,42 @@ pg_stat_get_slru(PG_FUNCTION_ARGS)
 	return (Datum) 0;
 }
 
-Datum
-pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.numscans);
-
-	PG_RETURN_INT64(result);
+#define PG_STAT_GET_XACT_RELENTRY_INT64(stat)			\
+Datum													\
+CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS)		\
+{														\
+	Oid         relid = PG_GETARG_OID(0);				\
+	int64       result;									\
+	PgStat_TableStatus *tabentry;						\
+														\
+	if ((tabentry = find_tabstat_entry(relid)) == NULL)	\
+		result = 0;										\
+	else												\
+		result = (int64) (tabentry->counts.stat);		\
+														\
+	PG_RETURN_INT64(result);							\
 }
 
-Datum
-pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
+/* pg_stat_get_xact_numscans */
+PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
 
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.tuples_returned);
+/* pg_stat_get_xact_tuples_returned */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
 
-	PG_RETURN_INT64(result);
-}
+/* pg_stat_get_xact_tuples_fetched */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
 
-Datum
-pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
+/* pg_stat_get_xact_tuples_hot_updated */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
 
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.tuples_fetched);
+/* pg_stat_get_xact_tuples_newpage_updated */
+PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
 
-	PG_RETURN_INT64(result);
-}
+/* pg_stat_get_xact_blocks_fetched */
+PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
+
+/* pg_stat_get_xact_blocks_hit */
+PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
 
 Datum
 pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
@@ -1606,66 +1598,6 @@ pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(result);
 }
 
-Datum
-pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.tuples_hot_updated);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_tuples_newpage_updated(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.tuples_newpage_updated);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.blocks_fetched);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		result;
-	PgStat_TableStatus *tabentry;
-
-	if ((tabentry = find_tabstat_entry(relid)) == NULL)
-		result = 0;
-	else
-		result = (int64) (tabentry->counts.blocks_hit);
-
-	PG_RETURN_INT64(result);
-}
-
 Datum
 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
 {
#15Michael Paquier
michael@paquier.xyz
In reply to: Drouvot, Bertrand (#14)
Re: Generate pg_stat_get_xact*() functions with Macros

On Fri, Mar 24, 2023 at 06:58:30AM +0100, Drouvot, Bertrand wrote:

- Does not include the refactoring for pg_stat_get_xact_tuples_inserted(),
pg_stat_get_xact_tuples_updated() and pg_stat_get_xact_tuples_deleted() (as
they depend of [2] mentioned above)

- Does not include the refactoring for
pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time(),
pg_stat_get_function_total_time() and
pg_stat_get_function_self_time(). I think they can be done in a
dedicated commit once we agree on the renaming for
PG_STAT_GET_DBENTRY_FLOAT8 (see Andres's comment up-thread) so that
the new macros can match the future agreement.

- Does include the refactoring of the new
- pg_stat_get_xact_tuples_newpage_updated() function (added in
- ae4fdde135)

Fine by me. One step is better than no steps, and this helps:
1 file changed, 29 insertions(+), 97 deletions(-)

I'll go apply that if there are no objections.
--
Michael

#16Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#15)
1 attachment(s)
Re: Generate pg_stat_get_xact*() functions with Macros

On Sat, Mar 25, 2023 at 11:50:50AM +0900, Michael Paquier wrote:

On Fri, Mar 24, 2023 at 06:58:30AM +0100, Drouvot, Bertrand wrote:

- Does not include the refactoring for
pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time(),
pg_stat_get_function_total_time() and
pg_stat_get_function_self_time(). I think they can be done in a
dedicated commit once we agree on the renaming for
PG_STAT_GET_DBENTRY_FLOAT8 (see Andres's comment up-thread) so that
the new macros can match the future agreement.

Thanks for the reminder. I have completely missed that this is
mentioned in [1]/messages/by-id/20230111225907.6el6c5j3hukizqxc@awork3.anarazel.de -- Michael, and that it is all about 8018ffb. The suggestion to
prefix the macro names with a "_MS" to outline the conversion sounds
like a good one seen from here. So please find attached a patch to do
this adjustment, completed with a similar switch for the two counters
of the function entries.

- Does include the refactoring of the new
- pg_stat_get_xact_tuples_newpage_updated() function (added in
- ae4fdde135)

Fine by me. One step is better than no steps, and this helps:
1 file changed, 29 insertions(+), 97 deletions(-)

I'll go apply that if there are no objections.

Just did this part to shave a bit more code.

[1]: /messages/by-id/20230111225907.6el6c5j3hukizqxc@awork3.anarazel.de -- Michael
--
Michael

Attachments:

pgstatfuncs-more-macros.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index e1dd1e0ad3..ff155e003f 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -152,29 +152,26 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(funcentry->numcalls);
 }
 
-Datum
-pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
-
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->total_time) / 1000.0);
+/* convert counter from microsec to millisec for display */
+#define PG_STAT_GET_FUNCENTRY_FLOAT8_MS(stat)						\
+Datum																\
+CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)				\
+{																	\
+	Oid			funcid = PG_GETARG_OID(0);							\
+	double		result;												\
+	PgStat_StatFuncEntry *funcentry;								\
+																	\
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)	\
+		PG_RETURN_NULL();											\
+	result = ((double) funcentry->stat) / 1000.0;					\
+	PG_RETURN_FLOAT8(result);										\
 }
 
-Datum
-pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
+/* pg_stat_get_function_total_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time)
 
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->self_time) / 1000.0);
-}
+/* pg_stat_get_function_self_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time)
 
 Datum
 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
@@ -1147,7 +1144,8 @@ pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
 		PG_RETURN_TIMESTAMPTZ(result);
 }
 
-#define PG_STAT_GET_DBENTRY_FLOAT8(stat)						\
+/* convert counter from microsec to millisec for display */
+#define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat)						\
 Datum															\
 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)				\
 {																\
@@ -1164,19 +1162,19 @@ CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)				\
 }
 
 /* pg_stat_get_db_active_time */
-PG_STAT_GET_DBENTRY_FLOAT8(active_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time)
 
 /* pg_stat_get_db_blk_read_time */
-PG_STAT_GET_DBENTRY_FLOAT8(blk_read_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time)
 
 /* pg_stat_get_db_blk_write_time */
-PG_STAT_GET_DBENTRY_FLOAT8(blk_write_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time)
 
 /* pg_stat_get_db_idle_in_transaction_time */
-PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
 
 /* pg_stat_get_db_session_time */
-PG_STAT_GET_DBENTRY_FLOAT8(session_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
 
 Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
#17Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Michael Paquier (#16)
Re: Generate pg_stat_get_xact*() functions with Macros

Hi,

On 3/27/23 3:20 AM, Michael Paquier wrote:

On Sat, Mar 25, 2023 at 11:50:50AM +0900, Michael Paquier wrote:

On Fri, Mar 24, 2023 at 06:58:30AM +0100, Drouvot, Bertrand wrote:

- Does not include the refactoring for
pg_stat_get_xact_function_total_time(),
pg_stat_get_xact_function_self_time(),
pg_stat_get_function_total_time() and
pg_stat_get_function_self_time(). I think they can be done in a
dedicated commit once we agree on the renaming for
PG_STAT_GET_DBENTRY_FLOAT8 (see Andres's comment up-thread) so that
the new macros can match the future agreement.

Thanks for the reminder. I have completely missed that this is
mentioned in [1], and that it is all about 8018ffb. The suggestion to
prefix the macro names with a "_MS" to outline the conversion sounds
like a good one seen from here. So please find attached a patch to do
this adjustment, completed with a similar switch for the two counters
of the function entries.

Thanks! LGTM, but what about also taking care of pg_stat_get_xact_function_total_time()
and pg_stat_get_xact_function_self_time() while at it?

- Does include the refactoring of the new
- pg_stat_get_xact_tuples_newpage_updated() function (added in
- ae4fdde135)

Fine by me. One step is better than no steps, and this helps:
1 file changed, 29 insertions(+), 97 deletions(-)

I'll go apply that if there are no objections.

Just did this part to shave a bit more code.

Thanks!

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#18Michael Paquier
michael@paquier.xyz
In reply to: Drouvot, Bertrand (#17)
Re: Generate pg_stat_get_xact*() functions with Macros

On Mon, Mar 27, 2023 at 07:45:26AM +0200, Drouvot, Bertrand wrote:

Thanks! LGTM, but what about also taking care of pg_stat_get_xact_function_total_time()
and pg_stat_get_xact_function_self_time() while at it?

With a macro that uses INSTR_TIME_GET_MILLISEC() to cope with
instr_time? Why not, that's one duplication less.
--
Michael

#19Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Michael Paquier (#18)
Re: Generate pg_stat_get_xact*() functions with Macros

On 3/27/23 8:40 AM, Michael Paquier wrote:

On Mon, Mar 27, 2023 at 07:45:26AM +0200, Drouvot, Bertrand wrote:

Thanks! LGTM, but what about also taking care of pg_stat_get_xact_function_total_time()
and pg_stat_get_xact_function_self_time() while at it?

With a macro that uses INSTR_TIME_GET_MILLISEC() to cope with
instr_time? Why not, that's one duplication less.

Yes, something like V1 up-thread was doing. I think it can be added with your current proposal.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#20Michael Paquier
michael@paquier.xyz
In reply to: Drouvot, Bertrand (#19)
Re: Generate pg_stat_get_xact*() functions with Macros

On Mon, Mar 27, 2023 at 08:54:13AM +0200, Drouvot, Bertrand wrote:

Yes, something like V1 up-thread was doing. I think it can be added with your current proposal.

Sure, I can write that. Or perhaps you'd prefer write something
yourself?
--
Michael

#21Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Michael Paquier (#20)
1 attachment(s)
Re: Generate pg_stat_get_xact*() functions with Macros

On 3/27/23 9:23 AM, Michael Paquier wrote:

On Mon, Mar 27, 2023 at 08:54:13AM +0200, Drouvot, Bertrand wrote:

Yes, something like V1 up-thread was doing. I think it can be added with your current proposal.

Sure, I can write that. Or perhaps you'd prefer write something
yourself?

Please find attached V2 adding pg_stat_get_xact_function_total_time()
and pg_stat_get_xact_function_self_time() to the party.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-pgstatfuncs-more-macros.patchtext/plain; charset=UTF-8; name=v2-0001-pgstatfuncs-more-macros.patchDownload
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index e1dd1e0ad3..d0bf61cc64 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -152,29 +152,26 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(funcentry->numcalls);
 }
 
-Datum
-pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_StatFuncEntry *funcentry;
-
-	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->total_time) / 1000.0);
-}
-
-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();
-	/* convert counter from microsec to millisec for display */
-	PG_RETURN_FLOAT8(((double) funcentry->self_time) / 1000.0);
-}
+/* convert counter from microsec to millisec for display */
+#define PG_STAT_GET_FUNCENTRY_FLOAT8_MS(stat)						\
+Datum																\
+CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)				\
+{																	\
+	Oid			funcid = PG_GETARG_OID(0);							\
+	double		result;												\
+	PgStat_StatFuncEntry *funcentry;								\
+																	\
+	if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)	\
+		PG_RETURN_NULL();											\
+	result = ((double) funcentry->stat) / 1000.0;					\
+	PG_RETURN_FLOAT8(result);										\
+}
+
+/* pg_stat_get_function_total_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time)
+
+/* pg_stat_get_function_self_time */
+PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time)
 
 Datum
 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
@@ -1147,7 +1144,8 @@ pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
 		PG_RETURN_TIMESTAMPTZ(result);
 }
 
-#define PG_STAT_GET_DBENTRY_FLOAT8(stat)						\
+/* convert counter from microsec to millisec for display */
+#define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat)						\
 Datum															\
 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)				\
 {																\
@@ -1164,19 +1162,19 @@ CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)				\
 }
 
 /* pg_stat_get_db_active_time */
-PG_STAT_GET_DBENTRY_FLOAT8(active_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time)
 
 /* pg_stat_get_db_blk_read_time */
-PG_STAT_GET_DBENTRY_FLOAT8(blk_read_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time)
 
 /* pg_stat_get_db_blk_write_time */
-PG_STAT_GET_DBENTRY_FLOAT8(blk_write_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time)
 
 /* pg_stat_get_db_idle_in_transaction_time */
-PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
 
 /* pg_stat_get_db_session_time */
-PG_STAT_GET_DBENTRY_FLOAT8(session_time)
+PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
 
 Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
@@ -1609,28 +1607,23 @@ pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(funcentry->numcalls);
 }
 
-Datum
-pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_FunctionCounts *funcentry;
-
-	if ((funcentry = find_funcstat_entry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->total_time));
-}
-
-Datum
-pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
-{
-	Oid			funcid = PG_GETARG_OID(0);
-	PgStat_FunctionCounts *funcentry;
+#define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat)				\
+Datum															\
+CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS)	\
+{																\
+	Oid			funcid = PG_GETARG_OID(0);						\
+	PgStat_FunctionCounts *funcentry;							\
+																\
+	if ((funcentry = find_funcstat_entry(funcid)) == NULL)		\
+		PG_RETURN_NULL();										\
+	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat));	\
+}																\
 
-	if ((funcentry = find_funcstat_entry(funcid)) == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->self_time));
-}
+/* pg_stat_get_xact_function_total_time */
+PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
 
+/* pg_stat_get_xact_function_self_time */
+PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
 
 /* Get the timestamp of the current statistics snapshot */
 Datum
#22Michael Paquier
michael@paquier.xyz
In reply to: Drouvot, Bertrand (#21)
Re: Generate pg_stat_get_xact*() functions with Macros

On Mon, Mar 27, 2023 at 10:11:21AM +0200, Drouvot, Bertrand wrote:

Please find attached V2 adding pg_stat_get_xact_function_total_time()
and pg_stat_get_xact_function_self_time() to the party.

The patch has one mistake: PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS does
not need a slash on its last line or it would include the next, empty
line. This could lead to mistakes (no need to send a new patch just
for that).
--
Michael

#23Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#22)
Re: Generate pg_stat_get_xact*() functions with Macros

On Mon, Mar 27, 2023 at 07:08:51PM +0900, Michael Paquier wrote:

The patch has one mistake: PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS does
not need a slash on its last line or it would include the next, empty
line. This could lead to mistakes (no need to send a new patch just
for that).

Adjusted that, and the rest was fine after a second look, so applied.
It looks like we are done for now with this thread, so I have marked
it as committed in the CF app.
--
Michael

#24Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Michael Paquier (#23)
Re: Generate pg_stat_get_xact*() functions with Macros

On 3/28/23 12:41 AM, Michael Paquier wrote:

On Mon, Mar 27, 2023 at 07:08:51PM +0900, Michael Paquier wrote:

The patch has one mistake: PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS does
not need a slash on its last line or it would include the next, empty
line. This could lead to mistakes (no need to send a new patch just
for that).

Adjusted that, and the rest was fine after a second look, so applied.
It looks like we are done for now with this thread, so I have marked
it as committed in the CF app.

Thanks for having corrected the mistake and applied the patch!

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com