trace_processor: add sort and filter support to counter table

Change-Id: Iaf36eae7fa268b4f4b00c307e21c0c90e91b5edb
diff --git a/src/trace_processor/counters_table.cc b/src/trace_processor/counters_table.cc
index b01400f..000891f 100644
--- a/src/trace_processor/counters_table.cc
+++ b/src/trace_processor/counters_table.cc
@@ -27,6 +27,45 @@
 
 using namespace sqlite_utils;
 
+PERFETTO_ALWAYS_INLINE int CompareCountersOnColumn(
+    const TraceStorage* storage,
+    size_t f_idx,
+    size_t s_idx,
+    const QueryConstraints::OrderBy& ob) {
+  const auto& co = storage->counters();
+  switch (ob.iColumn) {
+    case CountersTable::Column::kTimestamp:
+      return CompareValues(co.timestamps(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kValue:
+      return CompareValues(co.values(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kName:
+      return CompareValues(co.name_ids(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kRef:
+      return CompareValues(co.refs(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kDuration:
+      return CompareValues(co.durations(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kValueDelta:
+      return CompareValues(co.value_deltas(), f_idx, s_idx, ob.desc);
+    case CountersTable::Column::kRefType:
+      return CompareValues(co.types(), f_idx, s_idx, ob.desc);
+    default:
+      PERFETTO_FATAL("Unexpected column %d", ob.iColumn);
+  }
+}
+
+PERFETTO_ALWAYS_INLINE int CompareCounters(
+    const TraceStorage* storage,
+    size_t f_idx,
+    size_t s_idx,
+    const std::vector<QueryConstraints::OrderBy>& order_by) {
+  for (const auto& ob : order_by) {
+    int c = CompareCountersOnColumn(storage, f_idx, s_idx, ob);
+    if (c != 0)
+      return c;
+  }
+  return 0;
+}
+
 }  // namespace
 
 CountersTable::CountersTable(sqlite3*, const TraceStorage* storage)
@@ -51,49 +90,89 @@
 }
 
 std::unique_ptr<Table::Cursor> CountersTable::CreateCursor(
-    const QueryConstraints&,
-    sqlite3_value**) {
-  return std::unique_ptr<Table::Cursor>(new Cursor(storage_));
+    const QueryConstraints& qc,
+    sqlite3_value** argv) {
+  return std::unique_ptr<Table::Cursor>(new Cursor(storage_, qc, argv));
 }
 
 int CountersTable::BestIndex(const QueryConstraints&, BestIndexInfo* info) {
   // TODO(taylori): Work out cost dependant on constraints.
   info->estimated_cost =
       static_cast<uint32_t>(storage_->counters().counter_count());
+  info->order_by_consumed = true;
+
   return SQLITE_OK;
 }
 
-CountersTable::Cursor::Cursor(const TraceStorage* storage) : storage_(storage) {
-  num_rows_ = storage->counters().counter_count();
+CountersTable::Cursor::Cursor(const TraceStorage* storage,
+                              const QueryConstraints& qc,
+                              sqlite3_value** argv)
+    : storage_(storage) {
+  const auto& counters = storage->counters();
+
+  std::vector<bool> filter(counters.counter_count(), true);
+  for (size_t i = 0; i < qc.constraints().size(); i++) {
+    const auto& cs = qc.constraints()[i];
+    auto* v = argv[i];
+    switch (cs.iColumn) {
+      case CountersTable::Column::kTimestamp:
+        FilterColumn(counters.timestamps(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kValue:
+        FilterColumn(counters.values(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kName:
+        FilterColumn(counters.name_ids(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kRef:
+        FilterColumn(counters.refs(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kDuration:
+        FilterColumn(counters.durations(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kValueDelta:
+        FilterColumn(counters.value_deltas(), 0, cs, v, &filter);
+        break;
+      case CountersTable::Column::kRefType: {
+        // TODO(lalitm): add support for filtering here.
+      }
+    }
+  }
+
+  sorted_rows_ = CreateSortedIndexFromFilter(
+      0, filter, [this, &qc](uint32_t f, uint32_t s) {
+        return CompareCounters(storage_, f, s, qc.order_by()) < 0;
+      });
 }
 
 int CountersTable::Cursor::Column(sqlite3_context* context, int N) {
+  size_t row = sorted_rows_[next_row_idx_];
   switch (N) {
     case Column::kTimestamp: {
       sqlite3_result_int64(
           context,
-          static_cast<int64_t>(storage_->counters().timestamps()[row_]));
+          static_cast<int64_t>(storage_->counters().timestamps()[row]));
       break;
     }
     case Column::kValue: {
       sqlite3_result_int64(
-          context, static_cast<int64_t>(storage_->counters().values()[row_]));
+          context, static_cast<int64_t>(storage_->counters().values()[row]));
       break;
     }
     case Column::kName: {
       sqlite3_result_text(
           context,
-          storage_->GetString(storage_->counters().name_ids()[row_]).c_str(),
-          -1, nullptr);
+          storage_->GetString(storage_->counters().name_ids()[row]).c_str(), -1,
+          nullptr);
       break;
     }
     case Column::kRef: {
       sqlite3_result_int64(
-          context, static_cast<int64_t>(storage_->counters().refs()[row_]));
+          context, static_cast<int64_t>(storage_->counters().refs()[row]));
       break;
     }
     case Column::kRefType: {
-      switch (storage_->counters().types()[row_]) {
+      switch (storage_->counters().types()[row]) {
         case RefType::kCPU_ID: {
           sqlite3_result_text(context, "cpu", -1, nullptr);
           break;
@@ -119,14 +198,13 @@
     }
     case Column::kDuration: {
       sqlite3_result_int64(
-          context,
-          static_cast<int64_t>(storage_->counters().durations()[row_]));
+          context, static_cast<int64_t>(storage_->counters().durations()[row]));
       break;
     }
     case Column::kValueDelta: {
       sqlite3_result_int64(
           context,
-          static_cast<int64_t>(storage_->counters().value_deltas()[row_]));
+          static_cast<int64_t>(storage_->counters().value_deltas()[row]));
       break;
     }
     default:
@@ -137,12 +215,12 @@
 }
 
 int CountersTable::Cursor::Next() {
-  row_++;
+  next_row_idx_++;
   return SQLITE_OK;
 }
 
 int CountersTable::Cursor::Eof() {
-  return row_ >= num_rows_;
+  return next_row_idx_ >= sorted_rows_.size();
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/counters_table.h b/src/trace_processor/counters_table.h
index 90929ec..c35b887 100644
--- a/src/trace_processor/counters_table.h
+++ b/src/trace_processor/counters_table.h
@@ -51,7 +51,7 @@
  private:
   class Cursor : public Table::Cursor {
    public:
-    Cursor(const TraceStorage*);
+    Cursor(const TraceStorage*, const QueryConstraints&, sqlite3_value**);
 
     // Implementation of Table::Cursor.
     int Next() override;
@@ -59,8 +59,11 @@
     int Column(sqlite3_context*, int N) override;
 
    private:
-    size_t num_rows_;
-    size_t row_ = 0;
+    // Vector of row ids sorted by some order by constraints.
+    std::vector<uint32_t> sorted_rows_;
+
+    // An offset into |sorted_row_ids_| indicating the next row to return.
+    uint32_t next_row_idx_ = 0;
 
     const TraceStorage* const storage_;
   };
diff --git a/src/trace_processor/sched_slice_table.cc b/src/trace_processor/sched_slice_table.cc
index 079168f..0575f00 100644
--- a/src/trace_processor/sched_slice_table.cc
+++ b/src/trace_processor/sched_slice_table.cc
@@ -34,16 +34,6 @@
 
 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
 
-template <class T>
-inline int Compare(T first, T second, bool desc) {
-  if (first < second) {
-    return desc ? 1 : -1;
-  } else if (first > second) {
-    return desc ? -1 : 1;
-  }
-  return 0;
-}
-
 // Compares the slice at index |f| with the slice at index |s| on the
 // criteria in |order_by|.
 // Returns -1 if the first slice is before the second in the ordering, 1 if
@@ -56,13 +46,13 @@
   const auto& sl = storage->slices();
   switch (ob.iColumn) {
     case SchedSliceTable::Column::kTimestamp:
-      return Compare(sl.start_ns()[f_idx], sl.start_ns()[s_idx], ob.desc);
+      return CompareValues(sl.start_ns(), f_idx, s_idx, ob.desc);
     case SchedSliceTable::Column::kDuration:
-      return Compare(sl.durations()[f_idx], sl.durations()[s_idx], ob.desc);
+      return CompareValues(sl.durations(), f_idx, s_idx, ob.desc);
     case SchedSliceTable::Column::kCpu:
-      return Compare(sl.cpus()[f_idx], sl.cpus()[s_idx], ob.desc);
+      return CompareValues(sl.cpus(), f_idx, s_idx, ob.desc);
     case SchedSliceTable::Column::kUtid:
-      return Compare(sl.utids()[f_idx], sl.utids()[s_idx], ob.desc);
+      return CompareValues(sl.utids(), f_idx, s_idx, ob.desc);
     default:
       PERFETTO_FATAL("Unexpected column %d", ob.iColumn);
   }
@@ -133,8 +123,6 @@
                                      uint32_t min_idx,
                                      uint32_t max_idx) {
   const auto& slices = storage->slices();
-  ptrdiff_t min_idx_ptr = static_cast<ptrdiff_t>(min_idx);
-  ptrdiff_t max_idx_ptr = static_cast<ptrdiff_t>(max_idx);
 
   auto dist = static_cast<size_t>(max_idx - min_idx);
   std::vector<bool> filter(dist, true);
@@ -142,21 +130,15 @@
     const auto& cs = qc.constraints()[i];
     auto* v = argv[i];
     switch (cs.iColumn) {
-      case SchedSliceTable::Column::kCpu: {
-        auto it = slices.cpus().begin();
-        FilterColumn(it + min_idx_ptr, it + max_idx_ptr, cs, v, &filter);
+      case SchedSliceTable::Column::kCpu:
+        FilterColumn(slices.cpus(), min_idx, cs, v, &filter);
         break;
-      }
-      case SchedSliceTable::Column::kDuration: {
-        auto it = slices.durations().begin();
-        FilterColumn(it + min_idx_ptr, it + max_idx_ptr, cs, v, &filter);
+      case SchedSliceTable::Column::kDuration:
+        FilterColumn(slices.durations(), min_idx, cs, v, &filter);
         break;
-      }
-      case SchedSliceTable::Column::kUtid: {
-        auto it = slices.utids().begin();
-        FilterColumn(it + min_idx_ptr, it + max_idx_ptr, cs, v, &filter);
+      case SchedSliceTable::Column::kUtid:
+        FilterColumn(slices.utids(), min_idx, cs, v, &filter);
         break;
-      }
     }
   }
   return filter;
@@ -219,8 +201,8 @@
     return std::unique_ptr<Table::Cursor>(
         new FilterCursor(storage_, min_idx, max_idx, std::move(filter), desc));
   }
-  return std::unique_ptr<Table::Cursor>(new SortedCursor(
-      storage_, min_idx, max_idx, qc.order_by(), std::move(filter)));
+  return std::unique_ptr<Table::Cursor>(
+      new SortedCursor(storage_, min_idx, qc.order_by(), std::move(filter)));
 }
 
 int SchedSliceTable::BestIndex(const QueryConstraints& qc,
@@ -342,27 +324,14 @@
 
 SchedSliceTable::SortedCursor::SortedCursor(
     const TraceStorage* storage,
-    uint32_t min_idx,
-    uint32_t max_idx,
+    uint32_t offset,
     const std::vector<QueryConstraints::OrderBy>& ob,
     const std::vector<bool>& filter)
     : BaseCursor(storage) {
-  auto diff = static_cast<size_t>(max_idx - min_idx);
-  PERFETTO_CHECK(diff == filter.size());
-
-  auto set_bits = std::count(filter.begin(), filter.end(), true);
-  sorted_rows_.resize(static_cast<size_t>(set_bits));
-
-  auto it = std::find(filter.begin(), filter.end(), true);
-  for (size_t i = 0; it != filter.end(); i++) {
-    auto index = static_cast<uint32_t>(std::distance(filter.begin(), it));
-    sorted_rows_[i] = min_idx + index;
-    it = std::find(it + 1, filter.end(), true);
-  }
-  std::sort(sorted_rows_.begin(), sorted_rows_.end(),
-            [this, &ob](uint32_t f, uint32_t s) {
-              return CompareSlices(storage_, f, s, ob) < 0;
-            });
+  sorted_rows_ = CreateSortedIndexFromFilter(
+      offset, filter, [this, &ob](uint32_t f, uint32_t s) {
+        return CompareSlices(storage_, f, s, ob) < 0;
+      });
 }
 
 int SchedSliceTable::SortedCursor::Next() {
diff --git a/src/trace_processor/sched_slice_table.h b/src/trace_processor/sched_slice_table.h
index bd63df8..ea41cae 100644
--- a/src/trace_processor/sched_slice_table.h
+++ b/src/trace_processor/sched_slice_table.h
@@ -122,8 +122,7 @@
                  uint32_t max_idx,
                  const std::vector<QueryConstraints::OrderBy>&);
     SortedCursor(const TraceStorage* storage,
-                 uint32_t min_idx,
-                 uint32_t max_idx,
+                 uint32_t offset,
                  const std::vector<QueryConstraints::OrderBy>&,
                  const std::vector<bool>& filter);
 
diff --git a/src/trace_processor/sqlite_utils.h b/src/trace_processor/sqlite_utils.h
index 191f316..83d5074 100644
--- a/src/trace_processor/sqlite_utils.h
+++ b/src/trace_processor/sqlite_utils.h
@@ -68,57 +68,99 @@
   }
 }
 
+template <class D>
+int CompareValues(const D& deque, size_t a, size_t b, bool desc) {
+  const auto& first = deque[a];
+  const auto& second = deque[b];
+  if (first < second) {
+    return desc ? 1 : -1;
+  } else if (first > second) {
+    return desc ? -1 : 1;
+  }
+  return 0;
+}
+
 template <typename F>
-bool Compare(uint32_t actual, sqlite3_value* value) {
+bool CompareToSqliteValue(uint32_t actual, sqlite3_value* value) {
   PERFETTO_DCHECK(sqlite3_value_type(value) == SQLITE_INTEGER);
   return F()(actual, static_cast<uint32_t>(sqlite3_value_int64(value)));
 }
 
 template <typename F>
-bool Compare(uint64_t actual, sqlite3_value* value) {
-  PERFETTO_CHECK(sqlite3_value_type(value) == SQLITE_INTEGER);
+bool CompareToSqliteValue(uint64_t actual, sqlite3_value* value) {
+  PERFETTO_DCHECK(sqlite3_value_type(value) == SQLITE_INTEGER);
   return F()(actual, static_cast<uint64_t>(sqlite3_value_int64(value)));
 }
 
-template <class RandomAccessIterator>
-void FilterColumn(RandomAccessIterator begin,
-                  RandomAccessIterator end,
+template <typename F>
+bool CompareToSqliteValue(int64_t actual, sqlite3_value* value) {
+  PERFETTO_DCHECK(sqlite3_value_type(value) == SQLITE_INTEGER);
+  return F()(actual, static_cast<int64_t>(sqlite3_value_int64(value)));
+}
+
+template <typename F>
+bool CompareToSqliteValue(double actual, sqlite3_value* value) {
+  auto type = sqlite3_value_type(value);
+  PERFETTO_DCHECK(type == SQLITE_FLOAT || type == SQLITE_INTEGER);
+  return F()(actual, sqlite3_value_double(value));
+}
+
+template <class D>
+void FilterColumn(const D& deque,
+                  size_t offset,
                   const QueryConstraints::Constraint& constraint,
                   sqlite3_value* argv,
-                  std::vector<bool>* row_filter) {
-  using T = typename RandomAccessIterator::value_type;
-  PERFETTO_DCHECK(static_cast<size_t>(std::distance(begin, end)) ==
-                  row_filter->size());
+                  std::vector<bool>* filter) {
+  using T = typename D::value_type;
 
-  auto it = std::find(row_filter->begin(), row_filter->end(), true);
-  while (it != row_filter->end()) {
-    auto index = std::distance(row_filter->begin(), it);
+  auto it = std::find(filter->begin(), filter->end(), true);
+  while (it != filter->end()) {
+    auto filter_idx = static_cast<size_t>(std::distance(filter->begin(), it));
+    T actual = deque[offset + filter_idx];
     switch (constraint.op) {
       case SQLITE_INDEX_CONSTRAINT_EQ:
-        *it = Compare<std::equal_to<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::equal_to<T>>(actual, argv);
         break;
       case SQLITE_INDEX_CONSTRAINT_GE:
-        *it = Compare<std::greater_equal<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::greater_equal<T>>(actual, argv);
         break;
       case SQLITE_INDEX_CONSTRAINT_GT:
-        *it = Compare<std::greater<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::greater<T>>(actual, argv);
         break;
       case SQLITE_INDEX_CONSTRAINT_LE:
-        *it = Compare<std::less_equal<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::less_equal<T>>(actual, argv);
         break;
       case SQLITE_INDEX_CONSTRAINT_LT:
-        *it = Compare<std::less<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::less<T>>(actual, argv);
         break;
       case SQLITE_INDEX_CONSTRAINT_NE:
-        *it = Compare<std::not_equal_to<T>>(begin[index], argv);
+        *it = CompareToSqliteValue<std::not_equal_to<T>>(actual, argv);
         break;
       default:
         PERFETTO_CHECK(false);
     }
-    it = std::find(it + 1, row_filter->end(), true);
+    it = std::find(it + 1, filter->end(), true);
   }
 }
 
+template <class Comparator>
+std::vector<uint32_t> CreateSortedIndexFromFilter(
+    uint32_t offset,
+    const std::vector<bool>& filter,
+    Comparator comparator) {
+  auto set_bits = std::count(filter.begin(), filter.end(), true);
+
+  std::vector<uint32_t> sorted_rows(static_cast<size_t>(set_bits));
+  auto it = std::find(filter.begin(), filter.end(), true);
+  for (size_t i = 0; it != filter.end(); i++) {
+    auto filter_idx = static_cast<uint32_t>(std::distance(filter.begin(), it));
+    sorted_rows[i] = offset + filter_idx;
+    it = std::find(it + 1, filter.end(), true);
+  }
+  std::sort(sorted_rows.begin(), sorted_rows.end(), comparator);
+  return sorted_rows;
+}
+
 }  // namespace sqlite_utils
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/table.cc b/src/trace_processor/table.cc
index 228551d..72eb3c2 100644
--- a/src/trace_processor/table.cc
+++ b/src/trace_processor/table.cc
@@ -51,6 +51,8 @@
       return "UNSIGNED BIG INT";
     case Table::ColumnType::kInt:
       return "INT";
+    case Table::ColumnType::kDouble:
+      return "DOUBLE";
   }
   PERFETTO_CHECK(false);
 }
diff --git a/src/trace_processor/table.h b/src/trace_processor/table.h
index db1af75..5cf22f2 100644
--- a/src/trace_processor/table.h
+++ b/src/trace_processor/table.h
@@ -45,6 +45,7 @@
     kUlong = 2,
     kUint = 3,
     kInt = 4,
+    kDouble = 5,
   };
 
   // Describes a column of this table.