From fdcad7feb4dd43bb1614eb4faeb52e722e693e69 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Fri, 8 Feb 2019 14:17:34 +0000 Subject: [PATCH 1/4] Add test for sizeclass calculations --- src/test/func/sizeclass/sizeclass.cc | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/func/sizeclass/sizeclass.cc diff --git a/src/test/func/sizeclass/sizeclass.cc b/src/test/func/sizeclass/sizeclass.cc new file mode 100644 index 0000000..bcf7431 --- /dev/null +++ b/src/test/func/sizeclass/sizeclass.cc @@ -0,0 +1,53 @@ +#include +#include + +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(); +} \ No newline at end of file From 1272078487b78957cf15ce2b531cb978bd9f6fae Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Fri, 8 Feb 2019 20:32:38 +0000 Subject: [PATCH 2/4] Simplified size class calculation The rounding code can be integrated directly into the sizeclass code, which means, the code paths can be simplified slightly. The special case for zero mantissa bits is not required, as the compiler generates the same code from the more complex path due to eliminating dead code after folding the constant zero through. --- src/ds/bits.h | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/src/ds/bits.h b/src/ds/bits.h index 1ad466d..0be2b17 100644 --- a/src/ds/bits.h +++ b/src/ds/bits.h @@ -396,52 +396,33 @@ namespace snmalloc template 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 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 From 9981bad9b52a0680cfe6fd87f054ba2073f7f0b3 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Fri, 8 Feb 2019 20:37:45 +0000 Subject: [PATCH 3/4] clang format --- src/ds/bits.h | 6 +++--- src/test/func/sizeclass/sizeclass.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ds/bits.h b/src/ds/bits.h index 0be2b17..b0dc165 100644 --- a/src/ds/bits.h +++ b/src/ds/bits.h @@ -402,7 +402,7 @@ namespace snmalloc value = value - 1; size_t e = - bits::BITS - MANTISSA_BITS - LOW_BITS - clz(value | LEADING_BIT) ; + 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; @@ -417,8 +417,8 @@ namespace snmalloc value = value - 1; - size_t e = bits::BITS - - MANTISSA_BITS - LOW_BITS - clz_const(value | LEADING_BIT) ; + 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; diff --git a/src/test/func/sizeclass/sizeclass.cc b/src/test/func/sizeclass/sizeclass.cc index bcf7431..a98c201 100644 --- a/src/test/func/sizeclass/sizeclass.cc +++ b/src/test/func/sizeclass/sizeclass.cc @@ -1,7 +1,7 @@ #include #include -NOINLINE +NOINLINE uint8_t size_to_sizeclass(size_t size) { return snmalloc::size_to_sizeclass(size); @@ -39,8 +39,8 @@ int main(int, char**) 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; + << (size_t)size_to_sizeclass(i) << " but expected sizeclass " + << (size_t)sz << std::endl; failed = true; } } From e004641cecc9cfb1a963d31c2b5903c3bb0bb7cc Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Sat, 9 Feb 2019 14:11:30 +0000 Subject: [PATCH 4/4] Added to comment. --- src/ds/bits.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ds/bits.h b/src/ds/bits.h index b0dc165..0b09b71 100644 --- a/src/ds/bits.h +++ b/src/ds/bits.h @@ -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,6 +393,12 @@ 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 @@ -430,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