Merge "protozero: avoid trivial heap expansions"
diff --git a/Android.bp b/Android.bp
index f3f47ef..1b10e3d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3655,6 +3655,7 @@
         "protos/perfetto/metrics/android/cpu_metric.proto",
         "protos/perfetto/metrics/android/display_metrics.proto",
         "protos/perfetto/metrics/android/dma_heap_metric.proto",
+        "protos/perfetto/metrics/android/dvfs_metric.proto",
         "protos/perfetto/metrics/android/fastrpc_metric.proto",
         "protos/perfetto/metrics/android/g2d_metric.proto",
         "protos/perfetto/metrics/android/gpu_metric.proto",
@@ -3711,6 +3712,7 @@
         "protos/perfetto/metrics/android/cpu_metric.proto",
         "protos/perfetto/metrics/android/display_metrics.proto",
         "protos/perfetto/metrics/android/dma_heap_metric.proto",
+        "protos/perfetto/metrics/android/dvfs_metric.proto",
         "protos/perfetto/metrics/android/fastrpc_metric.proto",
         "protos/perfetto/metrics/android/g2d_metric.proto",
         "protos/perfetto/metrics/android/gpu_metric.proto",
@@ -8007,6 +8009,7 @@
         "src/trace_processor/metrics/sql/android/android_cpu_agg.sql",
         "src/trace_processor/metrics/sql/android/android_cpu_raw_metrics_per_core.sql",
         "src/trace_processor/metrics/sql/android/android_dma_heap.sql",
+        "src/trace_processor/metrics/sql/android/android_dvfs.sql",
         "src/trace_processor/metrics/sql/android/android_fastrpc.sql",
         "src/trace_processor/metrics/sql/android/android_gpu.sql",
         "src/trace_processor/metrics/sql/android/android_hwcomposer.sql",
diff --git a/BUILD b/BUILD
index 10d6905..c818210 100644
--- a/BUILD
+++ b/BUILD
@@ -1009,6 +1009,7 @@
         "src/trace_processor/metrics/sql/android/android_cpu_agg.sql",
         "src/trace_processor/metrics/sql/android/android_cpu_raw_metrics_per_core.sql",
         "src/trace_processor/metrics/sql/android/android_dma_heap.sql",
+        "src/trace_processor/metrics/sql/android/android_dvfs.sql",
         "src/trace_processor/metrics/sql/android/android_fastrpc.sql",
         "src/trace_processor/metrics/sql/android/android_gpu.sql",
         "src/trace_processor/metrics/sql/android/android_hwcomposer.sql",
@@ -2562,6 +2563,7 @@
         "protos/perfetto/metrics/android/cpu_metric.proto",
         "protos/perfetto/metrics/android/display_metrics.proto",
         "protos/perfetto/metrics/android/dma_heap_metric.proto",
+        "protos/perfetto/metrics/android/dvfs_metric.proto",
         "protos/perfetto/metrics/android/fastrpc_metric.proto",
         "protos/perfetto/metrics/android/g2d_metric.proto",
         "protos/perfetto/metrics/android/gpu_metric.proto",
diff --git a/docs/analysis/trace-processor.md b/docs/analysis/trace-processor.md
index 361e51a..3606c00 100644
--- a/docs/analysis/trace-processor.md
+++ b/docs/analysis/trace-processor.md
@@ -544,7 +544,7 @@
 create higher-level abstractions from raw events as intermediate artifacts.
 
 From previous example, the
-[startup metric](/src/trace_processor/metrics/android/android_startup.sql)
+[startup metric](/src/trace_processor/metrics/sql/android/android_startup.sql)
 creates the exact `launching` slice we want to display in the UI.
 
 The other benefit of aligning the two is that changes in metrics are
diff --git a/include/perfetto/ext/base/circular_queue.h b/include/perfetto/ext/base/circular_queue.h
index 82f4394..8b48d22 100644
--- a/include/perfetto/ext/base/circular_queue.h
+++ b/include/perfetto/ext/base/circular_queue.h
@@ -172,16 +172,20 @@
 #endif
   };
 
-  CircularQueue(size_t initial_capacity = 1024) { Grow(initial_capacity); }
+  explicit CircularQueue(size_t initial_capacity = 1024) {
+    Grow(initial_capacity);
+  }
 
-  CircularQueue(CircularQueue&& other) noexcept {
-    // Copy all fields using the (private) default copy assignment operator.
-    *this = other;
+  CircularQueue(CircularQueue&& other) noexcept
+      : entries_(std::move(other.entries_)),
+        capacity_(other.capacity_),
+        begin_(other.begin_),
+        end_(other.end_) {
     increment_generation();
     new (&other) CircularQueue();  // Reset the old queue so it's still usable.
   }
 
-  CircularQueue& operator=(CircularQueue&& other) {
+  CircularQueue& operator=(CircularQueue&& other) noexcept {
     this->~CircularQueue();                      // Destroy the current state.
     new (this) CircularQueue(std::move(other));  // Use the move ctor above.
     return *this;
@@ -194,7 +198,6 @@
     }
     clear();  // Invoke destructors on all alive entries.
     PERFETTO_DCHECK(empty());
-    free(entries_);
   }
 
   template <typename... Args>
@@ -247,7 +250,7 @@
 
  private:
   CircularQueue(const CircularQueue&) = delete;
-  CircularQueue& operator=(const CircularQueue&) = default;
+  CircularQueue& operator=(const CircularQueue&) = delete;
 
   void Grow(size_t new_capacity = 0) {
     // Capacity must be always a power of two. This allows Get() to use a simple
@@ -258,10 +261,8 @@
     // On 32-bit systems this might hit the 4GB wall and overflow. We can't do
     // anything other than crash in this case.
     PERFETTO_CHECK(new_capacity > capacity_);
-    size_t malloc_size = new_capacity * sizeof(T);
-    PERFETTO_CHECK(malloc_size > new_capacity);
 
-    T* new_vec = static_cast<T*>(AlignedAlloc(alignof(T), malloc_size));
+    AlignedUniquePtr<T[]> new_vec = AlignedAllocTyped<T[]>(new_capacity);
 
     // Move all elements in the expanded array.
     size_t new_size = 0;
@@ -272,12 +273,11 @@
     // required to call the dtor for them.
     for (uint64_t i = begin_; i < end_; i++)
       Get(i)->~T();
-    free(entries_);  // It's fine to free(nullptr) (for the ctor call case).
 
     begin_ = 0;
     end_ = new_size;
     capacity_ = new_capacity;
-    entries_ = new_vec;
+    entries_ = std::move(new_vec);
   }
 
   inline T* Get(uint64_t pos) {
@@ -289,7 +289,7 @@
 
   // Underlying storage. It's raw malloc-ed rather than being a unique_ptr<T[]>
   // to allow having uninitialized entries inside it.
-  T* entries_ = nullptr;
+  AlignedUniquePtr<T[]> entries_;
   size_t capacity_ = 0;  // Number of allocated slots (NOT bytes) in |entries_|.
 
   // The |begin_| and |end_| indexes are monotonic and never wrap. Modular arith
diff --git a/include/perfetto/ext/base/utils.h b/include/perfetto/ext/base/utils.h
index cedf0ec..b88655a 100644
--- a/include/perfetto/ext/base/utils.h
+++ b/include/perfetto/ext/base/utils.h
@@ -28,6 +28,7 @@
 
 #include <atomic>
 #include <functional>
+#include <memory>
 #include <string>
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
@@ -109,8 +110,6 @@
   return err == EAGAIN || err == EWOULDBLOCK;
 }
 
-void* AlignedAlloc(size_t alignment, size_t size);
-
 // setenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
 void SetEnv(const std::string& key, const std::string& value);
 
@@ -135,6 +134,33 @@
 // This is independent of cwd().
 std::string GetCurExecutableDir();
 
+// Memory returned by AlignedAlloc() must be freed via AlignedFree() not just
+// free. It makes a difference on Windows where _aligned_malloc() and
+// _aligned_free() must be paired.
+// Prefer using the AlignedAllocTyped() below which takes care of the pairing.
+void* AlignedAlloc(size_t alignment, size_t size);
+void AlignedFree(void*);
+
+// A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}.
+template <typename T>
+struct AlignedDeleter {
+  inline void operator()(T* ptr) const { AlignedFree(ptr); }
+};
+
+// The remove_extent<T> here and below is to allow defining unique_ptr<T[]>.
+// As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes
+// always a T*, not a T[]*.
+template <typename T>
+using AlignedUniquePtr =
+    std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
+
+template <typename T>
+AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
+  using TU = typename std::remove_extent<T>::type;
+  return AlignedUniquePtr<T>(
+      static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
+}
+
 }  // namespace base
 }  // namespace perfetto
 
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 9b0c5c0..c217438 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -25,6 +25,7 @@
     "cpu_metric.proto",
     "display_metrics.proto",
     "dma_heap_metric.proto",
+    "dvfs_metric.proto",
     "fastrpc_metric.proto",
     "g2d_metric.proto",
     "gpu_metric.proto",
diff --git a/protos/perfetto/metrics/android/dvfs_metric.proto b/protos/perfetto/metrics/android/dvfs_metric.proto
new file mode 100644
index 0000000..e7bb625
--- /dev/null
+++ b/protos/perfetto/metrics/android/dvfs_metric.proto
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+message AndroidDvfsMetric {
+
+  message BandStat {
+    // Operating frequency
+    optional int32 freq_value = 1;
+
+    // Percentage of duration in this operating frequency compared to all frequencies
+    optional double percentage = 2;
+
+    // Total duration in ns when the state was in this operating frequency
+    optional int64 duration_ns = 3;
+  }
+
+  message FrequencyResidency {
+    // Frequency representative name
+    optional string freq_name = 1;
+    // Each band statistics meta
+    repeated BandStat band_stat = 2;
+  }
+
+  // Frequency residency metrics from clock_set_rate ftrace event.
+  repeated FrequencyResidency freq_residencies = 1;
+}
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index 36b131b..c948145 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -23,6 +23,7 @@
 import "protos/perfetto/metrics/android/camera_metric.proto";
 import "protos/perfetto/metrics/android/display_metrics.proto";
 import "protos/perfetto/metrics/android/dma_heap_metric.proto";
+import "protos/perfetto/metrics/android/dvfs_metric.proto";
 import "protos/perfetto/metrics/android/fastrpc_metric.proto";
 import "protos/perfetto/metrics/android/g2d_metric.proto";
 import "protos/perfetto/metrics/android/gpu_metric.proto";
@@ -93,7 +94,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 39
+// Next id: 40
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -192,6 +193,9 @@
   // Metrics for the Camera team.
   optional AndroidCameraMetric android_camera = 38;
 
