From 7cd1669a3b9a4797908ed8d427ad2d7e73a44149 Mon Sep 17 00:00:00 2001 From: lihuiba Date: Mon, 23 Sep 2024 16:05:32 +0800 Subject: [PATCH] log2_truncate(), log2_round(), log2_round_up(), round_up_to_exp2() --- common/io-alloc.h | 26 ++++++++------------------ common/ring.h | 9 +-------- common/test/test.cpp | 6 +++--- common/test/test_scalepool.cpp | 8 ++++---- common/utility.h | 32 +++++++++++++++++++++++++++++--- thread/stack-allocator.cpp | 8 ++++---- 6 files changed, 49 insertions(+), 40 deletions(-) diff --git a/common/io-alloc.h b/common/io-alloc.h index 2fa6d214..9e4d160a 100644 --- a/common/io-alloc.h +++ b/common/io-alloc.h @@ -116,9 +116,8 @@ template< size_t ALIGNMENT = 4096> class PooledAllocator { - constexpr static bool is_power2(size_t n) { return (n & (n-1)) == 0; } - static_assert(is_power2(ALIGNMENT), "must be 2^n"); - static_assert(is_power2(MAX_ALLOCATION_SIZE), "must be 2^n"); + static_assert(is_power_of_2(ALIGNMENT), "must be 2^n"); + static_assert(is_power_of_2(MAX_ALLOCATION_SIZE), "must be 2^n"); static_assert(MAX_ALLOCATION_SIZE >= ALIGNMENT, "..."); const static size_t N_SLOTS = __builtin_ffsl(MAX_ALLOCATION_SIZE / 4096); public: @@ -151,7 +150,6 @@ class PooledAllocator } protected: - const int BASE_OFF = log2_round(ALIGNMENT); class Slot : public IdentityPool { public: @@ -177,19 +175,10 @@ class PooledAllocator } }; - static inline int log2_round(unsigned int x, bool round_up = false) { - assert(x > 0); - int ret = sizeof(x)*8 - 1 - __builtin_clz(x); - if (round_up && (1U << ret) < x) - return ret + 1; - return ret; - } - - int get_slot(unsigned int x, bool round_up = false) { - int i = log2_round(x, round_up); - if (i < BASE_OFF) - return 0; - return i - BASE_OFF; + int get_slot(unsigned int x, bool round_up) { + auto i = round_up ? log2_round_up(x) : log2_truncate(x); + auto BASE_OFF = log2_truncate(ALIGNMENT); + return (i < BASE_OFF) ? 0 : (i - BASE_OFF); } Slot slots[N_SLOTS]; @@ -211,7 +200,8 @@ class PooledAllocator size_t size = malloc_usable_size(ptr); #endif assert(size > 0); - slots[get_slot(size)].put(ptr); + assert(is_power_of_2(size)); + slots[get_slot(size, false)].put(ptr); return 0; } }; diff --git a/common/ring.h b/common/ring.h index 148a1ae5..c516f19d 100644 --- a/common/ring.h +++ b/common/ring.h @@ -18,6 +18,7 @@ limitations under the License. #include #include #include +#include #include // RingBase exists only to reduce the size of template RingQueue @@ -42,14 +43,6 @@ class RingBase return m_capacity; } - static uint32_t round_up_to_exp2(uint32_t x) - { - if (x == 0) return 1; - auto clz = __builtin_clz(x); // 'count leading zero' - uint32_t y = 1 << (31 - clz); - return (clz == 0 || y == x) ? y : y * 2; - } - int ensure_not_full() { while(full()) diff --git a/common/test/test.cpp b/common/test/test.cpp index 8e11c380..570176ba 100644 --- a/common/test/test.cpp +++ b/common/test/test.cpp @@ -60,13 +60,13 @@ char str[] = "2018/01/05 21:53:28|DEBUG| 2423423|test.cpp:254|virtual void LOGPe TEST(ring, round_up_to_exp2) { - EXPECT_EQ(RingBase::round_up_to_exp2(0), 1); - EXPECT_EQ(RingBase::round_up_to_exp2(1), 1); + EXPECT_EQ(round_up_to_exp2(0), 1); + EXPECT_EQ(round_up_to_exp2(1), 1); uint32_t i = 2; for (uint32_t exp2 = 2; exp2 <= (1<<25); exp2 *= 2) for ((void)i; i <= exp2; ++i) - EXPECT_EQ(RingBase::round_up_to_exp2(i), exp2); + EXPECT_EQ(round_up_to_exp2(i), exp2); } int rq_step = 0; diff --git a/common/test/test_scalepool.cpp b/common/test/test_scalepool.cpp index 011d6fc8..d9b51ffd 100644 --- a/common/test/test_scalepool.cpp +++ b/common/test/test_scalepool.cpp @@ -113,14 +113,14 @@ TEST(IOAlloc, basic) { for (auto &x:mem) { alloc.dealloc(x); } - while (mpool.slots[mpool.get_slot(64*1024, true)].m_size < 32) { + while (mpool.slots[mpool.get_slot(64*1024)].m_size < 32) { photon::thread_usleep(1000); } - while (mpool.slots[mpool.get_slot(64*1024, true)].m_size > 0) { + while (mpool.slots[mpool.get_slot(64*1024)].m_size > 0) { photon::thread_usleep(1000 * 1000); - LOG_DEBUG(VALUE(mpool.slots[mpool.get_slot(64*1024, true)].m_size)); + LOG_DEBUG(VALUE(mpool.slots[mpool.get_slot(64*1024)].m_size)); } - EXPECT_EQ(0U, mpool.slots[mpool.get_slot(64*1024, true)].m_size); + EXPECT_EQ(0U, mpool.slots[mpool.get_slot(64*1024)].m_size); } int main(int argc, char **argv) { diff --git a/common/utility.h b/common/utility.h index 02196bac..411cf720 100644 --- a/common/utility.h +++ b/common/utility.h @@ -127,9 +127,35 @@ struct is_function_pointer #define ENABLE_IF_NOT_POINTER(T) ENABLE_IF(!IS_POINTER(T)) -inline bool is_power_of_2(uint64_t x) -{ - return __builtin_popcountl(x) == 1; +inline constexpr bool is_power_of_2(uint64_t x) { + return !x || __builtin_popcountl(x) == 1; +} + +inline constexpr uint8_t log2_truncate(size_t x) { + assert(x > 0); + uint8_t exp = sizeof(x) * 8 - 1 - __builtin_clzl(x); + assert(x & (1UL << exp)); + return exp; +} + +inline constexpr uint8_t log2_round(size_t x) { + assert(x > 0); + uint8_t exp = log2_truncate(x); + assert(x & (1UL << exp)); + bool carry = exp && (x & (1UL << (exp - 1))); + return exp + carry; +} + +inline constexpr uint8_t log2_round_up(size_t x) { + assert(x > 0); + return (x <= 1) ? x : log2_truncate(x - 1) + 1; +} + +inline size_t round_up_to_exp2(size_t x) { + if (x == 0) return 1; + uint32_t y = 1UL << log2_truncate(x); + assert(x&y); + return y << (!!(x^y)); } template diff --git a/thread/stack-allocator.cpp b/thread/stack-allocator.cpp index ccc07d5a..dd090ea8 100644 --- a/thread/stack-allocator.cpp +++ b/thread/stack-allocator.cpp @@ -90,10 +90,10 @@ class PooledStackAllocator { }; // get_slot(length) returns first slot that larger or equal to length - static inline uint32_t get_slot(uint32_t length) { - static auto base = __builtin_clz(MIN_ALLOCATION_SIZE - 1); - auto index = __builtin_clz(length - 1); - return base > index ? base - index : 0; + uint32_t get_slot(uint32_t length) { + auto index = log2_round_up(length); + auto base = log2_truncate(MIN_ALLOCATION_SIZE); + return (index <= base) ? 0 : (index - base); } Slot slots[N_SLOTS];