OSDN Git Service

Tweak a few of the most heavily used function call points to zero out
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Oct 2002 17:19:55 +0000 (17:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Oct 2002 17:19:55 +0000 (17:19 +0000)
just the significant fields of FunctionCallInfoData, rather than MemSet'ing
the whole struct to zero.  Unused positions in the arg[] array will
thereby contain garbage rather than zeroes.  This buys back some of the
performance hit from increasing FUNC_MAX_ARGS.  Also tweak tuplesort.c
code for more speed by marking some routines 'inline'.  All together
these changes speed up simple sorts, like count(distinct int4column),
by about 25% on a P4 running RH Linux 7.2.

src/backend/executor/nodeAgg.c
src/backend/utils/fmgr/fmgr.c
src/backend/utils/sort/tuplesort.c

index 0ebf2f7..36ded53 100644 (file)
@@ -46,7 +46,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.88 2002/09/28 20:00:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.89 2002/10/04 17:19:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -275,8 +275,18 @@ advance_transition_function(AggStatePerAgg peraggstate,
                }
        }
 
-       /* OK to call the transition function */
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       /*
+        * OK to call the transition function
+        *
+        * This is heavily-used code, so manually zero just the necessary fields
+        * instead of using MemSet().  Compare FunctionCall2().
+        */
+
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
        fcinfo.flinfo = &peraggstate->transfn;
        fcinfo.nargs = 2;
        fcinfo.arg[0] = peraggstate->transValue;
index c0cef75..470d4a1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.62 2002/09/04 20:31:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.63 2002/10/04 17:19:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -689,6 +689,14 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
 
 /*-------------------------------------------------------------------------
  *             Support routines for callers of fmgr-compatible functions
+ *
+ * NOTE: the simplest way to reliably initialize a FunctionCallInfoData
+ * is to MemSet it to zeroes and then fill in the fields that should be
+ * nonzero.  However, in a few of the most heavily used paths, we instead
+ * just zero the fields that must be zero.  This saves a fair number of
+ * cycles so it's worth the extra maintenance effort.  Also see inlined
+ * version of FunctionCall2 in utils/sort/tuplesort.c if you need to change
+ * these routines!
  *-------------------------------------------------------------------------
  */
 
@@ -703,9 +711,15 @@ DirectFunctionCall1(PGFunction func, Datum arg1)
        FunctionCallInfoData fcinfo;
        Datum           result;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.flinfo = NULL;
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
        fcinfo.nargs = 1;
        fcinfo.arg[0] = arg1;
+       fcinfo.argnull[0] = false;
 
        result = (*func) (&fcinfo);
 
@@ -723,10 +737,17 @@ DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
        FunctionCallInfoData fcinfo;
        Datum           result;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.flinfo = NULL;
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
        fcinfo.nargs = 2;
        fcinfo.arg[0] = arg1;
        fcinfo.arg[1] = arg2;
+       fcinfo.argnull[0] = false;
+       fcinfo.argnull[1] = false;
 
        result = (*func) (&fcinfo);
 
@@ -936,10 +957,15 @@ FunctionCall1(FmgrInfo *flinfo, Datum arg1)
        FunctionCallInfoData fcinfo;
        Datum           result;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
        fcinfo.flinfo = flinfo;
        fcinfo.nargs = 1;
        fcinfo.arg[0] = arg1;
+       fcinfo.argnull[0] = false;
 
        result = FunctionCallInvoke(&fcinfo);
 
@@ -957,11 +983,17 @@ FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
        FunctionCallInfoData fcinfo;
        Datum           result;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
        fcinfo.flinfo = flinfo;
        fcinfo.nargs = 2;
        fcinfo.arg[0] = arg1;
        fcinfo.arg[1] = arg2;
+       fcinfo.argnull[0] = false;
+       fcinfo.argnull[1] = false;
 
        result = FunctionCallInvoke(&fcinfo);
 
