pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feed From: Kefan Yang <starordust@gmail.com>
To: Tomas Vondra <tomas.vondra@2ndquadrant.com>
Cc: Andrey Borodin <x4mmm@yandex-team.ru>
Cc: Peter Geoghegan <pg@bowt.ie>
Cc: alvherre@2ndquadrant.com <alvherre@2ndquadrant.com>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: RE: GSOC 2018 Project - A New Sorting Routine
Date: Mon, 23 Jul 2018 15:21:01 -0700
Message-ID: <5b5654cc.1c69fb81.5ea44.d698@mx.google.com> (raw )
In-Reply-To: <58417882-04e3-b23e-b53e-7d0720558335@2ndquadrant.com >
References: <CAF448YLZz5cD+w5qYQGMcfFPY9zAu2mkkiCtOPSBJmwbjuPNig@mail.gmail.com >
<57ae7691-6dc8-d6d0-361a-a7269e656273@2ndquadrant.com >
<CAF448YKLbmmSPbb_AFEaTKozjnFOEfT+s2eiSjfH=us34VNr4w@mail.gmail.com >
<CAF448YK0xhqK6mg3EeP-dt4j9V-VxkG8Vswmrt3t90OYSrNSsQ@mail.gmail.com >
<CAH2-Wzmj2XstMK58tJ0yEr+0MwpqMU8rfUB0j7GVe=p+yW5rTg@mail.gmail.com >
<00147235-69d3-d4f0-36c1-198d630af7ad@2ndquadrant.com >
<1C5B17F1-D37F-4730-A2E4-EB7288C6DC09@yandex-team.ru >
<78b9c822-e127-5250-a01c-4c51a50c82bd@2ndquadrant.com >
<5b4fad82.1c69fb81.7a6f6.d32b@mx.google.com >
<58417882-04e3-b23e-b53e-7d0720558335@2ndquadrant.com >
Hi Tomas!
I did a few tests on my own Linux machine, but the problem is that my resources on AWS(CPU, RAM and even Disk space) are very limited. I considered establishing virtual machine on my own PC but the performance is even worse.
My original patch has two main optimizations: (1) switch to heap sort when depth limit exceeded (2) check whether the array is presorted only once at the beginning. Now I want to test these optimizations separately. On AWS EC2 instance, regressions on CREATE INDEX cases seems to be less significant if we use (1) only, but I can only test up to 100000 records and 512MB memory using your scripts.
So would you mind re-running the tests using the two patches I provided in the attachment? That will be very helpful
Regards,
Kefan
From: Tomas Vondra
Sent: July 18, 2018 2:26 PM
To: Kefan Yang
Cc: Andrey Borodin; Peter Geoghegan; PostgreSQL Hackers
Subject: Re: GSOC 2018 Project - A New Sorting Routine
I don't have any script for that - load the files into a spreadsheet,
create pivot tables and you're done.
regards
On 07/18/2018 11:13 PM, Kefan Yang wrote:
> Hey Tomas!
>
>
>
> I am trying to reproduce the results on my machine. Could you please
> share the script to generate .ods files?
>
>
>
> Regards,
>
> Kefan
>
>
>
> *From: *Tomas Vondra <mailto:tomas.vondra@2ndquadrant.com>
> *Sent: *July 18, 2018 2:05 AM
> *To: *Andrey Borodin <mailto:x4mmm@yandex-team.ru >
> *Cc: *Peter Geoghegan <mailto:pg@bowt.ie>; Kefan Yang
> <mailto:starordust@gmail.com>; PostgreSQL Hackers
> <mailto:pgsql-hackers@lists.postgresql.org >
> *Subject: *Re: GSOC 2018 Project - A New Sorting Routine
>
>
>
>
>
>
>
> On 07/18/2018 07:06 AM, Andrey Borodin wrote:
>
>> Hi, Tomas!
>
>>
>
>>> 15 июля 2018 г., в 1:20, Tomas Vondra <tomas.vondra@2ndquadrant.com
>
>>> <mailto:tomas.vondra@2ndquadrant.com>> написал(а):
>
>>>
>
>>> So I doubt it's this, but I've tweaked the scripts to also set this GUC
>
>>> and restarted the tests on both machines. Let's see what that does.
>
>>
>
>> Do you observe any different results?
>
>>
>
>
>
> It did change the CREATE INDEX results, depending on the scale. The full
>
> data is available at [1] and [2], attached is a spreadsheet summary from
>
> the Xeon box.
>
>
>
> For the largest scale (1M rows) the regressions for CREATE INDEX queries
>
> mostly disappeared. For 10k rows it still affects CREATE INDEX with a
>
> text column, and the 100k case behaves just like before (so significant
>
> regressions for CREATE INDEX).
>
>
>
> I don't have time to investigate this further at the moment, but I'm
>
> still of the opinion that there's little to gain by replacing our
>
> current sort algorithm with this.
>
>
>
>
>
> [1] https://bitbucket.org/tvondra/sort-intro-sort-xeon/src/master/
>
> [2] https://bitbucket.org/tvondra/sort-intro-sort-i5/src/master/
>
>
>
> regards
>
>
>
> --
>
> Tomas Vondra http://www.2ndQuadrant.com
>
> PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>
>
>
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
[application/octet-stream] check_once.diff (9.7K, ../5b5654cc.1c69fb81.5ea44.d698@mx.google.com/3-check_once.diff)
download | inline diff:
diff --git a/src/backend/utils/sort/gen_qsort_tuple.pl b/src/backend/utils/sort/gen_qsort_tuple.pl
index 6186d0a..20d7fb4 100644
--- a/src/backend/utils/sort/gen_qsort_tuple.pl
+++ b/src/backend/utils/sort/gen_qsort_tuple.pl
@@ -108,6 +108,8 @@ sub emit_qsort_boilerplate
* worth the effort", but we have seen crashes in the field due to stack
* overrun, so that judgment seems wrong.
*/
+
+#include <math.h>
static void
swapfunc(SortTuple *a, SortTuple *b, size_t n)
@@ -146,7 +148,7 @@ med3_$SUFFIX(SortTuple *a, SortTuple *b, SortTuple *c$EXTRAARGS)
}
static void
-qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
+qsort_recursive_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
{
SortTuple *pa,
*pb,
@@ -157,8 +159,7 @@ qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
*pn;
size_t d1,
d2;
- int r,
- presorted;
+ int r;
loop:
CHECK_FOR_INTERRUPTS();
@@ -169,18 +170,7 @@ loop:
swap(pl, pl - 1);
return;
}
- presorted = 1;
- for (pm = a + 1; pm < a + n; pm++)
- {
- CHECK_FOR_INTERRUPTS();
- if (cmp_$SUFFIX(pm - 1, pm$CMPPARAMS) > 0)
- {
- presorted = 0;
- break;
- }
- }
- if (presorted)
- return;
+
pm = a + (n / 2);
if (n > 7)
{
@@ -238,11 +228,11 @@ loop:
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > 1)
- qsort_$SUFFIX(a, d1$EXTRAPARAMS);
+ qsort_recursive_$SUFFIX(a, d1$EXTRAPARAMS);
if (d2 > 1)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_$SUFFIX(pn - d2, d2$EXTRAPARAMS); */
+ /* qsort_recursive_$SUFFIX(pn - d2, d2$EXTRAPARAMS); */
a = pn - d2;
n = d2;
goto loop;
@@ -252,15 +242,35 @@ loop:
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > 1)
- qsort_$SUFFIX(pn - d2, d2$EXTRAPARAMS);
+ qsort_recursive_$SUFFIX(pn - d2, d2$EXTRAPARAMS);
if (d1 > 1)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_$SUFFIX(a, d1$EXTRAPARAMS); */
+ /* qsort_recursive_$SUFFIX(a, d1$EXTRAPARAMS); */
n = d1;
goto loop;
}
}
}
+
+static void
+qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
+{
+ int presorted = 1;
+ SortTuple* pm;
+ for (pm = a + 1; pm < a + n; pm++)
+ {
+ CHECK_FOR_INTERRUPTS();
+ if (cmp_$SUFFIX(pm - 1, pm$CMPPARAMS) > 0)
+ {
+ presorted = 0;
+ break;
+ }
+ }
+ if (presorted)
+ return;
+ qsort_recursive_$SUFFIX(a, n$EXTRAPARAMS);
+}
+
EOM
}
diff --git a/src/port/qsort.c b/src/port/qsort.c
index 1a8ee08..7341aed 100644
--- a/src/port/qsort.c
+++ b/src/port/qsort.c
@@ -44,6 +44,8 @@
* SUCH DAMAGE.
*/
+
+#include <math.h>
#include "c.h"
@@ -109,47 +111,35 @@ med3(char *a, char *b, char *c, int (*cmp) (const void *, const void *))
: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
}
-void
-pg_qsort(void *a, size_t n, size_t es, int (*cmp) (const void *, const void *))
+static void
+pg_qsort_recursive(void *a, size_t n, int swaptype, size_t es, int(*cmp) (const void *, const void *))
{
char *pa,
- *pb,
- *pc,
- *pd,
- *pl,
- *pm,
- *pn;
+ *pb,
+ *pc,
+ *pd,
+ *pl,
+ *pm,
+ *pn;
size_t d1,
- d2;
- int r,
- swaptype,
- presorted;
+ d2;
+ int r;
-loop:SWAPINIT(a, es);
+loop:
if (n < 7)
{
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
- pl -= es)
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl >(char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
swap(pl, pl - es);
return;
}
- presorted = 1;
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- {
- if (cmp(pm - es, pm) > 0)
- {
- presorted = 0;
- break;
- }
- }
- if (presorted)
- return;
- pm = (char *) a + (n / 2) * es;
+
+ pm = (char *)a + (n / 2) * es;
if (n > 7)
{
- pl = (char *) a;
- pn = (char *) a + (n - 1) * es;
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
if (n > 40)
{
size_t d = (n / 8) * es;
@@ -161,8 +151,8 @@ loop:SWAPINIT(a, es);
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
- pa = pb = (char *) a + es;
- pc = pd = (char *) a + (n - 1) * es;
+ pa = pb = (char *)a + es;
+ pc = pd = (char *)a + (n - 1) * es;
for (;;)
{
while (pb <= pc && (r = cmp(pb, a)) <= 0)
@@ -189,8 +179,8 @@ loop:SWAPINIT(a, es);
pb += es;
pc -= es;
}
- pn = (char *) a + n * es;
- d1 = Min(pa - (char *) a, pb - pa);
+ pn = (char *)a + n * es;
+ d1 = Min(pa - (char *)a, pb - pa);
vecswap(a, pb - d1, d1);
d1 = Min(pd - pc, pn - pd - es);
vecswap(pb, pn - d1, d1);
@@ -200,11 +190,11 @@ loop:SWAPINIT(a, es);
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > es)
- pg_qsort(a, d1 / es, es, cmp);
+ pg_qsort_recursive(a, d1 / es, swaptype, es, cmp);
if (d2 > es)
{
/* Iterate rather than recurse to save stack space */
- /* pg_qsort(pn - d2, d2 / es, es, cmp); */
+ /* pg_qsort_recursive(pn - d2, d2 / es, es, cmp); */
a = pn - d2;
n = d2 / es;
goto loop;
@@ -214,17 +204,36 @@ loop:SWAPINIT(a, es);
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > es)
- pg_qsort(pn - d2, d2 / es, es, cmp);
+ pg_qsort_recursive(pn - d2, d2 / es, swaptype, es, cmp);
if (d1 > es)
{
/* Iterate rather than recurse to save stack space */
- /* pg_qsort(a, d1 / es, es, cmp); */
+ /* pg_qsort_recursive(a, d1 / es, es, cmp); */
n = d1 / es;
goto loop;
}
}
}
+
+void
+pg_qsort(void *a, const size_t size, const size_t es, int(*cmp) (const void *, const void *)) {
+ int swaptype, presorted = 1;
+ char* pm;
+ for (pm = (char *)a + es; pm < (char *)a + size * es; pm += es)
+ {
+ if (cmp(pm - es, pm) > 0)
+ {
+ presorted = 0;
+ break;
+ }
+ }
+ if (presorted)
+ return;
+ SWAPINIT(a, es);
+ pg_qsort_recursive(a, size, swaptype, es, cmp);
+};
+
/*
* qsort comparator wrapper for strcmp.
*/
diff --git a/src/port/qsort_arg.c b/src/port/qsort_arg.c
index 24acd2c..7de3167 100644
--- a/src/port/qsort_arg.c
+++ b/src/port/qsort_arg.c
@@ -44,6 +44,8 @@
* SUCH DAMAGE.
*/
+
+#include <math.h>
#include "c.h"
@@ -102,54 +104,42 @@ swapfunc(char *a, char *b, size_t n, int swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static char *
-med3(char *a, char *b, char *c, qsort_arg_comparator cmp, void *arg)
+med3(char *a, char *b, char *c, qsort_arg_comparator cmp, void* arg)
{
return cmp(a, b, arg) < 0 ?
- (cmp(b, c, arg) < 0 ? b : (cmp(a, c, arg) < 0 ? c : a))
- : (cmp(b, c, arg) > 0 ? b : (cmp(a, c, arg) < 0 ? a : c));
+ (cmp(b, c , arg) < 0 ? b : (cmp(a, c, arg) < 0 ? c : a))
+ : (cmp(b, c, arg) > 0 ? b : (cmp(a, c, arg) < 0 ? a : c));
}
-void
-qsort_arg(void *a, size_t n, size_t es, qsort_arg_comparator cmp, void *arg)
+static void
+pg_qsort_arg_recursive(void *a, size_t n, int swaptype, size_t es, qsort_arg_comparator cmp, void* arg)
{
char *pa,
- *pb,
- *pc,
- *pd,
- *pl,
- *pm,
- *pn;
+ *pb,
+ *pc,
+ *pd,
+ *pl,
+ *pm,
+ *pn;
size_t d1,
- d2;
- int r,
- swaptype,
- presorted;
+ d2;
+ int r;
-loop:SWAPINIT(a, es);
+loop:
if (n < 7)
{
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl, arg) > 0;
- pl -= es)
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl >(char *) a && cmp(pl - es, pl, arg) > 0;
+ pl -= es)
swap(pl, pl - es);
return;
}
- presorted = 1;
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- {
- if (cmp(pm - es, pm, arg) > 0)
- {
- presorted = 0;
- break;
- }
- }
- if (presorted)
- return;
- pm = (char *) a + (n / 2) * es;
+
+ pm = (char *)a + (n / 2) * es;
if (n > 7)
{
- pl = (char *) a;
- pn = (char *) a + (n - 1) * es;
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
if (n > 40)
{
size_t d = (n / 8) * es;
@@ -161,8 +151,8 @@ loop:SWAPINIT(a, es);
pm = med3(pl, pm, pn, cmp, arg);
}
swap(a, pm);
- pa = pb = (char *) a + es;
- pc = pd = (char *) a + (n - 1) * es;
+ pa = pb = (char *)a + es;
+ pc = pd = (char *)a + (n - 1) * es;
for (;;)
{
while (pb <= pc && (r = cmp(pb, a, arg)) <= 0)
@@ -189,8 +179,8 @@ loop:SWAPINIT(a, es);
pb += es;
pc -= es;
}
- pn = (char *) a + n * es;
- d1 = Min(pa - (char *) a, pb - pa);
+ pn = (char *)a + n * es;
+ d1 = Min(pa - (char *)a, pb - pa);
vecswap(a, pb - d1, d1);
d1 = Min(pd - pc, pn - pd - es);
vecswap(pb, pn - d1, d1);
@@ -200,11 +190,11 @@ loop:SWAPINIT(a, es);
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > es)
- qsort_arg(a, d1 / es, es, cmp, arg);
+ pg_qsort_arg_recursive(a, d1 / es, swaptype, es, cmp, arg);
if (d2 > es)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_arg(pn - d2, d2 / es, es, cmp, arg); */
+ /* pg_qsort_arg_recursive(pn - d2, d2 / es, es, cmp, arg); */
a = pn - d2;
n = d2 / es;
goto loop;
@@ -214,13 +204,33 @@ loop:SWAPINIT(a, es);
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > es)
- qsort_arg(pn - d2, d2 / es, es, cmp, arg);
+ pg_qsort_arg_recursive(pn - d2, d2 / es, swaptype, es, cmp, arg);
if (d1 > es)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_arg(a, d1 / es, es, cmp, arg); */
+ /* pg_qsort_arg_recursive(a, d1 / es, es, cmp, arg); */
n = d1 / es;
goto loop;
}
}
}
+
+
+void
+qsort_arg(void *a, const size_t size, const size_t es, qsort_arg_comparator cmp, void* arg) {
+ int swaptype, presorted = 1;
+ char* pm;
+ for (pm = (char *)a + es; pm < (char *)a + size * es; pm += es)
+ {
+ if (cmp(pm - es, pm, arg) > 0)
+ {
+ presorted = 0;
+ break;
+ }
+ }
+ if (presorted)
+ return;
+ SWAPINIT(a, es);
+ pg_qsort_arg_recursive(a, size, swaptype, es, cmp, arg);
+};
+
[application/octet-stream] use_heap.diff (13.2K, ../5b5654cc.1c69fb81.5ea44.d698@mx.google.com/4-use_heap.diff)
download | inline diff:
diff --git a/src/backend/utils/sort/gen_qsort_tuple.pl b/src/backend/utils/sort/gen_qsort_tuple.pl
index 6186d0a..a9ae496 100644
--- a/src/backend/utils/sort/gen_qsort_tuple.pl
+++ b/src/backend/utils/sort/gen_qsort_tuple.pl
@@ -108,6 +108,8 @@ sub emit_qsort_boilerplate
* worth the effort", but we have seen crashes in the field due to stack
* overrun, so that judgment seems wrong.
*/
+
+#include <math.h>
static void
swapfunc(SortTuple *a, SortTuple *b, size_t n)
@@ -145,8 +147,63 @@ med3_$SUFFIX(SortTuple *a, SortTuple *b, SortTuple *c$EXTRAARGS)
(cmp_$SUFFIX(a, c$CMPPARAMS) < 0 ? a : c));
}
+/* heap sort: based on wikipedia */
+
+static inline void
+heap_shift_down_$SUFFIX(SortTuple *a, const size_t start, const size_t end$EXTRAARGS) {
+ size_t child, root = start;
+
+ while ((root << 1) + 1 <= end) {
+ CHECK_FOR_INTERRUPTS();
+
+ child = (root << 1) + 1;
+
+ if ((child < end) && cmp_$SUFFIX(a + child, a + (child + 1)$CMPPARAMS) < 0) {
+ child++;
+ }
+
+ if (cmp_$SUFFIX(a + root, a + child$CMPPARAMS) < 0) {
+ swap(a + root, a + child);
+ root = child;
+ }
+ else {
+ return;
+ }
+ }
+}
+
+static inline void
+heap_sort_$SUFFIX(SortTuple *a, const size_t size$EXTRAARGS) {
+
+ size_t start, end;
+ /* don't bother sorting an array of size <= 1 */
+ if (size <= 1) {
+ return;
+ }
+
+ end = size - 1;
+
+ /* heapify */
+ start = (end - 1) >> 1;
+ while (1) {
+ heap_shift_down_$SUFFIX(a, start, end$EXTRAPARAMS);
+
+ if (start == 0) {
+ break;
+ }
+
+ start--;
+ }
+
+ while (end > 0) {
+ swap(a + end, a);
+ heap_shift_down_$SUFFIX(a, 0, end - 1$EXTRAPARAMS);
+ end--;
+ }
+}
+
static void
-qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
+qsort_recursive_$SUFFIX(SortTuple *a, size_t n, size_t depth$EXTRAARGS)
{
SortTuple *pa,
*pb,
@@ -158,7 +215,7 @@ qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
size_t d1,
d2;
int r,
- presorted;
+ presorted;
loop:
CHECK_FOR_INTERRUPTS();
@@ -169,8 +226,9 @@ loop:
swap(pl, pl - 1);
return;
}
- presorted = 1;
- for (pm = a + 1; pm < a + n; pm++)
+
+ presorted = 1;
+ for (pm = a + 1; pm < a + n; pm++)
{
CHECK_FOR_INTERRUPTS();
if (cmp_$SUFFIX(pm - 1, pm$CMPPARAMS) > 0)
@@ -181,6 +239,13 @@ loop:
}
if (presorted)
return;
+
+ /* convert to heap sort if exceed depth limit */
+ if (!depth) {
+ heap_sort_$SUFFIX(a, n$EXTRAPARAMS);
+ return;
+ }
+
pm = a + (n / 2);
if (n > 7)
{
@@ -238,13 +303,14 @@ loop:
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > 1)
- qsort_$SUFFIX(a, d1$EXTRAPARAMS);
+ qsort_recursive_$SUFFIX(a, d1, depth - 1$EXTRAPARAMS);
if (d2 > 1)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_$SUFFIX(pn - d2, d2$EXTRAPARAMS); */
+ /* qsort_recursive_$SUFFIX(pn - d2, d2, depth - 1$EXTRAPARAMS); */
a = pn - d2;
n = d2;
+ depth--;
goto loop;
}
}
@@ -252,15 +318,23 @@ loop:
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > 1)
- qsort_$SUFFIX(pn - d2, d2$EXTRAPARAMS);
+ qsort_recursive_$SUFFIX(pn - d2, d2, depth - 1$EXTRAPARAMS);
if (d1 > 1)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_$SUFFIX(a, d1$EXTRAPARAMS); */
+ /* qsort_recursive_$SUFFIX(a, d1, depth - 1$EXTRAPARAMS); */
n = d1;
+ depth--;
goto loop;
}
}
}
+
+static void
+qsort_$SUFFIX(SortTuple *a, size_t n$EXTRAARGS)
+{
+ qsort_recursive_$SUFFIX(a, n, 2 * log(n)$EXTRAPARAMS);
+}
+
EOM
}
diff --git a/src/port/qsort.c b/src/port/qsort.c
index 1a8ee08..49175a7 100644
--- a/src/port/qsort.c
+++ b/src/port/qsort.c
@@ -44,6 +44,8 @@
* SUCH DAMAGE.
*/
+
+#include <math.h>
#include "c.h"
@@ -109,32 +111,85 @@ med3(char *a, char *b, char *c, int (*cmp) (const void *, const void *))
: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
}
-void
-pg_qsort(void *a, size_t n, size_t es, int (*cmp) (const void *, const void *))
+/* heap sort: based on wikipedia */
+
+static inline void
+heap_shift_down(void *a, const size_t start, const size_t end,
+ int swaptype, const size_t es, int(*cmp) (const void *, const void *)) {
+ size_t root = start;
+
+ while ((root << 1) + 1 <= end) {
+ size_t child = (root << 1) + 1;
+
+ if ((child < end) && cmp((char*)a + child * es, (char*)a + (child + 1)*es) < 0) {
+ child++;
+ }
+
+ if (cmp((char*)a + root * es, (char*)a + child * es) < 0) {
+ swap((char*)a + root * es, (char*)a + child * es);
+ root = child;
+ }
+ else {
+ return;
+ }
+ }
+}
+
+static inline void
+heap_sort(void *a, const size_t size, int swaptype, const size_t es, int(*cmp) (const void *, const void *)) {
+
+ size_t start, end;
+ /* don't bother sorting an array of size <= 1 */
+ if (size <= 1) {
+ return;
+ }
+
+ end = size - 1;
+
+ /* heapify */
+ start = (end - 1) >> 1;
+ while (1) {
+ heap_shift_down(a, start, end, swaptype, es, cmp);
+
+ if (start == 0) {
+ break;
+ }
+
+ start--;
+ }
+
+ while (end > 0) {
+ swap((char*)a + end * es, (char*)a);
+ heap_shift_down(a, 0, end - 1, swaptype, es, cmp);
+ end--;
+ }
+}
+
+static void
+pg_qsort_recursive(void *a, size_t n, size_t depth, int swaptype, size_t es, int(*cmp) (const void *, const void *))
{
char *pa,
- *pb,
- *pc,
- *pd,
- *pl,
- *pm,
- *pn;
+ *pb,
+ *pc,
+ *pd,
+ *pl,
+ *pm,
+ *pn;
size_t d1,
- d2;
+ d2;
int r,
- swaptype,
- presorted;
+ presorted;
-loop:SWAPINIT(a, es);
+loop:
if (n < 7)
{
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
- pl -= es)
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl >(char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
swap(pl, pl - es);
return;
}
- presorted = 1;
+ presorted = 1;
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
{
if (cmp(pm - es, pm) > 0)
@@ -145,11 +200,18 @@ loop:SWAPINIT(a, es);
}
if (presorted)
return;
- pm = (char *) a + (n / 2) * es;
+
+ /* convert to heap sort if exceed depth limit */
+ if (!depth) {
+ heap_sort(a, n, swaptype, es, cmp);
+ return;
+ }
+
+ pm = (char *)a + (n / 2) * es;
if (n > 7)
{
- pl = (char *) a;
- pn = (char *) a + (n - 1) * es;
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
if (n > 40)
{
size_t d = (n / 8) * es;
@@ -161,8 +223,8 @@ loop:SWAPINIT(a, es);
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
- pa = pb = (char *) a + es;
- pc = pd = (char *) a + (n - 1) * es;
+ pa = pb = (char *)a + es;
+ pc = pd = (char *)a + (n - 1) * es;
for (;;)
{
while (pb <= pc && (r = cmp(pb, a)) <= 0)
@@ -189,8 +251,8 @@ loop:SWAPINIT(a, es);
pb += es;
pc -= es;
}
- pn = (char *) a + n * es;
- d1 = Min(pa - (char *) a, pb - pa);
+ pn = (char *)a + n * es;
+ d1 = Min(pa - (char *)a, pb - pa);
vecswap(a, pb - d1, d1);
d1 = Min(pd - pc, pn - pd - es);
vecswap(pb, pn - d1, d1);
@@ -200,13 +262,14 @@ loop:SWAPINIT(a, es);
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > es)
- pg_qsort(a, d1 / es, es, cmp);
+ pg_qsort_recursive(a, d1 / es, depth - 1, swaptype, es, cmp);
if (d2 > es)
{
/* Iterate rather than recurse to save stack space */
- /* pg_qsort(pn - d2, d2 / es, es, cmp); */
+ /* pg_qsort_recursive(pn - d2, d2 / es, depth - 1, es, cmp); */
a = pn - d2;
n = d2 / es;
+ depth--;
goto loop;
}
}
@@ -214,17 +277,26 @@ loop:SWAPINIT(a, es);
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > es)
- pg_qsort(pn - d2, d2 / es, es, cmp);
+ pg_qsort_recursive(pn - d2, d2 / es, depth - 1, swaptype, es, cmp);
if (d1 > es)
{
/* Iterate rather than recurse to save stack space */
- /* pg_qsort(a, d1 / es, es, cmp); */
+ /* pg_qsort_recursive(a, d1 / es, depth - 1, es, cmp); */
n = d1 / es;
+ depth--;
goto loop;
}
}
}
+
+void
+pg_qsort(void *a, const size_t size, const size_t es, int(*cmp) (const void *, const void *)) {
+ int swaptype;
+ SWAPINIT(a, es);
+ pg_qsort_recursive(a, size, 2 * log(size), swaptype, es, cmp);
+};
+
/*
* qsort comparator wrapper for strcmp.
*/
diff --git a/src/port/qsort_arg.c b/src/port/qsort_arg.c
index 24acd2c..b785778 100644
--- a/src/port/qsort_arg.c
+++ b/src/port/qsort_arg.c
@@ -44,6 +44,8 @@
* SUCH DAMAGE.
*/
+
+#include <math.h>
#include "c.h"
@@ -102,39 +104,94 @@ swapfunc(char *a, char *b, size_t n, int swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static char *
-med3(char *a, char *b, char *c, qsort_arg_comparator cmp, void *arg)
+med3(char *a, char *b, char *c, qsort_arg_comparator cmp, void* arg)
{
return cmp(a, b, arg) < 0 ?
- (cmp(b, c, arg) < 0 ? b : (cmp(a, c, arg) < 0 ? c : a))
- : (cmp(b, c, arg) > 0 ? b : (cmp(a, c, arg) < 0 ? a : c));
+ (cmp(b, c , arg) < 0 ? b : (cmp(a, c, arg) < 0 ? c : a))
+ : (cmp(b, c, arg) > 0 ? b : (cmp(a, c, arg) < 0 ? a : c));
}
-void
-qsort_arg(void *a, size_t n, size_t es, qsort_arg_comparator cmp, void *arg)
+
+/* heap sort: based on wikipedia */
+
+static inline void
+heap_shift_down(void *a, const size_t start, const size_t end,
+ int swaptype, const size_t es, qsort_arg_comparator cmp, void* arg) {
+ size_t root = start;
+
+ while ((root << 1) + 1 <= end) {
+ size_t child = (root << 1) + 1;
+
+ if ((child < end) && cmp((char*)a + child * es, (char*)a + (child + 1)*es, arg) < 0) {
+ child++;
+ }
+
+ if (cmp((char*)a + root * es, (char*)a + child * es, arg) < 0) {
+ swap((char*)a + root * es, (char*)a + child * es);
+ root = child;
+ }
+ else {
+ return;
+ }
+ }
+}
+
+static inline void
+heap_sort(void *a, const size_t size, int swaptype, const size_t es, qsort_arg_comparator cmp, void* arg) {
+
+ size_t start, end;
+ /* don't bother sorting an array of size <= 1 */
+ if (size <= 1) {
+ return;
+ }
+
+ end = size - 1;
+
+ /* heapify */
+ start = (end - 1) >> 1;
+ while (1) {
+ heap_shift_down(a, start, end, swaptype, es, cmp, arg);
+
+ if (start == 0) {
+ break;
+ }
+
+ start--;
+ }
+
+ while (end > 0) {
+ swap((char*)a + end * es, (char*)a);
+ heap_shift_down(a, 0, end - 1, swaptype, es, cmp, arg);
+ end--;
+ }
+}
+
+static void
+pg_qsort_arg_recursive(void *a, size_t n, size_t depth, int swaptype, size_t es, qsort_arg_comparator cmp, void* arg)
{
char *pa,
- *pb,
- *pc,
- *pd,
- *pl,
- *pm,
- *pn;
+ *pb,
+ *pc,
+ *pd,
+ *pl,
+ *pm,
+ *pn;
size_t d1,
- d2;
+ d2;
int r,
- swaptype,
- presorted;
+ presorted;
-loop:SWAPINIT(a, es);
+loop:
if (n < 7)
{
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl, arg) > 0;
- pl -= es)
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl >(char *) a && cmp(pl - es, pl, arg) > 0;
+ pl -= es)
swap(pl, pl - es);
return;
}
- presorted = 1;
+
+ presorted = 1;
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
{
if (cmp(pm - es, pm, arg) > 0)
@@ -145,11 +202,18 @@ loop:SWAPINIT(a, es);
}
if (presorted)
return;
- pm = (char *) a + (n / 2) * es;
+
+ /* convert to heap sort if exceed depth limit */
+ if (!depth) {
+ heap_sort(a, n, swaptype, es, cmp, arg);
+ return;
+ }
+
+ pm = (char *)a + (n / 2) * es;
if (n > 7)
{
- pl = (char *) a;
- pn = (char *) a + (n - 1) * es;
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
if (n > 40)
{
size_t d = (n / 8) * es;
@@ -161,8 +225,8 @@ loop:SWAPINIT(a, es);
pm = med3(pl, pm, pn, cmp, arg);
}
swap(a, pm);
- pa = pb = (char *) a + es;
- pc = pd = (char *) a + (n - 1) * es;
+ pa = pb = (char *)a + es;
+ pc = pd = (char *)a + (n - 1) * es;
for (;;)
{
while (pb <= pc && (r = cmp(pb, a, arg)) <= 0)
@@ -189,8 +253,8 @@ loop:SWAPINIT(a, es);
pb += es;
pc -= es;
}
- pn = (char *) a + n * es;
- d1 = Min(pa - (char *) a, pb - pa);
+ pn = (char *)a + n * es;
+ d1 = Min(pa - (char *)a, pb - pa);
vecswap(a, pb - d1, d1);
d1 = Min(pd - pc, pn - pd - es);
vecswap(pb, pn - d1, d1);
@@ -200,13 +264,14 @@ loop:SWAPINIT(a, es);
{
/* Recurse on left partition, then iterate on right partition */
if (d1 > es)
- qsort_arg(a, d1 / es, es, cmp, arg);
+ pg_qsort_arg_recursive(a, d1 / es, depth - 1, swaptype, es, cmp, arg);
if (d2 > es)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_arg(pn - d2, d2 / es, es, cmp, arg); */
+ /* pg_qsort_arg_recursive(pn - d2, d2 / es, depth - 1, es, cmp, arg); */
a = pn - d2;
n = d2 / es;
+ depth--;
goto loop;
}
}
@@ -214,13 +279,23 @@ loop:SWAPINIT(a, es);
{
/* Recurse on right partition, then iterate on left partition */
if (d2 > es)
- qsort_arg(pn - d2, d2 / es, es, cmp, arg);
+ pg_qsort_arg_recursive(pn - d2, d2 / es, depth - 1, swaptype, es, cmp, arg);
if (d1 > es)
{
/* Iterate rather than recurse to save stack space */
- /* qsort_arg(a, d1 / es, es, cmp, arg); */
+ /* pg_qsort_arg_recursive(a, d1 / es, depth - 1, es, cmp, arg); */
n = d1 / es;
+ depth--;
goto loop;
}
}
}
+
+
+void
+qsort_arg(void *a, const size_t size, const size_t es, qsort_arg_comparator cmp, void* arg) {
+ int swaptype;
+ SWAPINIT(a, es);
+ pg_qsort_arg_recursive(a, size, 2 * log(size), swaptype, es, cmp, arg);
+};
+
view thread (15+ messages) latest in thread
Message-ID: <5b5654cc.1c69fb81.5ea44.d698@mx.google.com>
Permalink: ../5b5654cc.1c69fb81.5ea44.d698@mx.google.com/
Also on: postgresql.org/message-id/5b5654cc.1c69fb81.5ea44.d698@mx.google.com
copy link · copy postgr.es · copy git am
reply Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: starordust@gmail.com, tomas.vondra@2ndquadrant.com, x4mmm@yandex-team.ru, pg@bowt.ie, alvherre@2ndquadrant.com, pgsql-hackers@lists.postgresql.org
Subject: RE: GSOC 2018 Project - A New Sorting Routine
In-Reply-To: <5b5654cc.1c69fb81.5ea44.d698@mx.google.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox