Skip to content

Commit

Permalink
Changes libstdc++ hashable function to use double instead of long double
Browse files Browse the repository at this point in the history
Oracle quite a few years ago was changing the bucket calculation from
using float to calculate the primes.
I presume they were generating excessively large maps and needed larger
primes.
Originally they intended to just move up to double with the
implementation, but then a question was raised on the mailing list about
just using long double instead.

They decided at that point just to move to using long double as an
overkill solution solution.

The problem with this solution is that for anyone not running x86, this
can fall down a software floating point implementation path.
AArch64 is a good example where it will fall down a 128bit soft float
implementation for calculating this.

Instead of accepting terrible performance for our bucket calculations;
move the implementation down to double.
If some HPC class application ends up getting inefficient bucket
calculation at this point, maybe they should instead invest in a hashmap
implementation specifically optimized for huge data sets.
  • Loading branch information
Sonicadvance1 committed Sep 6, 2020
1 parent ee5c3db commit 8a2b738
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 11 deletions.
12 changes: 6 additions & 6 deletions libstdc++-v3/include/bits/hashtable_policy.h
Expand Up @@ -460,7 +460,7 @@ namespace __detail
// Return a bucket count appropriate for n elements
std::size_t
_M_bkt_for_elements(std::size_t __n) const
{ return __builtin_ceill(__n / (long double)_M_max_load_factor); }
{ return __builtin_ceill(__n / (double)_M_max_load_factor); }

// __n_bkt is current bucket count, __n_elt is current element count,
// and __n_ins is number of elements to be inserted. Do we need to
Expand Down Expand Up @@ -560,15 +560,15 @@ namespace __detail
_M_next_resize = numeric_limits<size_t>::max();
else
_M_next_resize
= __builtin_floorl(__res * (long double)_M_max_load_factor);
= __builtin_floorl(__res * (double)_M_max_load_factor);

return __res;
}

// Return a bucket count appropriate for n elements
std::size_t
_M_bkt_for_elements(std::size_t __n) const noexcept
{ return __builtin_ceill(__n / (long double)_M_max_load_factor); }
{ return __builtin_ceill(__n / (double)_M_max_load_factor); }

// __n_bkt is current bucket count, __n_elt is current element count,
// and __n_ins is number of elements to be inserted. Do we need to
Expand All @@ -583,16 +583,16 @@ namespace __detail
// If _M_next_resize is 0 it means that we have nothing allocated so
// far and that we start inserting elements. In this case we start
// with an initial bucket size of 11.
long double __min_bkts
double __min_bkts
= std::max<std::size_t>(__n_elt + __n_ins, _M_next_resize ? 0 : 11)
/ (long double)_M_max_load_factor;
/ (double)_M_max_load_factor;
if (__min_bkts >= __n_bkt)
return { true,
_M_next_bkt(std::max<std::size_t>(__builtin_floorl(__min_bkts) + 1,
__n_bkt * _S_growth_factor)) };

_M_next_resize
= __builtin_floorl(__n_bkt * (long double)_M_max_load_factor);
= __builtin_floorl(__n_bkt * (double)_M_max_load_factor);
return { false, 0 };
}
else
Expand Down
10 changes: 5 additions & 5 deletions libstdc++-v3/src/c++11/hashtable_c++0x.cc
Expand Up @@ -58,7 +58,7 @@ namespace __detail
return 1;

_M_next_resize =
__builtin_floorl(__fast_bkt[__n] * (long double)_M_max_load_factor);
__builtin_floorl(__fast_bkt[__n] * (double)_M_max_load_factor);
return __fast_bkt[__n];
}

Expand All @@ -81,7 +81,7 @@ namespace __detail
_M_next_resize = numeric_limits<size_t>::max();
else
_M_next_resize =
__builtin_floorl(*__next_bkt * (long double)_M_max_load_factor);
__builtin_floorl(*__next_bkt * (double)_M_max_load_factor);

return *__next_bkt;
}
Expand All @@ -105,16 +105,16 @@ namespace __detail
// If _M_next_resize is 0 it means that we have nothing allocated so
// far and that we start inserting elements. In this case we start
// with an initial bucket size of 11.
long double __min_bkts
double __min_bkts
= std::max<std::size_t>(__n_elt + __n_ins, _M_next_resize ? 0 : 11)
/ (long double)_M_max_load_factor;
/ (double)_M_max_load_factor;
if (__min_bkts >= __n_bkt)
return { true,
_M_next_bkt(std::max<std::size_t>(__builtin_floorl(__min_bkts) + 1,
__n_bkt * _S_growth_factor)) };

_M_next_resize
= __builtin_floorl(__n_bkt * (long double)_M_max_load_factor);
= __builtin_floorl(__n_bkt * (double)_M_max_load_factor);
return { false, 0 };
}
else
Expand Down

0 comments on commit 8a2b738

Please sign in to comment.