+  // Metrics for dynamic voltage and frequency scaling.
+  optional AndroidDvfsMetric android_dvfs = 39;
+
   // Demo extensions.
   extensions 450 to 499;
 
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 7128494..6cf96ca 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -202,6 +202,34 @@
 
 // End of protos/perfetto/metrics/android/dma_heap_metric.proto
 
+// Begin of protos/perfetto/metrics/android/dvfs_metric.proto
+
+message AndroidDvfsMetric {
+
+  message BandStat {
+    // Operating frequency
+    optional int32 freq_value = 1;
+
+    // Percentage of duration in this operating frequency compared to all frequencies
+    optional double percentage = 2;
+
+    // Total duration in ns when the state was in this operating frequency
+    optional int64 duration_ns = 3;
+  }
+
+  message FrequencyResidency {
+    // Frequency representative name
+    optional string freq_name = 1;
+    // Each band statistics meta
+    repeated BandStat band_stat = 2;
+  }
+
+  // Frequency residency metrics from clock_set_rate ftrace event.
+  repeated FrequencyResidency freq_residencies = 1;
+}
+
+// End of protos/perfetto/metrics/android/dvfs_metric.proto
+
 // Begin of protos/perfetto/metrics/android/fastrpc_metric.proto
 
 // fastrpc memory stats on Android.
@@ -1239,7 +1267,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 39
+// Next id: 40
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -1338,6 +1366,9 @@
   // Metrics for the Camera team.
   optional AndroidCameraMetric android_camera = 38;
 
+  // Metrics for dynamic voltage and frequency scaling.
+  optional AndroidDvfsMetric android_dvfs = 39;
+
   // Demo extensions.
   extensions 450 to 499;
 
diff --git a/src/base/utils.cc b/src/base/utils.cc
index c080388..b5d3d3c 100644
--- a/src/base/utils.cc
+++ b/src/base/utils.cc
@@ -258,5 +258,13 @@
   return res;
 }
 
+void AlignedFree(void* ptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+  _aligned_free(ptr);  // MSDN says it is fine to pass nullptr.
+#else
+  free(ptr);
+#endif
+}
+
 }  // namespace base
 }  // namespace perfetto
diff --git a/src/trace_processor/metrics/sql/BUILD.gn b/src/trace_processor/metrics/sql/BUILD.gn
index 2759d24..064630b 100644
--- a/src/trace_processor/metrics/sql/BUILD.gn
+++ b/src/trace_processor/metrics/sql/BUILD.gn
@@ -24,6 +24,7 @@
   "android/android_cpu_agg.sql",
   "android/android_cpu_raw_metrics_per_core.sql",
   "android/android_dma_heap.sql",
+  "android/android_dvfs.sql",
   "android/android_fastrpc.sql",
   "android/android_gpu.sql",
   "android/android_hwui_threads.sql",
diff --git a/src/trace_processor/metrics/sql/android/android_batt.sql b/src/trace_processor/metrics/sql/android/android_batt.sql
index 070a518..9b8de86 100644
--- a/src/trace_processor/metrics/sql/android/android_batt.sql
+++ b/src/trace_processor/metrics/sql/android/android_batt.sql
@@ -25,7 +25,7 @@
   SELECT distinct(ts) AS ts
   FROM counter c
   JOIN counter_track t on c.track_id = t.id
-  WHERE name LIKE 'batt.%'
+  WHERE name GLOB 'batt.*'
 ) AS all_ts
 LEFT JOIN (
   SELECT ts, value AS current_avg_ua
@@ -78,7 +78,7 @@
                 true
             ) AS new_group
         FROM slice
-        WHERE slice.name LIKE 'WakeLock %' AND dur != -1
+        WHERE slice.name GLOB 'WakeLock *' AND dur != -1
     )
 )
 GROUP BY group_id;
diff --git a/src/trace_processor/metrics/sql/android/android_camera.sql b/src/trace_processor/metrics/sql/android/android_camera.sql
index f8ba2af..791c922 100644
--- a/src/trace_processor/metrics/sql/android/android_camera.sql
+++ b/src/trace_processor/metrics/sql/android/android_camera.sql
@@ -30,7 +30,7 @@
 JOIN (
   SELECT max(start_ts), upid
   FROM process
-  WHERE name LIKE '%GoogleCamera%'
+  WHERE name GLOB '*GoogleCamera*'
   LIMIT 1
 ) AS gca USING (upid);
 
@@ -42,7 +42,7 @@
 JOIN (
   SELECT max(start_ts), upid
   FROM process
-  WHERE name LIKE '%camera.provider%'
+  WHERE name GLOB '*camera.provider*'
   LIMIT 1
 ) AS hal USING (upid);
 
diff --git a/src/trace_processor/metrics/sql/android/android_dvfs.sql b/src/trace_processor/metrics/sql/android/android_dvfs.sql
new file mode 100644
index 0000000..d8162b1
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/android_dvfs.sql
@@ -0,0 +1,93 @@
+--
+-- Copyright 2021 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
+--
+--     https://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.
+
+DROP VIEW IF EXISTS freq_slice;
+
+CREATE VIEW freq_slice AS
+  SELECT
+    counter.track_id AS track_id,
+    track.name AS freq_name,
+    ts,
+    value AS freq_value,
+    LEAD(ts, 1, (SELECT end_ts+1 FROM trace_bounds))
+      OVER (PARTITION by track.id ORDER BY ts)  - ts AS duration
+  FROM counter
+  LEFT JOIN track ON counter.track_id = track.id
+  WHERE track.name GLOB "* Frequency"
+  ORDER BY ts;
+
+DROP VIEW IF EXISTS freq_total_duration;
+
+CREATE VIEW freq_total_duration AS
+  SELECT
+    track_id,
+    freq_name,
+    SUM(duration) AS total_duration
+  FROM freq_slice
+  WHERE duration > 0
+  GROUP BY track_id, freq_name;
+
+DROP VIEW IF EXISTS dvfs_per_band_view;
+
+CREATE VIEW dvfs_per_band_view AS
+WITH
+freq_duration AS (
+  SELECT
+    track_id,
+    freq_name,
+    CAST(freq_value AS int) AS freq_value,
+    SUM(duration) AS duration_ns
+  FROM freq_slice
+  WHERE duration > 0
+  GROUP BY track_id, freq_name, freq_value
+)
+SELECT
+  freq_duration.track_id,
+  freq_duration.freq_name,
+  AndroidDvfsMetric_BandStat(
+     'freq_value', freq_value,
+     'percentage', duration_ns / (total_duration / 1e2),
+     'duration_ns', duration_ns
+  ) AS proto
+FROM freq_duration
+LEFT JOIN freq_total_duration
+USING(track_id)
+ORDER BY freq_duration.freq_name, freq_duration.freq_value;
+
+DROP VIEW IF EXISTS dvfs_per_freq_view;
+CREATE VIEW dvfs_per_freq_view AS
+  SELECT
+    AndroidDvfsMetric_FrequencyResidency(
+      'freq_name', freq_total_duration.freq_name,
+      'band_stat', (
+        SELECT
+          RepeatedField(proto)
+        FROM dvfs_per_band_view
+        WHERE dvfs_per_band_view.track_id = freq_total_duration.track_id
+      )
+    ) AS proto
+  FROM freq_total_duration
+  GROUP BY track_id, freq_name
+  ORDER BY freq_name;
+
+DROP VIEW IF EXISTS android_dvfs_output;
+CREATE VIEW android_dvfs_output AS
+  SELECT AndroidDVFSMetric(
+    'freq_residencies', (
+      SELECT
+        RepeatedField(proto)
+      FROM dvfs_per_freq_view
+    )
+  );
diff --git a/src/trace_processor/metrics/sql/android/android_fastrpc.sql b/src/trace_processor/metrics/sql/android/android_fastrpc.sql
index 81da811..e381668 100644
--- a/src/trace_processor/metrics/sql/android/android_fastrpc.sql
+++ b/src/trace_processor/metrics/sql/android/android_fastrpc.sql
@@ -9,7 +9,7 @@
   value
 FROM counter JOIN counter_track
   ON counter.track_id = counter_track.id
-WHERE (name LIKE 'mem.fastrpc[%');
+WHERE (name GLOB 'mem.fastrpc[[]*');
 
 DROP VIEW IF EXISTS fastrpc_subsystem_stats;
 CREATE VIEW fastrpc_subsystem_stats AS
@@ -29,7 +29,7 @@
   value AS instant_value,
   SUM(value) OVER win AS value
 FROM counter c JOIN thread_counter_track t ON c.track_id = t.id
