xref: /aosp_15_r20/external/perfetto/src/trace_processor/containers/row_map.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 #include "src/trace_processor/containers/row_map.h"
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <unordered_set>
22 #include <utility>
23 #include <variant>
24 #include <vector>
25 
26 #include "perfetto/base/logging.h"
27 #include "src/trace_processor/containers/bit_vector.h"
28 #include "src/trace_processor/containers/row_map_algorithms.h"
29 
30 namespace perfetto {
31 namespace trace_processor {
32 
33 namespace {
34 
35 using Range = RowMap::Range;
36 using OutputIndex = RowMap::OutputIndex;
37 using Variant = std::variant<Range, BitVector, std::vector<OutputIndex>>;
38 
Select(Range range,Range selector)39 RowMap Select(Range range, Range selector) {
40   PERFETTO_DCHECK(selector.start <= selector.end);
41   PERFETTO_DCHECK(selector.end <= range.size());
42 
43   return RowMap(range.start + selector.start, range.start + selector.end);
44 }
45 
Select(Range range,const BitVector & selector)46 RowMap Select(Range range, const BitVector& selector) {
47   PERFETTO_DCHECK(selector.size() <= range.size());
48 
49   // If |start| == 0 and |selector.size()| <= |end - start| (which is a
50   // precondition for this function), the BitVector we generate is going to be
51   // exactly |selector|.
52   //
53   // This is a fast path for the common situation where, post-filtering,
54   // SelectRows is called on all the table RowMaps with a BitVector. The self
55   // RowMap will always be a range so we expect this case to be hit at least
56   // once every filter operation.
57   if (range.start == 0u)
58     return RowMap(selector.Copy());
59 
60   // We only need to resize to |start| + |selector.size()| as we know any rows
61   // not covered by |selector| are going to be removed below.
62   BitVector bv(range.start, false);
63   bv.Resize(range.start + selector.size(), true);
64 
65   bv.UpdateSetBits(selector);
66   return RowMap(std::move(bv));
67 }
68 
Select(Range range,const std::vector<OutputIndex> & selector)69 RowMap Select(Range range, const std::vector<OutputIndex>& selector) {
70   std::vector<uint32_t> iv(selector.size());
71   for (uint32_t i = 0; i < selector.size(); ++i) {
72     PERFETTO_DCHECK(selector[i] < range.size());
73     iv[i] = selector[i] + range.start;
74   }
75   return RowMap(std::move(iv));
76 }
77 
Select(const BitVector & bv,Range selector)78 RowMap Select(const BitVector& bv, Range selector) {
79   PERFETTO_DCHECK(selector.end <= bv.CountSetBits());
80   if (selector.empty()) {
81     return {};
82   }
83   // If we're simply selecting every element in the bitvector, just
84   // return a copy of the BitVector without iterating.
85   if (selector.start == 0 && selector.end == bv.CountSetBits()) {
86     return RowMap(bv.Copy());
87   }
88   return RowMap(bv.IntersectRange(bv.IndexOfNthSet(selector.start),
89                                   bv.IndexOfNthSet(selector.end - 1) + 1));
90 }
91 
Select(const BitVector & bv,const BitVector & selector)92 RowMap Select(const BitVector& bv, const BitVector& selector) {
93   BitVector ret = bv.Copy();
94   ret.UpdateSetBits(selector);
95   return RowMap(std::move(ret));
96 }
97 
Select(const BitVector & bv,const std::vector<uint32_t> & selector)98 RowMap Select(const BitVector& bv, const std::vector<uint32_t>& selector) {
99   // The value of this constant was found by considering the benchmarks
100   // |BM_SelectBvWithIvByConvertToIv| and |BM_SelectBvWithIvByIndexOfNthSet|.
101   //
102   // We use this to find the ratio between |bv.CountSetBits()| and
103   // |selector.size()| where |SelectBvWithIvByIndexOfNthSet| was found to be
104   // faster than |SelectBvWithIvByConvertToIv|.
105   //
106   // Note: as of writing this, the benchmarks do not take into account the fill
107   // ratio of the BitVector; they assume 50% rate which almost never happens in
108   // practice. In the future, we could also take this into account (by
109   // considering the ratio between bv.size() and bv.CountSetBits()) but this
110   // causes an explosion in the state space for the benchmark so we're not
111   // considering this today.
112   //
113   // The current value of the constant was picked by running these benchmarks on
114   // a E5-2690 v4 and finding the crossover point using a spreadsheet.
115   constexpr uint32_t kIndexOfSetBitToSelectorRatio = 4;
116 
117   // If the selector is larger than a threshold, it's more efficient to convert
118   // the entire BitVector to an index vector and use SelectIvWithIv instead.
119   if (bv.CountSetBits() / kIndexOfSetBitToSelectorRatio < selector.size()) {
120     return RowMap(
121         row_map_algorithms::SelectBvWithIvByConvertToIv(bv, selector));
122   }
123   return RowMap(
124       row_map_algorithms::SelectBvWithIvByIndexOfNthSet(bv, selector));
125 }
126 
Select(const std::vector<uint32_t> & iv,Range selector)127 RowMap Select(const std::vector<uint32_t>& iv, Range selector) {
128   PERFETTO_DCHECK(selector.end <= iv.size());
129 
130   std::vector<uint32_t> ret(selector.size());
131   for (uint32_t i = selector.start; i < selector.end; ++i) {
132     ret[i - selector.start] = iv[i];
133   }
134   return RowMap(std::move(ret));
135 }
136 
Select(const std::vector<uint32_t> & iv,const BitVector & selector)137 RowMap Select(const std::vector<uint32_t>& iv, const BitVector& selector) {
138   PERFETTO_DCHECK(selector.size() <= iv.size());
139 
140   std::vector<uint32_t> copy = iv;
141   copy.resize(selector.size());
142 
143   uint32_t idx = 0;
144   auto it = std::remove_if(
145       copy.begin(), copy.end(),
146       [&idx, &selector](uint32_t) { return !selector.IsSet(idx++); });
147   copy.erase(it, copy.end());
148   return RowMap(std::move(copy));
149 }
150 
Select(const std::vector<uint32_t> & iv,const std::vector<uint32_t> & selector)151 RowMap Select(const std::vector<uint32_t>& iv,
152               const std::vector<uint32_t>& selector) {
153   return RowMap(row_map_algorithms::SelectIvWithIv(iv, selector));
154 }
155 
156 // O(N), but 64 times faster than doing it bit by bit, as we compare words in
157 // BitVectors.
IntersectInternal(BitVector & first,const BitVector & second)158 Variant IntersectInternal(BitVector& first, const BitVector& second) {
159   first.And(second);
160   return std::move(first);
161 }
162 
163 // O(1) complexity.
IntersectInternal(Range first,Range second)164 Variant IntersectInternal(Range first, Range second) {
165   // If both RowMaps have ranges, we can just take the smallest intersection
166   // of them as the new RowMap.
167   // We have this as an explicit fast path as this is very common for
168   // constraints on id and sorted columns to satisfy this condition.
169   OutputIndex start = std::max(first.start, second.start);
170   OutputIndex end = std::max(start, std::min(first.end, second.end));
171   return Range{start, end};
172 }
173 
174 // O(N + k) complexity, where N is the size of |second| and k is the number of
175 // elements that have to be removed from |first|.
IntersectInternal(std::vector<OutputIndex> & first,const std::vector<OutputIndex> & second)176 Variant IntersectInternal(std::vector<OutputIndex>& first,
177                           const std::vector<OutputIndex>& second) {
178   std::unordered_set<OutputIndex> lookup(second.begin(), second.end());
179   first.erase(std::remove_if(first.begin(), first.end(),
180                              [lookup](OutputIndex ind) {
181                                return lookup.find(ind) == lookup.end();
182                              }),
183               first.end());
184   return std::move(first);
185 }
186 
187 // O(1) complexity.
IntersectInternal(Range range,const BitVector & bv)188 Variant IntersectInternal(Range range, const BitVector& bv) {
189   return bv.IntersectRange(range.start, range.end);
190 }
191 
IntersectInternal(BitVector & bv,Range range)192 Variant IntersectInternal(BitVector& bv, Range range) {
193   return IntersectInternal(range, bv);
194 }
195 
IntersectInternal(const std::vector<OutputIndex> & index_vec,const BitVector & bv)196 Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
197                           const BitVector& bv) {
198   std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
199   new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
200                                [&bv](uint32_t i) { return !bv.IsSet(i); }),
201                 new_vec.end());
202   return std::move(new_vec);
203 }
204 
IntersectInternal(const BitVector & bv,const std::vector<OutputIndex> & index_vec)205 Variant IntersectInternal(const BitVector& bv,
206                           const std::vector<OutputIndex>& index_vec) {
207   return IntersectInternal(index_vec, bv);
208 }
209 
IntersectInternal(Range range,const std::vector<OutputIndex> & index_vec)210 Variant IntersectInternal(Range range,
211                           const std::vector<OutputIndex>& index_vec) {
212   std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
213   new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
214                                [range](uint32_t i) {
215                                  return i < range.start || i >= range.end;
216                                }),
217                 new_vec.end());
218   return std::move(new_vec);
219 }
220 
IntersectInternal(const std::vector<OutputIndex> & index_vec,Range range)221 Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
222                           Range range) {
223   return IntersectInternal(range, index_vec);
224 }
225 
226 }  // namespace
227 
RowMap()228 RowMap::RowMap() : RowMap(Range()) {}
229 
RowMap(uint32_t start,uint32_t end)230 RowMap::RowMap(uint32_t start, uint32_t end) : data_(Range{start, end}) {}
231 
RowMap(Variant def)232 RowMap::RowMap(Variant def) : data_(std::move(def)) {}
233 
RowMap(Range r)234 RowMap::RowMap(Range r) : data_(r) {}
235 
236 // Creates a RowMap backed by a BitVector.
RowMap(BitVector bit_vector)237 RowMap::RowMap(BitVector bit_vector) : data_(std::move(bit_vector)) {}
238 
239 // Creates a RowMap backed by an std::vector<uint32_t>.
RowMap(IndexVector vec)240 RowMap::RowMap(IndexVector vec) : data_(vec) {}
241 
Copy() const242 RowMap RowMap::Copy() const {
243   if (const auto* range = std::get_if<Range>(&data_)) {
244     return RowMap(*range);
245   }
246   if (const auto* bv = std::get_if<BitVector>(&data_)) {
247     return RowMap(bv->Copy());
248   }
249   if (const auto* vec = std::get_if<IndexVector>(&data_)) {
250     return RowMap(*vec);
251   }
252   NoVariantMatched();
253 }
254 
Max() const255 OutputIndex RowMap::Max() const {
256   if (const auto* range = std::get_if<Range>(&data_)) {
257     return range->end;
258   }
259   if (const auto* bv = std::get_if<BitVector>(&data_)) {
260     return bv->size();
261   }
262   if (const auto* vec = std::get_if<IndexVector>(&data_)) {
263     return vec->empty() ? 0 : *std::max_element(vec->begin(), vec->end()) + 1;
264   }
265   NoVariantMatched();
266 }
267 
SelectRowsSlow(const RowMap & selector) const268 RowMap RowMap::SelectRowsSlow(const RowMap& selector) const {
269   return std::visit(
270       [](const auto& def, const auto& selector_def) {
271         return Select(def, selector_def);
272       },
273       data_, selector.data_);
274 }
275 
Intersect(const RowMap & second)276 void RowMap::Intersect(const RowMap& second) {
277   data_ = std::visit(
278       [](auto& def, auto& selector_def) {
279         return IntersectInternal(def, selector_def);
280       },
281       data_, second.data_);
282 }
283 
Iterator(const RowMap * rm)284 RowMap::Iterator::Iterator(const RowMap* rm) : rm_(rm) {
285   if (const auto* range = std::get_if<Range>(&rm_->data_)) {
286     ordinal_ = range->start;
287     return;
288   }
289   if (const auto* bv = std::get_if<BitVector>(&rm_->data_)) {
290     results_ = bv->GetSetBitIndices();
291     return;
292   }
293 }
294 
295 }  // namespace trace_processor
296 }  // namespace perfetto
297