Merge changes I5ad9e5a5,Ief74d748

* changes:
  trace_processor: Remove PERFETTO_TP_ANDROID_PROBES build flag
  trace_processor: Remove PERFETTO_TP_SYSTEM_PROBES build flag
diff --git a/Android.bp b/Android.bp
index 827c726..5d95ca4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5628,14 +5628,31 @@
   ],
 }
 
+// GN: //src/trace_processor/containers:containers
+filegroup {
+  name: "perfetto_src_trace_processor_containers_containers",
+  srcs: [
+    "src/trace_processor/containers/bit_vector.cc",
+    "src/trace_processor/containers/bit_vector_iterators.cc",
+    "src/trace_processor/containers/row_map.cc",
+  ],
+}
+
+// GN: //src/trace_processor/containers:unittests
+filegroup {
+  name: "perfetto_src_trace_processor_containers_unittests",
+  srcs: [
+    "src/trace_processor/containers/bit_vector_unittest.cc",
+    "src/trace_processor/containers/row_map_unittest.cc",
+    "src/trace_processor/containers/sparse_vector_unittest.cc",
+  ],
+}
+
 // GN: //src/trace_processor/db:lib
 filegroup {
   name: "perfetto_src_trace_processor_db_lib",
   srcs: [
-    "src/trace_processor/db/bit_vector.cc",
-    "src/trace_processor/db/bit_vector_iterators.cc",
     "src/trace_processor/db/column.cc",
-    "src/trace_processor/db/row_map.cc",
     "src/trace_processor/db/table.cc",
   ],
 }
@@ -5644,10 +5661,7 @@
 filegroup {
   name: "perfetto_src_trace_processor_db_unittests",
   srcs: [
-    "src/trace_processor/db/bit_vector_unittest.cc",
     "src/trace_processor/db/compare_unittest.cc",
-    "src/trace_processor/db/row_map_unittest.cc",
-    "src/trace_processor/db/sparse_vector_unittest.cc",
   ],
 }
 
@@ -6590,6 +6604,8 @@
     ":perfetto_src_protozero_testing_messages_zero_gen",
     ":perfetto_src_protozero_unittests",
     ":perfetto_src_trace_processor_common",
+    ":perfetto_src_trace_processor_containers_containers",
+    ":perfetto_src_trace_processor_containers_unittests",
     ":perfetto_src_trace_processor_db_lib",
     ":perfetto_src_trace_processor_db_unittests",
     ":perfetto_src_trace_processor_descriptors",
@@ -6804,6 +6820,7 @@
     ":perfetto_src_base_base",
     ":perfetto_src_protozero_protozero",
     ":perfetto_src_trace_processor_common",
+    ":perfetto_src_trace_processor_containers_containers",
     ":perfetto_src_trace_processor_db_lib",
     ":perfetto_src_trace_processor_descriptors",
     ":perfetto_src_trace_processor_lib",
@@ -6911,6 +6928,7 @@
     ":perfetto_src_profiling_deobfuscator",
     ":perfetto_src_protozero_protozero",
     ":perfetto_src_trace_processor_common",
+    ":perfetto_src_trace_processor_containers_containers",
     ":perfetto_src_trace_processor_db_lib",
     ":perfetto_src_trace_processor_descriptors",
     ":perfetto_src_trace_processor_lib",
diff --git a/BUILD b/BUILD
index 71698f7..2435b10 100644
--- a/BUILD
+++ b/BUILD
@@ -572,20 +572,27 @@
     ],
 )
 
+# GN target: //src/trace_processor/containers:containers
+filegroup(
+    name = "src_trace_processor_containers_containers",
+    srcs = [
+        "src/trace_processor/containers/bit_vector.cc",
+        "src/trace_processor/containers/bit_vector.h",
+        "src/trace_processor/containers/bit_vector_iterators.cc",
+        "src/trace_processor/containers/bit_vector_iterators.h",
+        "src/trace_processor/containers/row_map.cc",
+        "src/trace_processor/containers/row_map.h",
+        "src/trace_processor/containers/sparse_vector.h",
+    ],
+)
+
 # GN target: //src/trace_processor/db:lib
 filegroup(
     name = "src_trace_processor_db_lib",
     srcs = [
-        "src/trace_processor/db/bit_vector.cc",
-        "src/trace_processor/db/bit_vector.h",
-        "src/trace_processor/db/bit_vector_iterators.cc",
-        "src/trace_processor/db/bit_vector_iterators.h",
         "src/trace_processor/db/column.cc",
         "src/trace_processor/db/column.h",
         "src/trace_processor/db/compare.h",
-        "src/trace_processor/db/row_map.cc",
-        "src/trace_processor/db/row_map.h",
-        "src/trace_processor/db/sparse_vector.h",
         "src/trace_processor/db/table.cc",
         "src/trace_processor/db/table.h",
         "src/trace_processor/db/typed_column.h",
@@ -2521,6 +2528,7 @@
         ":src_base_base",
         ":src_protozero_protozero",
         ":src_trace_processor_common",
+        ":src_trace_processor_containers_containers",
         ":src_trace_processor_db_lib",
         ":src_trace_processor_descriptors",
         ":src_trace_processor_export_json",
@@ -2599,6 +2607,7 @@
         ":src_base_unix_socket",
         ":src_protozero_protozero",
         ":src_trace_processor_common",
+        ":src_trace_processor_containers_containers",
         ":src_trace_processor_db_lib",
         ":src_trace_processor_descriptors",
         ":src_trace_processor_export_json",
@@ -2752,6 +2761,7 @@
         ":src_profiling_deobfuscator",
         ":src_protozero_protozero",
         ":src_trace_processor_common",
+        ":src_trace_processor_containers_containers",
         ":src_trace_processor_db_lib",
         ":src_trace_processor_descriptors",
         ":src_trace_processor_export_json",
diff --git a/BUILD.gn b/BUILD.gn
index 30f269d..4fdd937 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -82,6 +82,17 @@
   ]
 }
 
+if (enable_perfetto_trace_processor_json) {
+  executable("trace_processor_minimal_smoke_tests") {
+    testonly = true
+    deps = [
+      "gn:default_deps",
+      "src/trace_processor:storage_minimal_smoke_tests",
+    ]
+  }
+  all_targets += [ ":trace_processor_minimal_smoke_tests" ]
+}
+
 if (enable_perfetto_benchmarks) {
   import("gn/perfetto_benchmarks.gni")
   executable("perfetto_benchmarks") {
diff --git a/gn/perfetto_benchmarks.gni b/gn/perfetto_benchmarks.gni
index 4b0f331..122c6ff 100644
--- a/gn/perfetto_benchmarks.gni
+++ b/gn/perfetto_benchmarks.gni
@@ -18,7 +18,7 @@
   "gn:default_deps",
   "src/base:benchmarks",
   "src/traced/probes/ftrace:benchmarks",
-  "src/trace_processor/db:benchmarks",
+  "src/trace_processor/containers:benchmarks",
   "src/trace_processor/tables:benchmarks",
   "src/tracing:benchmarks",
   "test:benchmark_main",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 9604696..9d34b96 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -460,6 +460,7 @@
     "../base",
     "../protozero",
     "../protozero:testing_messages_zero",
+    "containers:unittests",
     "db:unittests",
     "tables:unittests",
   ]
@@ -537,6 +538,24 @@
   }
 }
 