-WHERE name LIKE 'mem.fastrpc_change%' AND value > 0
+WHERE name GLOB 'mem.fastrpc_change*' AND value > 0
 WINDOW win AS (
   PARTITION BY name ORDER BY ts
   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
diff --git a/src/trace_processor/metrics/sql/android/android_hwui_metric.sql b/src/trace_processor/metrics/sql/android/android_hwui_metric.sql
index 585e515..1a33e22 100644
--- a/src/trace_processor/metrics/sql/android/android_hwui_metric.sql
+++ b/src/trace_processor/metrics/sql/android/android_hwui_metric.sql
@@ -39,7 +39,7 @@
   thread_track.utid as render_thread_id
 FROM slice
 INNER JOIN thread_track ON (thread_track.id = slice.track_id)
-WHERE slice.name LIKE 'DrawFrame%' AND slice.dur >= 0
+WHERE slice.name GLOB 'DrawFrame*' AND slice.dur >= 0
 GROUP BY thread_track.utid;
 
 DROP VIEW IF EXISTS hwui_flush_commands;
@@ -79,7 +79,7 @@
 FROM slice
 INNER JOIN thread_track ON (thread_track.id = slice.track_id)
 INNER JOIN thread ON (thread.name='GPU completion' AND thread.utid = thread_track.utid)
-WHERE slice.name LIKE 'waiting for GPU completion%' AND slice.dur >= 0
+WHERE slice.name GLOB 'waiting for GPU completion*' AND slice.dur >= 0
 GROUP BY thread_track.utid;
 
 DROP VIEW IF EXISTS hwui_ui_record;
diff --git a/src/trace_processor/metrics/sql/android/android_hwui_threads.sql b/src/trace_processor/metrics/sql/android/android_hwui_threads.sql
index 942005b..ee6a3ab 100644
--- a/src/trace_processor/metrics/sql/android/android_hwui_threads.sql
+++ b/src/trace_processor/metrics/sql/android/android_hwui_threads.sql
@@ -69,7 +69,7 @@
     *,
     CAST(STR_SPLIT(name, ' ', 1) AS INTEGER) as vsync
   FROM {{table_name_prefix}}_main_thread_slices
-  WHERE name LIKE 'Choreographer#doFrame%';
+  WHERE name GLOB 'Choreographer#doFrame*';
 
 DROP TABLE IF EXISTS {{table_name_prefix}}_render_thread_slices;
 CREATE TABLE {{table_name_prefix}}_render_thread_slices AS
@@ -89,7 +89,7 @@
     *,
     CAST(STR_SPLIT(name, ' ', 1) AS INTEGER) as vsync
   FROM {{table_name_prefix}}_render_thread_slices
-  WHERE name LIKE 'DrawFrame%';
+  WHERE name GLOB 'DrawFrame*';
 
 DROP VIEW IF EXISTS {{table_name_prefix}}_gpu_completion_slices;
 CREATE VIEW {{table_name_prefix}}_gpu_completion_slices AS
@@ -103,7 +103,7 @@
   FROM slice
   JOIN thread_track ON slice.track_id = thread_track.id
   JOIN {{table_name_prefix}}_gpu_completion_thread thread USING (utid)
-  WHERE slice.name LIKE 'waiting for GPU completion %'
+  WHERE slice.name GLOB 'waiting for GPU completion *'
   AND dur > 0;
 
 DROP VIEW IF EXISTS {{table_name_prefix}}_hwc_release_slices;
@@ -118,5 +118,5 @@
   FROM slice
   JOIN thread_track ON slice.track_id = thread_track.id
   JOIN {{table_name_prefix}}_hwc_release_thread thread USING (utid)
-  WHERE slice.name LIKE 'waiting for HWC release %'
+  WHERE slice.name GLOB 'waiting for HWC release *'
   AND dur > 0;
diff --git a/src/trace_processor/metrics/sql/android/android_ion.sql b/src/trace_processor/metrics/sql/android/android_ion.sql
index 93fe8ac..4d61843 100644
--- a/src/trace_processor/metrics/sql/android/android_ion.sql
+++ b/src/trace_processor/metrics/sql/android/android_ion.sql
@@ -28,7 +28,7 @@
   value
 FROM counter JOIN counter_track
   ON counter.track_id = counter_track.id
-WHERE (name LIKE 'mem.ion.%' OR name = 'mem.ion');
+WHERE (name GLOB 'mem.ion.*' OR name = 'mem.ion');
 
 DROP VIEW IF EXISTS ion_heap_stats;
 CREATE VIEW ion_heap_stats AS
@@ -51,7 +51,7 @@
   value AS instant_value,
   SUM(value) OVER win AS value
 FROM counter c JOIN thread_counter_track t ON c.track_id = t.id
-WHERE (name LIKE 'mem.ion_change.%' OR name = 'mem.ion_change') AND value > 0
+WHERE (name GLOB 'mem.ion_change.*' OR name = 'mem.ion_change') AND value > 0
 WINDOW win AS (
   PARTITION BY name ORDER BY ts
   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
diff --git a/src/trace_processor/metrics/sql/android/android_jank.sql b/src/trace_processor/metrics/sql/android/android_jank.sql
index 44f7d81..9c2cc22 100644
--- a/src/trace_processor/metrics/sql/android/android_jank.sql
+++ b/src/trace_processor/metrics/sql/android/android_jank.sql
@@ -157,7 +157,7 @@
   ts,
   dur
 FROM android_jank_main_thread_slices
-WHERE name LIKE 'Choreographer#doFrame%'
+WHERE name GLOB 'Choreographer#doFrame*'
 AND dur >= 5000000;
 
 CREATE VIRTUAL TABLE IF NOT EXISTS android_jank_do_frame_slices_state_scheduled
@@ -213,7 +213,7 @@
   dur,
   'Expensive rendering with Canvas#saveLayer()' as alert_name
 FROM android_jank_render_thread_slices
-WHERE name LIKE '%alpha caused %saveLayer %'
+WHERE name GLOB '*alpha caused *saveLayer *'
 AND dur >= 1000000;
 
 -- Path texture churn
@@ -239,7 +239,7 @@
   dur,
   'Expensive Bitmap uploads' as alert_name
 FROM android_jank_render_thread_slices
-WHERE name LIKE 'Upload %x% Texture'
+WHERE name GLOB 'Upload *x* Texture'
 AND dur >= 3000000;
 
 -- Merge all alerts tables into one table
diff --git a/src/trace_processor/metrics/sql/android/android_lmk.sql b/src/trace_processor/metrics/sql/android/android_lmk.sql
index 8c66278..ca20c90 100644
--- a/src/trace_processor/metrics/sql/android/android_lmk.sql
+++ b/src/trace_processor/metrics/sql/android/android_lmk.sql
@@ -52,7 +52,7 @@
       slice.dur,
       CAST(STR_SPLIT(slice.name, ",", 1) AS INTEGER) AS pid
     FROM slice
-    WHERE slice.name LIKE 'lmk,%'
+    WHERE slice.name GLOB 'lmk,*'
 ),
 lmks_with_proc_name AS (
   SELECT
diff --git a/src/trace_processor/metrics/sql/android/android_multiuser_populator.sql b/src/trace_processor/metrics/sql/android/android_multiuser_populator.sql
index 140bd36..98a4b16 100644
--- a/src/trace_processor/metrics/sql/android/android_multiuser_populator.sql
+++ b/src/trace_processor/metrics/sql/android/android_multiuser_populator.sql
@@ -22,15 +22,28 @@
       {{end_event}}_time_ns AS event_end_time_ns
 FROM
   (
-    SELECT slice.ts AS user_start_time_ns
+    SELECT MIN(slice.ts) AS user_start_time_ns
     FROM slice
-    WHERE (slice.name LIKE "onBeforeStartUser%")
-    -- TODO: Use a signal based on SysUi so that it covers all switching, not just starting.
+    WHERE (
+        slice.name = "UserDetailView.Adapter#onClick" OR -- QuickSettings
+        slice.name = "UserDetailSettings.switchUser" OR -- Settings
+        slice.name = "shell_runSwitchUser" -- adb shell
+    )
   ),
   (
     SELECT slice.ts + slice.dur AS launcher_end_time_ns
     FROM slice
     WHERE (slice.name = "launching: com.google.android.apps.nexuslauncher")
+  ),
+  (
+    SELECT MIN(slice.ts) AS user_create_time_ns
+    FROM slice
+    WHERE (
+        slice.name = "UserDetailView.Adapter#onClick" OR -- QuickSettings
+        slice.name = "UserSettings.addUserNow" OR -- Settings
+        slice.name = "UserSettings.addGuest" OR -- Settings
+        slice.name = "shell_runCreateUser" -- adb shell
+    )
   );
 
 -- Calculation of the duration of the Multiuser event of interest.
@@ -93,7 +106,7 @@
     cpu_kcycles / (SELECT SUM(cpu_kcycles) FROM cpu_usage_all) * 100 AS cpu_percentage
 FROM
     cpu_usage_all
-ORDER BY cpu_mcycles DESC LIMIT 6;
+ORDER BY cpu_mcycles DESC LIMIT 25;
 
 
 -- Record the output for populating the proto.
diff --git a/src/trace_processor/metrics/sql/android/android_powrails.sql b/src/trace_processor/metrics/sql/android/android_powrails.sql
index 656cb15..626f7c4 100644
--- a/src/trace_processor/metrics/sql/android/android_powrails.sql
+++ b/src/trace_processor/metrics/sql/android/android_powrails.sql
@@ -20,7 +20,7 @@
 SELECT value, ts/1000000 AS ts, name
 FROM counter c
 JOIN counter_track t on c.track_id = t.id
-WHERE name LIKE 'power.%';
+WHERE name GLOB 'power.*';
 
 DROP VIEW IF EXISTS avg_used_powers;
 CREATE VIEW avg_used_powers AS
diff --git a/src/trace_processor/metrics/sql/android/android_simpleperf.sql b/src/trace_processor/metrics/sql/android/android_simpleperf.sql
index fa58575..1b7f85c 100644
--- a/src/trace_processor/metrics/sql/android/android_simpleperf.sql
+++ b/src/trace_processor/metrics/sql/android/android_simpleperf.sql
@@ -23,7 +23,7 @@
   name,
   value
 FROM counters
-WHERE name LIKE 'slc/qurg2\___:lvl=0x_%' ESCAPE '\';
+WHERE name GLOB 'slc/qurg2_??:lvl=0x_*';
 
 -- Find all counters from track that satisfies regex 'slc/qurg2_(wr|rd):lvl=0x(1|3|7)%'
 DROP VIEW IF EXISTS non_zero_qurg2;
@@ -31,7 +31,7 @@
 SELECT
   *
 FROM all_qurg2
-WHERE name NOT LIKE 'slc/qurg2\___:lvl=0x0%' ESCAPE '\';
+WHERE name NOT GLOB 'slc/qurg2_??:lvl=0x0*';
 
 DROP VIEW IF EXISTS android_simpleperf_output;
 CREATE VIEW android_simpleperf_output AS
diff --git a/src/trace_processor/metrics/sql/android/android_startup.sql b/src/trace_processor/metrics/sql/android/android_startup.sql
index 20eaefe..c097ece 100644
--- a/src/trace_processor/metrics/sql/android/android_startup.sql
+++ b/src/trace_processor/metrics/sql/android/android_startup.sql
@@ -58,7 +58,7 @@
 DROP VIEW IF EXISTS zygote_fork_slice;
 CREATE VIEW zygote_fork_slice AS
 SELECT slice.ts, slice.dur, STR_SPLIT(slice.name, ": ", 1) AS process_name
-FROM slice WHERE name LIKE 'Start proc: %';
+FROM slice WHERE name GLOB 'Start proc: *';
 
 DROP TABLE IF EXISTS zygote_forks_by_id;
 CREATE TABLE zygote_forks_by_id AS
@@ -147,28 +147,28 @@
   'inflate',
   'ResourcesManager#getResources',
   'binder transaction')
-  OR slice.name LIKE 'performResume:%'
-  OR slice.name LIKE 'performCreate:%'
-  OR slice.name LIKE 'location=% status=% filter=% reason=%'
-  OR slice.name LIKE 'OpenDexFilesFromOat%'
-  OR slice.name LIKE 'VerifyClass%'
-  OR slice.name LIKE 'Choreographer#doFrame%'
-  OR slice.name LIKE 'JIT compiling%'
-  OR slice.name LIKE '%mark sweep GC'
-  OR slice.name LIKE '%concurrent copying GC'
-  OR slice.name LIKE '%semispace GC';
+  OR slice.name GLOB 'performResume:*'
+  OR slice.name GLOB 'performCreate:*'
+  OR slice.name GLOB 'location=* status=* filter=* reason=*'
+  OR slice.name GLOB 'OpenDexFilesFromOat*'
+  OR slice.name GLOB 'VerifyClass*'
+  OR slice.name GLOB 'Choreographer#doFrame*'
+  OR slice.name GLOB 'JIT compiling*'
+  OR slice.name GLOB '*mark sweep GC'
+  OR slice.name GLOB '*concurrent copying GC'
+  OR slice.name GLOB '*semispace GC';
 
 DROP TABLE IF EXISTS main_process_slice;
 CREATE TABLE main_process_slice AS
 SELECT
   launch_id,
   CASE
-    WHEN slice_name LIKE 'OpenDexFilesFromOat%' THEN 'OpenDexFilesFromOat'
-    WHEN slice_name LIKE 'VerifyClass%' THEN 'VerifyClass'
-    WHEN slice_name LIKE 'JIT compiling%' THEN 'JIT compiling'
-    WHEN slice_name LIKE '%mark sweep GC' THEN 'GC'
-    WHEN slice_name LIKE '%concurrent copying GC' THEN 'GC'
-    WHEN slice_name LIKE '%semispace GC' THEN 'GC'
+    WHEN slice_name GLOB 'OpenDexFilesFromOat*' THEN 'OpenDexFilesFromOat'
+    WHEN slice_name GLOB 'VerifyClass*' THEN 'VerifyClass'
+    WHEN slice_name GLOB 'JIT compiling*' THEN 'JIT compiling'
+    WHEN slice_name GLOB '*mark sweep GC' THEN 'GC'
+    WHEN slice_name GLOB '*concurrent copying GC' THEN 'GC'
+    WHEN slice_name GLOB '*semispace GC' THEN 'GC'
     ELSE slice_name
   END AS name,
   AndroidStartupMetric_Slice(
@@ -192,7 +192,7 @@
   JOIN slice ON (
     slice.track_id = thread_track.id
     AND slice.ts >= launches.ts)
-  WHERE slice.name LIKE 'reportFullyDrawn%'
+  WHERE slice.name GLOB 'reportFullyDrawn*'
   GROUP BY launches.id
 )
 SELECT
@@ -224,9 +224,9 @@
     launch_id
   FROM main_process_slice_unaggregated
   WHERE (
-    slice_name LIKE '%mark sweep GC'
-    OR slice_name LIKE '%concurrent copying GC'
-    OR slice_name LIKE '%semispace GC');
+    slice_name GLOB '*mark sweep GC'
+    OR slice_name GLOB '*concurrent copying GC'
+    OR slice_name GLOB '*semispace GC');
 
 DROP TABLE IF EXISTS gc_slices_by_state;
 CREATE VIRTUAL TABLE gc_slices_by_state