index 6dfbd95..38e73f8 100644 (file)
@@ -78,7 +78,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.27 2002/09/04 20:31:33 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.28 2002/10/04 17:19:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1695,6 +1695,216 @@ qsort_comparetup(const void *a, const void *b)
 
 
 /*
+ * This routine selects an appropriate sorting function to implement
+ * a sort operator as efficiently as possible. The straightforward
+ * method is to use the operator's implementation proc --- ie, "<"
+ * comparison. However, that way often requires two calls of the function
+ * per comparison.     If we can find a btree three-way comparator function
+ * associated with the operator, we can use it to do the comparisons
+ * more efficiently.  We also support the possibility that the operator
+ * is ">" (descending sort), in which case we have to reverse the output
+ * of the btree comparator.
+ *
+ * Possibly this should live somewhere else (backend/catalog/, maybe?).
+ */
+void
+SelectSortFunction(Oid sortOperator,
+                                  RegProcedure *sortFunction,
+                                  SortFunctionKind *kind)
+{
+       Relation        relation;
+       HeapScanDesc scan;
+       ScanKeyData skey[1];
+       HeapTuple       tuple;
+       Form_pg_operator optup;
+       Oid                     opclass = InvalidOid;
+
+       /*
+        * Scan pg_amop to see if the target operator is registered as the "<"
+        * or ">" operator of any btree opclass.  It's possible that it might
+        * be registered both ways (eg, if someone were to build a "reverse
+        * sort" opclass for some reason); prefer the "<" case if so. If the
+        * operator is registered the same way in multiple opclasses, assume
+        * we can use the associated comparator function from any one.
+        */
+       ScanKeyEntryInitialize(&skey[0], 0x0,
+                                                  Anum_pg_amop_amopopr,
+                                                  F_OIDEQ,
+                                                  ObjectIdGetDatum(sortOperator));
+
+       relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
+       scan = heap_beginscan(relation, SnapshotNow, 1, skey);
+
+       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       {
+               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+               if (!opclass_is_btree(aform->amopclaid))
+                       continue;
+               if (aform->amopstrategy == BTLessStrategyNumber)
+               {
+                       opclass = aform->amopclaid;
+                       *kind = SORTFUNC_CMP;
+                       break;                          /* done looking */
+               }
+               else if (aform->amopstrategy == BTGreaterStrategyNumber)
+               {
+                       opclass = aform->amopclaid;
+                       *kind = SORTFUNC_REVCMP;
+                       /* keep scanning in hopes of finding a BTLess entry */
+               }
+       }
+
+       heap_endscan(scan);
+       heap_close(relation, AccessShareLock);
+
+       if (OidIsValid(opclass))
+       {
+               /* Found a suitable opclass, get its comparator support function */
+               tuple = SearchSysCache(AMPROCNUM,
+                                                          ObjectIdGetDatum(opclass),
+                                                          Int16GetDatum(BTORDER_PROC),
+                                                          0, 0);
+               if (HeapTupleIsValid(tuple))
+               {
+                       Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
+
+                       *sortFunction = aform->amproc;
+                       ReleaseSysCache(tuple);
+                       Assert(RegProcedureIsValid(*sortFunction));
+                       return;
+               }
+       }
+
+       /*
+        * Can't find a comparator, so use the operator as-is.  Decide whether
+        * it is forward or reverse sort by looking at its name (grotty, but
+        * this only matters for deciding which end NULLs should get sorted
+        * to).
+        */
+       tuple = SearchSysCache(OPEROID,
+                                                  ObjectIdGetDatum(sortOperator),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "SelectSortFunction: cache lookup failed for operator %u",
+                        sortOperator);
+       optup = (Form_pg_operator) GETSTRUCT(tuple);
+       if (strcmp(NameStr(optup->oprname), ">") == 0)
+               *kind = SORTFUNC_REVLT;
+       else
+               *kind = SORTFUNC_LT;
+       *sortFunction = optup->oprcode;
+       ReleaseSysCache(tuple);
+
+       Assert(RegProcedureIsValid(*sortFunction));
+}
+
+/*
+ * Inline-able copy of FunctionCall2() to save some cycles in sorting.
+ */
+static inline Datum
+myFunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
+{
+       FunctionCallInfoData fcinfo;
+       Datum           result;
+
+       /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */
+       fcinfo.context = NULL;
+       fcinfo.resultinfo = NULL;
+       fcinfo.isnull = false;
+
+       fcinfo.flinfo = flinfo;
+       fcinfo.nargs = 2;
+       fcinfo.arg[0] = arg1;
+       fcinfo.arg[1] = arg2;
+       fcinfo.argnull[0] = false;
+       fcinfo.argnull[1] = false;
+
+       result = FunctionCallInvoke(&fcinfo);
+
+       /* Check for null result, since caller is clearly not expecting one */
+       if (fcinfo.isnull)
+               elog(ERROR, "FunctionCall2: function %u returned NULL",
+                        fcinfo.flinfo->fn_oid);
+
+       return result;
+}
+
+/*
+ * Apply a sort function (by now converted to fmgr lookup form)
+ * and return a 3-way comparison result.  This takes care of handling
+ * NULLs and sort ordering direction properly.
+ */
+inline int32
+ApplySortFunction(FmgrInfo *sortFunction, SortFunctionKind kind,
+                                 Datum datum1, bool isNull1,
+                                 Datum datum2, bool isNull2)
+{
+       switch (kind)
+       {
+               case SORTFUNC_LT:
+                       if (isNull1)
+                       {
+                               if (isNull2)
+                                       return 0;
+                               return 1;               /* NULL sorts after non-NULL */
+                       }
+                       if (isNull2)
+                               return -1;
+                       if (DatumGetBool(myFunctionCall2(sortFunction, datum1, datum2)))
+                               return -1;              /* a < b */
+                       if (DatumGetBool(myFunctionCall2(sortFunction, datum2, datum1)))
+                               return 1;               /* a > b */
+                       return 0;
+
+               case SORTFUNC_REVLT:
+                       /* We reverse the ordering of NULLs, but not the operator */
+                       if (isNull1)
+                       {
+                               if (isNull2)
+                                       return 0;
+                               return -1;              /* NULL sorts before non-NULL */
+                       }
+                       if (isNull2)
+                               return 1;
+                       if (DatumGetBool(myFunctionCall2(sortFunction, datum1, datum2)))
+                               return -1;              /* a < b */
+                       if (DatumGetBool(myFunctionCall2(sortFunction, datum2, datum1)))
+                               return 1;               /* a > b */
+                       return 0;
+
+               case SORTFUNC_CMP:
+                       if (isNull1)
+                       {
+                               if (isNull2)
+                                       return 0;
+                               return 1;               /* NULL sorts after non-NULL */
+                       }
+                       if (isNull2)
+                               return -1;
+                       return DatumGetInt32(myFunctionCall2(sortFunction,
+                                                                                                datum1, datum2));
+
+               case SORTFUNC_REVCMP:
+                       if (isNull1)
+                       {
+                               if (isNull2)
+                                       return 0;
+                               return -1;              /* NULL sorts before non-NULL */
+                       }
+                       if (isNull2)
+                               return 1;
+                       return -DatumGetInt32(myFunctionCall2(sortFunction,
+                                                                                                 datum1, datum2));
+
+               default:
+                       elog(ERROR, "Invalid SortFunctionKind %d", (int) kind);
+                       return 0;                       /* can't get here, but keep compiler quiet */
+       }
+}
+
+
+/*
  * Routines specialized for HeapTuple case
  */
 
