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