@@ -254,7 +254,7 @@
 CREATE TABLE activity_names_materialized AS
 SELECT launch_id, slice_name, slice_ts
 FROM main_process_slice_unaggregated
-WHERE (slice_name LIKE 'performResume:%' OR slice_name LIKE 'performCreate:%');
+WHERE (slice_name GLOB 'performResume:*' OR slice_name GLOB 'performCreate:*');
 
 DROP TABLE IF EXISTS jit_compiled_methods_materialized;
 CREATE TABLE jit_compiled_methods_materialized AS
@@ -263,7 +263,7 @@
   COUNT(1) as count
 FROM main_process_slice_unaggregated
 WHERE
-  slice_name LIKE 'JIT compiling%'
+  slice_name GLOB 'JIT compiling*'
   AND thread_name = 'Jit thread pool'
 GROUP BY launch_id;
 
@@ -306,7 +306,7 @@
   'PROTO', '
     SELECT slice_proto
     FROM main_process_slice s
-    WHERE s.launch_id = $launch_id AND name LIKE $name
+    WHERE s.launch_id = $launch_id AND name GLOB $name
     LIMIT 1
   ');
 
@@ -445,7 +445,7 @@
       'time_activity_start', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityStart'),
       'time_activity_resume', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityResume'),
       'time_activity_restart', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityRestart'),
-      'time_choreographer', MAIN_PROCESS_SLICE_PROTO(launches.id, 'Choreographer#doFrame%'),
+      'time_choreographer', MAIN_PROCESS_SLICE_PROTO(launches.id, 'Choreographer#doFrame*'),
       'time_inflate', MAIN_PROCESS_SLICE_PROTO(launches.id, 'inflate'),
       'time_get_resources', MAIN_PROCESS_SLICE_PROTO(launches.id, 'ResourcesManager#getResources'),
       'time_dex_open', MAIN_PROCESS_SLICE_PROTO(launches.id, 'OpenDexFilesFromOat'),
@@ -519,7 +519,7 @@
         'compilation_reason', STR_SPLIT(name, ' reason=', 1)
       ))
       FROM main_process_slice s
-      WHERE name LIKE 'location=% status=% filter=% reason=%'
+      WHERE name GLOB 'location=* status=* filter=* reason=*'
     )
   ) as startup
 FROM launches;
diff --git a/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql b/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
index daa9fda..b00e491 100644
--- a/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
+++ b/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
@@ -53,7 +53,7 @@
   CAST(SUBSTR(s.name, 28) AS UINT32) AS fence_id,
   ts AS start_ts
 FROM slices s JOIN surfaceflinger_track t ON s.track_id = t.track_id
-WHERE s.name LIKE 'Trace GPU completion fence %';
+WHERE s.name GLOB 'Trace GPU completion fence *';
 
 DROP VIEW IF EXISTS gpu_waiting_end;
 CREATE VIEW gpu_waiting_end AS
@@ -62,7 +62,7 @@
   dur,
   ts+dur AS end_ts
 FROM slices s JOIN surfaceflinger_track t ON s.track_id = t.track_id
-WHERE s.name LIKE 'waiting for GPU completion %';
+WHERE s.name GLOB 'waiting for GPU completion *';
 
 DROP VIEW IF EXISTS gpu_waiting_span;
 CREATE VIEW gpu_waiting_span AS
diff --git a/src/trace_processor/metrics/sql/android/android_sysui_cuj.sql b/src/trace_processor/metrics/sql/android/android_sysui_cuj.sql
index 6b5c58d..073c247 100644
--- a/src/trace_processor/metrics/sql/android/android_sysui_cuj.sql
+++ b/src/trace_processor/metrics/sql/android/android_sysui_cuj.sql
@@ -30,11 +30,11 @@
   JOIN process USING (upid)
   JOIN process_metadata USING (upid)
   WHERE
-    slice.name LIKE 'J<%>'
+    slice.name GLOB 'J<*>'
     AND slice.dur > 0
     AND (
-      process.name LIKE 'com.google.android%'
-      OR process.name LIKE 'com.android.%')
+      process.name GLOB 'com.google.android*'
+      OR process.name GLOB 'com.android.*')
   ORDER BY ts desc
   LIMIT 1;
 
@@ -64,7 +64,7 @@
     CAST(actual.name as INTEGER) as vsync,
     actual.ts as ts_actual,
     actual.dur as dur_actual,
-    actual.jank_type LIKE '%App Deadline Missed%' as app_missed,
+    actual.jank_type GLOB '*App Deadline Missed*' as app_missed,
     actual.jank_type,
     actual.on_time_finish
   FROM android_sysui_cuj_last_cuj cuj
@@ -162,8 +162,8 @@
 CREATE TABLE android_sysui_cuj_jit_slices AS
 SELECT *
 FROM android_sysui_cuj_slices_in_cuj
-WHERE thread_name LIKE 'Jit thread pool%'
-AND name LIKE 'JIT compiling%'
+WHERE thread_name GLOB 'Jit thread pool*'
+AND name GLOB 'JIT compiling*'
 AND parent_id IS NULL;
 
 DROP TABLE IF EXISTS android_sysui_cuj_frames;
@@ -180,7 +180,7 @@
     JOIN android_sysui_cuj_render_thread_slices_in_cuj rts ON rts.ts < gcs.ts
     -- dispatchFrameCallbacks might be seen in case of
     -- drawing that happens on RT only (e.g. ripple effect)
-    WHERE (rts.name LIKE 'DrawFrame%' OR rts.name = 'dispatchFrameCallbacks')
+    WHERE (rts.name GLOB 'DrawFrame*' OR rts.name = 'dispatchFrameCallbacks')
     GROUP BY gcs.ts, gcs.ts_end, gcs.dur, gcs.idx
   ),
   frame_boundaries AS (
diff --git a/src/trace_processor/metrics/sql/android/cpu_info.sql b/src/trace_processor/metrics/sql/android/cpu_info.sql
index 1e04a3e..0f2c0f0 100644
--- a/src/trace_processor/metrics/sql/android/cpu_info.sql
+++ b/src/trace_processor/metrics/sql/android/cpu_info.sql
@@ -30,7 +30,7 @@
 FROM power_profile pp
 WHERE EXISTS (
   SELECT 1 FROM metadata
-  WHERE name = 'android_build_fingerprint' AND str_value LIKE '%' || pp.device || '%');
+  WHERE name = 'android_build_fingerprint' AND str_value GLOB '*' || pp.device || '*');
 
 DROP VIEW IF EXISTS core_cluster_per_cpu;
 CREATE VIEW core_cluster_per_cpu AS
diff --git a/src/trace_processor/metrics/sql/android/g2d_duration.sql b/src/trace_processor/metrics/sql/android/g2d_duration.sql
index b4a167b..653af6b 100644
--- a/src/trace_processor/metrics/sql/android/g2d_duration.sql
+++ b/src/trace_processor/metrics/sql/android/g2d_duration.sql
@@ -23,7 +23,7 @@
   value AS g2d_value,
   LEAD(value, 1, -1) OVER (PARTITION BY name ORDER BY ts) AS next_g2d_value
 FROM counter c JOIN thread_counter_track t ON t.id = c.track_id
-WHERE t.name LIKE 'g2d_frame_{{g2d_type}}%';
+WHERE t.name GLOB 'g2d_frame_{{g2d_type}}*';
 
 
 DROP VIEW IF EXISTS g2d_{{g2d_type}}_spans;
diff --git a/src/trace_processor/metrics/sql/android/power_drain_in_watts.sql b/src/trace_processor/metrics/sql/android/power_drain_in_watts.sql
index 1fbfec3..464da59 100644
--- a/src/trace_processor/metrics/sql/android/power_drain_in_watts.sql
+++ b/src/trace_processor/metrics/sql/android/power_drain_in_watts.sql
@@ -87,5 +87,4 @@
 FROM counter
   JOIN counter_track ON (counter.track_id = counter_track.id)
 WHERE counter_track.type = 'counter_track'
