• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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_DB_COLUMN_STORAGE_OVERLAY_H_
18 #define SRC_TRACE_PROCESSOR_DB_COLUMN_STORAGE_OVERLAY_H_
19 
20 #include <stdint.h>
21 
22 #include <memory>
23 #include <optional>
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/bit_vector_iterators.h"
29 #include "src/trace_processor/containers/row_map.h"
30 
31 namespace perfetto {
32 namespace trace_processor {
33 
34 // Contains indices which can be used to lookup data in one or more
35 // ColumnStorages.
36 //
37 // Implemented as a thin wrapper around RowMap so much of the documentation
38 // from RowMap also applies to this class.
39 class ColumnStorageOverlay {
40  public:
41   // Input type.
42   using InputRow = uint32_t;
43   using OutputIndex = uint32_t;
44 
45   // Allows efficient iteration over the rows of a ColumnStorageOverlay.
46   class Iterator {
47    public:
Iterator(RowMap::Iterator it)48     Iterator(RowMap::Iterator it) : it_(std::move(it)) {}
49 
50     Iterator(Iterator&&) noexcept = default;
51     Iterator& operator=(Iterator&&) = default;
52 
53     // Forwards the iterator to the next row of the ColumnStorageOverlay.
Next()54     void Next() { return it_.Next(); }
55 
56     // Returns if the iterator is still valid.
57     operator bool() const { return it_; }
58 
59     // Returns the index pointed to by this iterator.
index()60     OutputIndex index() const { return it_.index(); }
61 
62     // Returns the row of the index the iterator points to.
row()63     InputRow row() const { return it_.row(); }
64 
65    private:
66     RowMap::Iterator it_;
67   };
68 
69   // Creates an empty ColumnStorageOverlay.
70   // By default this will be implemented using a range.
ColumnStorageOverlay()71   ColumnStorageOverlay() : ColumnStorageOverlay(0) {}
72 
73   // Creates a |ColumnStorageOverlay| containing all rows between 0 and |size|.
ColumnStorageOverlay(uint32_t size)74   explicit ColumnStorageOverlay(uint32_t size)
75       : ColumnStorageOverlay(0, size) {}
76 
77   // Creates a |ColumnStorageOverlay| containing all rows between |start| and
78   // |end|.
ColumnStorageOverlay(uint32_t start,uint32_t end)79   explicit ColumnStorageOverlay(uint32_t start, uint32_t end)
80       : ColumnStorageOverlay(RowMap(start, end)) {}
81 
82   // Creates a |ColumnStorageOverlay| containing all rows corresponding to set
83   // bits in |bv|.
ColumnStorageOverlay(BitVector bv)84   explicit ColumnStorageOverlay(BitVector bv)
85       : ColumnStorageOverlay(RowMap(std::move(bv))) {}
86 
87   // Creates a |ColumnStorageOverlay| containing all rows in |rows|.
ColumnStorageOverlay(std::vector<uint32_t> rows)88   explicit ColumnStorageOverlay(std::vector<uint32_t> rows)
89       : ColumnStorageOverlay(RowMap(std::move(rows))) {}
90 
91   ColumnStorageOverlay(const ColumnStorageOverlay&) noexcept = delete;
92   ColumnStorageOverlay& operator=(const ColumnStorageOverlay&) = delete;
93 
94   ColumnStorageOverlay(ColumnStorageOverlay&&) noexcept = default;
95   ColumnStorageOverlay& operator=(ColumnStorageOverlay&&) = default;
96 
97   // Creates a copy of the ColumnStorageOverlay.
98   // We have an explicit copy function because ColumnStorageOverlay can hold
99   // onto large chunks of memory and we want to be very explicit when making a
100   // copy to avoid accidental leaks and copies.
Copy()101   ColumnStorageOverlay Copy() const {
102     return ColumnStorageOverlay(row_map_.Copy());
103   }
104 
105   // Returns the size of the ColumnStorageOverlay; that is the number of
106   // indices in the ColumnStorageOverlay.
size()107   uint32_t size() const { return row_map_.size(); }
108 
109   // Returns whether this ColumnStorageOverlay is empty.
empty()110   bool empty() const { return size() == 0; }
111 
112   // Returns the index at the given |row|.
Get(uint32_t row)113   OutputIndex Get(uint32_t row) const { return row_map_.Get(row); }
114 
115   // Returns the first row of the given |index| in the ColumnStorageOverlay.
RowOf(OutputIndex index)116   std::optional<InputRow> RowOf(OutputIndex index) const {
117     return row_map_.RowOf(index);
118   }
119 
120   // Performs an ordered insert of the index into the current
121   // ColumnStorageOverlay (precondition: this ColumnStorageOverlay is ordered
122   // based on the indices it contains).
123   //
124   // See RowMap::Insert for more information on this function.
Insert(OutputIndex index)125   void Insert(OutputIndex index) { return row_map_.Insert(index); }
126 
127   // Updates this ColumnStorageOverlay by 'picking' the indices given by
128   // |picker|.
129   //
130   // See RowMap::SelectRows for more information on this function.
SelectRows(const RowMap & selector)131   ColumnStorageOverlay SelectRows(const RowMap& selector) const {
132     return ColumnStorageOverlay(row_map_.SelectRows(selector));
133   }
134 
135   // Clears this ColumnStorageOverlay by resetting it to a newly constructed
136   // state.
Clear()137   void Clear() { *this = ColumnStorageOverlay(); }
138 
139   // Filters the current ColumnStorageOverlay into the RowMap given by |out|
140   // based on the return value of |p(idx)|.
141   //
142   // Precondition: |out| should be sorted by the indices inside it (this is
143   // required to keep this method efficient). This is automatically true if the
144   // mode of |out| is Range or BitVector but needs to be enforced if the mode is
145   // IndexVector.
146   //
147   // Specifically, the setup for each of the variables is as follows:
148   //  this: contains the indices passed to p to filter.
149   //  out : contains indicies into |this| and will be filtered down to only
150   //        contain indicies where p returns true.
151   //  p   : takes an index given by |this| and returns whether the index should
152   //        be retained in |out|.
153   //
154   // Concretely, the algorithm being invoked looks like (but more efficient
155   // based on the mode of |this| and |out|):
156   // for (idx : out)
157   //   this_idx = (*this)[idx]
158   //   if (!p(this_idx))
159   //     out->Remove(idx)
160   template <typename Predicate>
FilterInto(RowMap * out,Predicate p)161   void FilterInto(RowMap* out, Predicate p) const {
162     PERFETTO_DCHECK(size() >= out->size());
163 
164     if (out->empty()) {
165       // If the output ColumnStorageOverlay is empty, we don't need to do
166       // anything.
167       return;
168     }
169 
170     if (out->size() == 1) {
171       // If the output ColumnStorageOverlay has a single entry, just lookup
172       // that entry and see if we should keep it.
173       if (!p(Get(out->Get(0))))
174         out->Clear();
175       return;
176     }
177 
178     // TODO(lalitm): investigate whether we should have another fast path for
179     // cases where |out| has only a few entries so we can scan |out| instead of
180     // scanning |this|.
181 
182     // Ideally, we'd always just scan |out| and keep the indices in |this| which
183     // meet |p|. However, if |this| is a BitVector, we end up needing expensive
184     // |IndexOfNthSet| calls (as we need to convert the row to an index before
185     // passing it to |p|).
186     if (row_map_.IsBitVector()) {
187       FilterIntoScanSelfBv(out, p);
188       return;
189     }
190     auto ip = [this, p](uint32_t row) { return p(row_map_.Get(row)); };
191     out->Filter(ip);
192   }
193 
194   template <typename Comparator = bool(uint32_t, uint32_t)>
StableSort(std::vector<uint32_t> * out,Comparator c)195   void StableSort(std::vector<uint32_t>* out, Comparator c) const {
196     return row_map_.StableSort(out, c);
197   }
198 
199   // Returns the iterator over the rows in this ColumnStorageOverlay.
IterateRows()200   Iterator IterateRows() const { return Iterator(row_map_.IterateRows()); }
201 
202  private:
ColumnStorageOverlay(RowMap rm)203   explicit ColumnStorageOverlay(RowMap rm) : row_map_(std::move(rm)) {}
204 
205   // Filters the current ColumnStorageOverlay into |out| by performing a full
206   // scan on |row_map.bit_vector_|. See |FilterInto| for a full breakdown of the
207   // semantics of this function.
208 
209   template <typename Predicate>
210   struct FilterIntoScanSelfBvVisitor {
operatorFilterIntoScanSelfBvVisitor211     void operator()(RowMap::Range out_r) {
212       BitVector bv(out_r.end, false);
213       for (auto out_it = bv.IterateAllBits(); bv_iter;
214            bv_iter.Next(), out_it.Next()) {
215         uint32_t ordinal = bv_iter.ordinal();
216         if (ordinal < out_r.start)
217           continue;
218         if (ordinal >= out_r.end)
219           break;
220 
221         if (p(bv_iter.index())) {
222           out_it.Set();
223         }
224       }
225       *out = RowMap(std::move(bv));
226     }
operatorFilterIntoScanSelfBvVisitor227     void operator()(const BitVector& out_bv) {
228       auto out_it = out_bv.IterateAllBits();
229       for (; out_it; bv_iter.Next(), out_it.Next()) {
230         PERFETTO_DCHECK(bv_iter);
231         if (out_it.IsSet() && !p(bv_iter.index()))
232           out_it.Clear();
233       }
234     }
operatorFilterIntoScanSelfBvVisitor235     void operator()(std::vector<OutputIndex>& out_vec) {
236       PERFETTO_DCHECK(std::is_sorted(out_vec.begin(), out_vec.end()));
237       auto fn = [this](uint32_t i) {
238         while (bv_iter.ordinal() < i) {
239           bv_iter.Next();
240           PERFETTO_DCHECK(bv_iter);
241         }
242         PERFETTO_DCHECK(bv_iter.ordinal() == i);
243         return !p(bv_iter.index());
244       };
245       auto iv_it = std::remove_if(out_vec.begin(), out_vec.end(), fn);
246       out_vec.erase(iv_it, out_vec.end());
247     }
248     RowMap* out;
249     Predicate p;
250     internal::SetBitsIterator bv_iter;
251   };
252 
253   template <typename Predicate>
FilterIntoScanSelfBv(RowMap * out,Predicate p)254   void FilterIntoScanSelfBv(RowMap* out, Predicate p) const {
255     const BitVector* bv = std::get_if<BitVector>(&row_map_.data_);
256     auto it = bv->IterateSetBits();
257     std::visit(FilterIntoScanSelfBvVisitor<Predicate>{out, p, std::move(it)},
258                out->data_);
259   }
260 
261   RowMap row_map_;
262 };
263 
264 }  // namespace trace_processor
265 }  // namespace perfetto
266 
267 #endif  // SRC_TRACE_PROCESSOR_DB_COLUMN_STORAGE_OVERLAY_H_
268