]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
instrumentation: Move ExecProcNodeInstr to allow inlining
authorAndres Freund <andres@anarazel.de>
Wed, 8 Apr 2026 01:36:07 +0000 (21:36 -0400)
committerAndres Freund <andres@anarazel.de>
Wed, 8 Apr 2026 01:36:49 +0000 (21:36 -0400)
This moves the implementation of ExecProcNodeInstr, the ExecProcNode variant
that gets used when instrumentation is on, to be defined in instrument.c
instead of execProcNode.c, and marks functions it uses as inline.

This allows compilers to generate an optimized implementation, and shows a 4
to 12% reduction in instrumentation overhead for queries that move lots of
rows.

Author: Lukas Fittl <lukas@fittl.com>
Suggested-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CAP53PkzdBK8VJ1fS4AZ481LgMN8f9mJiC39ZRHqkFUSYq6KWmg@mail.gmail.com

src/backend/executor/execProcnode.c
src/backend/executor/instrument.c
src/include/executor/executor.h

index 132fe37ef60f8d4ba2b7247ffe12bc1f28641ec7..7c4c66e323fed3c0fcd0a7ac452c63cfc2d6786f 100644 (file)
 #include "nodes/nodeFuncs.h"
 
 static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
-static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
 static bool ExecShutdownNode_walker(PlanState *node, void *context);
 
 
@@ -471,25 +470,6 @@ ExecProcNodeFirst(PlanState *node)
 }
 
 
-/*
- * ExecProcNode wrapper that performs instrumentation calls.  By keeping
- * this a separate function, we avoid overhead in the normal case where
- * no instrumentation is wanted.
- */
-static TupleTableSlot *
-ExecProcNodeInstr(PlanState *node)
-{
-       TupleTableSlot *result;
-
-       InstrStartNode(node->instrument);
-
-       result = node->ExecProcNodeReal(node);
-
-       InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
-
-       return result;
-}
-
 
 /* ----------------------------------------------------------------
  *             MultiExecProcNode
index 4c3aec7fdeef65af9273a470a2f37c7486dde4e8..ffbcd5721339689c38b412d9231bdcd41935f1fd 100644 (file)
 
 #include <unistd.h>
 
+#include "executor/executor.h"
 #include "executor/instrument.h"
+#include "executor/tuptable.h"
+#include "nodes/execnodes.h"
 #include "portability/instr_time.h"
 #include "utils/guc_hooks.h"
 
@@ -46,7 +49,7 @@ InstrInitOptions(Instrumentation *instr, int instrument_options)
        instr->need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
 }
 
-void
+inline void
 InstrStart(Instrumentation *instr)
 {
        if (instr->need_timer)
@@ -125,14 +128,14 @@ InstrInitNode(NodeInstrumentation *instr, int instrument_options, bool async_mod
 }
 
 /* Entry to a plan node */
-void
+inline void
 InstrStartNode(NodeInstrumentation *instr)
 {
        InstrStart(&instr->instr);
 }
 
 /* Exit from a plan node */
-void
+inline void
 InstrStopNode(NodeInstrumentation *instr, double nTuples)
 {
        double          save_tuplecount = instr->tuplecount;
@@ -166,6 +169,28 @@ InstrStopNode(NodeInstrumentation *instr, double nTuples)
        }
 }
 
+/*
+ * ExecProcNode wrapper that performs instrumentation calls.  By keeping
+ * this a separate function, we avoid overhead in the normal case where
+ * no instrumentation is wanted.
+ *
+ * This is implemented in instrument.c as all the functions it calls directly
+ * are here, allowing them to be inlined even when not using LTO.
+ */
+TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
+{
+       TupleTableSlot *result;
+
+       InstrStartNode(node->instrument);
+
+       result = node->ExecProcNodeReal(node);
+
+       InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+
+       return result;
+}
+
 /* Update tuple count */
 void
 InstrUpdateTupleCount(NodeInstrumentation *instr, double nTuples)
@@ -298,7 +323,7 @@ BufferUsageAdd(BufferUsage *dst, const BufferUsage *add)
 }
 
 /* dst += add - sub */
-void
+inline void
 BufferUsageAccumDiff(BufferUsage *dst,
                                         const BufferUsage *add,
                                         const BufferUsage *sub)
@@ -328,7 +353,7 @@ BufferUsageAccumDiff(BufferUsage *dst,
 }
 
 /* helper functions for WAL usage accumulation */
-static void
+static inline void
 WalUsageAdd(WalUsage *dst, WalUsage *add)
 {
        dst->wal_bytes += add->wal_bytes;
@@ -338,7 +363,7 @@ WalUsageAdd(WalUsage *dst, WalUsage *add)
        dst->wal_buffers_full += add->wal_buffers_full;
 }
 
-void
+inline void
 WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
 {
        dst->wal_bytes += add->wal_bytes - sub->wal_bytes;
index 491c48865066a52af6e15544e4d6b8dc995ce90b..6980c6dceda8ae5b8d896da3cf530f151f38047e 100644 (file)
@@ -303,6 +303,13 @@ extern void ExecEndNode(PlanState *node);
 extern void ExecShutdownNode(PlanState *node);
 extern void ExecSetTupleBound(int64 tuples_needed, PlanState *child_node);
 
+/*
+ * ExecProcNodeInstr() is implemented in instrument.c, as that allows for
+ * inlining of the instrumentation functions, but thematically it ought to be
+ * in execProcnode.c.
+ */
+extern TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
 
 /* ----------------------------------------------------------------
  *             ExecProcNode