From c95e31bef6e9e14000b3003cecb6579986e786e2 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Thu, 18 Feb 2021 18:20:01 +0800 Subject: [PATCH] [era_debug] Display bitset entries in run-length fashion --- era/era_debug.cc | 128 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/era/era_debug.cc b/era/era_debug.cc index cf1f682..af6764c 100644 --- a/era/era_debug.cc +++ b/era/era_debug.cc @@ -266,6 +266,131 @@ namespace { typename ShowTraits::ref_counter rc_; }; + // FIXME: duplication + class show_bitset_block : public dbg::command { + typedef array_block rblock; + public: + explicit show_bitset_block(block_manager::ptr bm) + : bm_(bm), + BITS_PER_ARRAY_ENTRY(64) { + } + + virtual void exec(strings const& args, ostream &out) { + if (args.size() != 2) + throw runtime_error("incorrect number of arguments"); + + block_address block = boost::lexical_cast(args[1]); + block_manager::read_ref rr = bm_->read_lock(block); + + rblock b(rr, rc_); + show_bitset_entries(b, out); + } + + private: + void show_bitset_entries(rblock const& b, ostream &out) { + formatter::ptr f = create_xml_formatter(); + uint32_t nr_entries = b.nr_entries(); + + field(*f, "max_entries", b.max_entries()); + field(*f, "nr_entries", nr_entries); + field(*f, "value_size", b.value_size()); + + uint32_t end_pos = b.nr_entries() * BITS_PER_ARRAY_ENTRY; + std::pair range = next_set_bits(b, 0); + for (; range.first < end_pos; range = next_set_bits(b, range.second)) { + formatter::ptr f2 = create_xml_formatter(); + field(*f2, "begin", range.first); + field(*f2, "end", range.second); + f->child("set_bits", f2); + } + + f->output(out, 0); + } + + // Returns the range of set bits, starts from the offset. + pair next_set_bits(rblock const &b, uint32_t offset) { + uint32_t end_pos = b.nr_entries() * BITS_PER_ARRAY_ENTRY; + uint32_t begin = find_first_set(b, offset); + + if (begin == end_pos) // not found + return make_pair(end_pos, end_pos); + + uint32_t end = find_first_unset(b, begin + 1); + return make_pair(begin, end); + } + + // Returns the position (zero-based) of the first bit set + // in the array block, starts from the offset. + // Returns the pass-the-end position if not found. + uint32_t find_first_set(rblock const &b, uint32_t offset) { + uint32_t entry = offset / BITS_PER_ARRAY_ENTRY; + uint32_t nr_entries = b.nr_entries(); + + if (entry >= nr_entries) + return entry * BITS_PER_ARRAY_ENTRY; + + uint32_t idx = offset % BITS_PER_ARRAY_ENTRY; + uint64_t v = b.get(entry++) >> idx; + while (!v && entry < nr_entries) { + v = b.get(entry++); + idx = 0; + } + + if (!v) // not found + return entry * BITS_PER_ARRAY_ENTRY; + + return (entry - 1) * BITS_PER_ARRAY_ENTRY + idx + ffsll(static_cast(v)) - 1; + } + + // Returns the position (zero-based) of the first zero bit + // in the array block, starts from the offset. + // Returns the pass-the-end position if not found. + // FIXME: improve efficiency + uint32_t find_first_unset(rblock const& b, uint32_t offset) { + uint32_t entry = offset / BITS_PER_ARRAY_ENTRY; + uint32_t nr_entries = b.nr_entries(); + + if (entry >= nr_entries) + return entry * BITS_PER_ARRAY_ENTRY; + + uint32_t idx = offset % BITS_PER_ARRAY_ENTRY; + uint64_t v = b.get(entry++); + while (all_bits_set(v, idx) && entry < nr_entries) { + v = b.get(entry++); + idx = 0; + } + + if (all_bits_set(v, idx)) // not found + return entry * BITS_PER_ARRAY_ENTRY; + + return (entry - 1) * BITS_PER_ARRAY_ENTRY + idx + count_leading_bits(v, idx); + } + + // Returns true if all the bits beyond the position are set. + bool all_bits_set(uint64_t v, uint32_t offset) { + return (v >> offset) == (numeric_limits::max() >> offset); + } + + // Counts the number of leading 1's in the given value, starts from the offset + // FIXME: improve efficiency + uint32_t count_leading_bits(uint64_t v, uint32_t offset) { + uint32_t count = 0; + + v >>= offset; + while (v & 0x1) { + v >>= 1; + count++; + } + + return count; + } + + block_manager::ptr bm_; + uint64_traits::ref_counter rc_; + + const uint32_t BITS_PER_ARRAY_ENTRY; + }; + //-------------------------------- int debug(string const &path) { @@ -278,8 +403,7 @@ namespace { interp->register_command("hello", command::ptr(new hello)); interp->register_command("superblock", command::ptr(new show_superblock(bm))); interp->register_command("block_node", command::ptr(new show_btree_node(bm))); - interp->register_command("bitset_block", command::ptr(new show_array_block(bm, - uint64_show_traits::ref_counter()))); + interp->register_command("bitset_block", command::ptr(new show_bitset_block(bm))); interp->register_command("era_block", command::ptr(new show_array_block(bm, uint32_show_traits::ref_counter()))); interp->register_command("writeset_node", command::ptr(new show_btree_node(bm)));