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_H_ 18 #define SRC_TRACE_PROCESSOR_DB_COLUMN_STORAGE_H_ 19 20 #include <cstddef> 21 #include <cstdint> 22 #include <optional> 23 #include <vector> 24 25 #include "perfetto/base/compiler.h" 26 #include "perfetto/base/logging.h" 27 #include "perfetto/public/compiler.h" 28 #include "src/trace_processor/containers/bit_vector.h" 29 30 namespace perfetto::trace_processor { 31 32 // Base class for allowing type erasure when defining plug-in implementations 33 // of backing storage for columns. 34 class ColumnStorageBase { 35 public: 36 ColumnStorageBase() = default; 37 virtual ~ColumnStorageBase(); 38 39 ColumnStorageBase(const ColumnStorageBase&) = delete; 40 ColumnStorageBase& operator=(const ColumnStorageBase&) = delete; 41 42 ColumnStorageBase(ColumnStorageBase&&) = default; 43 ColumnStorageBase& operator=(ColumnStorageBase&&) noexcept = default; 44 45 virtual const void* data() const = 0; 46 virtual const BitVector* bv() const = 0; 47 virtual uint32_t size() const = 0; 48 virtual uint32_t non_null_size() const = 0; 49 }; 50 51 // Class used for implementing storage for non-null columns. 52 template <typename T> 53 class ColumnStorage final : public ColumnStorageBase { 54 public: 55 ColumnStorage() = default; 56 57 explicit ColumnStorage(const ColumnStorage&) = delete; 58 ColumnStorage& operator=(const ColumnStorage&) = delete; 59 60 ColumnStorage(ColumnStorage&&) = default; 61 ColumnStorage& operator=(ColumnStorage&&) noexcept = default; 62 Get(uint32_t idx)63 T Get(uint32_t idx) const { return vector_[idx]; } Append(T val)64 void Append(T val) { vector_.emplace_back(val); } Append(const std::vector<T> & vals)65 void Append(const std::vector<T>& vals) { 66 vector_.insert(vector_.end(), vals.begin(), vals.end()); 67 } AppendMultiple(T val,uint32_t count)68 void AppendMultiple(T val, uint32_t count) { 69 vector_.insert(vector_.end(), count, val); 70 } Set(uint32_t idx,T val)71 void Set(uint32_t idx, T val) { vector_[idx] = val; } ShrinkToFit()72 PERFETTO_NO_INLINE void ShrinkToFit() { vector_.shrink_to_fit(); } vector()73 const std::vector<T>& vector() const { return vector_; } 74 data()75 const void* data() const final { return vector_.data(); } bv()76 const BitVector* bv() const final { return nullptr; } size()77 uint32_t size() const final { return static_cast<uint32_t>(vector_.size()); } non_null_size()78 uint32_t non_null_size() const final { return size(); } 79 80 template <bool IsDense> Create()81 static ColumnStorage<T> Create() { 82 static_assert(!IsDense, "Invalid for non-null storage to be dense."); 83 return ColumnStorage<T>(); 84 } 85 86 // Create non-null storage from nullable storage without nulls. CreateFromAssertNonNull(ColumnStorage<std::optional<T>> null_storage)87 static ColumnStorage<T> CreateFromAssertNonNull( 88 ColumnStorage<std::optional<T>> null_storage) { 89 PERFETTO_CHECK(null_storage.size() == null_storage.non_null_size()); 90 ColumnStorage<T> x; 91 x.vector_ = std::move(null_storage).non_null_vector(); 92 return x; 93 } 94 95 private: 96 std::vector<T> vector_; 97 }; 98 99 // Class used for implementing storage for nullable columns. 100 template <typename T> 101 class ColumnStorage<std::optional<T>> final : public ColumnStorageBase { 102 public: 103 ColumnStorage() = default; 104 105 explicit ColumnStorage(const ColumnStorage&) = delete; 106 ColumnStorage& operator=(const ColumnStorage&) = delete; 107 108 ColumnStorage(ColumnStorage&&) = default; 109 ColumnStorage& operator=(ColumnStorage&&) noexcept = default; 110 Get(uint32_t idx)111 std::optional<T> Get(uint32_t idx) const { 112 bool contains = valid_.IsSet(idx); 113 if (mode_ == Mode::kDense) { 114 return contains ? std::make_optional(data_[idx]) : std::nullopt; 115 } 116 return contains ? std::make_optional(data_[valid_.CountSetBits(idx)]) 117 : std::nullopt; 118 } Append(T val)119 void Append(T val) { 120 data_.emplace_back(val); 121 valid_.AppendTrue(); 122 } Append(std::optional<T> val)123 void Append(std::optional<T> val) { 124 if (val) { 125 Append(*val); 126 } else { 127 AppendNull(); 128 } 129 } AppendMultipleNulls(uint32_t count)130 void AppendMultipleNulls(uint32_t count) { 131 if (mode_ == Mode::kDense) { 132 data_.resize(data_.size() + static_cast<uint32_t>(count)); 133 } 134 valid_.Resize(valid_.size() + static_cast<uint32_t>(count), false); 135 } AppendMultiple(T val,uint32_t count)136 void AppendMultiple(T val, uint32_t count) { 137 data_.insert(data_.end(), count, val); 138 valid_.Resize(valid_.size() + static_cast<uint32_t>(count), true); 139 } Append(const std::vector<T> & vals)140 void Append(const std::vector<T>& vals) { 141 data_.insert(data_.end(), vals.begin(), vals.end()); 142 valid_.Resize(valid_.size() + static_cast<uint32_t>(vals.size()), true); 143 } Set(uint32_t idx,T val)144 void Set(uint32_t idx, T val) { 145 if (mode_ == Mode::kDense) { 146 valid_.Set(idx); 147 data_[idx] = val; 148 } else { 149 // Generally, we will be setting a null row to non-null so optimize for 150 // that path. 151 uint32_t row = valid_.CountSetBits(idx); 152 bool was_set = valid_.Set(idx); 153 if (PERFETTO_UNLIKELY(was_set)) { 154 data_[row] = val; 155 } else { 156 data_.insert(data_.begin() + static_cast<ptrdiff_t>(row), val); 157 } 158 } 159 } IsDense()160 bool IsDense() const { return mode_ == Mode::kDense; } ShrinkToFit()161 PERFETTO_NO_INLINE void ShrinkToFit() { 162 data_.shrink_to_fit(); 163 valid_.ShrinkToFit(); 164 } 165 // For dense columns the size of the vector is equal to size of the bit 166 // vector. For sparse it's equal to count set bits of the bit vector. non_null_vector()167 const std::vector<T>& non_null_vector() const& { return data_; } non_null_bit_vector()168 const BitVector& non_null_bit_vector() const { return valid_; } 169 data()170 const void* data() const final { return non_null_vector().data(); } bv()171 const BitVector* bv() const final { return &non_null_bit_vector(); } size()172 uint32_t size() const final { return valid_.size(); } non_null_size()173 uint32_t non_null_size() const final { 174 return static_cast<uint32_t>(non_null_vector().size()); 175 } 176 177 template <bool IsDense> Create()178 static ColumnStorage<std::optional<T>> Create() { 179 return IsDense ? ColumnStorage<std::optional<T>>(Mode::kDense) 180 : ColumnStorage<std::optional<T>>(Mode::kSparse); 181 } 182 non_null_vector()183 std::vector<T> non_null_vector() && { return std::move(data_); } 184 185 private: 186 enum class Mode { 187 // Sparse mode is the default mode and ensures that nulls are stored using 188 // only 189 // a single bit (at the cost of making setting null entries to non-null 190 // O(n)). 191 kSparse, 192 193 // Dense mode forces the reservation of space for null entries which 194 // increases 195 // memory usage but allows for O(1) set operations. 196 kDense, 197 }; 198 ColumnStorage(Mode mode)199 explicit ColumnStorage(Mode mode) : mode_(mode) {} 200 AppendNull()201 void AppendNull() { 202 if (mode_ == Mode::kDense) { 203 data_.emplace_back(); 204 } 205 valid_.AppendFalse(); 206 } 207 208 Mode mode_ = Mode::kSparse; 209 std::vector<T> data_; 210 BitVector valid_; 211 }; 212 213 } // namespace perfetto::trace_processor 214 215 #endif // SRC_TRACE_PROCESSOR_DB_COLUMN_STORAGE_H_ 216