Home | History | Annotate | Download | only in trace_processor
      1 /*
      2  * Licensed under the Apache License, Version 2.0 (the "License");
      3  * you may not use this file except in compliance with the License.
      4  * You may obtain a copy of the License at
      5  *
      6  *      http://www.apache.org/licenses/LICENSE-2.0
      7  *
      8  * Unless required by applicable law or agreed to in writing, software
      9  * distributed under the License is distributed on an "AS IS" BASIS,
     10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     11  * See the License for the specific language governing permissions and
     12  * limitations under the License.
     13  */
     14 
     15 #ifndef SRC_TRACE_PROCESSOR_STORAGE_COLUMNS_H_
     16 #define SRC_TRACE_PROCESSOR_STORAGE_COLUMNS_H_
     17 
     18 #include <deque>
     19 #include <limits>
     20 #include <memory>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "src/trace_processor/filtered_row_index.h"
     25 #include "src/trace_processor/sqlite_utils.h"
     26 #include "src/trace_processor/trace_storage.h"
     27 
     28 namespace perfetto {
     29 namespace trace_processor {
     30 
     31 // A column of data backed by data storage.
     32 class StorageColumn {
     33  public:
     34   struct Bounds {
     35     uint32_t min_idx = 0;
     36     uint32_t max_idx = std::numeric_limits<uint32_t>::max();
     37     bool consumed = false;
     38   };
     39   using Predicate = std::function<bool(uint32_t)>;
     40   using Comparator = std::function<int(uint32_t, uint32_t)>;
     41 
     42   StorageColumn(std::string col_name, bool hidden);
     43   virtual ~StorageColumn();
     44 
     45   // Implements StorageCursor::ColumnReporter.
     46   virtual void ReportResult(sqlite3_context*, uint32_t row) const = 0;
     47 
     48   // Given a SQLite operator and value for the comparision, returns a
     49   // predicate which takes in a row index and returns whether the row should
     50   // be returned.
     51   virtual void Filter(int op, sqlite3_value*, FilteredRowIndex*) const = 0;
     52 
     53   // Given a order by constraint for this column, returns a comparator
     54   // function which compares data in this column at two indices.
     55   virtual Comparator Sort(const QueryConstraints::OrderBy& ob) const = 0;
     56 
     57   // Returns the type of this column.
     58   virtual Table::ColumnType GetType() const = 0;
     59 
     60   // Bounds a filter on this column between a minimum and maximum index.
     61   // Generally this is only possible if the column is sorted.
     62   virtual Bounds BoundFilter(int, sqlite3_value*) const { return Bounds{}; }
     63 
     64   // Returns whether this column is ordered.
     65   virtual bool HasOrdering() const { return false; }
     66 
     67   const std::string& name() const { return col_name_; }
     68   bool hidden() const { return hidden_; }
     69 
     70  private:
     71   std::string col_name_;
     72   bool hidden_ = false;
     73 };
     74 
     75 // The implementation of StorageColumn for Strings.
     76 // The actual retrieval of the numerics from the data types is left to the
     77 // Acessor trait (see below for definition).
     78 template <typename Accessor /* <NullTermStringView> */>
     79 class StringColumn final : public StorageColumn {
     80  public:
     81   StringColumn(std::string col_name, Accessor accessor, bool hidden = false)
     82       : StorageColumn(col_name, hidden), accessor_(accessor) {}
     83 
     84   void ReportResult(sqlite3_context* ctx, uint32_t row) const override {
     85     NullTermStringView str = accessor_.Get(row);
     86     if (str.c_str() == nullptr) {
     87       sqlite3_result_null(ctx);
     88     } else {
     89       sqlite3_result_text(ctx, str.c_str(), -1, sqlite_utils::kSqliteStatic);
     90     }
     91   }
     92 
     93   Bounds BoundFilter(int, sqlite3_value*) const override {
     94     Bounds bounds;
     95     bounds.max_idx = static_cast<uint32_t>(accessor_.Size());
     96     return bounds;
     97   }
     98 
     99   void Filter(int, sqlite3_value*, FilteredRowIndex*) const override {}
    100 
    101   Comparator Sort(const QueryConstraints::OrderBy& ob) const override {
    102     if (ob.desc) {
    103       return [this](uint32_t f, uint32_t s) {
    104         NullTermStringView a = accessor_.Get(f);
    105         NullTermStringView b = accessor_.Get(s);
    106         return sqlite_utils::CompareValuesDesc(a, b);
    107       };
    108     }
    109     return [this](uint32_t f, uint32_t s) {
    110       NullTermStringView a = accessor_.Get(f);
    111       NullTermStringView b = accessor_.Get(s);
    112       return sqlite_utils::CompareValuesAsc(a, b);
    113     };
    114   }
    115 
    116   Table::ColumnType GetType() const override {
    117     return Table::ColumnType::kString;
    118   }
    119 
    120   bool HasOrdering() const override { return accessor_.HasOrdering(); }
    121 
    122  private:
    123   Accessor accessor_;
    124 };
    125 
    126 // The implementation of StorageColumn for numeric data types.
    127 // The actual retrieval of the numerics from the data types is left to the
    128 // Acessor trait (see below for definition).
    129 template <typename Accessor,
    130           typename sqlite_utils::is_numeric<typename Accessor::Type>* = nullptr>
    131 class NumericColumn : public StorageColumn {
    132  public:
    133   // The type of the column. This is one of uint32_t, int32_t, uint64_t etc.
    134   using NumericType = typename Accessor::Type;
    135 
    136   NumericColumn(std::string col_name, bool hidden, Accessor accessor)
    137       : StorageColumn(col_name, hidden), accessor_(accessor) {}
    138   ~NumericColumn() override = default;
    139 
    140   void ReportResult(sqlite3_context* ctx, uint32_t row) const override {
    141     sqlite_utils::ReportSqliteResult(ctx, accessor_.Get(row));
    142   }
    143 
    144   Bounds BoundFilter(int op, sqlite3_value* sqlite_val) const override {
    145     Bounds bounds;
    146     bounds.max_idx = accessor_.Size();
    147 
    148     if (!accessor_.HasOrdering())
    149       return bounds;
    150 
    151     // Makes the below code much more readable.
    152     using namespace sqlite_utils;
    153 
    154     NumericType min = kTMin;
    155     NumericType max = kTMax;
    156     if (IsOpGe(op) || IsOpGt(op)) {
    157       min = FindGtBound<NumericType>(IsOpGe(op), sqlite_val);
    158     } else if (IsOpLe(op) || IsOpLt(op)) {
    159       max = FindLtBound<NumericType>(IsOpLe(op), sqlite_val);
    160     } else if (IsOpEq(op)) {
    161       auto val = FindEqBound<NumericType>(sqlite_val);
    162       min = val;
    163       max = val;
    164     }
    165 
    166     if (min <= kTMin && max >= kTMax)
    167       return bounds;
    168 
    169     bounds.min_idx = accessor_.LowerBoundIndex(min);
    170     bounds.max_idx = accessor_.UpperBoundIndex(max);
    171     bounds.consumed = true;
    172 
    173     return bounds;
    174   }
    175 
    176   void Filter(int op,
    177               sqlite3_value* value,
    178               FilteredRowIndex* index) const override {
    179     auto type = sqlite3_value_type(value);
    180 
    181     bool same_type = (kIsIntegralType && type == SQLITE_INTEGER) ||
    182                      (kIsRealType && type == SQLITE_FLOAT);
    183     if (sqlite_utils::IsOpEq(op) && same_type &&
    184         accessor_.CanFindEqualIndices()) {
    185       auto raw = sqlite_utils::ExtractSqliteValue<NumericType>(value);
    186       index->IntersectRows(accessor_.EqualIndices(raw));
    187       return;
    188     }
    189 
    190     if (kIsIntegralType && (type == SQLITE_INTEGER || type == SQLITE_NULL)) {
    191       FilterWithCast<int64_t>(op, value, index);
    192     } else if (type == SQLITE_INTEGER || type == SQLITE_FLOAT ||
    193                type == SQLITE_NULL) {
    194       FilterWithCast<double>(op, value, index);
    195     } else {
    196       PERFETTO_FATAL("Unexpected sqlite value to compare against");
    197     }
    198   }
    199 
    200   Comparator Sort(const QueryConstraints::OrderBy& ob) const override {
    201     if (ob.desc) {
    202       return [this](uint32_t f, uint32_t s) {
    203         return sqlite_utils::CompareValuesDesc(accessor_.Get(f),
    204                                                accessor_.Get(s));
    205       };
    206     }
    207     return [this](uint32_t f, uint32_t s) {
    208       return sqlite_utils::CompareValuesAsc(accessor_.Get(f), accessor_.Get(s));
    209     };
    210   }
    211 
    212   bool HasOrdering() const override { return accessor_.HasOrdering(); }
    213 
    214   Table::ColumnType GetType() const override {
    215     if (std::is_same<NumericType, int32_t>::value) {
    216       return Table::ColumnType::kInt;
    217     } else if (std::is_same<NumericType, uint8_t>::value ||
    218                std::is_same<NumericType, uint32_t>::value) {
    219       return Table::ColumnType::kUint;
    220     } else if (std::is_same<NumericType, int64_t>::value) {
    221       return Table::ColumnType::kLong;
    222     } else if (std::is_same<NumericType, double>::value) {
    223       return Table::ColumnType::kDouble;
    224     }
    225     PERFETTO_FATAL("Unexpected column type");
    226   }
    227 
    228  private:
    229   static constexpr bool kIsIntegralType = std::is_integral<NumericType>::value;
    230   static constexpr bool kIsRealType =
    231       std::is_floating_point<NumericType>::value;
    232 
    233   NumericType kTMin = std::numeric_limits<NumericType>::lowest();
    234   NumericType kTMax = std::numeric_limits<NumericType>::max();
    235 
    236   // Filters the rows of this column by creating the predicate from the sqlite
    237   // value using type |UpcastNumericType| and casting data from the column
    238   // to also be this type.
    239   // Note: We cast here to make numeric comparisions as accurate as possible.
    240   // For example, suppose NumericType == uint32_t and the sqlite value has
    241   // an integer. Then UpcastNumericType == int64_t because uint32_t can be
    242   // upcast to an int64_t and it's the most generic type we can compare using.
    243   // Alternatively if either the column or sqlite value is real, we will always
    244   // cast to a double before comparing.
    245   template <typename UpcastNumericType>
    246   void FilterWithCast(int op,
    247                       sqlite3_value* value,
    248                       FilteredRowIndex* index) const {
    249     auto predicate =
    250         sqlite_utils::CreateNumericPredicate<UpcastNumericType>(op, value);
    251     auto cast_predicate = [this,
    252                            predicate](uint32_t row) PERFETTO_ALWAYS_INLINE {
    253       return predicate(static_cast<UpcastNumericType>(accessor_.Get(row)));
    254     };
    255     index->FilterRows(cast_predicate);
    256   }
    257 
    258   Accessor accessor_;
    259 };
    260 
    261 // Defines an accessor for columns.
    262 // An accessor is a abstraction over the method to retrieve data in a column. As
    263 // there are many possible types of backing data (std::vector, std::deque,
    264 // creating on the flight etc.), this class hides this complexity behind an
    265 // interface to let the column implementation focus on actually interfacing
    266 // with SQLite and rest of trace processor.
    267 // This class exists as an interface for documentation purposes. There should
    268 // be no use of it apart from classes inheriting from it to ensure they comply
    269 // with the requirements of the interface.
    270 template <typename DataType>
    271 class Accessor {
    272  public:
    273   using Type = DataType;
    274 
    275   virtual ~Accessor() = default;
    276 
    277   // Returns the number of elements in the backing storage.
    278   virtual uint32_t Size() const = 0;
    279 
    280   // Returns the element located at index |idx|.
    281   virtual Type Get(uint32_t idx) const = 0;
    282 
    283   // Returns whether the backing data source is ordered. |LowerBoundIndex| and
    284   // |UpperBoundIndex| will be called only if HasOrdering() returns true.
    285   virtual bool HasOrdering() const { return false; }
    286 
    287   // Returns the index of the lower bound of the value.
    288   virtual uint32_t LowerBoundIndex(Type) const { PERFETTO_CHECK(false); }
    289 
    290   // Returns the index of the lower bound of the value.
    291   virtual uint32_t UpperBoundIndex(Type) const { PERFETTO_CHECK(false); }
    292 
    293   // Returns whether the backing data sources can efficiently provide the
    294   // indices of elements equal to a given value. |EqualIndices| will be called
    295   // only if |CanFindEqualIndices| returns true.
    296   virtual bool CanFindEqualIndices() const { return false; }
    297 
    298   // Returns the indices into the backing data source with value equal to
    299   // |value|.
    300   virtual std::vector<uint32_t> EqualIndices(Type) const {
    301     PERFETTO_CHECK(false);
    302   }
    303 };
    304 
    305 // An accessor implementation for string which uses a deque to store offsets
    306 // into a StringPool.
    307 class StringPoolAccessor : public Accessor<NullTermStringView> {
    308  public:
    309   StringPoolAccessor(const std::deque<StringPool::Id>* deque,
    310                      const StringPool* string_pool);
    311   ~StringPoolAccessor() override;
    312 
    313   uint32_t Size() const override {
    314     return static_cast<uint32_t>(deque_->size());
    315   }
    316 
    317   NullTermStringView Get(uint32_t idx) const override {
    318     return string_pool_->Get((*deque_)[idx]);
    319   }
    320 
    321  private:
    322   const std::deque<StringPool::Id>* deque_;
    323   const StringPool* string_pool_;
    324 };
    325 
    326 // An accessor implementation for string which uses a deque to store indices
    327 // into a vector of strings.
    328 template <typename Id>
    329 class StringVectorAccessor : public Accessor<NullTermStringView> {
    330  public:
    331   StringVectorAccessor(const std::deque<Id>* deque,
    332                        const std::vector<const char*>* string_map)
    333       : deque_(deque), string_map_(string_map) {}
    334   ~StringVectorAccessor() override = default;
    335 
    336   uint32_t Size() const override {
    337     return static_cast<uint32_t>(deque_->size());
    338   }
    339 
    340   NullTermStringView Get(uint32_t idx) const override {
    341     const char* ptr = (*string_map_)[(*deque_)[idx]];
    342     return ptr ? NullTermStringView(ptr) : NullTermStringView();
    343   }
    344 
    345  private:
    346   const std::deque<Id>* deque_;
    347   const std::vector<const char*>* string_map_;
    348 };
    349 
    350 // An accessor implementation for numeric columns which uses a deque as the
    351 // backing storage with an opitonal index for quick equality filtering.
    352 template <typename NumericType>
    353 class NumericDequeAccessor : public Accessor<NumericType> {
    354  public:
    355   NumericDequeAccessor(const std::deque<NumericType>* deque,
    356                        const std::deque<std::vector<uint32_t>>* index,
    357                        bool has_ordering)
    358       : deque_(deque), index_(index), has_ordering_(has_ordering) {}
    359   ~NumericDequeAccessor() override = default;
    360 
    361   uint32_t Size() const override {
    362     return static_cast<uint32_t>(deque_->size());
    363   }
    364 
    365   NumericType Get(uint32_t idx) const override { return (*deque_)[idx]; }
    366 
    367   bool HasOrdering() const override { return has_ordering_; }
    368 
    369   uint32_t LowerBoundIndex(NumericType value) const override {
    370     PERFETTO_DCHECK(HasOrdering());
    371     auto it = std::lower_bound(deque_->begin(), deque_->end(), value);
    372     return static_cast<uint32_t>(std::distance(deque_->begin(), it));
    373   }
    374 
    375   uint32_t UpperBoundIndex(NumericType value) const override {
    376     PERFETTO_DCHECK(HasOrdering());
    377     auto it = std::upper_bound(deque_->begin(), deque_->end(), value);
    378     return static_cast<uint32_t>(std::distance(deque_->begin(), it));
    379   }
    380 
    381   bool CanFindEqualIndices() const override {
    382     return std::is_integral<NumericType>::value && index_ != nullptr;
    383   }
    384 
    385   std::vector<uint32_t> EqualIndices(NumericType value) const override {
    386     PERFETTO_DCHECK(CanFindEqualIndices());
    387     if (value < 0 || static_cast<size_t>(value) >= index_->size())
    388       return {};
    389     return (*index_)[static_cast<size_t>(value)];
    390   }
    391 
    392  private:
    393   const std::deque<NumericType>* deque_ = nullptr;
    394   const std::deque<std::vector<uint32_t>>* index_ = nullptr;
    395   bool has_ordering_ = false;
    396 };
    397 
    398 class TsEndAccessor : public Accessor<int64_t> {
    399  public:
    400   TsEndAccessor(const std::deque<int64_t>* ts, const std::deque<int64_t>* dur);
    401   ~TsEndAccessor() override;
    402 
    403   uint32_t Size() const override { return static_cast<uint32_t>(ts_->size()); }
    404 
    405   int64_t Get(uint32_t idx) const override {
    406     return (*ts_)[idx] + (*dur_)[idx];
    407   }
    408 
    409  private:
    410   const std::deque<int64_t>* ts_ = nullptr;
    411   const std::deque<int64_t>* dur_ = nullptr;
    412 };
    413 
    414 class RowIdAccessor : public Accessor<int64_t> {
    415  public:
    416   RowIdAccessor(TableId table_id);
    417   ~RowIdAccessor() override;
    418 
    419   uint32_t Size() const override {
    420     return std::numeric_limits<uint32_t>::max();
    421   }
    422 
    423   int64_t Get(uint32_t idx) const override {
    424     return TraceStorage::CreateRowId(table_id_, idx);
    425   }
    426 
    427  private:
    428   TableId table_id_;
    429 };
    430 
    431 class RowAccessor : public Accessor<uint32_t> {
    432  public:
    433   RowAccessor();
    434   ~RowAccessor() override;
    435 
    436   uint32_t Size() const override {
    437     return std::numeric_limits<uint32_t>::max();
    438   }
    439 
    440   uint32_t Get(uint32_t idx) const override { return idx; }
    441 
    442   bool HasOrdering() const override { return true; }
    443 
    444   uint32_t LowerBoundIndex(uint32_t idx) const override { return idx; }
    445 
    446   uint32_t UpperBoundIndex(uint32_t idx) const override { return idx + 1; }
    447 };
    448 
    449 }  // namespace trace_processor
    450 }  // namespace perfetto
    451 
    452 #endif  // SRC_TRACE_PROCESSOR_STORAGE_COLUMNS_H_
    453