@@ -1991,182 +2201,3 @@ readtup_datum(Tuplesortstate *state, int tapenum, unsigned int len)
                                                                         MAXALIGN(sizeof(DatumTuple)));
        return (void *) tuple;
 }
-
-
-/*
- * This routine selects an appropriate sorting function to implement
- * a sort operator as efficiently as possible. The straightforward
- * method is to use the operator's implementation proc --- ie, "<"
- * comparison. However, that way often requires two calls of the function
- * per comparison.     If we can find a btree three-way comparator function
- * associated with the operator, we can use it to do the comparisons
- * more efficiently.  We also support the possibility that the operator
- * is ">" (descending sort), in which case we have to reverse the output
- * of the btree comparator.
- *
- * Possibly this should live somewhere else (backend/catalog/, maybe?).
- */
-void
-SelectSortFunction(Oid sortOperator,
-                                  RegProcedure *sortFunction,
-                                  SortFunctionKind *kind)
-{
-       Relation        relation;
-       HeapScanDesc scan;
-       ScanKeyData skey[1];
-       HeapTuple       tuple;
-       Form_pg_operator optup;
-       Oid                     opclass = InvalidOid;
-
-       /*
-        * Scan pg_amop to see if the target operator is registered as the "<"
-        * or ">" operator of any btree opclass.  It's possible that it might
-        * be registered both ways (eg, if someone were to build a "reverse
-        * sort" opclass for some reason); prefer the "<" case if so. If the
-        * operator is registered the same way in multiple opclasses, assume
-        * we can use the associated comparator function from any one.
-        */
-       ScanKeyEntryInitialize(&skey[0], 0x0,
-                                                  Anum_pg_amop_amopopr,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(sortOperator));
-
-       relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
-       scan = heap_beginscan(relation, SnapshotNow, 1, skey);
-
-       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-       {
-               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
-
-               if (!opclass_is_btree(aform->amopclaid))
-                       continue;
-               if (aform->amopstrategy == BTLessStrategyNumber)
-               {
-                       opclass = aform->amopclaid;
-                       *kind = SORTFUNC_CMP;
-                       break;                          /* done looking */
-               }
-               else if (aform->amopstrategy == BTGreaterStrategyNumber)
-               {
-                       opclass = aform->amopclaid;
-                       *kind = SORTFUNC_REVCMP;
-                       /* keep scanning in hopes of finding a BTLess entry */
-               }
-       }
-
-       heap_endscan(scan);
-       heap_close(relation, AccessShareLock);
-
-       if (OidIsValid(opclass))
-       {
-               /* Found a suitable opclass, get its comparator support function */
-               tuple = SearchSysCache(AMPROCNUM,
-                                                          ObjectIdGetDatum(opclass),
-                                                          Int16GetDatum(BTORDER_PROC),
-                                                          0, 0);
-               if (HeapTupleIsValid(tuple))
-               {
-                       Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
-
-                       *sortFunction = aform->amproc;
-                       ReleaseSysCache(tuple);
-                       Assert(RegProcedureIsValid(*sortFunction));
-                       return;
-               }
-       }
-
-       /*
-        * Can't find a comparator, so use the operator as-is.  Decide whether
-        * it is forward or reverse sort by looking at its name (grotty, but
-        * this only matters for deciding which end NULLs should get sorted
-        * to).
-        */
-       tuple = SearchSysCache(OPEROID,
-                                                  ObjectIdGetDatum(sortOperator),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "SelectSortFunction: cache lookup failed for operator %u",
-                        sortOperator);
-       optup = (Form_pg_operator) GETSTRUCT(tuple);
-       if (strcmp(NameStr(optup->oprname), ">") == 0)
-               *kind = SORTFUNC_REVLT;
-       else
-               *kind = SORTFUNC_LT;
-       *sortFunction = optup->oprcode;
-       ReleaseSysCache(tuple);
-
-       Assert(RegProcedureIsValid(*sortFunction));
-}
-
-/*
- * Apply a sort function (by now converted to fmgr lookup form)
- * and return a 3-way comparison result.  This takes care of handling
- * NULLs and sort ordering direction properly.
- */
-int32
-ApplySortFunction(FmgrInfo *sortFunction, SortFunctionKind kind,
-                                 Datum datum1, bool isNull1,
-                                 Datum datum2, bool isNull2)
-{
-       switch (kind)
-       {
-               case SORTFUNC_LT:
-                       if (isNull1)
-                       {
-                               if (isNull2)
-                                       return 0;
-                               return 1;               /* NULL sorts after non-NULL */
-                       }
-                       if (isNull2)
-                               return -1;
-                       if (DatumGetBool(FunctionCall2(sortFunction, datum1, datum2)))
-                               return -1;              /* a < b */
-                       if (DatumGetBool(FunctionCall2(sortFunction, datum2, datum1)))
-                               return 1;               /* a > b */
-                       return 0;
-
-               case SORTFUNC_REVLT:
-                       /* We reverse the ordering of NULLs, but not the operator */
-                       if (isNull1)
-                       {
-                               if (isNull2)
-                                       return 0;
-                               return -1;              /* NULL sorts before non-NULL */
-                       }
-                       if (isNull2)
-                               return 1;
-                       if (DatumGetBool(FunctionCall2(sortFunction, datum1, datum2)))
-                               return -1;              /* a < b */
-                       if (DatumGetBool(FunctionCall2(sortFunction, datum2, datum1)))
-                               return 1;               /* a > b */
-                       return 0;
-
-               case SORTFUNC_CMP:
-                       if (isNull1)
-                       {
-                               if (isNull2)
-                                       return 0;
-                               return 1;               /* NULL sorts after non-NULL */
-                       }
-                       if (isNull2)
-                               return -1;
-                       return DatumGetInt32(FunctionCall2(sortFunction,
-                                                                                          datum1, datum2));
-
-               case SORTFUNC_REVCMP:
-                       if (isNull1)
-                       {
-                               if (isNull2)
-                                       return 0;
-                               return -1;              /* NULL sorts before non-NULL */
-                       }
-                       if (isNull2)
-                               return 1;
-                       return -DatumGetInt32(FunctionCall2(sortFunction,
-                                                                                               datum1, datum2));
-
-               default:
-                       elog(ERROR, "Invalid SortFunctionKind %d", (int) kind);
-                       return 0;                       /* can't get here, but keep compiler quiet */
-       }
-}