Merge "trace_processor: migrate instants table to macro tables"
diff --git a/Android.bp b/Android.bp
index 3d8cdc7..063d31a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5701,7 +5701,6 @@
     "src/trace_processor/args_table.cc",
     "src/trace_processor/filtered_row_index.cc",
     "src/trace_processor/gfp_flags.cc",
-    "src/trace_processor/instants_table.cc",
     "src/trace_processor/metadata_table.cc",
     "src/trace_processor/process_table.cc",
     "src/trace_processor/raw_table.cc",
diff --git a/BUILD b/BUILD
index 85d887b..df87dec 100644
--- a/BUILD
+++ b/BUILD
@@ -790,8 +790,6 @@
         "src/trace_processor/filtered_row_index.h",
         "src/trace_processor/gfp_flags.cc",
         "src/trace_processor/gfp_flags.h",
-        "src/trace_processor/instants_table.cc",
-        "src/trace_processor/instants_table.h",
         "src/trace_processor/metadata_table.cc",
         "src/trace_processor/metadata_table.h",
         "src/trace_processor/process_table.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 71d87e5..d8a3f59 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -287,8 +287,6 @@
     "filtered_row_index.h",
     "gfp_flags.cc",
     "gfp_flags.h",
-    "instants_table.cc",
-    "instants_table.h",
     "metadata_table.cc",
     "metadata_table.h",
     "process_table.cc",
diff --git a/src/trace_processor/args_tracker.cc b/src/trace_processor/args_tracker.cc
index 88ccecf..cfd9f83 100644
--- a/src/trace_processor/args_tracker.cc
+++ b/src/trace_processor/args_tracker.cc
@@ -79,7 +79,8 @@
                                                                     set_id);
         break;
       case TableId::kInstants:
-        storage->mutable_instants()->set_arg_set_id(row, set_id);
+        storage->mutable_instant_table()->mutable_arg_set_id()->Set(row,
+                                                                    set_id);
         break;
       case TableId::kNestableSlices:
         storage->mutable_slice_table()->mutable_arg_set_id()->Set(row, set_id);
diff --git a/src/trace_processor/event_tracker.cc b/src/trace_processor/event_tracker.cc
index 8ee221a..348ac68 100644
--- a/src/trace_processor/event_tracker.cc
+++ b/src/trace_processor/event_tracker.cc
@@ -67,25 +67,27 @@
   return counter_values->Insert({timestamp, track_id.value, value});
 }
 
-uint32_t EventTracker::PushInstant(int64_t timestamp,
-                                   StringId name_id,
-                                   double value,
-                                   int64_t ref,
-                                   RefType ref_type,
-                                   bool resolve_utid_to_upid) {
-  auto* instants = context_->storage->mutable_instants();
-  uint32_t idx;
+InstantId EventTracker::PushInstant(int64_t timestamp,
+                                    StringId name_id,
+                                    int64_t ref,
+                                    RefType ref_type,
+                                    bool resolve_utid_to_upid) {
+  auto* instants = context_->storage->mutable_instant_table();
+  InstantId id;
   if (resolve_utid_to_upid) {
-    idx = instants->AddInstantEvent(timestamp, name_id, value, 0,
-                                    RefType::kRefUpid);
+    auto ref_type_id = context_->storage->InternString(
+        GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefUpid)]);
+    id = instants->Insert({timestamp, name_id, 0, ref_type_id});
     PendingUpidResolutionInstant pending;
-    pending.row = idx;
+    pending.row = *instants->id().IndexOf(id);
     pending.utid = static_cast<UniqueTid>(ref);
     pending_upid_resolution_instant_.emplace_back(pending);
   } else {
-    idx = instants->AddInstantEvent(timestamp, name_id, value, ref, ref_type);
+    auto ref_type_id = context_->storage->InternString(
+        GetRefTypeStringMap()[static_cast<size_t>(ref_type)]);
+    id = instants->Insert({timestamp, name_id, ref, ref_type_id});
   }
-  return idx;
+  return id;
 }
 
 void EventTracker::FlushPendingEvents() {
@@ -105,7 +107,8 @@
     // TODO(lalitm): having upid == 0 is probably not the correct approach here
     // but it's unclear what may be better.
     UniquePid upid = thread.upid.value_or(0);
-    context_->storage->mutable_instants()->set_ref(pending_instant.row, upid);
+    context_->storage->mutable_instant_table()->mutable_ref()->Set(
+        pending_instant.row, upid);
   }
 
   pending_upid_resolution_counter_.clear();