-  AND name LIKE "power.%";
-
+  AND name GLOB "power.*";
diff --git a/src/trace_processor/metrics/sql/android/process_metadata.sql b/src/trace_processor/metrics/sql/android/process_metadata.sql
index 6e0e6d3..6873bb2 100644
--- a/src/trace_processor/metrics/sql/android/process_metadata.sql
+++ b/src/trace_processor/metrics/sql/android/process_metadata.sql
@@ -32,7 +32,7 @@
       -- have seen a racy capture.
     WHEN length(process.name) = 15 AND (
       process.cmdline in ('zygote', 'zygote64', '<pre-initialized>')
-      OR process.cmdline like '%' || process.name)
+      OR process.cmdline GLOB '*' || process.name)
     THEN process.cmdline
     ELSE process.name
   END AS process_name,
@@ -51,7 +51,7 @@
     -- unique match
     uid_package_count.cnt = 1
     -- or process name starts with the package name
-    OR process.name LIKE plist.package_name || '%')
+    OR process.name GLOB plist.package_name || '*')
   );
 
 DROP VIEW IF EXISTS process_metadata;
diff --git a/src/trace_processor/metrics/sql/android/startup/hsc.sql b/src/trace_processor/metrics/sql/android/startup/hsc.sql
index 5c0a618..09db7d9 100644
--- a/src/trace_processor/metrics/sql/android/startup/hsc.sql
+++ b/src/trace_processor/metrics/sql/android/startup/hsc.sql
@@ -39,7 +39,7 @@
 FROM slices
 INNER JOIN process_track on slices.track_id = process_track.id
 INNER JOIN thread USING(upid)
-WHERE slices.name LIKE "animator%";
+WHERE slices.name GLOB "animator*";
 
 DROP VIEW IF EXISTS frame_times;
 CREATE VIEW frame_times AS
@@ -50,8 +50,8 @@
     launches.id AS launch_id,
     ROW_NUMBER() OVER(PARTITION BY launches.id ORDER BY functions.ts ASC) as number
 FROM functions
-INNER JOIN launches on launches.package LIKE '%' || functions.process_name || '%'
-WHERE functions.function_name LIKE "Choreographer#doFrame%" AND functions.ts > launches.ts;
+INNER JOIN launches on launches.package GLOB '*' || functions.process_name || '*'
+WHERE functions.function_name GLOB "Choreographer#doFrame*" AND functions.ts > launches.ts;
 
 DROP TABLE IF EXISTS hsc_based_startup_times;
 CREATE TABLE hsc_based_startup_times(package STRING, id INT, ts_total INT);
@@ -63,8 +63,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=2 AND frame_times.name LIKE "%roid.calcul%" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=2 AND frame_times.name GLOB "*roid.calcul*" AND frame_times.launch_id = launches.id;
 
 -- Calendar
 INSERT INTO hsc_based_startup_times
@@ -73,9 +73,9 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.name LIKE "%id.calendar%" AND frame_times.launch_id = launches.id
-ORDER BY ABS(frame_times.ts_end - (SELECT ts + dur FROM functions WHERE function_name LIKE "DrawFrame%" AND process_name LIKE "%id.calendar" ORDER BY ts LIMIT 1)) LIMIT 1;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.name GLOB "*id.calendar*" AND frame_times.launch_id = launches.id
+ORDER BY ABS(frame_times.ts_end - (SELECT ts + dur FROM functions WHERE function_name GLOB "DrawFrame*" AND process_name GLOB "*id.calendar" ORDER BY ts LIMIT 1)) LIMIT 1;
 
 -- Camera
 INSERT INTO hsc_based_startup_times
@@ -84,8 +84,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=2 AND frame_times.name LIKE "%GoogleCamera%" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=2 AND frame_times.name GLOB "*GoogleCamera*" AND frame_times.launch_id = launches.id;
 
 -- Chrome
 INSERT INTO hsc_based_startup_times
@@ -94,8 +94,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=1 AND frame_times.name LIKE "%chrome%" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=1 AND frame_times.name GLOB "*chrome*" AND frame_times.launch_id = launches.id;
 
 -- Clock
 INSERT INTO hsc_based_startup_times
@@ -104,8 +104,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts + dur FROM animators WHERE animator_name="animator:translationZ" AND process_name LIKE "%id.deskclock" ORDER BY (ts+dur) DESC LIMIT 1) AND frame_times.name LIKE "%id.deskclock" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts + dur FROM animators WHERE animator_name="animator:translationZ" AND process_name GLOB "*id.deskclock" ORDER BY (ts+dur) DESC LIMIT 1) AND frame_times.name GLOB "*id.deskclock" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Contacts
@@ -115,8 +115,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=3 AND frame_times.name LIKE "%id.contacts" AND frame_times.launch_id=launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=3 AND frame_times.name GLOB "*id.contacts" AND frame_times.launch_id=launches.id;
 
 -- Dialer
 INSERT INTO hsc_based_startup_times
@@ -125,8 +125,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=1 AND frame_times.name LIKE "%id.dialer" AND frame_times.launch_id=launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=1 AND frame_times.name GLOB "*id.dialer" AND frame_times.launch_id=launches.id;
 
 -- Facebook
 INSERT INTO hsc_based_startup_times
@@ -135,8 +135,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name LIKE "fb_startup_complete" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%ok.katana" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name GLOB "fb_startup_complete" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*ok.katana" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Facebook Messenger
@@ -146,8 +146,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name LIKE "msgr_cold_start_to_cached_content" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%book.orca" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name GLOB "msgr_cold_start_to_cached_content" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*book.orca" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Gmail
@@ -157,8 +157,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts + dur FROM animators WHERE animator_name="animator:elevation" AND process_name LIKE "%android.gm" ORDER BY (ts+dur) DESC LIMIT 1) AND frame_times.name LIKE "%android.gm" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts + dur FROM animators WHERE animator_name="animator:elevation" AND process_name GLOB "*android.gm" ORDER BY (ts+dur) DESC LIMIT 1) AND frame_times.name GLOB "*android.gm" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Instagram
@@ -168,8 +168,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name LIKE "ig_cold_start_to_cached_content" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%gram.android" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name GLOB "ig_cold_start_to_cached_content" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*gram.android" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Maps
@@ -179,8 +179,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=1 AND frame_times.name LIKE "%maps%" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=1 AND frame_times.name GLOB "*maps*" AND frame_times.launch_id = launches.id;
 
 -- Messages
 INSERT INTO hsc_based_startup_times
