Limit std::sort comparisons on small list

François Dumont frs.dumont@gmail.com
Thu Oct 3 20:04:00 GMT 2013


On 10/01/2013 11:35 PM, Paolo Carlini wrote:
> Hi,
>
>> Il giorno 01/ott/2013, alle ore 22:35, François Dumont<frs.dumont@gmail.com>  ha scritto:
>>
>>> On 09/30/2013 11:45 PM, Christopher Jefferson wrote:
>>>> Any ideas?
>>> This comes from way back in the SGI days by the look of things to me.
>>>
>>> The problem arises in __insertion_sort. The logic looks something like:
>>>
>>>   if (*__i < *__first)
>>> { Then *__i has to go all the way to the start of the array. Do that! }
>>> else
>>> { We don't know where *__i will go, but we know that if we start
>>> moving it back 1 square at a time, we will stop either at or before
>>> __first }
>>>
>>> That second part is __unguarded_linear_insert.
>>>
>>> In the case where actually *__i has to go all the way back to just
>>> after first, we do one comparison too many (we could stop one place
>>> before). However, the whole point of unguarded linear insert is that
>>> we are trading off one comparison to remove the need for a boundary
>>> condition check. We could add a check in the while of
>>> __unguarded_linear_insert of that form (__i > __first), but in many
>>> cases that would end up being more expensive than the comparisons,
>>> particularly because it is only in very rare cases that we expect to
>>> hit this case.
>>>
> Interesting, thanks. Numbers? Could you please see which numbers you get if you run the new performace test provided by Chris + variants of the subtest using pseudo-random numbers? I would say for shorter and longer lists and also averaging over a few different starting random seeds. In any case many repetitions to decresse the variance of the numbers. If/when you have something please send immediately over the tests themselves too: I know that even keeping fix the x86_64 architecture there are rather noticeable relative differences depending on the specific cpu, thus in any case I would like to run the same tests on my machines.
>
> Paolo
Note that this patch is not a solution to the problem explained by 
Christopher. It only avoids 1 comparison (and 2 moves) each time 
__insertion_sort is called without introducing more iterator comparison 
which is rather limited but rather safe too.

I tweak the performance test to make the result of the patch more obvious:

Without it I have:
sort.cc                      reverse 222097162 comparisons 29r   28u    
0s        0mem    0pf
sort.cc                      forwards 222433832 comparisons 28r   28u    
0s        0mem    0pf
sort.cc                      random 282514017 comparisons     102r 
102u    0s        0mem    0pf
stable_sort.cc               reverse 108815190 comparisons 58r   56u    
1s        0mem    0pf
stable_sort.cc               forwards 123367742 comparisons 50r   48u    
1s        0mem    0pf
stable_sort.cc               random 227422991 comparisons     130r 
129u    1s        0mem    0pf

With it I have:
sort.cc                      reverse 222097162 comparisons 27r   27u    
0s        0mem    0pf
sort.cc                      forwards 222433832 comparisons 27r   27u    
0s        0mem    0pf
sort.cc                      random 282514017 comparisons     103r 
102u    0s        0mem    0pf
stable_sort.cc               reverse 108815190 comparisons 58r   57u    
1s        0mem    0pf
stable_sort.cc               forwards 121939170 comparisons 51r   50u    
1s        0mem    0pf
stable_sort.cc               random 226708173 comparisons     130r 
129u    1s        0mem    0pf

So no impact on sort because the number of elements involved is too 
important. Good, even if limited, impact on stable_sort because it 
reduces the number of comparison by about 0.5% in the random case. I 
have added a test to check that on small number of elements it has the 
expected impact, only 1 comparison when 2 elements in the array.

I don't know if Christopher wants to give his opinion but what this 
patch does is only unrolling a for to deal with the first loop in a 
special way.

Tested under Linux x86_64.

2013-10-03  François Dumont  <fdumont@gcc.gnu.org>

     * include/bits/stl_algo.h (__insertion_sort): Avoid a redundant
     comparison.
     * testsuite/25_algorithms/sort/1.cc (test02): New.
     * testsuite/performance/25_algorithms/stable_sort.cc: Display
     number of comparisons within the report.
     * testsuite/performance/25_algorithms/sort.cc: Likewise.

François

-------------- next part --------------
A non-text attachment was scrubbed...
Name: sort.patch
Type: text/x-patch
Size: 6048 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20131003/cf1fb4cf/attachment.bin>


More information about the Libstdc++ mailing list