Merge pull request #16 from Microsoft/Sizeclass
Simplified sizeclass calculations and added tests.
This commit is contained in:
@@ -378,7 +378,9 @@ namespace snmalloc
|
||||
* Map large range of strictly positive integers
|
||||
* into an exponent and mantissa pair.
|
||||
*
|
||||
* The reverse mapping is given as:
|
||||
* The reverse mapping is given by first adding one to the value, and then
|
||||
* extracting the bottom MANTISSA bits as m, and the rest as e.
|
||||
* Then each value maps as:
|
||||
*
|
||||
* e | m | value
|
||||
* ---------------------------------
|
||||
@@ -391,57 +393,44 @@ namespace snmalloc
|
||||
* smallest exponent and mantissa with a
|
||||
* reverse mapping not less than the value.
|
||||
*
|
||||
* The e and m in the forward mapping and reverse are not the same, and the
|
||||
* initial increment in from_exp_mant and the decrement in to_exp_mant
|
||||
* handle the different ways it is calculating and using the split.
|
||||
* This is due to the rounding of bits below the mantissa in the
|
||||
* representation, which is confusing but leads to the fastest code.
|
||||
*
|
||||
* Does not work for value=0.
|
||||
***********************************************/
|
||||
template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
|
||||
static size_t to_exp_mant(size_t value)
|
||||
{
|
||||
value += ((size_t)1 << (LOW_BITS)) - 1;
|
||||
value >>= LOW_BITS;
|
||||
size_t LEADING_BIT = ((size_t)1 << (MANTISSA_BITS + LOW_BITS)) >> 1;
|
||||
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
|
||||
|
||||
if (MANTISSA_BITS > 0)
|
||||
{
|
||||
size_t LEADING_BIT = ((size_t)1 << MANTISSA_BITS) >> 1;
|
||||
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
|
||||
value = value - 1;
|
||||
|
||||
value = value - 1;
|
||||
size_t e =
|
||||
bits::BITS - MANTISSA_BITS - LOW_BITS - clz(value | LEADING_BIT);
|
||||
size_t b = (e == 0) ? 0 : 1;
|
||||
size_t m = (value >> (LOW_BITS + e - b)) & MANTISSA_MASK;
|
||||
|
||||
size_t e = (bits::BITS - clz(value | LEADING_BIT)) - MANTISSA_BITS;
|
||||
size_t shift_e = (e == 0) ? 0 : e - 1;
|
||||
size_t m = (value >> shift_e) & MANTISSA_MASK;
|
||||
|
||||
return (e << MANTISSA_BITS) + m;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bits::next_pow2_bits(value);
|
||||
}
|
||||
return (e << MANTISSA_BITS) + m;
|
||||
}
|
||||
|
||||
template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
|
||||
constexpr static size_t to_exp_mant_const(size_t value)
|
||||
{
|
||||
value += ((size_t)1 << LOW_BITS) - 1;
|
||||
value >>= LOW_BITS;
|
||||
size_t LEADING_BIT = ((size_t)1 << (MANTISSA_BITS + LOW_BITS)) >> 1;
|
||||
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
|
||||
|
||||
if (MANTISSA_BITS > 0)
|
||||
{
|
||||
size_t LEADING_BIT = (size_t)1 << (MANTISSA_BITS - 1);
|
||||
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
|
||||
value = value - 1;
|
||||
|
||||
value = value - 1;
|
||||
size_t e =
|
||||
bits::BITS - MANTISSA_BITS - LOW_BITS - clz_const(value | LEADING_BIT);
|
||||
size_t b = (e == 0) ? 0 : 1;
|
||||
size_t m = (value >> (LOW_BITS + e - b)) & MANTISSA_MASK;
|
||||
|
||||
size_t e =
|
||||
(bits::BITS - clz_const(value | LEADING_BIT)) - MANTISSA_BITS;
|
||||
size_t shift_e = (e == 0) ? 0 : e - 1;
|
||||
size_t m = (value >> shift_e) & MANTISSA_MASK;
|
||||
|
||||
return (e << MANTISSA_BITS) + m;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bits::next_pow2_bits_const(value);
|
||||
}
|
||||
return (e << MANTISSA_BITS) + m;
|
||||
}
|
||||
|
||||
template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
|
||||
@@ -449,12 +438,13 @@ namespace snmalloc
|
||||
{
|
||||
if (MANTISSA_BITS > 0)
|
||||
{
|
||||
m_e = m_e + 1;
|
||||
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
|
||||
size_t m = m_e & MANTISSA_MASK;
|
||||
size_t e = m_e >> MANTISSA_BITS;
|
||||
size_t b = e == 0 ? 0 : 1;
|
||||
size_t shifted_e = e - b;
|
||||
size_t extended_m = (m + ((size_t)b << MANTISSA_BITS)) + 1;
|
||||
size_t extended_m = (m + ((size_t)b << MANTISSA_BITS));
|
||||
return extended_m << (shifted_e + LOW_BITS);
|
||||
}
|
||||
else
|
||||
|
||||
53
src/test/func/sizeclass/sizeclass.cc
Normal file
53
src/test/func/sizeclass/sizeclass.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <iostream>
|
||||
#include <snmalloc.h>
|
||||
|
||||
NOINLINE
|
||||
uint8_t size_to_sizeclass(size_t size)
|
||||
{
|
||||
return snmalloc::size_to_sizeclass(size);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
bool failed = false;
|
||||
size_t size_low = 0;
|
||||
|
||||
std::cout << "0 has sizeclass: " << (size_t)snmalloc::size_to_sizeclass(0)
|
||||
<< std::endl;
|
||||
|
||||
std::cout << "sizeclass |-> [size_low, size_high] " << std::endl;
|
||||
|
||||
for (uint8_t sz = 0; sz < snmalloc::NUM_SIZECLASSES; sz++)
|
||||
{
|
||||
// Separate printing for small and medium sizeclasses
|
||||
if (sz == snmalloc::NUM_SMALL_CLASSES)
|
||||
std::cout << std::endl;
|
||||
|
||||
size_t size = snmalloc::sizeclass_to_size(sz);
|
||||
std::cout << (size_t)sz << " |-> "
|
||||
<< "[" << size_low + 1 << ", " << size << "]" << std::endl;
|
||||
|
||||
if (size < size_low)
|
||||
{
|
||||
std::cout << "Sizeclass " << (size_t)sz << " is " << size
|
||||
<< " which is less than " << size_low << std::endl;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
for (size_t i = size_low + 1; i <= size; i++)
|
||||
{
|
||||
if (size_to_sizeclass(i) != sz)
|
||||
{
|
||||
std::cout << "Size " << i << " has sizeclass "
|
||||
<< (size_t)size_to_sizeclass(i) << " but expected sizeclass "
|
||||
<< (size_t)sz << std::endl;
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
size_low = size;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
abort();
|
||||
}
|
||||
Reference in New Issue
Block a user