+if (enable_perfetto_trace_processor_json) {
+  source_set("storage_minimal_smoke_tests") {
+    testonly = true
+    sources = [
+      "storage_minimal_smoke_test.cc",
+    ]
+    deps = [
+      ":export_json",
+      ":storage_minimal",
+      "../../gn:default_deps",
+      "../../gn:gtest_and_gmock",
+      "../../gn:gtest_main",
+      "../../gn:jsoncpp",
+      "../base:test_support",
+    ]
+  }
+}
+
 perfetto_fuzzer_test("trace_processor_fuzzer") {
   testonly = true
   sources = [
diff --git a/src/trace_processor/containers/BUILD.gn b/src/trace_processor/containers/BUILD.gn
new file mode 100644
index 0000000..c6c5d73
--- /dev/null
+++ b/src/trace_processor/containers/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright (C) 2019 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.
+
+import("../../../gn/test.gni")
+
+source_set("containers") {
+  sources = [
+    "bit_vector.cc",
+    "bit_vector.h",
+    "bit_vector_iterators.cc",
+    "bit_vector_iterators.h",
+    "row_map.cc",
+    "row_map.h",
+    "sparse_vector.h",
+  ]
+  deps = [
+    "../:common",
+    "../../../gn:default_deps",
+    "../../../include/perfetto/base",
+    "../../../include/perfetto/ext/base",
+  ]
+}
+
+perfetto_unittest_source_set("unittests") {
+  testonly = true
+  sources = [
+    "bit_vector_unittest.cc",
+    "row_map_unittest.cc",
+    "sparse_vector_unittest.cc",
+  ]
+  deps = [
+    ":containers",
+    "../../../gn:default_deps",
+    "../../../gn:gtest_and_gmock",
+  ]
+}
+
+if (enable_perfetto_benchmarks) {
+  source_set("benchmarks") {
+    testonly = true
+    deps = [
+      ":containers",
+      "../../../gn:benchmark",
+      "../../../gn:default_deps",
+    ]
+    sources = [
+      "bit_vector_benchmark.cc",
+      "row_map_benchmark.cc",
+      "sparse_vector_benchmark.cc",
+    ]
+  }
+}
diff --git a/src/trace_processor/db/bit_vector.cc b/src/trace_processor/containers/bit_vector.cc
similarity index 94%
rename from src/trace_processor/db/bit_vector.cc
rename to src/trace_processor/containers/bit_vector.cc
index 0d2f3d8..0ec5bcc 100644
--- a/src/trace_processor/db/bit_vector.cc
+++ b/src/trace_processor/containers/bit_vector.cc
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/bit_vector.h"
+#include "src/trace_processor/containers/bit_vector.h"
 
-#include "src/trace_processor/db/bit_vector_iterators.h"
+#include "src/trace_processor/containers/bit_vector_iterators.h"
 
 namespace perfetto {
 namespace trace_processor {
diff --git a/src/trace_processor/db/bit_vector.h b/src/trace_processor/containers/bit_vector.h
similarity index 98%
rename from src/trace_processor/db/bit_vector.h
rename to src/trace_processor/containers/bit_vector.h
index bed71a6..58b9e23 100644
--- a/src/trace_processor/db/bit_vector.h
+++ b/src/trace_processor/containers/bit_vector.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_H_
-#define SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_H_
+#ifndef SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -655,4 +655,4 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
-#endif  // SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_H_
+#endif  // SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_H_
diff --git a/src/trace_processor/db/bit_vector_benchmark.cc b/src/trace_processor/containers/bit_vector_benchmark.cc
similarity index 98%
rename from src/trace_processor/db/bit_vector_benchmark.cc
rename to src/trace_processor/containers/bit_vector_benchmark.cc
index 54c00f9..b4a0c27 100644
--- a/src/trace_processor/db/bit_vector_benchmark.cc
+++ b/src/trace_processor/containers/bit_vector_benchmark.cc
@@ -16,7 +16,7 @@
 
 #include <benchmark/benchmark.h>
 
-#include "src/trace_processor/db/bit_vector.h"
+#include "src/trace_processor/containers/bit_vector.h"
 
 namespace {
 
@@ -36,7 +36,7 @@
     b->Arg(1234567);
   }
 }
-}
+}  // namespace
 
 static void BM_BitVectorAppendTrue(benchmark::State& state) {
   BitVector bv;
diff --git a/src/trace_processor/db/bit_vector_iterators.cc b/src/trace_processor/containers/bit_vector_iterators.cc
similarity index 98%
rename from src/trace_processor/db/bit_vector_iterators.cc
rename to src/trace_processor/containers/bit_vector_iterators.cc
index 281384c..5424365 100644
--- a/src/trace_processor/db/bit_vector_iterators.cc
+++ b/src/trace_processor/containers/bit_vector_iterators.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/bit_vector_iterators.h"
+#include "src/trace_processor/containers/bit_vector_iterators.h"
 
 namespace perfetto {
 namespace trace_processor {
diff --git a/src/trace_processor/db/bit_vector_iterators.h b/src/trace_processor/containers/bit_vector_iterators.h
similarity index 95%
rename from src/trace_processor/db/bit_vector_iterators.h
rename to src/trace_processor/containers/bit_vector_iterators.h
index 365e8ef..0047812 100644
--- a/src/trace_processor/db/bit_vector_iterators.h
+++ b/src/trace_processor/containers/bit_vector_iterators.h
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
-#define SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
+#ifndef SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_
 
-#include "src/trace_processor/db/bit_vector.h"
+#include "src/trace_processor/containers/bit_vector.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -187,4 +187,4 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
-#endif  // SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
+#endif  // SRC_TRACE_PROCESSOR_CONTAINERS_BIT_VECTOR_ITERATORS_H_
diff --git a/src/trace_processor/db/bit_vector_unittest.cc b/src/trace_processor/containers/bit_vector_unittest.cc
similarity index 98%
rename from src/trace_processor/db/bit_vector_unittest.cc
rename to src/trace_processor/containers/bit_vector_unittest.cc
index 7b5aad7..e185afd 100644
--- a/src/trace_processor/db/bit_vector_unittest.cc
+++ b/src/trace_processor/containers/bit_vector_unittest.cc
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/bit_vector.h"
+#include "src/trace_processor/containers/bit_vector.h"
 
 #include <random>
 
-#include "src/trace_processor/db/bit_vector_iterators.h"
+#include "src/trace_processor/containers/bit_vector_iterators.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
diff --git a/src/trace_processor/db/row_map.cc b/src/trace_processor/containers/row_map.cc
similarity index 98%
rename from src/trace_processor/db/row_map.cc
rename to src/trace_processor/containers/row_map.cc
index cb16e4d..b10d0cb 100644
--- a/src/trace_processor/db/row_map.cc
+++ b/src/trace_processor/containers/row_map.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/row_map.h"
+#include "src/trace_processor/containers/row_map.h"
 
 namespace perfetto {
 namespace trace_processor {
diff --git a/src/trace_processor/db/row_map.h b/src/trace_processor/containers/row_map.h
similarity index 95%
rename from src/trace_processor/db/row_map.h
rename to src/trace_processor/containers/row_map.h
index 9b2805e..00ad7d2 100644
--- a/src/trace_processor/db/row_map.h
+++ b/src/trace_processor/containers/row_map.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef SRC_TRACE_PROCESSOR_DB_ROW_MAP_H_
-#define SRC_TRACE_PROCESSOR_DB_ROW_MAP_H_
+#ifndef SRC_TRACE_PROCESSOR_CONTAINERS_ROW_MAP_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_ROW_MAP_H_
 
 #include <stdint.h>
 
@@ -24,8 +24,8 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/optional.h"
-#include "src/trace_processor/db/bit_vector.h"
-#include "src/trace_processor/db/bit_vector_iterators.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/bit_vector_iterators.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -381,31 +381,13 @@
   //   if (!other.Contains(idx))
   //     Remove(idx)
   void Intersect(const RowMap& other) {
-    uint32_t size = other.size();
-
-    if (size == 0u) {
-      // If other is empty, then we will also end up being empty.
-      *this = RowMap();
-      return;
-    }
-
-    if (size == 1u) {
-      // If other just has a single row, see if we also have that row. If we
-      // do, then just return that row. Otherwise, make ourselves empty.
-      uint32_t row = other.Get(0);
-      *this = Contains(row) ? RowMap::SingleRow(row) : RowMap();
-      return;
-    }
-
     if (mode_ == Mode::kRange && other.mode_ == Mode::kRange) {
       // If both RowMaps have ranges, we can just take the smallest intersection
       // of them as the new RowMap.
-      // This case is important to optimize as it comes up with sorted columns.
+      // We have this as an explicit fast path as this is very common for
+      // constraints on id and sorted columns to satisfy this condition.
       start_idx_ = std::max(start_idx_, other.start_idx_);
-      end_idx_ = std::min(end_idx_, other.end_idx_);
-
-      if (end_idx_ <= start_idx_)
-        *this = RowMap();
+      end_idx_ = std::max(start_idx_, std::min(end_idx_, other.end_idx_));
       return;
     }
 
@@ -634,4 +616,4 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
-#endif  // SRC_TRACE_PROCESSOR_DB_ROW_MAP_H_
+#endif  // SRC_TRACE_PROCESSOR_CONTAINERS_ROW_MAP_H_
diff --git a/src/trace_processor/db/row_map_benchmark.cc b/src/trace_processor/containers/row_map_benchmark.cc
similarity index 99%
rename from src/trace_processor/db/row_map_benchmark.cc
rename to src/trace_processor/containers/row_map_benchmark.cc
index 1d6892e..47d66cd 100644
--- a/src/trace_processor/db/row_map_benchmark.cc
+++ b/src/trace_processor/containers/row_map_benchmark.cc
@@ -16,7 +16,7 @@
 
 #include <benchmark/benchmark.h>
 
-#include "src/trace_processor/db/row_map.h"
+#include "src/trace_processor/containers/row_map.h"
 
 using perfetto::trace_processor::BitVector;
 using perfetto::trace_processor::RowMap;
diff --git a/src/trace_processor/db/row_map_unittest.cc b/src/trace_processor/containers/row_map_unittest.cc
similarity index 99%
rename from src/trace_processor/db/row_map_unittest.cc
rename to src/trace_processor/containers/row_map_unittest.cc
index 042154d..c85b5fe 100644
--- a/src/trace_processor/db/row_map_unittest.cc
+++ b/src/trace_processor/containers/row_map_unittest.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/row_map.h"
+#include "src/trace_processor/containers/row_map.h"
 
 #include <memory>
 
diff --git a/src/trace_processor/db/sparse_vector.h b/src/trace_processor/containers/sparse_vector.h
similarity index 93%
rename from src/trace_processor/db/sparse_vector.h
rename to src/trace_processor/containers/sparse_vector.h
index 7fb0d87..5c803d3 100644
--- a/src/trace_processor/db/sparse_vector.h
+++ b/src/trace_processor/containers/sparse_vector.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef SRC_TRACE_PROCESSOR_DB_SPARSE_VECTOR_H_
-#define SRC_TRACE_PROCESSOR_DB_SPARSE_VECTOR_H_
+#ifndef SRC_TRACE_PROCESSOR_CONTAINERS_SPARSE_VECTOR_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_SPARSE_VECTOR_H_
 
 #include <stdint.h>
 
@@ -23,7 +23,7 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/optional.h"
-#include "src/trace_processor/db/row_map.h"
+#include "src/trace_processor/containers/row_map.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -115,4 +115,4 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
-#endif  // SRC_TRACE_PROCESSOR_DB_SPARSE_VECTOR_H_
+#endif  // SRC_TRACE_PROCESSOR_CONTAINERS_SPARSE_VECTOR_H_
diff --git a/src/trace_processor/db/sparse_vector_benchmark.cc b/src/trace_processor/containers/sparse_vector_benchmark.cc
similarity index 96%
rename from src/trace_processor/db/sparse_vector_benchmark.cc
rename to src/trace_processor/containers/sparse_vector_benchmark.cc
index ed1bed2..626b738 100644
--- a/src/trace_processor/db/sparse_vector_benchmark.cc
+++ b/src/trace_processor/containers/sparse_vector_benchmark.cc
@@ -16,7 +16,7 @@
 
 #include <benchmark/benchmark.h>
 
-#include "src/trace_processor/db/sparse_vector.h"
+#include "src/trace_processor/containers/sparse_vector.h"
 
 namespace {
 
diff --git a/src/trace_processor/db/sparse_vector_unittest.cc b/src/trace_processor/containers/sparse_vector_unittest.cc
similarity index 96%
rename from src/trace_processor/db/sparse_vector_unittest.cc
rename to src/trace_processor/containers/sparse_vector_unittest.cc
index cd8e43a..6e81b0b 100644
--- a/src/trace_processor/db/sparse_vector_unittest.cc
+++ b/src/trace_processor/containers/sparse_vector_unittest.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "src/trace_processor/db/sparse_vector.h"
+#include "src/trace_processor/containers/sparse_vector.h"
 
 #include "test/gtest_and_gmock.h"
 
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index 30e2518..73373e8 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -16,16 +16,9 @@
 
 source_set("lib") {
   sources = [
-    "bit_vector.cc",
-    "bit_vector.h",
-    "bit_vector_iterators.cc",
-    "bit_vector_iterators.h",
     "column.cc",
     "column.h",
     "compare.h",
-    "row_map.cc",
-    "row_map.h",
-    "sparse_vector.h",
     "table.cc",
     "table.h",
     "typed_column.h",
@@ -36,16 +29,14 @@
     "../../../include/perfetto/base",
     "../../../include/perfetto/ext/base",
     "../../../include/perfetto/trace_processor",
+    "../containers",
   ]
 }
 
 perfetto_unittest_source_set("unittests") {
   testonly = true
   sources = [
-    "bit_vector_unittest.cc",
     "compare_unittest.cc",
-    "row_map_unittest.cc",
-    "sparse_vector_unittest.cc",
   ]
   deps = [
     ":lib",
@@ -53,19 +44,3 @@
     "../../../gn:gtest_and_gmock",
   ]
 }
-
-if (enable_perfetto_benchmarks) {
-  source_set("benchmarks") {
-    testonly = true
-    deps = [
-      ":lib",
-      "../../../gn:benchmark",
-      "../../../gn:default_deps",
-    ]
-    sources = [
-      "bit_vector_benchmark.cc",
-      "row_map_benchmark.cc",
-      "sparse_vector_benchmark.cc",
-    ]
-  }
-}
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index 0e3d927..d4e600a 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -22,9 +22,9 @@
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/containers/sparse_vector.h"
 #include "src/trace_processor/db/compare.h"
-#include "src/trace_processor/db/row_map.h"
-#include "src/trace_processor/db/sparse_vector.h"
 #include "src/trace_processor/string_pool.h"
 
 namespace perfetto {
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
index b6bc5a6..c020758 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -29,6 +29,8 @@
 #include "src/trace_processor/trace_processor_context.h"
 #include "src/trace_processor/trace_storage.h"
 
+#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+
 namespace perfetto {
 namespace trace_processor {
 
@@ -43,51 +45,124 @@
 class PacketSequenceState {
  public:
   // Entry in an interning index, refers to the interned message.
-  struct InternedMessageView {
-    InternedMessageView(TraceBlobView msg) : message(std::move(msg)) {}
+  class InternedMessageView {
+   public:
+    InternedMessageView(TraceBlobView msg) : message_(std::move(msg)) {}
 
+    InternedMessageView(InternedMessageView&&) noexcept = default;
+    InternedMessageView& operator=(InternedMessageView&&) = default;
+
+    // Allow copy by cloning the TraceBlobView. This is required for
+    // UpdateTracePacketDefaults().
+    InternedMessageView(const InternedMessageView& view)
+        : message_(view.message_.slice(0, view.message_.length())) {}
+    InternedMessageView& operator=(const InternedMessageView& view) {
+      this->message_ = view.message_.slice(0, view.message_.length());
+      this->decoder_ = nullptr;
+      this->decoder_type_ = nullptr;
+      this->submessages_.clear();
+      return *this;
+    }
+
+    // Lazily initializes and returns the decoder object for the message. The
+    // decoder is stored in the InternedMessageView to avoid having to parse the
+    // message multiple times.
     template <typename MessageType>
     typename MessageType::Decoder* GetOrCreateDecoder() {
-      if (!decoder) {
+      if (!decoder_) {
         // Lazy init the decoder and save it away, so that we don't have to
         // reparse the message every time we access the interning entry.
-        decoder = std::unique_ptr<void, std::function<void(void*)>>(
-            new typename MessageType::Decoder(message.data(), message.length()),
+        decoder_ = std::unique_ptr<void, std::function<void(void*)>>(
+            new
+            typename MessageType::Decoder(message_.data(), message_.length()),
             [](void* obj) {
               delete reinterpret_cast<typename MessageType::Decoder*>(obj);
             });
-        decoder_type = PERFETTO_TYPE_IDENTIFIER;
+        decoder_type_ = PERFETTO_TYPE_IDENTIFIER;
       }
       // Verify that the type of the decoder didn't change.
       if (PERFETTO_TYPE_IDENTIFIER &&
-          strcmp(decoder_type,
+          strcmp(decoder_type_,
                  // GCC complains if this arg can be null.
                  PERFETTO_TYPE_IDENTIFIER ? PERFETTO_TYPE_IDENTIFIER : "") !=
               0) {
         PERFETTO_FATAL(
             "Interning entry accessed under different types! previous type: "
             "%s. new type: %s.",
-            decoder_type, __PRETTY_FUNCTION__);
+            decoder_type_, __PRETTY_FUNCTION__);
       }
-      return reinterpret_cast<typename MessageType::Decoder*>(decoder.get());
+      return reinterpret_cast<typename MessageType::Decoder*>(decoder_.get());
     }
 
-    TraceBlobView message;
-    std::unique_ptr<void, std::function<void(void*)>> decoder;
+    // Lookup a submessage of the interned message, which is then itself stored
+    // as InternedMessageView, so that we only need to parse it once. Returns
+    // nullptr if the field isn't set.
+    // TODO(eseckler): Support repeated fields.
+    template <typename MessageType, uint32_t FieldId>
+    InternedMessageView* GetOrCreateSubmessageView() {
+      auto it = submessages_.find(FieldId);
+      if (it != submessages_.end())
+        return it->second.get();
+      auto* decoder = GetOrCreateDecoder<MessageType>();
+      // Calls the at() template method on the decoder.
+      auto field = decoder->template at<FieldId>().as_bytes();
+      if (!field.data)
+        return nullptr;
+      const size_t offset = message_.offset_of(field.data);
+      TraceBlobView submessage = message_.slice(offset, field.size);
+      InternedMessageView* submessage_view =
+          new InternedMessageView(std::move(submessage));
+      submessages_.emplace_hint(
+          it, FieldId, std::unique_ptr<InternedMessageView>(submessage_view));
+      return submessage_view;
+    }
+
+    const TraceBlobView& message() { return message_; }
 
    private:
-    const char* decoder_type = nullptr;
+    using SubMessageViewMap =
+        std::unordered_map<uint32_t /*field_id*/,
+                           std::unique_ptr<InternedMessageView>>;
+
+    TraceBlobView message_;
+
+    // Stores the decoder for the message_, so that the message does not have to
+    // be re-decoded every time the interned message is looked up. Lazily
+    // initialized in GetOrCreateDecoder(). Since we don't know the type of the
+    // decoder until GetOrCreateDecoder() is called, we store the decoder as a
+    // void* unique_pointer with a destructor function that's supplied in
+    // GetOrCreateDecoder() when the decoder is created.
+    std::unique_ptr<void, std::function<void(void*)>> decoder_;
+
+    // Type identifier for the decoder. Only valid in debug builds and on
+    // supported platforms. Used to verify that GetOrCreateDecoder() is always
+    // called with the same template argument.
+    const char* decoder_type_ = nullptr;
+
+    // Views of submessages of the interned message. Submessages are lazily
+    // added by GetOrCreateSubmessageView(). By storing submessages and their
+    // decoders, we avoid having to decode submessages multiple times if they
+    // looked up often.
+    SubMessageViewMap submessages_;
   };
 
   using InternedMessageMap =
       std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
   using InternedFieldMap =
       std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
-  using InternedDataGenerationList = std::vector<InternedFieldMap>;
+
+  struct GenerationData {
+    InternedFieldMap interned_data;
+    base::Optional<InternedMessageView> trace_packet_defaults;
+  };
+
+  // TODO(eseckler): Reference count the generations so that we can get rid of
+  // past generations once all packets referring to them have been parsed.
+  using GenerationList = std::vector<GenerationData>;
 
   PacketSequenceState(TraceProcessorContext* context)
       : context_(context), stack_profile_tracker_(context) {
-    interned_data_.emplace_back();
+    generations_.emplace_back();
   }
 
   int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
@@ -115,7 +190,7 @@
 
   void OnIncrementalStateCleared() {
     packet_loss_ = false;
-    interned_data_.emplace_back();  // Bump generation number
+    generations_.emplace_back();  // Bump generation number
   }
 
   void SetThreadDescriptor(int32_t pid,
@@ -138,9 +213,8 @@
     return stack_profile_tracker_;
   }
 
-  // Returns the index of the current generation in the
-  // InternedDataGenerationList.
-  size_t current_generation() const { return interned_data_.size() - 1; }
+  // Returns the index of the current generation in the GenerationList.
+  size_t current_generation() const { return generations_.size() - 1; }
 
   bool track_event_timestamps_valid() const {
     return track_event_timestamps_valid_;
@@ -167,7 +241,7 @@
     }
     iid = field.as_uint64();
 
-    auto* map = &interned_data_.back()[field_id];
+    auto* map = &generations_.back().interned_data[field_id];
     auto res = map->emplace(iid, InternedMessageView(std::move(message)));
 
     // If a message with this ID is already interned in the same generation,
@@ -176,16 +250,18 @@
     // TODO(eseckler): This DCHECK assumes that the message is encoded the
     // same way if it is re-emitted.
     PERFETTO_DCHECK(res.second ||
-                    (res.first->second.message.length() == message_size &&
-                     memcmp(res.first->second.message.data(), message_start,
+                    (res.first->second.message().length() == message_size &&
+                     memcmp(res.first->second.message().data(), message_start,
                             message_size) == 0));
   }
 
+  // Returns |nullptr| if the message with the given |iid| was not found (also
+  // records a stat in this case).
   template <uint32_t FieldId, typename MessageType>
   typename MessageType::Decoder* LookupInternedMessage(size_t generation,
                                                        uint64_t iid) {
-    PERFETTO_CHECK(generation <= interned_data_.size());
-    auto* field_map = &interned_data_[generation];
+    PERFETTO_CHECK(generation <= generations_.size());
+    auto* field_map = &generations_[generation].interned_data;
     auto field_it = field_map->find(FieldId);
     if (field_it != field_map->end()) {
       auto* message_map = &field_it->second;
@@ -201,6 +277,37 @@
     return nullptr;
   }
 
+  void UpdateTracePacketDefaults(TraceBlobView trace_packet_defaults) {
+    if (generations_.back().trace_packet_defaults) {
+      // The new defaults should only apply to subsequent messages on the
+      // sequence. Add a new generation with the updated defaults but the
+      // current generation's interned data state.
+      const InternedFieldMap& current_interned_data =
+          generations_.back().interned_data;
+      generations_.emplace_back();
+      generations_.back().interned_data = current_interned_data;
+    }
+    generations_.back().trace_packet_defaults =
+        InternedMessageView(std::move(trace_packet_defaults));
+  }
+
+  // Returns |nullptr| if no defaults were set in the given generation.
+  InternedMessageView* GetTracePacketDefaultsView(size_t generation) {
+    PERFETTO_CHECK(generation <= generations_.size());
+    if (!generations_[generation].trace_packet_defaults)
+      return nullptr;
+    return &generations_[generation].trace_packet_defaults.value();
+  }
+
+  // Returns |nullptr| if no defaults were set in the given generation.
+  typename protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults(
+      size_t generation) {
+    InternedMessageView* view = GetTracePacketDefaultsView(generation);
+    if (!view)
+      return nullptr;
+    return view->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
+  }
+
  private:
   TraceProcessorContext* context_;
 
@@ -229,7 +336,7 @@
   int64_t track_event_thread_timestamp_ns_ = 0;
   int64_t track_event_thread_instruction_count_ = 0;
 
-  InternedDataGenerationList interned_data_;
+  GenerationList generations_;
   StackProfileTracker stack_profile_tracker_;
 };
 
diff --git a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
index 97d7689..8ac2b36 100644
--- a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
+++ b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
@@ -186,63 +186,8 @@
     return util::ErrStatus(
         "Failed to parse proto packet fully; the trace is probably corrupt.");
 
-  auto timestamp =
-      decoder.has_timestamp()
-          ? static_cast<int64_t>(decoder.timestamp())
-          : std::max(latest_timestamp_, context_->sorter->max_timestamp());
-
   const uint32_t seq_id = decoder.trusted_packet_sequence_id();
-
-  if ((decoder.has_chrome_events() || decoder.has_chrome_metadata()) &&
-      (!decoder.timestamp_clock_id() ||
-       decoder.timestamp_clock_id() ==
-           protos::pbzero::ClockSnapshot::Clock::MONOTONIC)) {
-    // Chrome event timestamps are in MONOTONIC domain, but may occur in traces
-    // where (a) no clock snapshots exist or (b) no clock_id is specified for
-    // their timestamps. Adjust to trace time if we have a clock snapshot.
-    // TODO(eseckler): Set timestamp_clock_id and emit ClockSnapshots in chrome
-    // and then remove this.
-    auto trace_ts = context_->clock_tracker->ToTraceTime(
-        protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
-    if (trace_ts.has_value())
-      timestamp = trace_ts.value();
-  } else if (decoder.timestamp_clock_id()) {
-    // If the TracePacket specifies a non-zero clock-id, translate the timestamp
-    // into the trace-time clock domain.
-    PERFETTO_DCHECK(decoder.has_timestamp());
-    ClockTracker::ClockId clock_id = decoder.timestamp_clock_id();
-    bool is_seq_scoped = ClockTracker::IsReservedSeqScopedClockId(clock_id);
-    if (is_seq_scoped) {
-      if (!seq_id) {
-        return util::ErrStatus(
-            "TracePacket specified a sequence-local clock id (%" PRIu32
-            ") but the TraceWriter's sequence_id is zero (the service is "
-            "probably too old)",
-            decoder.timestamp_clock_id());
-      }
-      clock_id = ClockTracker::SeqScopedClockIdToGlobal(
-          seq_id, decoder.timestamp_clock_id());
-    }
-    auto trace_ts = context_->clock_tracker->ToTraceTime(clock_id, timestamp);
-    if (!trace_ts.has_value()) {
-      // ToTraceTime() will increase the |clock_sync_failure| stat on failure.
-      static const char seq_extra_err[] =
-          " Because the clock id is sequence-scoped, the ClockSnapshot must be "
-          "emitted on the same TraceWriter sequence of the packet that refers "
-          "to that clock id.";
-      return util::ErrStatus(
-          "Failed to convert TracePacket's timestamp from clock_id=%" PRIu32
-          " seq_id=%" PRIu32
-          ". This is usually due to the lack of a prior ClockSnapshot proto.%s",
-          decoder.timestamp_clock_id(), seq_id,
-          is_seq_scoped ? seq_extra_err : "");
-    }
-    timestamp = trace_ts.value();
-  }
-  latest_timestamp_ = std::max(timestamp, latest_timestamp_);
-
-  auto* state = GetIncrementalStateForPacketSequence(
-      decoder.trusted_packet_sequence_id());
+  auto* state = GetIncrementalStateForPacketSequence(seq_id);
 
   uint32_t sequence_flags = decoder.sequence_flags();
 
@@ -254,6 +199,25 @@
     HandlePreviousPacketDropped(decoder);
   }
 
+  // It is important that we parse defaults before parsing other fields such as
+  // the timestamp, since the defaults could affect them.
+  if (decoder.has_trace_packet_defaults()) {
+    auto field = decoder.trace_packet_defaults();
+    const size_t offset = packet.offset_of(field.data);
+    ParseTracePacketDefaults(decoder, packet.slice(offset, field.size));
+  }
+
+  if (decoder.has_interned_data()) {
+    auto field = decoder.interned_data();
+    const size_t offset = packet.offset_of(field.data);
+    ParseInternedData(decoder, packet.slice(offset, field.size));
+  }
+
+  if (decoder.has_clock_snapshot()) {
+    return ParseClockSnapshot(decoder.clock_snapshot(),
+                              decoder.trusted_packet_sequence_id());
+  }
+
   if (decoder.sequence_flags() &
       protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE) {
     if (!seq_id) {
@@ -269,18 +233,70 @@
     }
   }
 
-  if (decoder.has_clock_snapshot()) {
-    return ParseClockSnapshot(decoder.clock_snapshot(),
-                              decoder.trusted_packet_sequence_id());
-  }
+  protos::pbzero::TracePacketDefaults::Decoder* defaults =
+      state->GetTracePacketDefaults(state->current_generation());
 
-  // TODO(eseckler): Parse TracePacketDefaults.
+  int64_t timestamp;
+  if (decoder.has_timestamp()) {
+    timestamp = static_cast<int64_t>(decoder.timestamp());
 
-  if (decoder.has_interned_data()) {
-    auto field = decoder.interned_data();
-    const size_t offset = packet.offset_of(field.data);
-    ParseInternedData(decoder, packet.slice(offset, field.size));
+    uint32_t timestamp_clock_id =
+        decoder.has_timestamp_clock_id()
+            ? decoder.timestamp_clock_id()
+            : (defaults ? defaults->timestamp_clock_id() : 0);
+
+    if ((decoder.has_chrome_events() || decoder.has_chrome_metadata()) &&
+        (!timestamp_clock_id ||
+         timestamp_clock_id ==
+             protos::pbzero::ClockSnapshot::Clock::MONOTONIC)) {
+      // Chrome event timestamps are in MONOTONIC domain, but may occur in
+      // traces where (a) no clock snapshots exist or (b) no clock_id is
+      // specified for their timestamps. Adjust to trace time if we have a clock
+      // snapshot.
+      // TODO(eseckler): Set timestamp_clock_id and emit ClockSnapshots in
+      // chrome and then remove this.
+      auto trace_ts = context_->clock_tracker->ToTraceTime(
+          protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
+      if (trace_ts.has_value())
+        timestamp = trace_ts.value();
+    } else if (timestamp_clock_id) {
+      // If the TracePacket specifies a non-zero clock-id, translate the
+      // timestamp into the trace-time clock domain.
+      ClockTracker::ClockId converted_clock_id = timestamp_clock_id;
+      bool is_seq_scoped =
+          ClockTracker::IsReservedSeqScopedClockId(converted_clock_id);
+      if (is_seq_scoped) {
+        if (!seq_id) {
+          return util::ErrStatus(
+              "TracePacket specified a sequence-local clock id (%" PRIu32
+              ") but the TraceWriter's sequence_id is zero (the service is "
+              "probably too old)",
+              timestamp_clock_id);
+        }
+        converted_clock_id =
+            ClockTracker::SeqScopedClockIdToGlobal(seq_id, timestamp_clock_id);
+      }
+      auto trace_ts =
+          context_->clock_tracker->ToTraceTime(converted_clock_id, timestamp);
+      if (!trace_ts.has_value()) {
+        // ToTraceTime() will increase the |clock_sync_failure| stat on failure.
+        static const char seq_extra_err[] =
+            " Because the clock id is sequence-scoped, the ClockSnapshot must "
+            "be emitted on the same TraceWriter sequence of the packet that "
+            "refers to that clock id.";
+        return util::ErrStatus(
+            "Failed to convert TracePacket's timestamp from clock_id=%" PRIu32
+            " seq_id=%" PRIu32
+            ". This is usually due to the lack of a prior ClockSnapshot "
+            "proto.%s",
+            timestamp_clock_id, seq_id, is_seq_scoped ? seq_extra_err : "");
+      }
+      timestamp = trace_ts.value();
+    }
+  } else {
+    timestamp = std::max(latest_timestamp_, context_->sorter->max_timestamp());
   }
+  latest_timestamp_ = std::max(timestamp, latest_timestamp_);
 
   auto& modules = context_->modules_by_field;
   for (uint32_t field_id = 1; field_id < modules.size(); ++field_id) {
@@ -380,6 +396,21 @@
       ->OnPacketLoss();
 }
 
+void ProtoTraceTokenizer::ParseTracePacketDefaults(
+    const protos::pbzero::TracePacket_Decoder& packet_decoder,
+    TraceBlobView trace_packet_defaults) {
+  if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
+    PERFETTO_ELOG(
+        "TracePacketDefaults packet without trusted_packet_sequence_id");
+    context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+    return;
+  }
+
+  auto* state = GetIncrementalStateForPacketSequence(
+      packet_decoder.trusted_packet_sequence_id());
+  state->UpdateTracePacketDefaults(std::move(trace_packet_defaults));
+}
+
 void ProtoTraceTokenizer::ParseInternedData(
     const protos::pbzero::TracePacket::Decoder& packet_decoder,
     TraceBlobView interned_data) {
diff --git a/src/trace_processor/importers/proto/proto_trace_tokenizer.h b/src/trace_processor/importers/proto/proto_trace_tokenizer.h
index bdefa2e..0612068 100644
--- a/src/trace_processor/importers/proto/proto_trace_tokenizer.h
+++ b/src/trace_processor/importers/proto/proto_trace_tokenizer.h
@@ -67,6 +67,8 @@
   void HandleIncrementalStateCleared(
       const protos::pbzero::TracePacket_Decoder&);
   void HandlePreviousPacketDropped(const protos::pbzero::TracePacket_Decoder&);
+  void ParseTracePacketDefaults(const protos::pbzero::TracePacket_Decoder&,
+                                TraceBlobView trace_packet_defaults);
   void ParseInternedData(const protos::pbzero::TracePacket_Decoder&,
                          TraceBlobView interned_data);
   PacketSequenceState* GetIncrementalStateForPacketSequence(
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 85507b3..3ba6b59 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -193,6 +193,21 @@
                                        ConstBytes blob) {
   using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
 
+  protos::pbzero::TrackEventDefaults::Decoder* defaults = nullptr;
+  auto* packet_defaults_view =
+      sequence_state->GetTracePacketDefaultsView(sequence_state_generation);
+  if (packet_defaults_view) {
+    auto* track_event_defaults_view =
+        packet_defaults_view
+            ->GetOrCreateSubmessageView<protos::pbzero::TracePacketDefaults,
+                                        protos::pbzero::TracePacketDefaults::
+                                            kTrackEventDefaultsFieldNumber>();
+    if (track_event_defaults_view) {
+      defaults = track_event_defaults_view
+                     ->GetOrCreateDecoder<protos::pbzero::TrackEventDefaults>();
+    }
+  }
+
   protos::pbzero::TrackEvent::Decoder event(blob.data, blob.size);
 
   const auto legacy_event_blob = event.legacy_event();
@@ -275,9 +290,14 @@
     name_id = storage->InternString(event.name());
   }
 
-  // TODO(eseckler): Also consider track_uuid from TrackEventDefaults.
-  // Fall back to the default descriptor track (uuid 0).
-  uint64_t track_uuid = event.has_track_uuid() ? event.track_uuid() : 0u;
+  // Consider track_uuid from the packet and TrackEventDefaults, fall back to
+  // the default descriptor track (uuid 0).
+  uint64_t track_uuid =
+      event.has_track_uuid()
+          ? event.track_uuid()
+          : (defaults && defaults->has_track_uuid() ? defaults->track_uuid()
+                                                    : 0u);
+
   TrackId track_id;
   base::Optional<UniqueTid> utid;
   base::Optional<UniqueTid> upid;
diff --git a/src/trace_processor/storage_minimal_smoke_test.cc b/src/trace_processor/storage_minimal_smoke_test.cc
new file mode 100644
index 0000000..1aa037d
--- /dev/null
+++ b/src/trace_processor/storage_minimal_smoke_test.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 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 <cstdio>
+#include <string>
+
+#include <json/reader.h>
+#include <json/value.h>
+
+#include "perfetto/ext/trace_processor/export_json.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/trace_processor/trace_processor_storage.h"
+#include "src/base/test/utils.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+class JsonStringOutputWriter : public json::OutputWriter {
+ public:
+  util::Status AppendString(const std::string& string) override {
+    buffer += string;
+    return util::OkStatus();
+  }
+  std::string buffer;
+};
+
+class StorageMinimalSmokeTest : public ::testing::Test {
+ public:
+  StorageMinimalSmokeTest()
+      : storage_(TraceProcessorStorage::CreateInstance(Config())) {}
+
+ protected:
+  std::unique_ptr<TraceProcessorStorage> storage_;
+};
+
+TEST_F(StorageMinimalSmokeTest, GraphicEventsIgnored) {
+  const size_t MAX_SIZE = 1 << 20;
+  auto f = fopen(base::GetTestDataPath("test/data/gpu_trace.pb").c_str(), "rb");
+  std::unique_ptr<uint8_t[]> buf(new uint8_t[MAX_SIZE]);
+  auto rsize = fread(reinterpret_cast<char*>(buf.get()), 1, MAX_SIZE, f);
+  storage_->Parse(std::move(buf), rsize);
+  storage_->NotifyEndOfFile();
+
+  JsonStringOutputWriter output_writer;
+  auto status = json::ExportJson(storage_.get(), &output_writer);
+  Json::Reader reader;
+  Json::Value result;
+  reader.parse(output_writer.buffer, result);
+
+  ASSERT_EQ(result["traceEvents"].size(), 0u);
+}
+
+TEST_F(StorageMinimalSmokeTest, TrackEventsImported) {
+  const size_t MAX_SIZE = 1 << 20;
+  auto f = fopen("test/trace_processor/track_event_typed_args.pb", "rb");
+  std::unique_ptr<uint8_t[]> buf(new uint8_t[MAX_SIZE]);
+  auto rsize = fread(reinterpret_cast<char*>(buf.get()), 1, MAX_SIZE, f);
+  storage_->Parse(std::move(buf), rsize);
+  storage_->NotifyEndOfFile();
+
+  JsonStringOutputWriter output_writer;
+  auto status = json::ExportJson(storage_.get(), &output_writer);
+  Json::Reader reader;
+  Json::Value result;
+  reader.parse(output_writer.buffer, result);
+
+  ASSERT_EQ(result["traceEvents"].size(), 4u);
+}
+
+}  // namespace
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/tables/macros_benchmark.cc b/src/trace_processor/tables/macros_benchmark.cc
index 008bcab..12296fd 100644
--- a/src/trace_processor/tables/macros_benchmark.cc
+++ b/src/trace_processor/tables/macros_benchmark.cc
@@ -108,7 +108,7 @@
 }
 BENCHMARK(BM_TableIteratorChild)->Apply(TableFilterArgs);
 
-static void BM_TableFilterIdColumn(benchmark::State& state) {
+static void BM_TableFilterRootId(benchmark::State& state) {
   StringPool pool;
   RootTestTable root(&pool, nullptr);
 
@@ -120,7 +120,66 @@
     benchmark::DoNotOptimize(root.Filter({root.id().eq(30)}));
   }
 }
-BENCHMARK(BM_TableFilterIdColumn)->Apply(TableFilterArgs);
+BENCHMARK(BM_TableFilterRootId)->Apply(TableFilterArgs);
+
+static void BM_TableFilterRootIdAndOther(benchmark::State& state) {
+  StringPool pool;
+  RootTestTable root(&pool, nullptr);
+
+  uint32_t size = static_cast<uint32_t>(state.range(0));
+
+  for (uint32_t i = 0; i < size; ++i) {
+    RootTestTable::Row root_row;
+    root_row.root_non_null = i * 4;
+    root.Insert(root_row);
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(root.Filter(
+        {root.id().eq(root.size() - 1), root.root_non_null().gt(100)}));
+  }
+}
+BENCHMARK(BM_TableFilterRootIdAndOther)->Apply(TableFilterArgs);
+
+static void BM_TableFilterChildId(benchmark::State& state) {
+  StringPool pool;
+  RootTestTable root(&pool, nullptr);
+  ChildTestTable child(&pool, &root);
+
+  uint32_t size = static_cast<uint32_t>(state.range(0));
+  for (uint32_t i = 0; i < size; ++i) {
+    root.Insert({});
+    child.Insert({});
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(child.Filter({child.id().eq(30)}));
+  }
+}
+BENCHMARK(BM_TableFilterChildId)->Apply(TableFilterArgs);
+
+static void BM_TableFilterChildIdAndSortedInRoot(benchmark::State& state) {
+  StringPool pool;
+  RootTestTable root(&pool, nullptr);
+  ChildTestTable child(&pool, &root);
+
+  uint32_t size = static_cast<uint32_t>(state.range(0));
+  for (uint32_t i = 0; i < size; ++i) {
+    RootTestTable::Row root_row;
+    root_row.root_sorted = i * 2;
+    root.Insert(root_row);
+
+    ChildTestTable::Row child_row;
+    child_row.root_sorted = i * 2 + 1;
+    child.Insert(child_row);
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        child.Filter({child.id().eq(30), child.root_sorted().gt(1024)}));
+  }
+}
+BENCHMARK(BM_TableFilterChildIdAndSortedInRoot)->Apply(TableFilterArgs);
 
 static void BM_TableFilterRootNonNullEqMatchMany(benchmark::State& state) {
   StringPool pool;
@@ -320,25 +379,6 @@
 }
 BENCHMARK(BM_TableFilterChildSortedEqInParent)->Apply(TableFilterArgs);
 
-static void BM_TableFilterIdAndOtherParent(benchmark::State& state) {
-  StringPool pool;
-  RootTestTable root(&pool, nullptr);
-
-  uint32_t size = static_cast<uint32_t>(state.range(0));
-
-  for (uint32_t i = 0; i < size; ++i) {
-    RootTestTable::Row root_row;
-    root_row.root_non_null = i * 4;
-    root.Insert(root_row);
-  }
-
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(root.Filter(
-        {root.id().eq(root.size() - 1), root.root_non_null().gt(100)}));
-  }
-}
-BENCHMARK(BM_TableFilterIdAndOtherParent)->Apply(TableFilterArgs);
-
 static void BM_TableSortRootNonNull(benchmark::State& state) {
   StringPool pool;
   RootTestTable root(&pool, nullptr);
diff --git a/src/trace_processor/trace_blob_view.h b/src/trace_processor/trace_blob_view.h
index 46cc424..7a7889b 100644
--- a/src/trace_processor/trace_blob_view.h
+++ b/src/trace_processor/trace_blob_view.h
@@ -51,7 +51,7 @@
   TraceBlobView(const TraceBlobView&) = delete;
   TraceBlobView& operator=(const TraceBlobView&) = delete;
 
-  TraceBlobView slice(size_t offset, size_t length) {
+  TraceBlobView slice(size_t offset, size_t length) const {
     PERFETTO_DCHECK(offset + length <= offset_ + length_);
     return TraceBlobView(shbuf_, offset, length);
   }
diff --git a/test/ci/linux_tests.sh b/test/ci/linux_tests.sh
index 11f60a0..62bf1c7 100755
--- a/test/ci/linux_tests.sh
+++ b/test/ci/linux_tests.sh
@@ -23,6 +23,7 @@
 
 ${OUT_PATH}/perfetto_unittests
 ${OUT_PATH}/perfetto_integrationtests
+${OUT_PATH}/trace_processor_minimal_smoke_tests
 
 # If this is a split host+target build, use the trace_processoer_shell binary
 # from the host directory. In some cases (e.g. lsan x86 builds) the host binary
diff --git a/test/trace_processor/clock_sync.out b/test/trace_processor/clock_sync.out
index 77ee53f..aca328a 100644
--- a/test/trace_processor/clock_sync.out
+++ b/test/trace_processor/clock_sync.out
@@ -4,4 +4,7 @@
 1003,7
 1005,9
 2006,11
-3007,13
+2010,12
+2013,13
+3007,14
+3010,15
diff --git a/test/trace_processor/clock_sync.py b/test/trace_processor/clock_sync.py
index 9dded25..e097024 100644
--- a/test/trace_processor/clock_sync.py
+++ b/test/trace_processor/clock_sync.py
@@ -68,10 +68,25 @@
 
 # This counter should be translated @ BOOTTIME : 3000 + 7
 trace.add_gpu_counter(
-    ts=7, clock_id=SEQ_CLOCK1, counter_id=42, value=13, seq_id=3)
+    ts=7, clock_id=SEQ_CLOCK1, counter_id=42, value=14, seq_id=3)
 
 # This counter should be translated @ BOOTTIME : 2000 + 6
 trace.add_gpu_counter(
     ts=6, clock_id=SEQ_CLOCK1, seq_id=2, counter_id=42, value=11)
 
+# Set default clock for sequence 2.
+defaults_packet = trace.add_packet()
+defaults_packet.trusted_packet_sequence_id = 2
+defaults_packet.trace_packet_defaults.timestamp_clock_id = SEQ_CLOCK1
+
+# This counter should be translated @ BOOTTIME : 2000 + 10
+trace.add_gpu_counter(ts=10, seq_id=2, counter_id=42, value=12)
+
+# Manually specified clock_id overrides the default clock.
+trace.add_gpu_counter(
+    ts=2013, clock_id=CLOCK_BOOTTIME, seq_id=2, counter_id=42, value=13)
+
+# Other sequence's default clock isn't changed, so this should be in BOOTTIME.
+trace.add_gpu_counter(ts=3010, counter_id=42, value=15, seq_id=3)
+
 print(trace.trace.SerializeToString())
diff --git a/test/trace_processor/index b/test/trace_processor/index
index 6793acd..1d6dee0 100644
--- a/test/trace_processor/index
+++ b/test/trace_processor/index
@@ -151,6 +151,7 @@
 track_event_same_tids.textproto track_event_slices.sql track_event_same_tids_slices.out
 track_event_typed_args.textproto track_event_slices.sql track_event_typed_args_slices.out
 track_event_typed_args.textproto track_event_args.sql track_event_typed_args_args.out
+track_event_tracks.textproto track_event_slices.sql track_event_tracks_slices.out
 
 # Parsing of an html file with systrace data inside
 ../data/systrace.html systrace_html.sql systrace_html.out
diff --git a/test/trace_processor/track_event_same_tids_slices.out b/test/trace_processor/track_event_same_tids_slices.out
index 350acf9..48fa77b 100644
--- a/test/trace_processor/track_event_same_tids_slices.out
+++ b/test/trace_processor/track_event_same_tids_slices.out
@@ -1,3 +1,3 @@
-"ts","dur","category","name","arg_set_id"
-1000,0,"cat","name1",0
-2000,0,"cat","name2",0
+"thread","ts","dur","category","name","arg_set_id"
+"t1",1000,0,"cat","name1",0
+"t2",2000,0,"cat","name2",0
diff --git a/test/trace_processor/track_event_slices.sql b/test/trace_processor/track_event_slices.sql
index 68772b4..42f7b69 100644
--- a/test/trace_processor/track_event_slices.sql
+++ b/test/trace_processor/track_event_slices.sql
@@ -13,4 +13,14 @@
 -- See the License for the specific language governing permissions and
 -- limitations under the License.
 --
-select ts, dur, category, name, arg_set_id from slice order by ts asc;
\ No newline at end of file
+select
+  thread.name as thread,
+  slice.ts,
+  slice.dur,
+  slice.category,
+  slice.name,
+  slice.arg_set_id
+from slice
+left join thread_track on slice.track_id = thread_track.id
+left join thread on thread_track.utid = thread.utid
+order by ts asc;
diff --git a/test/trace_processor/track_event_tracks.textproto b/test/trace_processor/track_event_tracks.textproto
new file mode 100644
index 0000000..fd8cdc8
--- /dev/null
+++ b/test/trace_processor/track_event_tracks.textproto
@@ -0,0 +1,69 @@
+# Sequence 1 defaults to track for "t1".
+packet {
+  trusted_packet_sequence_id: 1
+  timestamp: 0
+  incremental_state_cleared: true
+  track_descriptor {
+    uuid: 1
+    thread {
+      pid: 5
+      tid: 1
+      thread_name: "t1"
+    }
+  }
+  trace_packet_defaults {
+    track_event_defaults {
+      track_uuid: 1
+    }
+  }
+}
+# Sequence 2 defaults to track for "t2".
+packet {
+  trusted_packet_sequence_id: 2
+  timestamp: 0
+  incremental_state_cleared: true
+  track_descriptor {
+    uuid: 2
+    thread {
+      pid: 5
+      tid: 2
+      thread_name: "t2"
+    }
+  }
+  trace_packet_defaults {
+    track_event_defaults {
+      track_uuid: 2
+    }
+  }
+}
+# Should appear on default track "t1".
+packet {
+  trusted_packet_sequence_id: 1
+  timestamp: 1000
+  track_event {
+    categories: "cat"
+    name: "name1"
+    type: 3
+  }
+}
+# Should appear on default track "t2".
+packet {
+  trusted_packet_sequence_id: 2
+  timestamp: 2000
+  track_event {
+    categories: "cat"
+    name: "name2"
+    type: 3
+  }
+}
+# Should appear on overridden track "t2".
+packet {
+  trusted_packet_sequence_id: 1
+  timestamp: 3000
+  track_event {
+    track_uuid: 2
+    categories: "cat"
+    name: "name3"
+    type: 3
+  }
+}
diff --git a/test/trace_processor/track_event_tracks_slices.out b/test/trace_processor/track_event_tracks_slices.out
new file mode 100644
index 0000000..93c7186
--- /dev/null
+++ b/test/trace_processor/track_event_tracks_slices.out
@@ -0,0 +1,4 @@
+"thread","ts","dur","category","name","arg_set_id"
+"t1",1000,0,"cat","name1",0
+"t2",2000,0,"cat","name2",0
+"t2",3000,0,"cat","name3",0
diff --git a/test/trace_processor/track_event_typed_args.pb b/test/trace_processor/track_event_typed_args.pb
new file mode 100644
index 0000000..c478cb0
--- /dev/null
+++ b/test/trace_processor/track_event_typed_args.pb
Binary files differ
diff --git a/test/trace_processor/track_event_typed_args_slices.out b/test/trace_processor/track_event_typed_args_slices.out
index d280266..6a9a969 100644
--- a/test/trace_processor/track_event_typed_args_slices.out
+++ b/test/trace_processor/track_event_typed_args_slices.out
@@ -1,4 +1,4 @@
-"ts","dur","category","name","arg_set_id"
-1000,0,"cat","name1",2
-2000,0,"cat","name2",3
-3000,0,"cat","name3",4
+"thread","ts","dur","category","name","arg_set_id"
+"t1",1000,0,"cat","name1",2
+"t1",2000,0,"cat","name2",3
+"t1",3000,0,"cat","name3",4