Merge pull request #9524 from liewegas/wip-ctz

common: add cbits/ctz/clz bit op helpers, replace open-coded calc_bits_for helpers

Reviewed-by: Samuel Just <sjust@redhat.com>
This commit is contained in:
Sage Weil 2016-06-15 15:14:30 -04:00 committed by GitHub
commit e09acd7b54
8 changed files with 133 additions and 35 deletions

View File

@ -16,6 +16,7 @@
#include <vector>
#include <list>
#include "include/intarith.h"
#include "include/encoding.h"
namespace ceph {
@ -59,21 +60,12 @@ public:
}
void add(int32_t v) {
int bin = calc_bits_of(v);
int bin = cbits(v);
_expand_to(bin + 1);
h[bin]++;
_contract();
}
static int calc_bits_of(int t) {
int b = 0;
while (t > 0) {
t = t >> 1;
b++;
}
return b;
}
bool operator==(const pow2_hist_t &r) const {
return h == r.h;
}
@ -89,7 +81,7 @@ public:
int get_position_micro(int32_t v, uint64_t *lower, uint64_t *upper) {
if (v < 0)
return -1;
unsigned bin = calc_bits_of(v);
unsigned bin = cbits(v);
uint64_t lower_sum = 0, upper_sum = 0, total = 0;
for (unsigned i=0; i<h.size(); ++i) {
if (i <= bin)

View File

@ -35,4 +35,57 @@
# define SHIFT_ROUND_UP(x,y) (((x)+(1<<(y))-1) >> (y))
#endif
// count trailing zeros.
// NOTE: the builtin is nondeterministic on 0 input
static inline unsigned ctz(unsigned v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_ctz(v);
}
static inline unsigned ctzl(unsigned long v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_ctzl(v);
}
static inline unsigned ctzll(unsigned long long v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_ctzll(v);
}
// count leading zeros
// NOTE: the builtin is nondeterministic on 0 input
static inline unsigned clz(unsigned v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_clz(v);
}
static inline unsigned clzl(unsigned long v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_clzl(v);
}
static inline unsigned clzll(unsigned long long v) {
if (v == 0)
return sizeof(v) * 8;
return __builtin_clzll(v);
}
// count bits (set + any 0's that follow)
static inline unsigned cbits(unsigned v) {
if (v == 0)
return 0;
return (sizeof(v) * 8) - __builtin_clz(v);
}
static inline unsigned cbitsl(unsigned long v) {
if (v == 0)
return 0;
return (sizeof(v) * 8) - __builtin_clzl(v);
}
static inline unsigned cbitsll(unsigned long long v) {
if (v == 0)
return 0;
return (sizeof(v) * 8) - __builtin_clzll(v);
}
#endif

View File

@ -962,7 +962,7 @@ void PGMonitor::register_pg(OSDMap *osdmap,
parent = pgid;
while (1) {
// remove most significant bit
int msb = pool.calc_bits_of(parent.ps());
int msb = cbits(parent.ps());
if (!msb)
break;
parent.set_ps(parent.ps() & ~(1<<(msb-1)));

View File

@ -26,11 +26,7 @@ StupidAllocator::~StupidAllocator()
unsigned StupidAllocator::_choose_bin(uint64_t orig_len)
{
uint64_t len = orig_len / g_conf->bdev_block_size;
int bin = 0;
while (len && bin + 1 < (int)free.size()) {
len >>= 1;
bin++;
}
int bin = std::min((int)cbits(len), (int)free.size() - 1);
dout(30) << __func__ << " len " << orig_len << " -> " << bin << dendl;
return bin;
}

View File

@ -464,7 +464,7 @@ ostream& operator<<(ostream& out, const spg_t &pg)
pg_t pg_t::get_ancestor(unsigned old_pg_num) const
{
int old_bits = pg_pool_t::calc_bits_of(old_pg_num);
int old_bits = cbits(old_pg_num);
int old_mask = (1 << old_bits) - 1;
pg_t ret = *this;
ret.m_seed = ceph_stable_mod(m_seed, old_pg_num, old_mask);
@ -479,7 +479,7 @@ bool pg_t::is_split(unsigned old_pg_num, unsigned new_pg_num, set<pg_t> *childre
bool split = false;
if (true) {
int old_bits = pg_pool_t::calc_bits_of(old_pg_num);
int old_bits = cbits(old_pg_num);
int old_mask = (1 << old_bits) - 1;
for (int n = 1; ; n++) {
int next_bit = (n << (old_bits-1));
@ -498,7 +498,7 @@ bool pg_t::is_split(unsigned old_pg_num, unsigned new_pg_num, set<pg_t> *childre
}
if (false) {
// brute force
int old_bits = pg_pool_t::calc_bits_of(old_pg_num);
int old_bits = cbits(old_pg_num);
int old_mask = (1 << old_bits) - 1;
for (unsigned x = old_pg_num; x < new_pg_num; ++x) {
unsigned o = ceph_stable_mod(x, old_pg_num, old_mask);
@ -517,7 +517,7 @@ unsigned pg_t::get_split_bits(unsigned pg_num) const {
assert(pg_num > 1);
// Find unique p such that pg_num \in [2^(p-1), 2^p)
unsigned p = pg_pool_t::calc_bits_of(pg_num);
unsigned p = cbits(pg_num);
assert(p); // silence coverity #751330
if ((m_seed % (1<<(p-1))) < (pg_num % (1<<(p-1))))
@ -528,7 +528,7 @@ unsigned pg_t::get_split_bits(unsigned pg_num) const {
pg_t pg_t::get_parent() const
{
unsigned bits = pg_pool_t::calc_bits_of(m_seed);
unsigned bits = cbits(m_seed);
assert(bits);
pg_t retval = *this;
retval.m_seed &= ~((~0)<<(bits - 1));
@ -1193,20 +1193,10 @@ void pg_pool_t::convert_to_pg_shards(const vector<int> &from, set<pg_shard_t>* t
}
}
int pg_pool_t::calc_bits_of(int t)
{
int b = 0;
while (t > 0) {
t = t >> 1;
++b;
}
return b;
}
void pg_pool_t::calc_pg_masks()
{
pg_num_mask = (1 << calc_bits_of(pg_num-1)) - 1;
pgp_num_mask = (1 << calc_bits_of(pgp_num-1)) - 1;
pg_num_mask = (1 << cbits(pg_num-1)) - 1;
pgp_num_mask = (1 << cbits(pgp_num-1)) - 1;
}
unsigned pg_pool_t::get_pg_num_divisor(pg_t pgid) const

View File

@ -1438,7 +1438,6 @@ public:
return quota_max_objects;
}
static int calc_bits_of(int t);
void calc_pg_masks();
/*

View File

@ -126,6 +126,11 @@ ceph_test_rados_watch_notify_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS)
bin_DEBUGPROGRAMS += ceph_test_rados_watch_notify
endif # LINUX
unittest_intarith_SOURCES = test/test_intarith.cc
unittest_intarith_LDADD = $(UNITTEST_LDADD)
unittest_intarith_CXXFLAGS = $(UNITTEST_CXXFLAGS)
check_TESTPROGRAMS += unittest_intarith
unittest_librados_SOURCES = test/librados/librados.cc
unittest_librados_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) $(UNITTEST_LDADD)
unittest_librados_CXXFLAGS = $(UNITTEST_CXXFLAGS)

63
src/test/test_intarith.cc Normal file
View File

@ -0,0 +1,63 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#include <iostream>
#include <gtest/gtest.h>
#include "include/intarith.h"
TEST(intarith, cbits) {
ASSERT_EQ(0u, cbits(0));
ASSERT_EQ(1u, cbits(1));
ASSERT_EQ(2u, cbits(2));
ASSERT_EQ(2u, cbits(3));
ASSERT_EQ(3u, cbits(4));
ASSERT_EQ(0u, cbitsl(0));
ASSERT_EQ(1u, cbitsl(1));
ASSERT_EQ(2u, cbitsl(2));
ASSERT_EQ(2u, cbitsl(3));
ASSERT_EQ(3u, cbitsl(4));
ASSERT_EQ(9u, cbits(0x100));
ASSERT_EQ(32u, cbits(0xffffffff));
ASSERT_EQ(32u, cbitsl(0xffffffff));
ASSERT_EQ(32u, cbitsll(0xffffffff));
ASSERT_EQ(64u, cbitsll(0xffffffffffffffff));
}
TEST(intarith, clz) {
ASSERT_EQ(32u, clz(0));
ASSERT_EQ(31u, clz(1));
ASSERT_EQ(30u, clz(2));
ASSERT_EQ(30u, clz(3));
ASSERT_EQ(29u, clz(4));
ASSERT_EQ(64u, clzll(0));
ASSERT_EQ(63u, clzll(1));
ASSERT_EQ(62u, clzll(2));
ASSERT_EQ(62u, clzll(3));
ASSERT_EQ(61u, clzll(4));
ASSERT_EQ(23u, clz(0x100));
ASSERT_EQ(55u, clzll(0x100));
ASSERT_EQ(0u, clz(0xffffffff));
ASSERT_EQ(32u, clzll(0xffffffff));
ASSERT_EQ(0u, clzll(0xffffffffffffffff));
}
TEST(intarith, ctz) {
ASSERT_EQ(32u, ctz(0));
ASSERT_EQ(0u, ctz(1));
ASSERT_EQ(1u, ctz(2));
ASSERT_EQ(0u, ctz(3));
ASSERT_EQ(2u, ctz(4));
ASSERT_EQ(64u, ctzll(0));
ASSERT_EQ(0u, ctzll(1));
ASSERT_EQ(1u, ctzll(2));
ASSERT_EQ(0u, ctzll(3));
ASSERT_EQ(2u, ctzll(4));
ASSERT_EQ(8u, ctz(0x100));
ASSERT_EQ(8u, ctzll(0x100));
ASSERT_EQ(0u, ctz(0xffffffff));
ASSERT_EQ(0u, ctzl(0xffffffff));
ASSERT_EQ(0u, ctzll(0xffffffff));
ASSERT_EQ(20u, ctzll(0xffffffff00000));
ASSERT_EQ(48u, ctzll(0xff000000000000ull));
}