This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: PR 51386
- From: François Dumont <frs dot dumont at gmail dot com>
- To: Paolo Carlini <paolo dot carlini at oracle dot com>
- Cc: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Date: Tue, 06 Dec 2011 09:05:12 +0100
- Subject: Re: PR 51386
- References: <4EDB4F03.5050107@oracle.com> <4EDD2DAE.70507@gmail.com> <4EDD3413.9000602@oracle.com>
On 12/05/2011 10:13 PM, Paolo Carlini wrote:
Hi,
> Tested under linux x86_64, load_factor test is much faster now.
How much, exactly?
About 2000 times faster. I have temporarily added the slow part of
load_factor test in a performance test to measure it, do you want to
keep this ? I hadn't proposed it before because a max load factor of 0.3
is quite unusual. load_factor test simply challenge a possible use case
that has little chances to be experimented in a production environment.
>
> 2011-12-05 François Dumont <fdumont@gcc.gnu.org>
>
> PR 51386
PR libstdc++/51386
>
> * include/bits/hashtable_policy.h
(_Prime_rehash_policy::_M_next_bkt):
> Fix computation of _M_prev_resize so that hashtable do not
keep on
> being rehashed when _M_max_load_factor is lower than 1.
>
> Ok to commit ?
The whole patch doesn't really look self-explaining, but I'm willing
to largely trust you ;) Please improve a bit the English in the comments:
> Index: include/bits/hashtable_policy.h
> ===================================================================
> --- include/bits/hashtable_policy.h (revision 181975)
> +++ include/bits/hashtable_policy.h (working copy)
> @@ -298,25 +298,34 @@
> _Prime_rehash_policy::
> _M_next_bkt(std::size_t __n) const
> {
> - // Optimize lookups involving the first elements of __prime_list.
> - // (useful to speed-up, eg, constructors)
> - static const unsigned long __fast_bkt[12]
> - = { 2, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11 };
> + // Optimize lookups involving the first elements of
__prime_list (useful to
> + // speed-up, eg, constructors). The contained values are
already containing
> + // a minimal grow step.
I would say "The values already include a minimal grow step" and avoid
the repetition. But to be honest, I don't like much that the numbers
are not the same numbers as in __prime_list. This should be *purely* a
trick to improve the speed of the search, should not serve other
purposes. Can we decouple the two things? Sooner or later the
inconsistency would byte us, I'm sure. Please reason this way: imagine
the trick was not there, re-do the patch, and, at the *very* end, put
the trick back *only* to avoid calling lower_bound.
I finally restore the original values, the small containers will simply
grow slower at the beginning, not a big deal.
Ok to commit ?
François
Index: include/bits/hashtable_policy.h
===================================================================
--- include/bits/hashtable_policy.h (revision 181975)
+++ include/bits/hashtable_policy.h (working copy)
@@ -300,23 +300,30 @@
{
// Optimize lookups involving the first elements of __prime_list.
// (useful to speed-up, eg, constructors)
- static const unsigned long __fast_bkt[12]
+ static const unsigned char __fast_bkt[12]
= { 2, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11 };
+ if (__n <= 11)
+ {
+ _M_prev_resize = 0;
+ _M_next_resize
+ = __builtin_ceil(__fast_bkt[__n] * (long double)_M_max_load_factor);
+ return __fast_bkt[__n];
+ }
+
const unsigned long* __p
- = __n <= 11 ? __fast_bkt + __n
- : std::lower_bound(__prime_list + 5,
- __prime_list + _S_n_primes, __n);
+ = std::lower_bound(__prime_list + 5, __prime_list + _S_n_primes, __n);
- _M_prev_resize = __builtin_floor(*__p * (long double)_M_max_load_factor);
- if (__p != __fast_bkt)
- _M_prev_resize = std::min(_M_prev_resize,
- static_cast<std::size_t>(*(__p - 1)));
- // Lets guaranty a minimal grow step of 11:
+ // Shrink will take place only if the number of elements is small enough
+ // so that the prime number 2 steps before __p is large enough to still
+ // conform to the max load factor:
+ _M_prev_resize
+ = __builtin_floor(*(__p - 2) * (long double)_M_max_load_factor);
+
+ // Let's guaranty that a minimal grow step of 11 is used
if (*__p - __n < 11)
- __p = std::lower_bound(__prime_list + 5,
- __prime_list + _S_n_primes, __n + 11);
- _M_next_resize = __builtin_floor(*__p * (long double)_M_max_load_factor);
+ __p = std::lower_bound(__p, __prime_list + _S_n_primes, __n + 11);
+ _M_next_resize = __builtin_ceil(*__p * (long double)_M_max_load_factor);
return *__p;
}