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