1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_ 18 #define SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_ 19 20 #include "src/trace_processor/containers/bit_vector.h" 21 22 namespace perfetto { 23 namespace trace_processor { 24 namespace internal { 25 26 // Base iterator class for all iterators on BitVector. 27 // 28 // This class implements caching of one Block at a time to reduce pointer 29 // chasing. It also defers updating counts on Clear calls until the end of each 30 // block. 31 class BaseIterator { 32 public: 33 BaseIterator(BitVector* bv); 34 ~BaseIterator(); 35 36 BaseIterator(BaseIterator&&) noexcept = default; 37 BaseIterator& operator=(BaseIterator&&) = default; 38 39 // Sets the current bit the iterator points to. Set()40 void Set() { 41 if (!IsSet()) { 42 block_.Set(block_offset()); 43 44 is_block_changed_ = true; 45 ++set_bit_count_diff_; 46 } 47 } 48 49 // Clears the current bit the iterator points to. Clear()50 void Clear() { 51 if (IsSet()) { 52 block_.Clear(block_offset()); 53 54 is_block_changed_ = true; 55 --set_bit_count_diff_; 56 } 57 } 58 59 // Returns whether the current bit the iterator points to is set. IsSet()60 bool IsSet() { return BitVector::ConstBlock(block_).IsSet(block_offset()); } 61 62 // Returns the index of the current bit the iterator points to. index()63 uint32_t index() const { return index_; } 64 65 protected: 66 // Sets the index this iterator points to the given value. 67 // 68 // This method also performs some extra work on block boundaries 69 // as it caches the block to improve performance by reducing pointer 70 // chasing on every IsSet and Clear calls. SetIndex(uint32_t index)71 void SetIndex(uint32_t index) { 72 // We should always move the index forward. 73 PERFETTO_DCHECK(index >= index_); 74 75 uint32_t old_index = index_; 76 index_ = index; 77 78 // If we've reached the end of the iterator, just bail out. 79 if (index >= size_) 80 return; 81 82 uint32_t old_block = bv_->IndexToAddress(old_index).block_idx; 83 uint32_t new_block = bv_->IndexToAddress(index).block_idx; 84 85 // Fast path: we're in the same block so we don't need to do 86 // any other work. 87 if (PERFETTO_LIKELY(old_block == new_block)) 88 return; 89 90 // Slow path: we have to change block so this will involve flushing the old 91 // block and counts (if necessary). 92 OnBlockChange(old_block, new_block); 93 } 94 95 // Handles flushing count changes and caches a new block. 96 void OnBlockChange(uint32_t old_block, uint32_t new_block); 97 size()98 uint32_t size() const { return size_; } 99 bv()100 const BitVector& bv() const { return *bv_; } 101 102 private: 103 BaseIterator(const BaseIterator&) = delete; 104 BaseIterator& operator=(const BaseIterator&) = delete; 105 block_offset()106 BitVector::BlockOffset block_offset() const { 107 uint16_t bit_idx_inside_block = index_ % BitVector::Block::kBits; 108 109 BitVector::BlockOffset bo; 110 bo.word_idx = bit_idx_inside_block / BitVector::BitWord::kBits; 111 bo.bit_idx = bit_idx_inside_block % BitVector::BitWord::kBits; 112 return bo; 113 } 114 115 uint32_t index_ = 0; 116 uint32_t size_ = 0; 117 118 bool is_block_changed_ = false; 119 int32_t set_bit_count_diff_ = 0; 120 121 BitVector* bv_; 122 BitVector::Block block_{bv_->words_.data()}; 123 }; 124 125 // Iterator over all the bits in a bitvector. 126 class AllBitsIterator : public BaseIterator { 127 public: 128 AllBitsIterator(const BitVector*); 129 130 // Increments the iterator to point to the next bit. Next()131 void Next() { SetIndex(index() + 1); } 132 133 // Increments the iterator to skip the next |n| bits and point to the 134 // following one. 135 // Precondition: n >= 1 & index() + n <= size(). Skip(uint32_t n)136 void Skip(uint32_t n) { 137 PERFETTO_DCHECK(n >= 1); 138 PERFETTO_DCHECK(index() + n <= size()); 139 140 SetIndex(index() + n); 141 } 142 143 // Returns whether the iterator is valid. 144 operator bool() const { return index() < size(); } 145 }; 146 147 // Iterator over all the set bits in a bitvector. 148 // 149 // This iterator works by first finding a batch of indices of set bits. 150 // Then, the fast path involves simply incrementing a counter to go to 151 // the next index in this batch. On every batch boundary, we hit the 152 // slow path where we need to find another n set bits. 153 class SetBitsIterator : public BaseIterator { 154 public: 155 SetBitsIterator(const BitVector*); 156 157 // Increments the iterator to point to the next set bit. Next()158 void Next() { 159 // If we are out of bounds, just bail out. 160 if (PERFETTO_UNLIKELY(++set_bit_index_ >= set_bit_count_)) 161 return; 162 163 if (PERFETTO_UNLIKELY(set_bit_index_ % kBatchSize == 0)) 164 ReadSetBitBatch(batch_.back() + 1); 165 166 SetIndex(batch_[set_bit_index_ % kBatchSize]); 167 } 168 169 // Returns whether the iterator is valid. 170 operator bool() const { return set_bit_index_ < set_bit_count_; } 171 172 // Returns the index of the bit interms of set bits (i.e. how many times 173 // Next() has been called). ordinal()174 uint32_t ordinal() const { return set_bit_index_; } 175 176 private: 177 static constexpr uint32_t kBatchSize = 1024; 178 179 // Reads a full batch of set bit indices from the bitvector and stores them 180 // in |batch_| below. 181 // 182 // This batch of indices is used on the fast path to quickly jump between 183 // set bits. 184 void ReadSetBitBatch(uint32_t start_idx); 185 186 uint32_t set_bit_index_ = 0; 187 uint32_t set_bit_count_ = 0; 188 189 // Contains an array of indexes; each index points to a set bit in the 190 // bitvector. 191 std::array<uint32_t, kBatchSize> batch_; 192 }; 193 194 } // namespace internal 195 } // namespace trace_processor 196 } // namespace perfetto 197 198 #endif // SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_ 199