@@ -189,8 +189,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts_end > (SELECT ts + dur FROM animators WHERE animator_name="animator:translationZ" AND process_name LIKE "%apps.messaging%" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%apps.messaging%" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts_end > (SELECT ts + dur FROM animators WHERE animator_name="animator:translationZ" AND process_name GLOB "*apps.messaging*" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*apps.messaging*" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Netflix
@@ -200,8 +200,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts < (SELECT ts FROM animators WHERE animator_name LIKE "animator%" AND process_name LIKE "%lix.mediaclient" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%lix.mediaclient%" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts < (SELECT ts FROM animators WHERE animator_name GLOB "animator*" AND process_name GLOB "*lix.mediaclient" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*lix.mediaclient*" AND frame_times.launch_id = launches.id
 ORDER BY ts_total DESC LIMIT 1;
 
 -- Photos
@@ -211,8 +211,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=1 AND frame_times.name LIKE "%apps.photos%" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=1 AND frame_times.name GLOB "*apps.photos*" AND frame_times.launch_id = launches.id;
 
 -- Settings was deprecated in favor of reportFullyDrawn b/169694037.
 
@@ -223,8 +223,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=1 AND frame_times.name LIKE "%napchat.android" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=1 AND frame_times.name GLOB "*napchat.android" AND frame_times.launch_id = launches.id;
 
 -- Twitter
 INSERT INTO hsc_based_startup_times
@@ -233,8 +233,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts_end > (SELECT ts FROM animators WHERE animator_name="animator" AND process_name LIKE "%tter.android" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%tter.android" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts_end > (SELECT ts FROM animators WHERE animator_name="animator" AND process_name GLOB "*tter.android" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*tter.android" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- WhatsApp
@@ -244,8 +244,8 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name LIKE "wa_startup_complete" ORDER BY ts LIMIT 1) AND frame_times.name LIKE "%om.whatsapp" AND frame_times.launch_id = launches.id
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.ts > (SELECT ts+dur FROM slices WHERE slices.name GLOB "wa_startup_complete" ORDER BY ts LIMIT 1) AND frame_times.name GLOB "*om.whatsapp" AND frame_times.launch_id = launches.id
 ORDER BY ts_total LIMIT 1;
 
 -- Youtube
@@ -255,5 +255,5 @@
     launches.id as id,
     frame_times.ts_end - launches.ts as ts_total
 FROM frame_times
-INNER JOIN launches on launches.package LIKE '%' || frame_times.name || '%'
-WHERE frame_times.number=2 AND frame_times.name LIKE "%id.youtube" AND frame_times.launch_id = launches.id;
+INNER JOIN launches on launches.package GLOB '*' || frame_times.name || '*'
+WHERE frame_times.number=2 AND frame_times.name GLOB "*id.youtube" AND frame_times.launch_id = launches.id;
diff --git a/src/trace_processor/metrics/sql/android/startup/launches.sql b/src/trace_processor/metrics/sql/android/startup/launches.sql
index 104ec40..c3be64c 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches.sql
@@ -49,7 +49,7 @@
 FROM slice s
 JOIN process_track t ON s.track_id = t.id
 JOIN process USING(upid)
-WHERE s.name LIKE 'launching: %'
+WHERE s.name GLOB 'launching: *'
 AND (process.name IS NULL OR process.name = 'system_server');
 
 -- Filter activity_intent_recv_spans, keeping only the ones that triggered
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_processes.sql b/src/trace_processor/metrics/sql/chrome/chrome_processes.sql
index dd3be51..a7b378b 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_processes.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_processes.sql
@@ -64,8 +64,6 @@
 FROM prefix,
   suffix;
 
--- Use GLOB here instead of LIKE as it's case-sensitive which means we don't
--- match the Android system zygote.
 DROP VIEW IF EXISTS all_chrome_processes;
 CREATE VIEW all_chrome_processes AS
 SELECT upid, m.type AS process_type
diff --git a/src/trace_processor/metrics/sql/chrome/gesture_jank.sql b/src/trace_processor/metrics/sql/chrome/gesture_jank.sql
index 981e246..c13a051 100644
--- a/src/trace_processor/metrics/sql/chrome/gesture_jank.sql
+++ b/src/trace_processor/metrics/sql/chrome/gesture_jank.sql
@@ -47,15 +47,15 @@
       SELECT COUNT(*) >= 3 FROM (
         SELECT name FROM chrome_process
         WHERE
-          name LIKE "Browser" OR
-          name LIKE "Renderer" OR
-          name LIKE "Gpu" OR
-          name LIKE 'com.android.chrome%' OR
-          name LIKE 'com.chrome.beta%' OR
-          name LIKE 'com.chrome.dev%' OR
-          name LIKE 'com.chrome.canary%' OR
-          name LIKE 'com.google.android.apps.chrome%' OR
-          name LIKE 'org.chromium.chrome%'
+          name GLOB "Browser" OR
+          name GLOB "Renderer" OR
+          name GLOB "Gpu" OR
+          name GLOB 'com.android.chrome*' OR
+          name GLOB 'com.chrome.beta*' OR
+          name GLOB 'com.chrome.dev*' OR
+          name GLOB 'com.chrome.canary*' OR
+          name GLOB 'com.google.android.apps.chrome*' OR
+          name GLOB 'org.chromium.chrome*'
         GROUP BY name
     )) END AS have_enough_chrome_processes;
 
diff --git a/src/trace_processor/metrics/sql/chrome/rail_modes.sql b/src/trace_processor/metrics/sql/chrome/rail_modes.sql
index d86c25f..d28f665 100644
--- a/src/trace_processor/metrics/sql/chrome/rail_modes.sql
+++ b/src/trace_processor/metrics/sql/chrome/rail_modes.sql
@@ -352,7 +352,7 @@
   ts,
   dur
 FROM slice s
-WHERE name LIKE "InputLatency::%"
+WHERE name GLOB "InputLatency::*"
   AND NOT EXISTS (
     SELECT 1
     FROM slice
diff --git a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_blocking_task.sql b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_blocking_task.sql
index d061413..14ddd83 100644
--- a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_blocking_task.sql
+++ b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_blocking_task.sql
@@ -57,8 +57,8 @@
   track_id AS id
 FROM slice
 WHERE
-  EXTRACT_ARG(arg_set_id, "task.posted_from.file_name") LIKE
-      "%gpu/command_buffer/service/scheduler.cc"
+  EXTRACT_ARG(arg_set_id, "task.posted_from.file_name") GLOB
+      "*gpu/command_buffer/service/scheduler.cc"
 LIMIT 1;
 
 -- TODO(nuskos): Determine a good way to get all the renderer track_ids (each
@@ -178,8 +178,8 @@
     ) AND
     track_id = (SELECT id FROM browser_main_track_id)
   ) OR (
-    EXTRACT_ARG(arg_set_id, "task.posted_from.file_name") LIKE
-        "%components/viz/common/frame_sinks/copy_output_request.cc" AND
+    EXTRACT_ARG(arg_set_id, "task.posted_from.file_name") GLOB
+        "*components/viz/common/frame_sinks/copy_output_request.cc" AND
     track_id = (SELECT id FROM viz_compositor_track_id)
   ) OR (
     name = "SkiaOutputSurfaceImplOnGpu::CopyOutput" AND
diff --git a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
index a57fe70..a45ac79 100644
--- a/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
+++ b/src/trace_processor/metrics/sql/chrome/scroll_jank_cause_queuing_delay.sql
@@ -76,10 +76,10 @@
         slice.ts + slice.dur > queuing.ancestor_end AND
         queuing.maybe_next_ancestor_ts > slice.ts AND
         slice.track_id = queuing.next_track_id AND
-        queuing.description NOT LIKE
-            "InputLatency.LatencyInfo.%ank.STEP_DRAW_AND_SWAP-to-End" AND
-        queuing.description NOT LIKE
-            "InputLatency.LatencyInfo.%ank.STEP_FINISHED_SWAP_BUFFERS-to-End"
+        queuing.description NOT GLOB
+            "InputLatency.LatencyInfo.*ank.STEP_DRAW_AND_SWAP-to-End" AND
+        queuing.description NOT GLOB
+            "InputLatency.LatencyInfo.*ank.STEP_FINISHED_SWAP_BUFFERS-to-End"
   WHERE
     queuing_time_ns IS NOT NULL AND
     queuing_time_ns > 0;
diff --git a/src/trace_processor/metrics/sql/experimental/blink_gc_metric.sql b/src/trace_processor/metrics/sql/experimental/blink_gc_metric.sql
index 096d9c3..c260332 100644
--- a/src/trace_processor/metrics/sql/experimental/blink_gc_metric.sql
+++ b/src/trace_processor/metrics/sql/experimental/blink_gc_metric.sql
@@ -83,7 +83,7 @@
   INNER JOIN thread ON thread_track.utid = thread.id
   WHERE
     slice.dur >= 0 AND (
-    slice.name LIKE "V8.GC%" OR (slice.name LIKE "BlinkGC%" AND NOT forced)
+    slice.name GLOB "V8.GC*" OR (slice.name GLOB "BlinkGC*" AND NOT forced)
   )
 );
 
@@ -100,7 +100,7 @@
   blink_non_aggregated_gc_event_name AS event_name ON
       event_name.name = blink_gc_cpu_slice.name
 WHERE
-  blink_gc_cpu_slice.name LIKE "BlinkGC%" AND NOT forced;
+  blink_gc_cpu_slice.name GLOB "BlinkGC*" AND NOT forced;
 
 -- This groups all the events by name and epoch for from "blink_slice" for easy
 -- access.
@@ -245,7 +245,7 @@
     -- This subquery replaces metrics.v8.utils.isGarbageCollectionEvent().
     SELECT name FROM ANCESTOR_SLICE(blink_gc_cpu_slice.id) AS ancestor
     WHERE
-      ancestor.name LIKE "V8.GC%" AND
+      ancestor.name GLOB "V8.GC*" AND
       ancestor.name != 'V8.GCLowMemoryNotification'
     LIMIT 1
   ) IS NULL
diff --git a/src/trace_processor/metrics/sql/experimental/frame_times.sql b/src/trace_processor/metrics/sql/experimental/frame_times.sql
index 4e0ccdb..488963f 100644
--- a/src/trace_processor/metrics/sql/experimental/frame_times.sql
+++ b/src/trace_processor/metrics/sql/experimental/frame_times.sql
@@ -17,7 +17,7 @@
 CREATE VIEW InteractionEvents AS
 SELECT
   ts, dur, ts AS ts_ir, dur AS dur_ir
-FROM slice WHERE name LIKE 'Interaction.%';
+FROM slice WHERE name GLOB 'Interaction.*';
 
 DROP VIEW IF EXISTS GestureLegacyEvents;
 CREATE VIEW GestureLegacyEvents AS
diff --git a/src/trace_processor/metrics/sql/experimental/reported_by_page.sql b/src/trace_processor/metrics/sql/experimental/reported_by_page.sql
index 2685433..9936b31 100644
--- a/src/trace_processor/metrics/sql/experimental/reported_by_page.sql
+++ b/src/trace_processor/metrics/sql/experimental/reported_by_page.sql
@@ -23,7 +23,7 @@
 SELECT ts, name, EXTRACT_ARG(arg_set_id, "debug.data.navigationId") as nav_id
 FROM slice
 WHERE category = 'blink.user_timing' AND
-    (name = 'navigationStart' OR name LIKE 'telemetry:reported_by_page:%')
+    (name = 'navigationStart' OR name GLOB 'telemetry:reported_by_page:*')
 ORDER BY nav_id, ts ASC;
 
 --------------------------------------------------------------------------------