diff --git a/src/trace_processor/event_tracker.h b/src/trace_processor/event_tracker.h
index 7e27807..983dad0 100644
--- a/src/trace_processor/event_tracker.h
+++ b/src/trace_processor/event_tracker.h
@@ -56,12 +56,11 @@
       UniqueTid utid);
 
   // This method is called when a instant event is seen in the trace.
-  virtual uint32_t PushInstant(int64_t timestamp,
-                               StringId name_id,
-                               double value,
-                               int64_t ref,
-                               RefType ref_type,
-                               bool resolve_utid_to_upid = false);
+  virtual InstantId PushInstant(int64_t timestamp,
+                                StringId name_id,
+                                int64_t ref,
+                                RefType ref_type,
+                                bool resolve_utid_to_upid = false);
 
   // Called at the end of trace to flush any events which are pending to the
   // storage.
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index b3013a6..d61c63c 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -477,8 +477,8 @@
   uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
   StringId name_id = context_->storage->InternString(sw.comm());
   auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
-  context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, 0 /* value */,
-                                       utid, RefType::kRefUtid);
+  context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, utid,
+                                       RefType::kRefUtid);
 }
 
 void FtraceParser::ParseSchedWaking(int64_t ts, ConstBytes blob) {
@@ -486,8 +486,8 @@
   uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
   StringId name_id = context_->storage->InternString(sw.comm());
   auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
-  context_->event_tracker->PushInstant(ts, sched_waking_name_id_, 0 /* value */,
-                                       utid, RefType::kRefUtid);
+  context_->event_tracker->PushInstant(ts, sched_waking_name_id_, utid,
+                                       RefType::kRefUtid);
 }
 
 void FtraceParser::ParseSchedProcessFree(int64_t ts, ConstBytes blob) {
@@ -612,8 +612,13 @@
 
   UniqueTid utid = context_->process_tracker->GetOrCreateThread(
       static_cast<uint32_t>(sig.pid()));
-  context_->event_tracker->PushInstant(ts, signal_generate_id_, sig.sig(), utid,
-                                       RefType::kRefUtid);
+  InstantId id = context_->event_tracker->PushInstant(ts, signal_generate_id_,
+                                                      utid, RefType::kRefUtid);
+  uint32_t row = *context_->storage->instant_table().id().IndexOf(id);
+
+  StringId key = context_->storage->InternString("signal.sig");
+  context_->args_tracker->AddArg(TableId::kInstants, row, key, key,
+                                 Variadic::Integer(sig.sig()));
 }
 
 void FtraceParser::ParseSignalDeliver(int64_t ts,
@@ -621,8 +626,13 @@
                                       ConstBytes blob) {
   protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
-  context_->event_tracker->PushInstant(ts, signal_deliver_id_, sig.sig(), utid,
-                                       RefType::kRefUtid);
+  InstantId id = context_->event_tracker->PushInstant(ts, signal_deliver_id_,
+                                                      utid, RefType::kRefUtid);
+  uint32_t row = *context_->storage->instant_table().id().IndexOf(id);
+
+  StringId key = context_->storage->InternString("signal.sig");
+  context_->args_tracker->AddArg(TableId::kInstants, row, key, key,
+                                 Variadic::Integer(sig.sig()));
 }
 
 void FtraceParser::ParseLowmemoryKill(int64_t ts, ConstBytes blob) {
@@ -639,8 +649,9 @@
   if (!opt_utid)
     return;
 
-  uint32_t row = context_->event_tracker->PushInstant(
-      ts, lmk_id_, 0, opt_utid.value(), RefType::kRefUtid, true);
+  InstantId id = context_->event_tracker->PushInstant(
+      ts, lmk_id_, opt_utid.value(), RefType::kRefUtid, true);
+  uint32_t row = *context_->storage->instant_table().id().IndexOf(id);
 
   // Store the comm as an arg.
   auto comm_id = context_->storage->InternString(
diff --git a/src/trace_processor/importers/ftrace/sched_event_tracker.cc b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
index 562a62a..df5f575 100644
--- a/src/trace_processor/importers/ftrace/sched_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
@@ -293,9 +293,10 @@
 
   // Add a waking entry to the instants.
   auto wakee_utid = context_->process_tracker->GetOrCreateThread(wakee_pid);
-  auto* instants = context_->storage->mutable_instants();
-  instants->AddInstantEvent(ts, sched_waking_id_, /*value=*/0, wakee_utid,
-                            RefType::kRefUtid);
+  auto* instants = context_->storage->mutable_instant_table();
+  auto ref_type_id = context_->storage->InternString(
+      GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefUtid)]);
+  instants->Insert({ts, sched_waking_id_, wakee_utid, ref_type_id});
 }
 
 void SchedEventTracker::FlushPendingEvents() {
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
index 83a5e31..660c680 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
@@ -251,8 +251,9 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          uint32_t row = context_->event_tracker->PushInstant(
-              ts, name, 0, utid, RefType::kRefUtid);
+          InstantId id = context_->event_tracker->PushInstant(
+              ts, name, utid, RefType::kRefUtid);
+          uint32_t row = *context_->storage->instant_table().id().IndexOf(id);
           for (const Arg& arg : args) {
             context_->args_tracker->AddArg(
                 TableId::kInstants, row, arg.name, arg.name,
@@ -376,8 +377,9 @@
           }
           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
               name, correlation_id);
-          uint32_t row = context_->event_tracker->PushInstant(
-              ts, name, 0, track_id.value, RefType::kRefTrack);
+          InstantId id = context_->event_tracker->PushInstant(
+              ts, name, track_id.value, RefType::kRefTrack);
+          uint32_t row = *context_->storage->instant_table().id().IndexOf(id);
           for (const Arg& arg : args) {
             context_->args_tracker->AddArg(
                 TableId::kInstants, row, arg.name, arg.name,
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 6026684..0394ea7 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -129,14 +129,6 @@
                base::Optional<CounterId>(int64_t timestamp,
                                          double value,
                                          TrackId track_id));
-
-  MOCK_METHOD6(PushInstant,
-               uint32_t(int64_t timestamp,
-                        StringId name_id,
-                        double value,
-                        int64_t ref,
-                        RefType ref_type,
-                        bool resolve_utid_to_upid));
 };
 
 class MockProcessTracker : public ProcessTracker {
diff --git a/src/trace_processor/importers/systrace/systrace_parser.cc b/src/trace_processor/importers/systrace/systrace_parser.cc
index a22adeb..b6642a2 100644
--- a/src/trace_processor/importers/systrace/systrace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_parser.cc
@@ -160,7 +160,7 @@
         if (killed_pid != 0) {
           UniquePid killed_upid =
               context_->process_tracker->GetOrCreateProcess(killed_pid);
-          context_->event_tracker->PushInstant(ts, lmk_id_, 0, killed_upid,
+          context_->event_tracker->PushInstant(ts, lmk_id_, killed_upid,
                                                RefType::kRefUpid);
         }
         // TODO(lalitm): we should not add LMK events to the counters table
diff --git a/src/trace_processor/importers/systrace/systrace_trace_parser.cc b/src/trace_processor/importers/systrace/systrace_trace_parser.cc
index 734c566..2ffaac4 100644
--- a/src/trace_processor/importers/systrace/systrace_trace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_trace_parser.cc
@@ -212,8 +212,7 @@
     StringId name_id = context_->storage->InternString(base::StringView(comm));
     auto wakee_utid =
         context_->process_tracker->UpdateThreadName(wakee_pid.value(), name_id);
-    context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_,
-                                         0 /* value */, wakee_utid,
+    context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, wakee_utid,
                                          RefType::kRefUtid);
   } else if (event_name == "cpu_idle") {
     base::Optional<uint32_t> event_cpu = base::StringToUInt32(args["cpu_id"]);
diff --git a/src/trace_processor/instants_table.cc b/src/trace_processor/instants_table.cc
deleted file mode 100644
index 0c119e5..0000000
--- a/src/trace_processor/instants_table.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/instants_table.h"
-
-#include <string>
-
-#include "src/trace_processor/storage_columns.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-InstantsTable::InstantsTable(sqlite3*, const TraceStorage* storage)
-    : storage_(storage) {}
-
-void InstantsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  SqliteTable::Register<InstantsTable>(db, storage, "instants");
-}
-
-StorageSchema InstantsTable::CreateStorageSchema() {
-  const auto& instants = storage_->instants();
-  return StorageSchema::Builder()
-      .AddGenericNumericColumn("id", RowAccessor())
-      .AddOrderedNumericColumn("ts", &instants.timestamps())
-      .AddStringColumn("name", &instants.name_ids(), &storage_->string_pool())
-      .AddNumericColumn("value", &instants.values())
-      .AddNumericColumn("ref", &instants.refs())
-      .AddStringColumn("ref_type", &instants.types(), &GetRefTypeStringMap())
-      .AddNumericColumn("arg_set_id", &instants.arg_set_ids())
-      .Build({"name", "ts", "ref"});
-}
-
-uint32_t InstantsTable::RowCount() {
-  return static_cast<uint32_t>(storage_->instants().instant_count());
-}
-
-int InstantsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
-  info->estimated_cost =
-      static_cast<uint32_t>(storage_->instants().instant_count());
-  info->sqlite_omit_order_by = true;
-
-  // Only the string columns are handled by SQLite
-  size_t name_index = schema().ColumnIndexFromName("name");
-  size_t ref_type_index = schema().ColumnIndexFromName("ref_type");
-  for (size_t i = 0; i < qc.constraints().size(); i++) {
-    info->sqlite_omit_constraint[i] =
-        qc.constraints()[i].column != static_cast<int>(name_index) &&
-        qc.constraints()[i].column != static_cast<int>(ref_type_index);
-  }
-
-  return SQLITE_OK;
-}
-}  // namespace trace_processor
-}  // namespace perfetto
diff --git a/src/trace_processor/instants_table.h b/src/trace_processor/instants_table.h
deleted file mode 100644
index 7fc81fd..0000000
--- a/src/trace_processor/instants_table.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
-#define SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
-
-#include "src/trace_processor/storage_table.h"
-#include "src/trace_processor/trace_storage.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class InstantsTable : public StorageTable {
- public:
-  static void RegisterTable(sqlite3* db, const TraceStorage* storage);
-
-  InstantsTable(sqlite3*, const TraceStorage*);
-
-  // StorageTable implementation.
-  StorageSchema CreateStorageSchema() override;
-  uint32_t RowCount() override;
-  int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
-
- private:
-  const TraceStorage* const storage_;
-};
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
diff --git a/src/trace_processor/tables/slice_tables.h b/src/trace_processor/tables/slice_tables.h
index 4d2be49..3c34ff6 100644
--- a/src/trace_processor/tables/slice_tables.h
+++ b/src/trace_processor/tables/slice_tables.h
@@ -38,6 +38,17 @@
 
 PERFETTO_TP_TABLE(PERFETTO_TP_SLICE_TABLE_DEF);
 
