ui: Improve runtime of CPU by thread/process

Improve UI runtime of "CPU by thread" and "CPU by process" by doing the
thread/process association onetime upfront, instead of re-generating the
table every iteration a UI selection changes.

UI Profiling (cumulative sum):
  CPU by thread: ~7s -> ~6s
  CPU by process: ~10s -> ~7s
  Wattson by thread: ~16s -> ~15s
  Wattson by process: ~30s -> ~30s

Bug: 354256369
Change-Id: I931b4ec2098a154658d412d2315bd0cd278a3aa7
Signed-off-by: Samuel Wu <wusamuel@google.com>
diff --git a/Android.bp b/Android.bp
index 065b82a..1f7ea40 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13368,6 +13368,7 @@
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql",
+        "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads_w_processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/tracks.sql",
         "src/trace_processor/perfetto_sql/stdlib/wattson/arm_dsu.sql",
         "src/trace_processor/perfetto_sql/stdlib/wattson/cpu_idle.sql",
diff --git a/BUILD b/BUILD
index c2db657..0394bc1 100644
--- a/BUILD
+++ b/BUILD
@@ -2870,6 +2870,7 @@
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql",
+        "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads_w_processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/tracks.sql",
     ],
 )
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
index b02d5a7..0d0ba62 100644
--- a/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
@@ -20,6 +20,7 @@
     "processes.sql",
     "slices.sql",
     "threads.sql",
+    "threads_w_processes.sql",
     "tracks.sql",
   ]
 }
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads_w_processes.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads_w_processes.sql
new file mode 100644
index 0000000..11da32d
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads_w_processes.sql
@@ -0,0 +1,43 @@
+--
+-- Copyright 2024 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.
+
+-- Establish relationships between thread and process
+CREATE PERFETTO TABLE _thread_process_summary AS
+SELECT
+  thread.utid,
+  thread.upid,
+  thread.tid,
+  process.pid,
+  thread.name as thread_name,
+  process.name as process_name
+FROM thread
+LEFT JOIN process USING (upid);
+
+-- Add thread_state info to thread/process/package
+CREATE PERFETTO TABLE _state_w_thread_process_summary AS
+SELECT
+  thread_state.ts,
+  thread_state.dur,
+  thread_state.cpu,
+  thread_state.state,
+  m.utid,
+  m.upid,
+  m.tid,
+  m.pid,
+  m.thread_name,
+  m.process_name
+FROM _thread_process_summary as m
+JOIN thread_state USING (utid);
+
diff --git a/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts b/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
index 46a7711..df177d2 100644
--- a/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
@@ -37,18 +37,24 @@
     }
     if (selectedCpus.length === 0) return false;
 
-    const query = `create view ${this.kind} as
-        SELECT process.name as process_name, pid,
-        sum(dur) AS total_dur,
-        sum(dur)/count(1) as avg_dur,
-        count(1) as occurrences
-        FROM process
-        JOIN thread USING(upid)
-        JOIN thread_state USING(utid)
-        WHERE cpu IN (${selectedCpus}) AND
-        state = "Running" AND
-        thread_state.ts + thread_state.dur > ${area.start} AND
-        thread_state.ts < ${area.end} group by upid`;
+    const query = `
+        INCLUDE PERFETTO MODULE viz.summary.threads_w_processes;
+
+        create view ${this.kind} as
+        SELECT
+          process_name,
+          pid,
+          sum(dur) AS total_dur,
+          sum(dur)/count(1) as avg_dur,
+          count(1) as occurrences
+        FROM _state_w_thread_process_summary
+        WHERE
+          cpu IN (${selectedCpus})
+          AND upid is NOT NULL
+          AND state = "Running"
+          AND ts + dur > ${area.start}
+          AND ts < ${area.end}
+        GROUP by upid`;
 
     await engine.query(query);
     return true;
diff --git a/ui/src/controller/aggregation/thread_aggregation_controller.ts b/ui/src/controller/aggregation/thread_aggregation_controller.ts
index 4e8a1c7..8954d8b 100644
--- a/ui/src/controller/aggregation/thread_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/thread_aggregation_controller.ts
@@ -46,22 +46,23 @@
     if (this.utids === undefined || this.utids.length === 0) return false;
 
     const query = `
+      INCLUDE PERFETTO MODULE viz.summary.threads_w_processes;
+
       create view ${this.kind} as
       SELECT
-        process.name as process_name,
+        process_name,
         pid,
-        thread.name as thread_name,
+        thread_name,
         tid,
         state || ',' || IFNULL(io_wait, 'NULL') as concat_state,
         sum(dur) AS total_dur,
         sum(dur)/count(1) as avg_dur,
         count(1) as occurrences
-      FROM thread
-      JOIN thread_state USING(utid)
-      LEFT JOIN process USING(upid)
-      WHERE utid IN (${this.utids}) AND
-      thread_state.ts + thread_state.dur > ${area.start} AND
-      thread_state.ts < ${area.end}
+      FROM _state_w_thread_process_summary
+      WHERE
+        utid IN (${this.utids})
+        AND ts + dur > ${area.start}
+        AND ts < ${area.end}
       GROUP BY utid, concat_state
     `;