@@ -38,8 +38,8 @@
       nav_id = p.nav_id AND
       ts < p.ts AND (
         -- Viewable/interactive markers measure time from nav start.
-        (p.name LIKE 'telemetry:reported_by_page:%' AND
-         p.name NOT LIKE 'telemetry:reported_by_page:benchmark%' AND
+        (p.name GLOB 'telemetry:reported_by_page:*' AND
+         p.name NOT GLOB 'telemetry:reported_by_page:benchmark*' AND
          name = 'navigationStart') OR
         -- Benchmark end markers measure time from the most recent begin marker.
         (p.name = 'telemetry:reported_by_page:benchmark_end' AND
diff --git a/src/trace_processor/metrics/sql/webview/webview_power_usage.sql b/src/trace_processor/metrics/sql/webview/webview_power_usage.sql
index 96104fc..29dad50 100644
--- a/src/trace_processor/metrics/sql/webview/webview_power_usage.sql
+++ b/src/trace_processor/metrics/sql/webview/webview_power_usage.sql
@@ -32,8 +32,8 @@
   SELECT *
   FROM slice WHERE
   depth = 0 AND
-  ((category like '%toplevel%' OR category = 'Java') AND
-  name NOT LIKE '%looper%');
+  ((category GLOB '*toplevel*' OR category = 'Java') AND
+  name NOT GLOB '*looper*');
 
 DROP TABLE IF EXISTS webview_browser_slices;
 
@@ -55,8 +55,8 @@
   ON thread.upid = process.upid
   INNER JOIN thread
   ON thread_track.utid = thread.utid
-  WHERE process.name NOT LIKE '%SandboxedProcessService%'
-  AND process.name NOT LIKE '%chrome%'
+  WHERE process.name NOT GLOB '*SandboxedProcessService*'
+  AND process.name NOT GLOB '*chrome*'
   AND app_name IS NOT NULL;
 
 DROP TABLE IF EXISTS webview_browser_slices_power;
@@ -87,7 +87,7 @@
   FROM process
   INNER JOIN thread
   ON thread.upid = process.upid
-  WHERE process.name LIKE '%webview%SandboxedProcessService%'
+  WHERE process.name GLOB '*webview*SandboxedProcessService*'
   AND app_name IS NOT NULL;
 
 DROP TABLE IF EXISTS webview_renderer_power_summary;
@@ -136,8 +136,8 @@
   JOIN process ON thread.upid = process.upid
   WHERE thread.upid IN
     (SELECT DISTINCT(webview_browser_slices.upid) FROM webview_browser_slices)
-  AND process.name NOT LIKE '%SandboxedProcessService%'
-  AND process.name NOT LIKE '%chrome%'
+  AND process.name NOT GLOB '*SandboxedProcessService*'
+  AND process.name NOT GLOB '*chrome*'
   AND app_name IS NOT NULL;
 
 DROP TABLE IF EXISTS host_app_power_summary;
@@ -175,9 +175,9 @@
 CREATE TABLE webview_only_threads AS
 SELECT *
 FROM host_app_threads
-  WHERE name LIKE 'Chrome%' OR name LIKE 'CookieMonster%'
-  OR name LIKE 'CompositorTileWorker%' OR name LIKE 'ThreadPool%ground%'
-  OR NAME LIKE 'ThreadPoolService%' OR  name like 'VizCompositorThread%'
+  WHERE name GLOB 'Chrome*' OR name GLOB 'CookieMonster*'
+  OR name GLOB 'CompositorTileWorker*' OR name GLOB 'ThreadPool*ground*'
+  OR NAME GLOB 'ThreadPoolService*' OR  name GLOB 'VizCompositorThread*'
   OR name IN ('AudioThread', 'DedicatedWorker thread', 'GpuMemoryThread',
   'JavaBridge', 'LevelDBEnv.IDB', 'MemoryInfra', 'NetworkService', 'VizWebView');
 
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index c94c320..0eb8e34 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1 b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
index b00e60a..5d91f78 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor.sha1
@@ -2,5 +2,5 @@
 // SHA1(tools/gen_binary_descriptors)
 // 9fc6d77de57ec76a80b76aa282f4c7cf5ce55eec
 // SHA1(protos/perfetto/metrics/metrics.proto)
-// 8130cb1a62e55e42bb97a682ca0503161460b4ee
+// fe8af2b2dce211830488daf2357aea79b4b2a539
   
\ No newline at end of file
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 70213e4..ca3725d 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -654,6 +654,23 @@
   }
 };
 
+struct Glob : public SqlFunction {
+  static base::Status Run(void*,
+                          size_t,
+                          sqlite3_value** argv,
+                          SqlValue& out,
+                          Destructors&) {
+    const char* pattern =
+        reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
+    const char* text =
+        reinterpret_cast<const char*>(sqlite3_value_text(argv[1]));
+    if (pattern && text) {
+      out = SqlValue::Long(sqlite3_strglob(pattern, text) == 0);
+    }
+    return base::OkStatus();
+  }
+};
+
 void SetupMetrics(TraceProcessor* tp,
                   sqlite3* db,
                   std::vector<metrics::SqlMetricFile>* sql_metrics,
@@ -742,6 +759,7 @@
   db_.reset(std::move(db));
 
   // New style function registration.
+  RegisterFunction<Glob>(db, "glob", 2);
   RegisterFunction<Hash>(db, "HASH", -1);
   RegisterFunction<Demangle>(db, "DEMANGLE", 1);
   RegisterFunction<SourceGeq>(db, "SOURCE_GEQ", -1);
diff --git a/test/trace_processor/graphics/clock_sync.sql b/test/trace_processor/graphics/clock_sync.sql
index 227767b..ac9e48a 100644
--- a/test/trace_processor/graphics/clock_sync.sql
+++ b/test/trace_processor/graphics/clock_sync.sql
@@ -15,4 +15,4 @@
 --
 select ts, cast(value as integer) as int_value
 from counters
-where name like 'gpu_counter%'
\ No newline at end of file
+where name GLOB 'gpu_counter*'
\ No newline at end of file
diff --git a/test/trace_processor/parsing/android_log_counts.sql b/test/trace_processor/parsing/android_log_counts.sql
index 09fc250..35a2a47 100644
--- a/test/trace_processor/parsing/android_log_counts.sql
+++ b/test/trace_processor/parsing/android_log_counts.sql
@@ -17,6 +17,6 @@
 select count(*) as cnt from android_logs where prio = 3 union all
 select count(*) as cnt from android_logs where prio > 4 union all
 select count(*) as cnt from android_logs where tag = 'screen_toggled' union all
-select count(*) as cnt from android_logs where tag like '%_pss' union all
-select count(*) as cnt from android_logs where msg like '%i2c_write%' or msg like '%I2C_Write%' union all
+select count(*) as cnt from android_logs where tag GLOB '*_pss' union all
+select count(*) as cnt from android_logs where msg GLOB '*i2c?write*' or msg GLOB '*I2C?Write*' union all
 select count(*) as cnt from android_logs where ts >= 1510113924391 and ts < 1512610021879;
diff --git a/test/trace_processor/parsing/android_log_msgs.sql b/test/trace_processor/parsing/android_log_msgs.sql
index 9b46f43..1666095 100644
--- a/test/trace_processor/parsing/android_log_msgs.sql
+++ b/test/trace_processor/parsing/android_log_msgs.sql
@@ -20,7 +20,7 @@
 create view v3 as
 select tag, count(*)
 from android_logs
-where msg like '%wakelock%' or msg like '%Wakelock%' or msg like '%WakeLock%' or msg like '%wakeLock%'
+where msg GLOB '*wakelock*' or msg GLOB '*Wakelock*' or msg GLOB '*WakeLock*' or msg GLOB '*wakeLock*'
 group by tag;
 
 create view v4 as select msg, 1 from android_logs limit 10;
diff --git a/test/trace_processor/parsing/android_multiuser_switch.textproto b/test/trace_processor/parsing/android_multiuser_switch.textproto
index 223ddb6..4798139 100644
--- a/test/trace_processor/parsing/android_multiuser_switch.textproto
+++ b/test/trace_processor/parsing/android_multiuser_switch.textproto
@@ -5,7 +5,7 @@
       timestamp: 3000000000 # 3e9
       pid: 4064
       print {
-        buf: "S|1204|onBeforeStartUser-10|0\n"
+        buf: "S|1204|UserDetailView.Adapter#onClick|0\n"
       }
     }
   }
@@ -17,7 +17,7 @@
       timestamp: 3100000000
       pid: 4064
       print {
-        buf: "F|1204|onBeforeStartUser-10|0\n"
+        buf: "F|1204|UserDetailView.Adapter#onClick|0\n"
       }
     }
   }
diff --git a/test/trace_processor/parsing/args_string_filter_null.sql b/test/trace_processor/parsing/args_string_filter_null.sql
index 50f90e1..c42e2f3 100644
--- a/test/trace_processor/parsing/args_string_filter_null.sql
+++ b/test/trace_processor/parsing/args_string_filter_null.sql
@@ -39,7 +39,7 @@
 UNION
 select string_value
 from args
-where string_value LIKE NULL
+where string_value GLOB NULL
 UNION
 select string_value
 from args
diff --git a/test/trace_processor/parsing/ion_stat.sql b/test/trace_processor/parsing/ion_stat.sql
index 1032ac6..5cdc8d0 100644
--- a/test/trace_processor/parsing/ion_stat.sql
+++ b/test/trace_processor/parsing/ion_stat.sql
@@ -1,4 +1,4 @@
 SELECT t.name, c.ts, c.value
 FROM counter c
 JOIN track t ON c.track_id = t.id
-WHERE t.name LIKE 'mem.ion%';
+WHERE t.name GLOB 'mem.ion*';
diff --git a/test/trace_processor/parsing/mm_event.sql b/test/trace_processor/parsing/mm_event.sql
index 5130db6..56d4eab 100644
--- a/test/trace_processor/parsing/mm_event.sql
+++ b/test/trace_processor/parsing/mm_event.sql
@@ -17,6 +17,6 @@
 from counter
 inner join process_counter_track
   on counter.track_id = process_counter_track.id
-where name like 'mem.mm.%'
+where name GLOB 'mem.mm.*'
 order by ts
 limit 40
diff --git a/test/trace_processor/parsing/stats.sql b/test/trace_processor/parsing/stats.sql
index d68b28f..02316b2 100644
--- a/test/trace_processor/parsing/stats.sql
+++ b/test/trace_processor/parsing/stats.sql
@@ -14,4 +14,4 @@
 -- limitations under the License.
 --
 select name, idx, severity, source, value
-from stats where name like 'ftrace_cpu_%' or name like 'traced_buf_%';
\ No newline at end of file
+from stats where name GLOB 'ftrace_cpu_*' or name GLOB 'traced_buf_*';
\ No newline at end of file
diff --git a/test/trace_processor/power/dvfs_metric.out b/test/trace_processor/power/dvfs_metric.out
new file mode 100644
index 0000000..4b38bd2
--- /dev/null
+++ b/test/trace_processor/power/dvfs_metric.out
@@ -0,0 +1,33 @@
+android_dvfs {
+  freq_residencies {
+    freq_name: "bus_throughput Frequency"
+    band_stat: {
+      freq_value: 1014000
+      percentage: 75.0
+      duration_ns: 3000000
+    }
+    band_stat: {
+      freq_value: 2028000
+      percentage: 25.0
+      duration_ns: 1000000
+    }
+  }
+  freq_residencies {
+    freq_name: "domain@1 Frequency"
+    band_stat: {
+      freq_value: 400000
+      percentage: 40.0
+      duration_ns: 2000000
+    }
+    band_stat: {
+      freq_value: 553000
+      percentage: 40.0
+      duration_ns: 2000000
+    }
+    band_stat: {
+      freq_value: 1024000
+      percentage: 20.0
+      duration_ns: 1000000
+    }
+  }
+}
diff --git a/test/trace_processor/power/dvfs_metric.textproto b/test/trace_processor/power/dvfs_metric.textproto
new file mode 100644
index 0000000..8301519
--- /dev/null
+++ b/test/trace_processor/power/dvfs_metric.textproto
@@ -0,0 +1,55 @@
+packet {
+  ftrace_events {
+    cpu: 0
+    event {
+      timestamp: 200001000000
+      pid: 2
+      clock_set_rate {
+        name : "domain@1"
+        state: 400000
+      }
+    }
+    event {
+      timestamp: 200002000000
+      pid: 2
+      clock_set_rate {
+        name : "bus_throughput"
+        state: 1014000
+      }
+    }
+    event {
+      timestamp: 200003000000
+      pid: 2
+      clock_set_rate {
+        name: "domain@1"
+        state: 1024000
+      }
+    }
+    event {
+      timestamp: 200004000000
+      pid: 2
+      clock_set_rate {
+        name: "domain@1"
+        state: 553000
+      }
+    }
+    event {
+      timestamp: 200005000000
+      pid: 2
+      clock_set_rate {
+        name: "bus_throughput"
+        state: 2028000
+      }
+    }
+    event {
+      timestamp: 200005999999
+      pid: 527
+      clock_set_rate {
+        name: "domain@1"
+        state: 553000
+      }
+    }
+  }
+  trusted_uid: 9999
+  trusted_packet_sequence_id: 2
+}
diff --git a/test/trace_processor/power/index b/test/trace_processor/power/index
index 004f7a3..cb4e178 100644
--- a/test/trace_processor/power/index
+++ b/test/trace_processor/power/index
@@ -3,3 +3,7 @@
 power_rails_custom_clock.textproto power_rails_event.sql power_rails_event_power_rails_custom_clock.out
 power_rails.textproto power_rails_timestamp_sort.sql power_rails_timestamp_sort.out
 power_rails_well_known.textproto power_rails.sql power_rails_well_known_power_rails.out
