+#!/usr/bin/perl -w
+
+#
+# gen_qsort_tuple.pl
+#
+# This script generates specialized versions of the quicksort algorithm for
+# tuple sorting. The quicksort code is derived from the NetBSD code. The
+# code generated by this script runs significantly faster than vanilla qsort
+# when used to sort tuples. This speedup comes from a number of places.
+# The major effects are (1) inlining simple tuple comparators is much faster
+# than jumping through a function pointer and (2) swap and vecswap operations
+# specialized to the particular data type of interest (in this case, SortTuple)
+# are faster than the generic routines.
+#
+# Modifications from vanilla NetBSD source:
+# Add do ... while() macro fix
+# Remove __inline, _DIAGASSERTs, __P
+# Remove ill-considered "swap_cnt" switch to insertion sort,
+# in favor of a simple check for presorted input.
+# Instead of sorting arbitrary objects, we're always sorting SortTuples
+# Add CHECK_FOR_INTERRUPTS()
+#
+# CAUTION: if you change this file, see also qsort.c and qsort_arg.c
+#
+
+use strict;
+
+my $SUFFIX;
+my $EXTRAARGS;
+my $EXTRAPARAMS;
+my $CMPPARAMS;
+
+emit_qsort_boilerplate();
+
+$SUFFIX = 'tuple';
+$EXTRAARGS = ', SortTupleComparator cmp_tuple, Tuplesortstate *state';
+$EXTRAPARAMS = ', cmp_tuple, state';
+$CMPPARAMS = ', state';
+emit_qsort_implementation();
+
+$SUFFIX = 'ssup';
+$EXTRAARGS = ', SortSupport ssup';
+$EXTRAPARAMS = ', ssup';
+$CMPPARAMS = ', ssup';
+print <<'EOM';
+#define cmp_ssup(a, b, ssup) \
+ ApplySortComparator((a)->datum1, (a)->isnull1, \
+ (b)->datum1, (b)->isnull1, ssup)
+EOM
+emit_qsort_implementation();
+
+sub emit_qsort_boilerplate
+{
+ print <<'EOM';
/*
- * qsort_tuple.c: specialized version of qsort, for SortTuple objects
- *
- * This file is included by tuplesort.c, rather than compiled separately.
- *
- * Modifications from vanilla NetBSD source:
- * Add do ... while() macro fix
- * Remove __inline, _DIAGASSERTs, __P
- * Remove ill-considered "swap_cnt" switch to insertion sort,
- * in favor of a simple check for presorted input.
- *
- * CAUTION: if you change this file, see also qsort.c and qsort_arg.c
- *
- * src/backend/utils/sort/qsort_tuple.c
+ * autogenerated by src/backend/utils/sort/gen_qsort.pl, do not edit
+ * This file is included by tuplesort.c, rather than compiled separately.
*/
/* $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $ */
} while (0);
#define vecswap(a, b, n) if ((n) > 0) swapfunc((a), (b), (size_t)(n))
+EOM
+}
+sub emit_qsort_implementation
+{
+ print <<EOM;
static SortTuple *
-med3_tuple(SortTuple *a, SortTuple *b, SortTuple *c, SortTupleComparator cmp,
- Tuplesortstate *state)
+med3_$SUFFIX(SortTuple *a, SortTuple *b, SortTuple *c$EXTRAARGS)
{
- return cmp(a, b, state) < 0 ?
- (cmp(b, c, state) < 0 ? b : (cmp(a, c, state) < 0 ? c : a))
- : (cmp(b, c, state) > 0 ? b : (cmp(a, c, state) < 0 ? a : c));
+ return cmp_$SUFFIX(a, b$CMPPARAMS) < 0 ?
+ (cmp_$SUFFIX(b, c$CMPPARAMS) < 0 ? b :
+ (cmp_$SUFFIX(a, c$CMPPARAMS) < 0 ? c : a))
+ : (cmp_$SUFFIX(b, c$CMPPARAMS) > 0 ? b :
+ (cmp_$SUFFIX(a, c$CMPPARAMS) < 0 ? a : c));
}
static void
-qsort_tuple(SortTuple *a, size_t n, SortTupleComparator cmp,
- Tuplesortstate *state)
+qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
{
SortTuple *pa,
*pb,
if (n < 7)
{
for (pm = a + 1; pm < a + n; pm++)
- for (pl = pm; pl > a && cmp(pl - 1, pl, state) > 0; pl--)
+ for (pl = pm; pl > a && cmp_$SUFFIX(pl - 1, pl$CMPPARAMS) > 0; pl--)
swap(pl, pl - 1);
return;
}
for (pm = a + 1; pm < a + n; pm++)
{
CHECK_FOR_INTERRUPTS();
- if (cmp(pm - 1, pm, state) > 0)
+ if (cmp_$SUFFIX(pm - 1, pm$CMPPARAMS) > 0)
{
presorted = 0;
break;
if (n > 40)
{
d = (n / 8);
- pl = med3_tuple(pl, pl + d, pl + 2 * d, cmp, state);
- pm = med3_tuple(pm - d, pm, pm + d, cmp, state);
- pn = med3_tuple(pn - 2 * d, pn - d, pn, cmp, state);
+ pl = med3_$SUFFIX(pl, pl + d, pl + 2 * d$EXTRAPARAMS);
+ pm = med3_$SUFFIX(pm - d, pm, pm + d$EXTRAPARAMS);
+ pn = med3_$SUFFIX(pn - 2 * d, pn - d, pn$EXTRAPARAMS);
}
- pm = med3_tuple(pl, pm, pn, cmp, state);
+ pm = med3_$SUFFIX(pl, pm, pn$EXTRAPARAMS);
}
swap(a, pm);
pa = pb = a + 1;
pc = pd = a + (n - 1);
for (;;)
{
- while (pb <= pc && (r = cmp(pb, a, state)) <= 0)
+ while (pb <= pc && (r = cmp_$SUFFIX(pb, a$CMPPARAMS)) <= 0)
{
CHECK_FOR_INTERRUPTS();
if (r == 0)
}
pb++;
}
- while (pb <= pc && (r = cmp(pc, a, state)) >= 0)
+ while (pb <= pc && (r = cmp_$SUFFIX(pc, a$CMPPARAMS)) >= 0)
{
CHECK_FOR_INTERRUPTS();
if (r == 0)
r = Min(pd - pc, pn - pd - 1);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > 1)
- qsort_tuple(a, r, cmp, state);
+ qsort_$SUFFIX(a, r$EXTRAPARAMS);
if ((r = pd - pc) > 1)
{
/* Iterate rather than recurse to save stack space */
n = r;
goto loop;
}
-/* qsort_tuple(pn - r, r, cmp, state);*/
+/* qsort_tuple(pn - r, r$EXTRAPARAMS);*/
+}
+
+EOM
}