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