Unordered container insertion hints

François Dumont frs.dumont@gmail.com
Thu Jun 6 20:33:00 GMT 2013


On 05/24/2013 01:00 AM, Paolo Carlini wrote:
> On 05/23/2013 10:01 PM, François Dumont wrote:
>> Some feedback regarding this patch ?
> Two quick ones: what if the hint is wrong? I suppose the insertion 
> succeeds anyway, it's only a little waste of time, right?

Right.

> Is it possible that for instance something throws in that case and 
> would not now (when the hint is simply ignored)? In case, check and 
> re-check we are still conforming.
I consider the hint only if it is equivalent to the inserted element so 
I invoke the equal_to functor for that. The invocation of the equal_to 
functor is already done if no hint is granted at the same location. So 
usage of the hint has no impact on exception safety.
>
> In any case, I think it's quite easy to notice if an implementation is 
> using the hint in this way or a similar one basing on some simple 
> benchmarks, without looking of course at the actual implementation 
> code. Do we have any idea what other implementations are doing? Like, 
> eg, they invented something for unordered_set and map too? Or a better 
> way to exploit the hint for the multi variants?

     I only bench llvm/clang implementation and notice no different with 
or without hint, I guess it is simply ignored. I haven't plan to check 
or bench other implementations. The usage of hint I am introducing is 
quite natural considering the new unordered containers data model. And 
if anyone has a better idea to deal with it then he is welcome to 
contribute !

> Eventually I suppose we want to add a performance testcase to our 
> testsuite.
Good request and the reason why it took me so long to answer. Writing 
such benchmark have shown me that users should be very careful with it 
cause it can do more bad than good.

unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions w/o 
hint     120r  120u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
any hint     130r  130u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
good hint      54r   54u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
perfect hint      36r   36u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions w/o 
hint      40r   40u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
any hint      38r   38u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
bad hint      49r   50u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
perfect hint      34r   35u    0s 64000016mem    0pf

     The small number represents how many time the same element is 
inserted and the big one the number of different elements. 100 X 20000 
means that we loop 100 times inserting the 20000 elements during each 
loop. 20000 X 100 means that the main loop is on the elements and we 
insert each 100 times. Being able to insert all the equivalent elements 
at the same time or not has a major impact on the performances to get 
the same result. This is because when a new element is inserted it will 
be first in its bucket and the following 99 insertions will benefit from 
it even without any hint.

     The bench also show that a bad hint can be worst than no hint. A 
bad hint is one that once used require to check that next bucket is not 
impacted by the insertion. To do so it requires a hash code computation 
(if it is not cached like in my use case) and check. I have added a word 
about being able to check performance before using hints. Here is the 
result using the default std::hash<std::string>, hash code is being cached.

unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions w/o 
hint      76r   76u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
any hint      83r   83u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
good hint      29r   29u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 100 X 20000 insertions with 
perfect hint      24r   23u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions w/o 
hint      27r   26u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
any hint      24r   24u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
bad hint      27r   27u    0s 64000016mem    0pf
unordered_multiset_hint.cc    unordered_set 20000 X 100 insertions with 
perfect hint      23r   23u    0s 64000016mem    0pf

Almost no impact in this case when using a bad hint. I consider adding 
another condition to the use of the hint which is to have the element 
after the hint also equivalent to the inserted element. This way we are 
sure that next bucket won't be affected and do not need to compute a 
hash code. But the result was a rather counter-intuitive hint. To get a 
good one you had to do:

std::unordered_multiset<std::string> ums;
const std::string foo("foo");
ums.insert(foo);
auto hint = ums.insert(foo);
ums.insert(hint, foo);

     it means keeping the second insertion iterator as the best hint to 
insert foo string. Not very convenient to use in real life and quite 
error prone cause if you keep the first insertion hint then you get 
stuck with the worst hint ever !

Compared to the previous patch I have just added some __builtin_expect 
cause hint are not likely to be used very often.

Tested under Linux x86_64, ok to commit ? With or without doc ?

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

     * include/bits/hashtable_policy.h (_Insert_base): Consider hint in
     insert methods.
     * include/bits/hashtable.h: Likewise.
     * testsuite/23_containers/unordered_multimap/insert/hint.cc: New.
     * 
testsuite/performance/23_containers/insert/unordered_multiset_hint.cc:
     New.
     * doc/xml/manual/containers.xml: Document hinting in unordered
     containers.

François

-------------- next part --------------
A non-text attachment was scrubbed...
Name: hinting.patch
Type: text/x-patch
Size: 26288 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20130606/7b0d34a2/attachment.bin>


More information about the Libstdc++ mailing list