+
+# Dynamic Voltage and Frequency Scaling
+
+dvfs_metric.textproto android_dvfs dvfs_metric.out
diff --git a/test/trace_processor/power/power_rails.sql b/test/trace_processor/power/power_rails.sql
index c095608..31af227 100644
--- a/test/trace_processor/power/power_rails.sql
+++ b/test/trace_processor/power/power_rails.sql
@@ -15,6 +15,6 @@
 --
 select name, AVG(value), COUNT(*)
 from counters
-where name like "power.%"
+where name GLOB "power.*"
 group by name
 limit 20
\ No newline at end of file
diff --git a/test/trace_processor/power/power_rails_event.sql b/test/trace_processor/power/power_rails_event.sql
index 9a1a254..ca04ce2 100644
--- a/test/trace_processor/power/power_rails_event.sql
+++ b/test/trace_processor/power/power_rails_event.sql
@@ -15,5 +15,5 @@
 --
 select ts, value
 from counters
-where name like "power.%"
+where name GLOB "power.*"
 limit 20
diff --git a/tools/check_sql_metrics.py b/tools/check_sql_metrics.py
index 2fe57df..65dcff2 100755
--- a/tools/check_sql_metrics.py
+++ b/tools/check_sql_metrics.py
@@ -31,6 +31,7 @@
   with open(path) as f:
     lines = [l.strip() for l in f.readlines()]
 
+  # Check that CREATE VIEW/TABLE has a matching DROP VIEW/TABLE before it.
   errors = 0
   d_type, d_name = None, None
   for line in lines:
@@ -43,15 +44,29 @@
       continue
     type, name = m.group(1), m.group(2)
     if type != d_type or name != d_name:
-      sys.stderr.write(('%s:\n  "%s" vs %s %s\n') % (path, line, d_type, d_name))
+      sys.stderr.write(
+          ('Missing DROP %s before CREATE %s\n') % (d_type, d_type))
+      sys.stderr.write(('%s:\n"%s" vs %s %s\n') % (path, line, d_type, d_name))
       errors += 1
     d_type, d_name = None, None
+
+  # Ban the use of LIKE in non-comment lines.
+  for line in lines:
+    if line.startswith('--'):
+      continue
+
+    if 'like' in line.casefold():
+      sys.stderr.write(
+          'LIKE is banned in trace processor metrics. Prefer GLOB instead.')
+      errors += 1
+
   return errors
 
 
 def main():
   errors = 0
-  metrics_sources = os.path.join(ROOT_DIR, 'src', 'trace_processor', 'metrics')
+  metrics_sources = os.path.join(ROOT_DIR, 'src', 'trace_processor', 'metrics',
+                                 'sql')
   for root, _, files in os.walk(metrics_sources, topdown=True):
     for f in files:
       path = os.path.join(root, f)
diff --git a/ui/build.js b/ui/build.js
index e9d6c60..e01e45d 100644
--- a/ui/build.js
+++ b/ui/build.js
@@ -82,6 +82,8 @@
   verbose: false,
   debug: false,
   startHttpServer: false,
+  httpServerListenHost: '127.0.0.1',
+  httpServerListenPort: 10000,
   wasmModules: ['trace_processor', 'trace_to_text'],
 
   // The fields below will be changed by main() after cmdline parsing.
@@ -126,6 +128,8 @@
   parser.addArgument('--out', {help: 'Output directory'});
   parser.addArgument(['--watch', '-w'], {action: 'storeTrue'});
   parser.addArgument(['--serve', '-s'], {action: 'storeTrue'});
+  parser.addArgument('--serve-host', {help: '--serve bind host'});
+  parser.addArgument('--serve-port', {help: '--serve bind port', type: 'int'});
   parser.addArgument(['--verbose', '-v'], {action: 'storeTrue'});
   parser.addArgument(['--no-build', '-n'], {action: 'storeTrue'});
   parser.addArgument(['--no-wasm', '-W'], {action: 'storeTrue'});
@@ -150,6 +154,12 @@
   cfg.verbose = !!args.verbose;
   cfg.debug = !!args.debug;
   cfg.startHttpServer = args.serve;
+  if (args.serve_host) {
+    cfg.httpServerListenHost = args.serve_host
+  }
+  if (args.serve_port) {
+    cfg.httpServerListenPort = args.serve_port
+  }
   if (args.interactive) {
     process.env.PERFETTO_UI_TESTS_INTERACTIVE = '1';
   }
@@ -421,8 +431,9 @@
 }
 
 function startServer() {
-  const port = 10000;
-  console.log(`Starting HTTP server on http://localhost:${port}`);
+  console.log(
+      'Starting HTTP server on',
+      `http://${cfg.httpServerListenHost}:${cfg.httpServerListenPort}`);
   http.createServer(function(req, res) {
         console.debug(req.method, req.url);
         let uri = req.url.split('?', 1)[0];
@@ -481,7 +492,7 @@
           res.end();
         });
       })
-      .listen(port, '127.0.0.1');
+      .listen(cfg.httpServerListenPort, cfg.httpServerListenHost);
 }
 
 function isDistComplete() {
diff --git a/ui/release/channels.json b/ui/release/channels.json
index 597d0f2..5ee2472 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -6,7 +6,7 @@
     },
     {
       "name": "canary",
-      "rev": "dc27087559ea8ff3677f8a9cc909e690e1ccfdaa"
+      "rev": "78d87a701cdcab64ca0937baed175d27ef38ef9c"
     },
     {
       "name": "autopush",
diff --git a/ui/src/assets/record.scss b/ui/src/assets/record.scss
index 737e434..110920d 100644
--- a/ui/src/assets/record.scss
+++ b/ui/src/assets/record.scss
@@ -309,16 +309,15 @@
   }
 
   .config-button {
-    border-radius: 10px;
+    border-radius: 100%;
     margin-right: 10px;
     text-align: center;
     justify-items: center;
     font-family: 'Raleway', sans-serif;
     padding: 7px;
-    width: 75px;
 
     &:hover:enabled {
-      box-shadow: 0 0 4px 0px #999;
+      box-shadow: 0 0 3px 0px #aaa;
     }
 
     &:not(:enabled) {
@@ -363,7 +362,7 @@
 
     input {
       border-radius: 20px;
-      border-color: #0000003d;
+      border: 1px solid #eee;
       line-height: 36px;
       padding: 0 10px;
       font-size: 18px;
diff --git a/ui/src/frontend/post_message_handler.ts b/ui/src/frontend/post_message_handler.ts
index ffa8c28..68d010f 100644
--- a/ui/src/frontend/post_message_handler.ts
+++ b/ui/src/frontend/post_message_handler.ts
@@ -91,6 +91,15 @@
     throw new Error('Incoming message trace buffer is empty');
   }
 
+  /* Removing this event listener because it is fired multiple times
+   * with the same payload, causing issues such as b/182502595. This can be
+   * reproduced by taking https://jsfiddle.net/primiano/1hd0a4wj/68/ and
+   * replacing 'ui.perfetto.dev' -> 'localhost:10000'. If you open multiple
+   * traces or the same trace multiple times, every tab will receive a message
+   * for every window.open() call.
+   */
+  window.removeEventListener('message', postMessageHandler);
+
   const openTrace = () => {
     // For external traces, we need to disable other features such as
     // downloading and sharing a trace.
diff --git a/ui/src/frontend/record_page.ts b/ui/src/frontend/record_page.ts
index ca28930..dd1150c 100644
--- a/ui/src/frontend/record_page.ts
+++ b/ui/src/frontend/record_page.ts
@@ -899,14 +899,15 @@
   return m(
       'button',
       {
-        class: 'config-button load',
+        class: 'config-button',
+        title: 'Apply configuration settings',
         disabled: loadedConfigEqual(configType, globals.state.lastLoadedConfig),
         onclick: () => {
           globals.dispatch(Actions.setRecordConfig({config, configType}));
           globals.rafScheduler.scheduleFullRedraw();
         }
       },
-      'load');
+      m('i.material-icons', 'file_upload'));
 }
 
 function displayRecordConfigs() {
@@ -924,7 +925,8 @@
       loadConfigButton(item.config, {type: 'NAMED', name: item.title}),
       m('button',
         {
-          class: 'config-button save',
+          class: 'config-button',
+          title: 'Overwrite configuration with current settings',
           onclick: () => {
             if (confirm(`Overwrite config "${
                     item.title}" with current settings?`)) {
@@ -937,16 +939,17 @@
             }
           }
         },
-        'save'),
+        m('i.material-icons', 'save')),
       m('button',
         {
-          class: 'config-button delete',
+          class: 'config-button',
+          title: 'Remove configuration',
           onclick: () => {
             recordConfigStore.delete(item.key);
             globals.rafScheduler.scheduleFullRedraw();
           }
         },
-        'delete'),
+        m('i.material-icons', 'delete')),
     ]));
 
     const errorItems = [];
@@ -999,9 +1002,10 @@
           }),
           m('button',
             {
-              class: 'config-button save long',
+              class: 'config-button',
               disabled: !canSave,
-              title: canSave ? '' : 'Duplicate name, saving disabled',
+              title: canSave ? 'Save current config' :
+                               'Duplicate name, saving disabled',
               onclick: () => {
                 recordConfigStore.save(
                     globals.state.recordConfig, ConfigTitleState.getTitle());
@@ -1009,24 +1013,25 @@
                 ConfigTitleState.clearTitle();
               }
             },
-            'Save current config')
-        ]),
-      m('.reset-wrapper',
-        m('button',
-          {
-            class: 'config-button reset',
-            onclick: () => {
-              if (confirm(
-                      'Current configuration will be cleared. Are you sure?')) {
-                globals.dispatch(Actions.setRecordConfig({
-                  config: createEmptyRecordConfig(),
-                  configType: {type: 'NONE'}
-                }));
-                globals.rafScheduler.scheduleFullRedraw();
+            m('i.material-icons', 'save')),
+          m('button',
+            {
+              class: 'config-button',
+              title: 'Clear current configuration',
+              onclick: () => {
+                if (confirm(
+                        'Current configuration will be cleared. ' +
+                        'Are you sure?')) {
+                  globals.dispatch(Actions.setRecordConfig({
+                    config: createEmptyRecordConfig(),
+                    configType: {type: 'NONE'}
+                  }));
+                  globals.rafScheduler.scheduleFullRedraw();
+                }
               }
-            }
-          },
-          'Clear current config')),
+            },
+            m('i.material-icons', 'delete_forever'))
+        ]),
       displayRecordConfigs());
 }