+#define PERFETTO_TP_INSTANT_TABLE_DEF(NAME, PARENT, C) \
+  NAME(InstantTable, "instant")                        \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                    \
+  C(int64_t, ts, Column::Flag::kSorted)                \
+  C(StringPool::Id, name)                              \
+  C(int64_t, ref)                                      \
+  C(StringPool::Id, ref_type)                          \
+  C(uint32_t, arg_set_id)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_INSTANT_TABLE_DEF);
+
 #define PERFETTO_TP_GPU_SLICES_DEF(NAME, PARENT, C) \
   NAME(GpuSliceTable, "internal_gpu_slice")         \
   PERFETTO_TP_ROOT_TABLE(PARENT, C)                 \
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index b4ff778..78f4f56 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -26,7 +26,6 @@
 #include "src/trace_processor/android_logs_table.h"
 #include "src/trace_processor/args_table.h"
 #include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
-#include "src/trace_processor/instants_table.h"
 #include "src/trace_processor/metadata_table.h"
 #include "src/trace_processor/process_table.h"
 #include "src/trace_processor/raw_table.h"
@@ -193,6 +192,18 @@
     sqlite3_free(error);
   }
 
+  sqlite3_exec(db,
+               "CREATE VIEW instants AS "
+               "SELECT "
+               "*, "
+               "0.0 as value "
+               "FROM instant;",
+               0, 0, &error);
+  if (error) {
+    PERFETTO_ELOG("Error initializing: %s", error);
+    sqlite3_free(error);
+  }
+
   // Legacy view for "slice" table with a deprecated table name.
   // TODO(eseckler): Remove this view when all users have switched to "slice".
   sqlite3_exec(db,
@@ -367,7 +378,6 @@
   ThreadTable::RegisterTable(*db_, context_.storage.get());
   SpanJoinOperatorTable::RegisterTable(*db_, context_.storage.get());
   WindowOperatorTable::RegisterTable(*db_, context_.storage.get());
-  InstantsTable::RegisterTable(*db_, context_.storage.get());
   StatsTable::RegisterTable(*db_, context_.storage.get());
   AndroidLogsTable::RegisterTable(*db_, context_.storage.get());
   RawTable::RegisterTable(*db_, context_.storage.get());
@@ -378,6 +388,8 @@
 
   DbSqliteTable::RegisterTable(*db_, &storage->slice_table(),
                                storage->slice_table().table_name());
+  DbSqliteTable::RegisterTable(*db_, &storage->instant_table(),
+                               storage->instant_table().table_name());
   DbSqliteTable::RegisterTable(*db_, &storage->gpu_slice_table(),
                                storage->gpu_slice_table().table_name());
 
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index c3c4077..86ce439 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -126,8 +126,6 @@
   int64_t end_ns = std::numeric_limits<int64_t>::min();
   MaybeUpdateMinMax(slices_.start_ns().begin(), slices_.start_ns().end(),
                     &start_ns, &end_ns);
-  MaybeUpdateMinMax(instants_.timestamps().begin(),
-                    instants_.timestamps().end(), &start_ns, &end_ns);
   MaybeUpdateMinMax(android_log_.timestamps().begin(),
                     android_log_.timestamps().end(), &start_ns, &end_ns);
   MaybeUpdateMinMax(raw_events_.timestamps().begin(),
@@ -137,6 +135,7 @@
   DbTableMaybeUpdateMinMax(slice_table_.ts(), &start_ns, &end_ns);
   DbTableMaybeUpdateMinMax(heap_profile_allocation_table_.ts(), &start_ns,
                            &end_ns);
+  DbTableMaybeUpdateMinMax(instant_table_.ts(), &start_ns, &end_ns);
 
   if (start_ns == std::numeric_limits<int64_t>::max()) {
     return std::make_pair(0, 0);
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 5e6679d..316e36e 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -80,6 +80,8 @@
 
 using SliceId = tables::SliceTable::Id;
 
+using InstantId = tables::InstantTable::Id;
+
 using MappingId = tables::StackProfileMappingTable::Id;
 
 // TODO(lalitm): this is a temporary hack while migrating the counters table and
@@ -433,49 +435,6 @@
     std::deque<int64_t> times_ended_;
   };
 
-  class Instants {
-   public:
-    inline uint32_t AddInstantEvent(int64_t timestamp,
-                                    StringId name_id,
-                                    double value,
-                                    int64_t ref,
-                                    RefType type) {
-      timestamps_.emplace_back(timestamp);
-      name_ids_.emplace_back(name_id);
-      values_.emplace_back(value);
-      refs_.emplace_back(ref);
-      types_.emplace_back(type);
-      arg_set_ids_.emplace_back(kInvalidArgSetId);
-      return static_cast<uint32_t>(instant_count() - 1);
-    }
-
-    void set_ref(uint32_t row, int64_t ref) { refs_[row] = ref; }
-
-    void set_arg_set_id(uint32_t row, ArgSetId id) { arg_set_ids_[row] = id; }
-
-    size_t instant_count() const { return timestamps_.size(); }
-
-    const std::deque<int64_t>& timestamps() const { return timestamps_; }
-
-    const std::deque<StringId>& name_ids() const { return name_ids_; }
-
-    const std::deque<double>& values() const { return values_; }
-
-    const std::deque<int64_t>& refs() const { return refs_; }
-
-    const std::deque<RefType>& types() const { return types_; }
-
-    const std::deque<ArgSetId>& arg_set_ids() const { return arg_set_ids_; }
-
-   private:
-    std::deque<int64_t> timestamps_;
-    std::deque<StringId> name_ids_;
-    std::deque<double> values_;
-    std::deque<int64_t> refs_;
-    std::deque<RefType> types_;
-    std::deque<ArgSetId> arg_set_ids_;
-  };
-
   class RawEvents {
    public:
     inline uint32_t AddRawEvent(int64_t timestamp,
@@ -831,8 +790,8 @@
   const SqlStats& sql_stats() const { return sql_stats_; }
   SqlStats* mutable_sql_stats() { return &sql_stats_; }
 
-  const Instants& instants() const { return instants_; }
-  Instants* mutable_instants() { return &instants_; }
+  const tables::InstantTable& instant_table() const { return instant_table_; }
+  tables::InstantTable* mutable_instant_table() { return &instant_table_; }
 
   const AndroidLogs& android_logs() const { return android_log_; }
   AndroidLogs* mutable_android_log() { return &android_log_; }
@@ -1052,7 +1011,7 @@
   // These are instantaneous events in the trace. They have no duration
   // and do not have a value that make sense to track over time.
   // e.g. signal events
-  Instants instants_;
+  tables::InstantTable instant_table_{&string_pool_, nullptr};
 
   // Raw events are every ftrace event in the trace. The raw event includes
   // the timestamp and the pid. The args for the raw event will be in the