mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Rich Felker <dalias@libc.org>
To: Markus Wichmann <nullplan@gmx.net>
Cc: musl@lists.openwall.com
Subject: Re: [musl] Re:Re: [musl] qsort
Date: Thu, 9 Feb 2023 14:03:16 -0500	[thread overview]
Message-ID: <20230209190316.GU4163@brightrain.aerifal.cx> (raw)
In-Reply-To: <20230201180115.GB2626@voyager>

On Wed, Feb 01, 2023 at 07:01:15PM +0100, Markus Wichmann wrote:
> On Mon, Jan 30, 2023 at 06:04:39PM +0800, David Wang wrote:
> > WIth glibc,  average report is  "qsort:3351271634  vs   sort:4358412048"
> > But on alpine,  it is "qsort:9585927992  vs   sort:4354856330"
> >
> > On average, qsort with musl is significantly slower than c++ sort,
> > while with glibc the average performance of qsort is bettern than c++
> > sort.
> >
> 
> It seems to me as though smoothsort does not optimize for the number of
> comparisons.
> 
> > Is there any story about the implementation of qsort in musl?  I feel
> > it focused on performance improvement for some special kind of domain,
> > but not clear what it is.
> >
> 
> Smoothsort has the desirable property of being adaptive. Its runtime
> gets closer to O(n) the more sorted the input already is. glibc uses
> mergesort or quicksort (the latter as fallback) and neither of them has
> that property. Plus, mergesort requires scratch storage and has a
> significantly harder time sorting arrays with large elements, because
> you end up constantly copying stuff. glibc tries to mitigate this by
> indirectly sorting once the elements go above 32 bytes in size.
> 
> Basically, glibc is optimized for the comparisons, musl more for the
> number of swaps. Although we really shouldn't loose sight of the
> compares entirely, since those are indirect function calls, and current
> processors seem to dislike those.
> 
> Anyway, there is an inefficiency in musl's smoothsort implementation,
> namely in the sift() function:
> 
> 
> | if(cmp(ar[0], lf, arg) >= 0 && cmp(ar[0], rt, arg) >= 0) {
> | 	break;
> | }
> | if(cmp(lf, rt, arg) >= 0) {
> | 	ar[i++] = lf;
> | 	head = lf;
> | 	pshift -= 1;
> | } else {
> | 	ar[i++] = rt;
> | 	head = rt;
> | 	pshift -= 2;
> | }
> 
> As you can see, this does two or three comparisions, but actually needs
> to do only two in any case: If we detect ar[0] >= lf && ar[0] < rt, then
> by transitivity we have also detected rt > lf, so there is no need to
> compare lf and rt directly anymore. I have not really found a good way
> to formulate code that takes advantage of that, maybe something like
> this?
> 
> 
> 		if(cmp(ar[0], lf, arg) < 0) {
> 			if(cmp(lf, rt, arg) >= 0) {
> 				ar[i++] = lf;
> 				head = lf;
> 				pshift -= 1;
> 			} else {
> go_right:
> 				ar[i++] = rt;
> 				head = rt;
> 				pshift -= 2;
> 			}
> 		} else if (cmp(ar[0], rt, arg) < 0) {
> 			goto go_right;
> 		} else {
> 			break;
> 		}
> 
> Yeah, not great. But it does use only two compares ever. This ought to
> lower the number of compares in your test somewhat.

I think we should pursue this. IIRC there was another fairly
significant missed optimization in qsort discussed a while back, where
discussion dropped off because the person involved turned out to be
impossible to work with.

On the overall topic of qsort and quicksort, quicksort is just not a
viable algorithm by itself because it's O(n²) time. glibc does not use
it by itself, but uses "introsort", a fancy way to say it introspects
the quicksort (rather just counts the depth) and switches to an O(n
log n) algorithm once it's descended too many levels. Alternatively,
there are ways to pick the pivot element (quickselect) that guarantee
O(n log n) overall performance, but the pivot selection is so heavy as
to make it impractical.

It might make sense for us to adopt an approach like introsort, using
smoothsort as the fallback, especially if we could preserve the
property of being fast on mostly/entirely sorted inputs. But I'm not
sure if that's possible.

Before we consider any such change though we should probably see
profiling data to determine where the time is being spent in
smoothsort, in case it's stupid stuff that's fixable.

Rich

  parent reply	other threads:[~2023-02-09 19:03 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-20  1:49 Guy
2023-01-20 12:55 ` alice
2023-01-30 10:04   ` [musl] " David Wang
2023-02-01 18:01     ` Markus Wichmann
2023-02-02  2:12       ` [musl] " David Wang
2023-02-03  5:22         ` [musl] " David Wang
2023-02-03  8:03           ` Alexander Monakov
2023-02-03  9:01             ` [musl] " David Wang
2023-02-09 19:03       ` Rich Felker [this message]
2023-02-09 19:20         ` Alexander Monakov
2023-02-09 19:52           ` Rich Felker
2023-02-09 20:18             ` Rich Felker
2023-02-09 20:27               ` Pierpaolo Bernardi
2023-02-10  4:10             ` Markus Wichmann
2023-02-10 10:00         ` [musl] " David Wang
2023-02-10 13:10           ` Rich Felker
2023-02-10 13:45             ` [musl] " David Wang
2023-02-10 14:19               ` Rich Felker
2023-02-11  5:12                 ` [musl] " David Wang
2023-02-11  5:44                   ` alice
2023-02-11  8:39                     ` Joakim Sindholt
2023-02-11  9:06                       ` alice
2023-02-11  9:31                         ` [musl] " David Wang
2023-02-11 13:35                         ` Rich Felker
2023-02-11 17:18                           ` David Wang
2023-02-16 15:15       ` David Wang
2023-02-16 16:07         ` Rich Felker
2023-02-17  1:35           ` [musl] " David Wang
2023-02-17 13:17           ` Alexander Monakov
2023-02-17 15:07             ` Rich Felker
2023-02-11  9:22     ` [musl] " Markus Wichmann
2023-02-11  9:36       ` [musl] " David Wang
2023-02-11  9:51       ` David Wang
2023-01-20 13:32 ` [musl] qsort Valery Ushakov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230209190316.GU4163@brightrain.aerifal.cx \
    --to=dalias@libc.org \
    --cc=musl@lists.openwall.com \
    --cc=nullplan@gmx.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).