• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
18 #define SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_H_
19 
20 #include <algorithm>
21 #include <cstdint>
22 #include <initializer_list>
23 #include <iterator>
24 #include <utility>
25 #include <vector>
26 
27 #include "perfetto/base/compiler.h"
28 #include "perfetto/base/logging.h"
29 #include "perfetto/public/compiler.h"
30 
31 namespace perfetto {
32 namespace protos::pbzero {
33 class SerializedColumn_BitVector;
34 class SerializedColumn_BitVector_Decoder;
35 }  // namespace protos::pbzero
36 
37 namespace trace_processor {
38 namespace internal {
39 
40 class BaseIterator;
41 class SetBitsIterator;
42 
43 }  // namespace internal
44 
45 // A BitVector which compactly stores a vector of bools using a single bit
46 // for each bool.
47 class BitVector {
48  public:
49   static constexpr uint32_t kBitsInWord = 64;
50 
51   // Builder class which allows efficiently creating a BitVector by appending
52   // words. Using this class is generally far more efficient than trying to set
53   // bits directly in a BitVector or even appending one bit at a time.
54   class Builder {
55    public:
56     // Creates a Builder for building a BitVector of |size| bits.
57     explicit Builder(uint32_t size, uint32_t skip = 0)
words_(BlockCount (size)* Block::kWords)58         : words_(BlockCount(size) * Block::kWords),
59           global_bit_offset_(skip),
60           size_(size),
61           skipped_blocks_(skip / Block::kBits) {
62       PERFETTO_CHECK(global_bit_offset_ <= size_);
63     }
64 
65     // Appends a single bit to the builder.
66     // Note: |AppendWord| is far more efficient than this method so should be
67     // preferred.
Append(bool value)68     void Append(bool value) {
69       PERFETTO_DCHECK(global_bit_offset_ < size_);
70 
71       words_[global_bit_offset_ / BitWord::kBits] |=
72           static_cast<uint64_t>(value) << global_bit_offset_ % BitWord::kBits;
73       global_bit_offset_++;
74     }
75 
76     // Appends a whole word to the Builder. Builder has to end on a word
77     // boundary before calling this function.
AppendWord(uint64_t word)78     void AppendWord(uint64_t word) {
79       PERFETTO_DCHECK(global_bit_offset_ % BitWord::kBits == 0);
80       PERFETTO_DCHECK(global_bit_offset_ + BitWord::kBits <= size_);
81 
82       words_[global_bit_offset_ / BitWord::kBits] = word;
83       global_bit_offset_ += BitWord::kBits;
84     }
85 
86     // Creates a BitVector from this Builder.
Build()87     BitVector Build() && {
88       if (size_ == 0)
89         return {};
90 
91       std::vector<uint32_t> counts(BlockCount(size_));
92       PERFETTO_CHECK(skipped_blocks_ <= counts.size());
93       for (uint32_t i = skipped_blocks_ + 1; i < counts.size(); ++i) {
94         counts[i] = counts[i - 1] +
95                     ConstBlock(&words_[Block::kWords * (i - 1)]).CountSetBits();
96       }
97       return {std::move(words_), std::move(counts), size_};
98     }
99 
100     // Returns the number of bits which are in complete words which can be
101     // appended to this builder before having to fallback to |Append| due to
102     // being close to the end.
BitsInCompleteWordsUntilFull()103     uint32_t BitsInCompleteWordsUntilFull() const {
104       uint32_t next_word = WordCount(global_bit_offset_);
105       uint32_t end_word = WordFloor(size_);
106       uint32_t complete_words = next_word < end_word ? end_word - next_word : 0;
107       return complete_words * BitWord::kBits;
108     }
109 
110     // Returns the number of bits which should be appended using |Append| either
111     // hitting a word boundary (and thus able to use |AppendWord|) or until the
112     // BitVector is full (i.e. no more Appends should happen), whichever would
113     // happen first.
BitsUntilWordBoundaryOrFull()114     uint32_t BitsUntilWordBoundaryOrFull() const {
115       if (global_bit_offset_ == 0 && size_ < BitWord::kBits) {
116         return size_;
117       }
118       uint8_t word_bit_offset = global_bit_offset_ % BitWord::kBits;
119       return std::min(BitsUntilFull(),
120                       (BitWord::kBits - word_bit_offset) % BitWord::kBits);
121     }
122 
123     // Returns the number of bits which should be appended using |Append| before
124     // hitting a word boundary (and thus able to use |AppendWord|) or until the
125     // BitVector is full (i.e. no more Appends should happen).
BitsUntilFull()126     uint32_t BitsUntilFull() const { return size_ - global_bit_offset_; }
127 
128    private:
129     std::vector<uint64_t> words_;
130     uint32_t global_bit_offset_ = 0;
131     uint32_t size_ = 0;
132     uint32_t skipped_blocks_ = 0;
133   };
134 
135   // Creates an empty BitVector.
136   BitVector();
137 
138   BitVector(std::initializer_list<bool> init);
139 
140   // Creates a BitVector of |count| size filled with |value|.
141   explicit BitVector(uint32_t count, bool value = false);
142 
143   BitVector(const BitVector&) = delete;
144   BitVector& operator=(const BitVector&) = delete;
145 
146   // Enable moving BitVectors as they have no unmovable state.
147   BitVector(BitVector&&) noexcept = default;
148   BitVector& operator=(BitVector&&) = default;
149 
150   // Create a copy of the BitVector.
151   BitVector Copy() const;
152 
153   // Bitwise Not of the BitVector.
154   void Not();
155 
156   // Bitwise Or of the BitVector.
157   void Or(const BitVector&);
158 
159   // Bitwise And of the BitVector.
160   void And(const BitVector&);
161 
162   // Returns the size of the BitVector.
size()163   uint32_t size() const { return static_cast<uint32_t>(size_); }
164 
165   // Returns whether the bit at |idx| is set.
IsSet(uint32_t idx)166   bool IsSet(uint32_t idx) const {
167     PERFETTO_DCHECK(idx < size());
168 
169     Address addr = IndexToAddress(idx);
170     return ConstBlockFromIndex(addr.block_idx).IsSet(addr.block_offset);
171   }
172 
173   // Returns the number of set bits in the BitVector.
CountSetBits()174   uint32_t CountSetBits() const { return CountSetBits(size()); }
175 
176   // Returns the number of set bits between the start of the BitVector
177   // (inclusive) and the index |end| (exclusive).
CountSetBits(uint32_t end)178   uint32_t CountSetBits(uint32_t end) const {
179     if (end == 0)
180       return 0;
181 
182     // Although the external interface we present uses an exclusive |end|,
183     // internally it's a lot nicer to work with an inclusive |end| (mainly
184     // because we get block rollovers on exclusive ends which means we need
185     // to have if checks to ensure we don't overflow the number of blocks).
186     Address addr = IndexToAddress(end - 1);
187 
188     // Add the number of set bits until the start of the block to the number
189     // of set bits until the end address inside the block.
190     return counts_[addr.block_idx] +
191            ConstBlockFromIndex(addr.block_idx).CountSetBits(addr.block_offset);
192   }
193 
194   // Returns the index of the |n|th set bit. Should only be called with |n| <
195   // CountSetBits().
IndexOfNthSet(uint32_t n)196   uint32_t IndexOfNthSet(uint32_t n) const {
197     PERFETTO_DCHECK(n < CountSetBits());
198 
199     // First search for the block which, up until the start of it, has more than
200     // n bits set. Note that this should never return |counts.begin()| as
201     // that should always be 0.
202     // TODO(lalitm): investigate whether we can make this faster with small
203     // binary search followed by a linear search instead of binary searching the
204     // full way.
205     auto it = std::upper_bound(counts_.begin(), counts_.end(), n);
206     PERFETTO_DCHECK(it != counts_.begin());
207 
208     // Go back one block to find the block which has the bit we are looking for.
209     uint32_t block_idx =
210         static_cast<uint32_t>(std::distance(counts_.begin(), it) - 1);
211 
212     // Figure out how many set bits forward we are looking inside the block
213     // by taking away the number of bits at the start of the block from n.
214     uint32_t set_in_block = n - counts_[block_idx];
215 
216     // Compute the address of the bit in the block then convert the full
217     // address back to an index.
218     BlockOffset block_offset =
219         ConstBlockFromIndex(block_idx).IndexOfNthSet(set_in_block);
220     return AddressToIndex(Address{block_idx, block_offset});
221   }
222 
223   // Sets the bit at index |idx| to true and returns the previous value.
Set(uint32_t idx)224   bool Set(uint32_t idx) {
225     // Set the bit to the correct value inside the block but store the old
226     // bit to help fix the counts.
227     auto addr = IndexToAddress(idx);
228     bool old_value =
229         ConstBlockFromIndex(addr.block_idx).IsSet(addr.block_offset);
230 
231     // If the old value was unset, set the bit and add one to the count.
232     if (PERFETTO_LIKELY(!old_value)) {
233       BlockFromIndex(addr.block_idx).Set(addr.block_offset);
234 
235       auto size = static_cast<uint32_t>(counts_.size());
236       for (uint32_t i = addr.block_idx + 1; i < size; ++i) {
237         counts_[i]++;
238       }
239     }
240     return old_value;
241   }
242 
243   // Sets the bit at index |idx| to false.
Clear(uint32_t idx)244   void Clear(uint32_t idx) {
245     // Set the bit to the correct value inside the block but store the old
246     // bit to help fix the counts.
247     auto addr = IndexToAddress(idx);
248     bool old_value =
249         ConstBlockFromIndex(addr.block_idx).IsSet(addr.block_offset);
250 
251     // If the old value was set, clear the bit and subtract one from all the
252     // counts.
253     if (PERFETTO_LIKELY(old_value)) {
254       BlockFromIndex(addr.block_idx).Clear(addr.block_offset);
255 
256       auto size = static_cast<uint32_t>(counts_.size());
257       for (uint32_t i = addr.block_idx + 1; i < size; ++i) {
258         counts_[i]--;
259       }
260     }
261   }
262 
263   // Appends true to the BitVector.
AppendTrue()264   void AppendTrue() {
265     AppendFalse();
266     Address addr = IndexToAddress(size() - 1);
267     BlockFromIndex(addr.block_idx).Set(addr.block_offset);
268   }
269 
270   // Appends false to the BitVector.
AppendFalse()271   void AppendFalse() {
272     Address addr = IndexToAddress(size_);
273     uint32_t old_blocks_size = BlockCount();
274     uint32_t new_blocks_size = addr.block_idx + 1;
275 
276     if (PERFETTO_UNLIKELY(new_blocks_size > old_blocks_size)) {
277       uint32_t t = CountSetBits();
278       words_.resize(words_.size() + Block::kWords);
279       counts_.emplace_back(t);
280     }
281 
282     size_++;
283     // We don't need to clear the bit as we ensure that anything after
284     // size_ is always set to false.
285   }
286 
287   // Resizes the BitVector to the given |size|.
288   // Truncates the BitVector if |size| < |size()| or fills the new space with
289   // |filler| if |size| > |size()|. Calling this method is a noop if |size| ==
290   // |size()|.
291   void Resize(uint32_t new_size, bool filler = false);
292 
293   // Creates a BitVector of size |end| with the bits between |start| and |end|
294   // filled by calling the filler function |f(index of bit)|.
295   //
296   // As an example, suppose RangeForTesting(3, 7, [](x) { return x < 5 }). This
297   // would result in the following BitVector: [0 0 0 1 1 0 0]
298   template <typename Filler = bool(uint32_t)>
RangeForTesting(uint32_t start,uint32_t end,Filler f)299   PERFETTO_WARN_UNUSED_RESULT static BitVector RangeForTesting(uint32_t start,
300                                                                uint32_t end,
301                                                                Filler f) {
302     // Compute the block index and BitVector index where we start and end
303     // working one block at a time.
304     uint32_t start_fast_block = BlockCount(start);
305     uint32_t start_fast_idx = BlockToIndex(start_fast_block);
306     BitVector bv(start, false);
307 
308     // Minimum value of start_fast_idx is numer of bits in block, so we need to
309     // seperate calculation for shorter ranges.
310     if (start_fast_idx > end) {
311       for (uint32_t i = start; i < end; ++i) {
312         bv.Append(f(i));
313       }
314       return bv;
315     }
316 
317     uint32_t end_fast_block = BlockFloor(end);
318     uint32_t end_fast_idx = BlockToIndex(end_fast_block);
319 
320     // Fill up to |start_fast_index| with values from the filler.
321     for (uint32_t i = start; i < start_fast_idx; ++i) {
322       bv.Append(f(i));
323     }
324 
325     // Assert words_ vector is full and size_ is properly calculated.
326     PERFETTO_DCHECK(bv.words_.size() % Block::kWords == 0);
327     PERFETTO_DCHECK(bv.words_.size() * BitWord::kBits == bv.size_);
328 
329     // At this point we can work one block at a time.
330     bv.words_.resize(bv.words_.size() +
331                      Block::kWords * (end_fast_block - start_fast_block));
332     for (uint32_t i = start_fast_block; i < end_fast_block; ++i) {
333       uint64_t* block_start_word = &bv.words_[i * Block::kWords];
334       Block(block_start_word).FromFiller(bv.size_, f);
335       bv.counts_.emplace_back(bv.CountSetBits());
336       bv.size_ += Block::kBits;
337     }
338 
339     // Add the last few elements to finish up to |end|.
340     for (uint32_t i = end_fast_idx; i < end; ++i) {
341       bv.Append(f(i));
342     }
343 
344     return bv;
345   }
346 
347   // Creates BitVector from a vector of sorted indices. Set bits in the
348   // resulting BitVector are values from the index vector.
349   // Note for callers - the passed index vector has to:
350   // - be sorted
351   // - have first element >= 0
352   // - last value smaller than numeric limit of uint32_t.
353   PERFETTO_WARN_UNUSED_RESULT static BitVector FromSortedIndexVector(
354       const std::vector<int64_t>&);
355 
356   // Creates a BitVector of size `min(range_end, size())` with bits between
357   // |start| and |end| filled with corresponding bits from |this| BitVector.
358   PERFETTO_WARN_UNUSED_RESULT BitVector
359   IntersectRange(uint32_t range_start, uint32_t range_end) const;
360 
361   // Requests the removal of unused capacity.
362   // Matches the semantics of std::vector::shrink_to_fit.
ShrinkToFit()363   void ShrinkToFit() {
364     words_.shrink_to_fit();
365     counts_.shrink_to_fit();
366   }
367 
368   // Updates the ith set bit of this BitVector with the value of
369   // |other.IsSet(i)|.
370   //
371   // This is the best way to batch update all the bits which are set; for
372   // example when filtering rows, we want to filter all rows which are currently
373   // included but ignore rows which have already been excluded.
374   //
375   // For example suppose the following:
376   // this:  1 1 0 0 1 0 1
377   // other: 0 1 1 0
378   // This will change this to the following:
379   // this:  0 1 0 0 1 0 0
380   void UpdateSetBits(const BitVector& other);
381 
382   // For each set bit position  in |other|, Selects the value of each bit in
383   // |this| and stores them contiguously in |this|.
384   //
385   // Precondition: |this.size()| <= |other.size()|.
386   //
387   // For example suppose the following:
388   // this:  1 1 0 0 1 0 1
389   // other: 0 1 0 1 0 1 0 0 1 0
390   // |this| will change this to the following:
391   // this:  1 0 0
392   void SelectBits(const BitVector& other);
393 
394   // Returns the approximate cost (in bytes) of storing a BitVector with size
395   // |n|. This can be used to make decisions about whether using a BitVector is
396   // worthwhile.
397   // This cost should not be treated as exact - it just gives an indication of
398   // the memory needed.
ApproxBytesCost(uint32_t n)399   static constexpr uint32_t ApproxBytesCost(uint32_t n) {
400     // The two main things making up a BitVector is the cost of the blocks of
401     // bits and the cost of the counts vector.
402     return BlockCount(n) * Block::kBits + BlockCount(n) * sizeof(uint32_t);
403   }
404 
405   // Returns a vector<uint32_t> containing the indices of all the set bits
406   // in the BitVector.
407   std::vector<uint32_t> GetSetBitIndices() const;
408 
409   // Serialize internals of BitVector to proto.
410   void Serialize(protos::pbzero::SerializedColumn_BitVector* msg) const;
411 
412   // Deserialize BitVector from proto.
413   void Deserialize(
414       const protos::pbzero::SerializedColumn_BitVector_Decoder& bv_msg);
415 
416  private:
417   using SetBitsIterator = internal::SetBitsIterator;
418   friend class internal::BaseIterator;
419   friend class internal::SetBitsIterator;
420 
421   // Represents the offset of a bit within a block.
422   struct BlockOffset {
423     uint16_t word_idx;
424     uint16_t bit_idx;
425   };
426 
427   // Represents the address of a bit within the BitVector.
428   struct Address {
429     uint32_t block_idx;
430     BlockOffset block_offset;
431   };
432 
433   // Represents the smallest collection of bits we can refer to as
434   // one unit.
435   //
436   // Currently, this is implemented as a 64 bit integer as this is the
437   // largest type which we can assume to be present on all platforms.
438   class BitWord {
439    public:
440     static constexpr uint32_t kBits = 64;
441 
BitWord(uint64_t * word)442     explicit BitWord(uint64_t* word) : word_(word) {}
443 
444     // Bitwise ors the given |mask| to the current value.
Or(uint64_t mask)445     void Or(uint64_t mask) { *word_ |= mask; }
446 
447     // Bitwise ands the given |mask| to the current value.
And(uint64_t mask)448     void And(uint64_t mask) { *word_ &= mask; }
449 
450     // Bitwise not.
Not()451     void Not() { *word_ = ~(*word_); }
452 
453     // Sets the bit at the given index to true.
Set(uint32_t idx)454     void Set(uint32_t idx) {
455       PERFETTO_DCHECK(idx < kBits);
456 
457       // Or the value for the true shifted up to |idx| with the word.
458       Or(1ull << idx);
459     }
460 
461     // Sets the bit at the given index to false.
Clear(uint32_t idx)462     void Clear(uint32_t idx) {
463       PERFETTO_DCHECK(idx < kBits);
464 
465       // And the integer of all bits set apart from |idx| with the word.
466       *word_ &= ~(1ull << idx);
467     }
468 
469     // Clears all the bits (i.e. sets the atom to zero).
ClearAll()470     void ClearAll() { *word_ = 0; }
471 
472     // Retains all bits up to and including the bit at |idx| and clears
473     // all bits after this point.
ClearAfter(uint32_t idx)474     void ClearAfter(uint32_t idx) {
475       PERFETTO_DCHECK(idx < kBits);
476       *word_ = WordUntil(idx);
477     }
478 
479     // Sets all bits between the bit at |start| and |end| (inclusive).
Set(uint32_t start,uint32_t end)480     void Set(uint32_t start, uint32_t end) {
481       uint32_t diff = end - start;
482       *word_ |= (MaskAllBitsSetUntil(diff) << static_cast<uint64_t>(start));
483     }
484 
485     // Return a mask of all the bits up to and including bit at |idx|.
MaskAllBitsSetUntil(uint32_t idx)486     static uint64_t MaskAllBitsSetUntil(uint32_t idx) {
487       // Start with 1 and shift it up (idx + 1) bits we get:
488       // top : 00000000010000000
489       uint64_t top = 1ull << ((idx + 1ull) % kBits);
490 
491       // We need to handle the case where idx == 63. In this case |top| will be
492       // zero because 1 << ((idx + 1) % 64) == 1 << (64 % 64) == 1.
493       // In this case, we actually want top == 0. We can do this by shifting
494       // down by (idx + 1) / kBits - this will be a noop for every index other
495       // than idx == 63. This should also be free on x86 because of the mod
496       // instruction above.
497       top = top >> ((idx + 1) / kBits);
498 
499       // Then if we take away 1, we get precisely the mask we want.
500       return top - 1u;
501     }
502 
503    private:
504     // Returns the bits up to and including the bit at |idx|.
WordUntil(uint32_t idx)505     uint64_t WordUntil(uint32_t idx) const {
506       PERFETTO_DCHECK(idx < kBits);
507 
508       // To understand what is happeninng here, consider an example.
509       // Suppose we want to all the bits up to the 7th bit in the atom
510       //               7th
511       //                |
512       //                v
513       // atom: 01010101011111000
514       //
515       // The easiest way to do this would be if we had a mask with only
516       // the bottom 7 bits set:
517       // mask: 00000000001111111
518       uint64_t mask = MaskAllBitsSetUntil(idx);
519 
520       // Finish up by and'ing the atom with the computed mask.
521       return *word_ & mask;
522     }
523 
524     uint64_t* word_;
525   };
526 
527   class ConstBitWord {
528    public:
529     static constexpr uint32_t kBits = 64;
530 
ConstBitWord(const uint64_t * word)531     explicit ConstBitWord(const uint64_t* word) : word_(word) {}
532 
533     // Returns whether the bit at the given index is set.
IsSet(uint32_t idx)534     bool IsSet(uint32_t idx) const {
535       PERFETTO_DCHECK(idx < kBits);
536       return (*word_ >> idx) & 1ull;
537     }
538 
539     // Returns the index of the nth set bit.
540     // Undefined if |n| >= |CountSetBits()|.
IndexOfNthSet(uint32_t n)541     uint16_t IndexOfNthSet(uint32_t n) const {
542       PERFETTO_DCHECK(n < kBits);
543 
544       // The below code is very dense but essentially computes the nth set
545       // bit inside |atom| in the "broadword" style of programming (sometimes
546       // referred to as "SIMD within a register").
547       //
548       // Instead of treating a uint64 as an individual unit, broadword
549       // algorithms treat them as a packed vector of uint8. By doing this, they
550       // allow branchless algorithms when considering bits of a uint64.
551       //
552       // In benchmarks, this algorithm has found to be the fastest, portable
553       // way of computing the nth set bit (if we were only targetting new
554       // versions of x64, we could also use pdep + ctz but unfortunately
555       // this would fail on WASM - this about 2.5-3x faster on x64).
556       //
557       // The code below was taken from the paper
558       // http://vigna.di.unimi.it/ftp/papers/Broadword.pdf
559       uint64_t s = *word_ - ((*word_ & 0xAAAAAAAAAAAAAAAA) >> 1);
560       s = (s & 0x3333333333333333) + ((s >> 2) & 0x3333333333333333);
561       s = ((s + (s >> 4)) & 0x0F0F0F0F0F0F0F0F) * L8;
562 
563       uint64_t b = (BwLessThan(s, n * L8) >> 7) * L8 >> 53 & ~7ull;
564       uint64_t l = n - ((s << 8) >> b & 0xFF);
565       s = (BwGtZero(((*word_ >> b & 0xFF) * L8) & 0x8040201008040201) >> 7) *
566           L8;
567 
568       uint64_t ret = b + ((BwLessThan(s, l * L8) >> 7) * L8 >> 56);
569 
570       return static_cast<uint16_t>(ret);
571     }
572 
573     // Returns the number of set bits.
CountSetBits()574     uint32_t CountSetBits() const {
575       return static_cast<uint32_t>(PERFETTO_POPCOUNT(*word_));
576     }
577 
578     // Returns the number of set bits up to and including the bit at |idx|.
CountSetBits(uint32_t idx)579     uint32_t CountSetBits(uint32_t idx) const {
580       PERFETTO_DCHECK(idx < kBits);
581       return static_cast<uint32_t>(PERFETTO_POPCOUNT(WordUntil(idx)));
582     }
583 
584    private:
585     // Constant with all the low bit of every byte set.
586     static constexpr uint64_t L8 = 0x0101010101010101;
587 
588     // Constant with all the high bit of every byte set.
589     static constexpr uint64_t H8 = 0x8080808080808080;
590 
591     // Returns a packed uint64 encoding whether each byte of x is less
592     // than each corresponding byte of y.
593     // This is computed in the "broadword" style of programming; see
594     // IndexOfNthSet for details on this.
BwLessThan(uint64_t x,uint64_t y)595     static uint64_t BwLessThan(uint64_t x, uint64_t y) {
596       return (((y | H8) - (x & ~H8)) ^ x ^ y) & H8;
597     }
598 
599     // Returns a packed uint64 encoding whether each byte of x is greater
600     // than or equal zero.
601     // This is computed in the "broadword" style of programming; see
602     // IndexOfNthSet for details on this.
BwGtZero(uint64_t x)603     static uint64_t BwGtZero(uint64_t x) { return (((x | H8) - L8) | x) & H8; }
604 
605     // Returns the bits up to and including the bit at |idx|.
WordUntil(uint32_t idx)606     uint64_t WordUntil(uint32_t idx) const {
607       PERFETTO_DCHECK(idx < kBits);
608 
609       // To understand what is happeninng here, consider an example.
610       // Suppose we want to all the bits up to the 7th bit in the atom
611       //               7th
612       //                |
613       //                v
614       // atom: 01010101011111000
615       //
616       // The easiest way to do this would be if we had a mask with only
617       // the bottom 7 bits set:
618       // mask: 00000000001111111
619       uint64_t mask = BitWord::MaskAllBitsSetUntil(idx);
620 
621       // Finish up by and'ing the atom with the computed mask.
622       return *word_ & mask;
623     }
624 
625     const uint64_t* word_;
626   };
627 
628   // Represents a group of bits with a bitcount such that it is
629   // efficient to work on these bits.
630   //
631   // On x86 architectures we generally target for trace processor, the
632   // size of a cache line is 64 bytes (or 512 bits). For this reason,
633   // we make the size of the block contain 8 atoms as 8 * 64 == 512.
634   class Block {
635    public:
636     // See class documentation for how these constants are chosen.
637     static constexpr uint16_t kWords = 8;
638     static constexpr uint32_t kBits = kWords * BitWord::kBits;
639 
Block(uint64_t * start_word)640     explicit Block(uint64_t* start_word) : start_word_(start_word) {}
641 
642     // Sets the bit at the given address to true.
Set(const BlockOffset & addr)643     void Set(const BlockOffset& addr) {
644       PERFETTO_DCHECK(addr.word_idx < kWords);
645       BitWord(&start_word_[addr.word_idx]).Set(addr.bit_idx);
646     }
647 
648     // Sets the bit at the given address to false.
Clear(const BlockOffset & addr)649     void Clear(const BlockOffset& addr) {
650       PERFETTO_DCHECK(addr.word_idx < kWords);
651 
652       BitWord(&start_word_[addr.word_idx]).Clear(addr.bit_idx);
653     }
654 
655     // Retains all bits up to and including the bit at |addr| and clears
656     // all bits after this point.
ClearAfter(const BlockOffset & offset)657     void ClearAfter(const BlockOffset& offset) {
658       PERFETTO_DCHECK(offset.word_idx < kWords);
659 
660       // In the first atom, keep the bits until the address specified.
661       BitWord(&start_word_[offset.word_idx]).ClearAfter(offset.bit_idx);
662 
663       // For all subsequent atoms, we just clear the whole atom.
664       for (uint32_t i = offset.word_idx + 1; i < kWords; ++i) {
665         BitWord(&start_word_[i]).ClearAll();
666       }
667     }
668 
669     // Set all the bits between the offsets given by |start| and |end|
670     // (inclusive).
Set(const BlockOffset & start,const BlockOffset & end)671     void Set(const BlockOffset& start, const BlockOffset& end) {
672       if (start.word_idx == end.word_idx) {
673         // If there is only one word we will change, just set the range within
674         // the word.
675         BitWord(&start_word_[start.word_idx]).Set(start.bit_idx, end.bit_idx);
676         return;
677       }
678 
679       // Otherwise, we have more than one word to set. To do this, we will
680       // do this in three steps.
681 
682       // First, we set the first word from the start to the end of the word.
683       BitWord(&start_word_[start.word_idx])
684           .Set(start.bit_idx, BitWord::kBits - 1);
685 
686       // Next, we set all words (except the last).
687       for (uint32_t i = start.word_idx + 1; i < end.word_idx; ++i) {
688         BitWord(&start_word_[i]).Set(0, BitWord::kBits - 1);
689       }
690 
691       // Finally, we set the word block from the start to the end offset.
692       BitWord(&start_word_[end.word_idx]).Set(0, end.bit_idx);
693     }
694 
Or(Block & sec)695     void Or(Block& sec) {
696       for (uint32_t i = 0; i < kWords; ++i) {
697         BitWord(&start_word_[i]).Or(sec.start_word_[i]);
698       }
699     }
700 
701     template <typename Filler>
FromFiller(uint32_t offset,Filler f)702     void FromFiller(uint32_t offset, Filler f) {
703       // We choose to iterate the bits as the outer loop as this allows us
704       // to reuse the mask and the bit offset between iterations of the loop.
705       // This makes a small (but noticable) impact in the performance of this
706       // function.
707       for (uint32_t i = 0; i < BitWord::kBits; ++i) {
708         uint64_t mask = 1ull << i;
709         uint32_t offset_with_bit = offset + i;
710         for (uint32_t j = 0; j < Block::kWords; ++j) {
711           bool res = f(offset_with_bit + j * BitWord::kBits);
712           BitWord(&start_word_[j]).Or(res ? mask : 0);
713         }
714       }
715     }
716 
ReplaceWith(Block block)717     void ReplaceWith(Block block) {
718       for (uint32_t i = 0; i < BitWord::kBits; ++i) {
719         start_word_[i] = block.start_word()[i];
720       }
721     }
722 
start_word()723     uint64_t* start_word() { return start_word_; }
724 
725    private:
726     uint64_t* start_word_;
727   };
728 
729   class ConstBlock {
730    public:
731     // See class documentation for how these constants are chosen.
732     static constexpr uint16_t kWords = Block::kWords;
733     static constexpr uint32_t kBits = kWords * BitWord::kBits;
734 
ConstBlock(const uint64_t * start_word)735     explicit ConstBlock(const uint64_t* start_word) : start_word_(start_word) {}
ConstBlock(Block block)736     explicit ConstBlock(Block block) : start_word_(block.start_word()) {}
737 
738     // Returns whether the bit at the given address is set.
IsSet(const BlockOffset & addr)739     bool IsSet(const BlockOffset& addr) const {
740       PERFETTO_DCHECK(addr.word_idx < kWords);
741       return ConstBitWord(start_word_ + addr.word_idx).IsSet(addr.bit_idx);
742     }
743 
744     // Gets the offset of the nth set bit in this block.
IndexOfNthSet(uint32_t n)745     BlockOffset IndexOfNthSet(uint32_t n) const {
746       uint32_t count = 0;
747       for (uint16_t i = 0; i < kWords; ++i) {
748         // Keep a running count of all the set bits in the atom.
749         uint32_t value = count + ConstBitWord(start_word_ + i).CountSetBits();
750         if (value <= n) {
751           count = value;
752           continue;
753         }
754 
755         // The running count of set bits is more than |n|. That means this
756         // atom contains the bit we are looking for.
757 
758         // Take away the number of set bits to the start of this atom from
759         // |n|.
760         uint32_t set_in_atom = n - count;
761 
762         // Figure out the index of the set bit inside the atom and create the
763         // address of this bit from that.
764         uint16_t bit_idx =
765             ConstBitWord(start_word_ + i).IndexOfNthSet(set_in_atom);
766         PERFETTO_DCHECK(bit_idx < 64);
767         return BlockOffset{i, bit_idx};
768       }
769       PERFETTO_FATAL("Index out of bounds");
770     }
771 
772     // Gets the number of set bits within a block up to and including the bit
773     // at the given address.
CountSetBits(const BlockOffset & addr)774     uint32_t CountSetBits(const BlockOffset& addr) const {
775       PERFETTO_DCHECK(addr.word_idx < kWords);
776 
777       // Count all the set bits in the atom until we reach the last atom
778       // index.
779       uint32_t count = 0;
780       for (uint32_t i = 0; i < addr.word_idx; ++i) {
781         count += ConstBitWord(&start_word_[i]).CountSetBits();
782       }
783 
784       // For the last atom, only count the bits upto and including the bit
785       // index.
786       return count + ConstBitWord(&start_word_[addr.word_idx])
787                          .CountSetBits(addr.bit_idx);
788     }
789 
790     // Gets the number of set bits within a block up.
CountSetBits()791     uint32_t CountSetBits() const {
792       uint32_t count = 0;
793       for (uint32_t i = 0; i < kWords; ++i) {
794         count += ConstBitWord(&start_word_[i]).CountSetBits();
795       }
796       return count;
797     }
798 
799    private:
800     const uint64_t* start_word_;
801   };
802 
803   BitVector(std::vector<uint64_t> words,
804             std::vector<uint32_t> counts,
805             uint32_t size);
806 
807   // Returns the number of 8 elements blocks in the BitVector.
BlockCount()808   uint32_t BlockCount() {
809     return static_cast<uint32_t>(words_.size()) / Block::kWords;
810   }
811 
BlockFromIndex(uint32_t idx)812   Block BlockFromIndex(uint32_t idx) {
813     PERFETTO_DCHECK(Block::kWords * (idx + 1) <= words_.size());
814 
815     uint64_t* start_word = &words_[Block::kWords * idx];
816     return Block(start_word);
817   }
818 
ConstBlockFromIndex(uint32_t idx)819   ConstBlock ConstBlockFromIndex(uint32_t idx) const {
820     PERFETTO_DCHECK(Block::kWords * (idx + 1) <= words_.size());
821 
822     return ConstBlock(&words_[Block::kWords * idx]);
823   }
824 
825   // Set all the bits between the addresses given by |start| and |end|
826   // (inclusive).
827   // Note: this method does not update the counts vector - that is the
828   // responsibility of the caller.
Set(const Address & start,const Address & end)829   void Set(const Address& start, const Address& end) {
830     static constexpr BlockOffset kFirstBlockOffset = BlockOffset{0, 0};
831     static constexpr BlockOffset kLastBlockOffset =
832         BlockOffset{Block::kWords - 1, BitWord::kBits - 1};
833 
834     if (start.block_idx == end.block_idx) {
835       // If there is only one block we will change, just set the range within
836       // the block.
837       BlockFromIndex(start.block_idx).Set(start.block_offset, end.block_offset);
838       return;
839     }
840 
841     // Otherwise, we have more than one block to set. To do this, we will
842     // do this in three steps.
843 
844     // First, we set the first block from the start to the end of the block.
845     BlockFromIndex(start.block_idx).Set(start.block_offset, kLastBlockOffset);
846 
847     // Next, we set all blocks (except the last).
848     for (uint32_t cur_block_idx = start.block_idx + 1;
849          cur_block_idx < end.block_idx; ++cur_block_idx) {
850       BlockFromIndex(cur_block_idx).Set(kFirstBlockOffset, kLastBlockOffset);
851     }
852 
853     // Finally, we set the last block from the start to the end offset.
854     BlockFromIndex(end.block_idx).Set(kFirstBlockOffset, end.block_offset);
855   }
856 
857   // Helper function to append a bit. Generally, prefer to call AppendTrue
858   // or AppendFalse instead of this function if you know the type - they will
859   // be faster.
Append(bool value)860   void Append(bool value) {
861     if (value) {
862       AppendTrue();
863     } else {
864       AppendFalse();
865     }
866   }
867 
868   // Iterate all the set bits in the BitVector.
869   //
870   // Usage:
871   // for (auto it = bv.IterateSetBits(); it; it.Next()) {
872   //   ...
873   // }
874   SetBitsIterator IterateSetBits() const;
875 
876   // Returns the index of the word which would store |idx|.
WordFloor(uint32_t idx)877   static constexpr uint32_t WordFloor(uint32_t idx) {
878     return idx / BitWord::kBits;
879   }
880 
881   // Returns number of words (int64_t) required to store |bit_count| bits.
WordCount(uint32_t bit_count)882   static uint32_t WordCount(uint32_t bit_count) {
883     // See |BlockCount| for an explanation of this trick.
884     return (bit_count + BitWord::kBits - 1) / BitWord::kBits;
885   }
886 
IndexToAddress(uint32_t idx)887   static Address IndexToAddress(uint32_t idx) {
888     Address a;
889     a.block_idx = idx / Block::kBits;
890 
891     uint16_t bit_idx_inside_block = idx % Block::kBits;
892     a.block_offset.word_idx = bit_idx_inside_block / BitWord::kBits;
893     a.block_offset.bit_idx = bit_idx_inside_block % BitWord::kBits;
894     return a;
895   }
896 
AddressToIndex(Address addr)897   static uint32_t AddressToIndex(Address addr) {
898     return addr.block_idx * Block::kBits +
899            addr.block_offset.word_idx * BitWord::kBits +
900            addr.block_offset.bit_idx;
901   }
902 
903   // Returns number of blocks (arrays of 8 int64_t) required to store
904   // |bit_count| bits.
905   //
906   // This is useful to be able to find indices where "fast" algorithms can
907   // start which work on entire blocks.
BlockCount(uint32_t bit_count)908   static constexpr uint32_t BlockCount(uint32_t bit_count) {
909     // Adding |Block::kBits - 1| gives us a quick way to get the count. We
910     // do this instead of adding 1 at the end because that gives incorrect
911     // answers for bit_count % Block::kBits == 0.
912     return (bit_count + Block::kBits - 1) / Block::kBits;
913   }
914 
915   // Returns the index of the block which would store |idx|.
BlockFloor(uint32_t idx)916   static constexpr uint32_t BlockFloor(uint32_t idx) {
917     return idx / Block::kBits;
918   }
919 
920   // Converts a block index to a index in the BitVector.
BlockToIndex(uint32_t block_idx)921   static constexpr uint32_t BlockToIndex(uint32_t block_idx) {
922     return block_idx * Block::kBits;
923   }
924 
925   // Updates the counts in |counts| by counting the set bits in |words|.
UpdateCounts(const std::vector<uint64_t> & words,std::vector<uint32_t> & counts)926   static void UpdateCounts(const std::vector<uint64_t>& words,
927                            std::vector<uint32_t>& counts) {
928     PERFETTO_CHECK(words.size() == counts.size() * Block::kWords);
929     for (uint32_t i = 1; i < counts.size(); ++i) {
930       counts[i] = counts[i - 1] +
931                   ConstBlock(&words[Block::kWords * (i - 1)]).CountSetBits();
932     }
933   }
934 
935   uint32_t size_ = 0;
936   // See class documentation for how these constants are chosen.
937   static constexpr uint16_t kWordsInBlock = Block::kWords;
938   static constexpr uint32_t kBitsInBlock = kWordsInBlock * BitWord::kBits;
939   std::vector<uint32_t> counts_;
940   std::vector<uint64_t> words_;
941 };
942 
943 }  // namespace trace_processor
944 }  // namespace perfetto
945 
946 #endif  // SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_H_
947