ui: overhaul track decider queries to make things faster
This CL overhauls a bunch of queries in track_decider to improve
load performance.
Specifically, the main thing we are doing is extracting a bunch of O(event)
queries into the standard library and compute a summary over each of the
event tables exactly once. This significantly reduces the amount of
redundant computation that needs to be performed.
Change-Id: I49c07f681c7128cf37852ad66a8a2a8e2e17b2b5
diff --git a/Android.bp b/Android.bp
index db1ef89..afcb092 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12486,6 +12486,10 @@
"src/trace_processor/perfetto_sql/stdlib/stack_trace/jit.sql",
"src/trace_processor/perfetto_sql/stdlib/time/conversion.sql",
"src/trace_processor/perfetto_sql/stdlib/v8/jit.sql",
+ "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/tracks.sql",
"src/trace_processor/perfetto_sql/stdlib/wattson/arm_dsu.sql",
"src/trace_processor/perfetto_sql/stdlib/wattson/cpu_freq.sql",
"src/trace_processor/perfetto_sql/stdlib/wattson/cpu_idle.sql",
diff --git a/BUILD b/BUILD
index 0608cb1..389e3b8 100644
--- a/BUILD
+++ b/BUILD
@@ -2621,6 +2621,17 @@
],
)
+# GN target: //src/trace_processor/perfetto_sql/stdlib/viz/summary:summary
+perfetto_filegroup(
+ name = "src_trace_processor_perfetto_sql_stdlib_viz_summary_summary",
+ srcs = [
+ "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/tracks.sql",
+ ],
+)
+
# GN target: //src/trace_processor/perfetto_sql/stdlib/wattson:wattson
perfetto_filegroup(
name = "src_trace_processor_perfetto_sql_stdlib_wattson_wattson",
@@ -2656,6 +2667,7 @@
":src_trace_processor_perfetto_sql_stdlib_stack_trace_stack_trace",
":src_trace_processor_perfetto_sql_stdlib_time_time",
":src_trace_processor_perfetto_sql_stdlib_v8_v8",
+ ":src_trace_processor_perfetto_sql_stdlib_viz_summary_summary",
":src_trace_processor_perfetto_sql_stdlib_wattson_wattson",
],
outs = [
diff --git a/src/trace_processor/perfetto_sql/stdlib/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
index 4c492d1..349e2f6 100644
--- a/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
@@ -36,6 +36,7 @@
"stack_trace",
"time",
"v8",
+ "viz/summary",
"wattson",
]
generated_header = "stdlib.h"
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
new file mode 100644
index 0000000..3f664bd
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright (C) 2023 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/perfetto_sql.gni")
+
+perfetto_sql_source_set("summary") {
+ sources = [
+ "processes.sql",
+ "slices.sql",
+ "threads.sql",
+ "tracks.sql",
+ ]
+}
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql
new file mode 100644
index 0000000..18aa202
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql
@@ -0,0 +1,93 @@
+--
+-- 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.
+
+INCLUDE PERFETTO MODULE viz.summary.slices;
+INCLUDE PERFETTO MODULE viz.summary.threads;
+
+CREATE PERFETTO TABLE _process_track_summary AS
+SELECT upid, SUM(cnt) AS slice_count
+FROM process_track
+JOIN _slice_track_summary USING (id)
+GROUP BY upid;
+
+CREATE PERFETTO TABLE _heap_profile_allocation_summary AS
+SELECT upid, COUNT() AS allocation_count
+FROM heap_profile_allocation
+GROUP BY upid;
+
+CREATE PERFETTO TABLE _heap_profile_graph_summary AS
+SELECT upid, COUNT() AS graph_object_count
+FROM heap_graph_object;
+
+CREATE PERFETTO TABLE _thread_process_grouped_summary AS
+SELECT
+ upid,
+ MAX(max_running_dur) AS max_running_dur,
+ SUM(sum_running_dur) AS sum_running_dur,
+ SUM(running_count) AS running_count,
+ SUM(slice_count) AS slice_count,
+ SUM(perf_sample_count) AS perf_sample_count
+FROM _thread_available_info_summary
+JOIN thread USING (utid)
+WHERE upid IS NOT NULL
+GROUP BY upid;
+
+CREATE PERFETTO TABLE _process_available_info_summary AS
+WITH r AS (
+ SELECT
+ upid,
+ t_summary.upid as summary_upid,
+ t_summary.max_running_dur AS max_running_dur,
+ t_summary.sum_running_dur,
+ t_summary.running_count,
+ t_summary.slice_count AS thread_slice_count,
+ t_summary.perf_sample_count AS perf_sample_count,
+ (
+ SELECT slice_count
+ FROM _process_track_summary
+ WHERE upid = p.upid
+ ) AS process_slice_count,
+ (
+ SELECT allocation_count
+ FROM _heap_profile_allocation_summary
+ WHERE upid = p.upid
+ ) AS allocation_count,
+ (
+ SELECT graph_object_count
+ FROM _heap_profile_graph_summary
+ WHERE upid = p.upid
+ ) AS graph_object_count
+ FROM process p
+ LEFT JOIN _thread_process_grouped_summary t_summary USING (upid)
+)
+SELECT
+ upid,
+ IFNULL(max_running_dur, 0) AS max_running_dur,
+ IFNULL(sum_running_dur, 0) AS sum_running_dur,
+ IFNULL(running_count, 0) AS running_count,
+ IFNULL(thread_slice_count, 0) AS thread_slice_count,
+ IFNULL(perf_sample_count, 0) AS perf_sample_count,
+ IFNULL(process_slice_count, 0) AS process_slice_count,
+ IFNULL(allocation_count, 0) AS allocation_count,
+ IFNULL(graph_object_count, 0) AS graph_object_count
+FROM r
+WHERE
+ NOT(
+ r.summary_upid IS NULL
+ AND process_slice_count IS NULL
+ AND allocation_count IS NULL
+ AND graph_object_count IS NULL
+ )
+ OR upid IN (SELECT upid FROM process_counter_track);
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql
new file mode 100644
index 0000000..c698859
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql
@@ -0,0 +1,24 @@
+--
+-- 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.
+
+CREATE PERFETTO TABLE _slice_track_summary AS
+SELECT
+ track_id as id,
+ COUNT() AS cnt,
+ MIN(dur) AS min_dur,
+ MAX(dur) AS max_dur,
+ MAX(depth) AS max_depth
+FROM slice
+GROUP BY track_id;
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql
new file mode 100644
index 0000000..ed74acf
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql
@@ -0,0 +1,77 @@
+--
+-- 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.
+
+INCLUDE PERFETTO MODULE viz.summary.slices;
+
+CREATE PERFETTO TABLE _sched_summary AS
+SELECT
+ utid,
+ MAX(dur) AS max_running_dur,
+ SUM(dur) AS sum_running_dur,
+ COUNT() AS running_count
+FROM sched
+WHERE utid != 0 AND dur != -1
+GROUP BY utid;
+
+CREATE PERFETTO TABLE _thread_track_summary AS
+SELECT utid, SUM(cnt) AS slice_count
+FROM thread_track
+JOIN _slice_track_summary USING (id)
+GROUP BY utid;
+
+CREATE PERFETTO TABLE _perf_sample_summary AS
+SELECT utid, count() AS perf_sample_cnt
+FROM perf_sample
+WHERE callsite_id IS NOT NULL
+GROUP BY utid;
+
+CREATE PERFETTO TABLE _thread_available_info_summary AS
+WITH raw AS (
+ SELECT
+ utid,
+ ss.max_running_dur,
+ ss.sum_running_dur,
+ ss.running_count,
+ (
+ SELECT slice_count
+ FROM _thread_track_summary
+ WHERE utid = t.utid
+ ) AS slice_count,
+ (
+ SELECT perf_sample_cnt
+ FROM _perf_sample_summary
+ WHERE utid = t.utid
+ ) AS perf_sample_count
+ FROM thread t
+ LEFT JOIN _sched_summary ss USING (utid)
+)
+SELECT
+ utid,
+ IFNULL(max_running_dur, 0) AS max_running_dur,
+ IFNULL(sum_running_dur, 0) AS sum_running_dur,
+ IFNULL(running_count, 0) AS running_count,
+ IFNULL(slice_count, 0) AS slice_count,
+ IFNULL(perf_sample_count, 0) AS perf_sample_count
+FROM raw r
+WHERE
+ NOT (
+ r.max_running_dur IS NULL
+ AND r.sum_running_dur IS NULL
+ AND r.running_count IS NULL
+ AND r.slice_count IS NULL
+ AND r.perf_sample_count IS NULL
+ )
+ OR utid IN (SELECT utid FROM cpu_profile_stack_sample)
+ OR utid IN (SELECT utid FROM thread_counter_track);
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/tracks.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/tracks.sql
new file mode 100644
index 0000000..7a1d5d0
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/tracks.sql
@@ -0,0 +1,36 @@
+--
+-- 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.
+
+INCLUDE PERFETTO MODULE viz.summary.slices;
+
+CREATE PERFETTO TABLE _process_track_summary_by_upid_and_name AS
+SELECT
+ upid,
+ name,
+ GROUP_CONCAT(id) AS track_ids,
+ COUNT() AS track_count
+FROM process_track
+JOIN _slice_track_summary USING (id)
+GROUP BY upid, name;
+
+CREATE PERFETTO TABLE _uid_track_track_summary_by_uid_and_name AS
+SELECT
+ uid,
+ name,
+ GROUP_CONCAT(id) AS track_ids,
+ COUNT() AS track_count
+FROM uid_track
+JOIN _slice_track_summary USING (id)
+GROUP BY uid, name;
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 5194215..c1f0d6e 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -201,20 +201,14 @@
// ensure it's only run once.
async function defineMaxLayoutDepthSqlFunction(engine: Engine): Promise<void> {
await engine.query(`
- create or replace perfetto table __max_layout_depth_state as
- select track_id, max(depth) as max_depth
- from slice
- group by track_id
- order by track_id;
-
create perfetto function __max_layout_depth(track_count INT, track_ids STRING)
returns INT AS
select iif(
$track_count = 1,
(
select max_depth
- from __max_layout_depth_state
- where track_id = cast($track_ids AS int)
+ from _slice_track_summary
+ where id = cast($track_ids AS int)
),
(
select max(layout_depth)
@@ -517,6 +511,7 @@
// Make sure the helper views are available before we start adding tracks.
await this.initialiseHelperViews();
+ await this.includeSummaryTables();
await defineMaxLayoutDepthSqlFunction(engine);
@@ -1097,6 +1092,22 @@
}
}
+ async includeSummaryTables() {
+ const engine = assertExists<Engine>(this.engine);
+
+ this.updateStatus('Creating slice summaries');
+ await engine.query(`include perfetto module viz.summary.slices;`);
+
+ this.updateStatus('Creating thread summaries');
+ await engine.query(`include perfetto module viz.summary.threads;`);
+
+ this.updateStatus('Creating processes summaries');
+ await engine.query(`include perfetto module viz.summary.processes;`);
+
+ this.updateStatus('Creating track summaries');
+ await engine.query(`include perfetto module viz.summary.tracks;`);
+ }
+
private updateStatus(msg: string): void {
globals.dispatch(
Actions.updateStatus({
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index d8f42fb..b6dd388 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -167,64 +167,35 @@
async addGlobalAsyncTracks(engine: EngineProxy): Promise<void> {
const rawGlobalAsyncTracks = await engine.query(`
- with tracks_with_slices as materialized (
- select distinct track_id
- from slice
- ),
- global_tracks as (
- select
- track.parent_id as parent_id,
- track.id as track_id,
- track.name as name
- from track
- join tracks_with_slices on tracks_with_slices.track_id = track.id
- where
- track.type = "track"
- or track.type = "gpu_track"
- or track.type = "cpu_track"
- ),
- global_tracks_grouped as (
- select
- parent_id,
- name,
- group_concat(track_id) as trackIds,
- count(track_id) as trackCount
- from global_tracks track
- group by parent_id, name
+ with global_tracks_grouped as (
+ select distinct t.parent_id, t.name
+ from track t
+ join _slice_track_summary using (id)
+ where t.type in ('track', 'gpu_track', 'cpu_track')
)
select
- t.parent_id as parentId,
- p.name as parentName,
t.name as name,
- t.trackIds as trackIds,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
+ t.parent_id as parentId,
+ p.name as parentName
from global_tracks_grouped AS t
left join track p on (t.parent_id = p.id)
- order by p.name, t.name;
+ order by p.name, t.name
`);
const it = rawGlobalAsyncTracks.iter({
name: STR_NULL,
- parentName: STR_NULL,
parentId: NUM_NULL,
- maxDepth: NUM_NULL,
+ parentName: STR_NULL,
});
const parentIdToGroupId = new Map<number, string>();
-
for (; it.valid(); it.next()) {
const kind = ASYNC_SLICE_TRACK_KIND;
const rawName = it.name === null ? undefined : it.name;
const rawParentName = it.parentName === null ? undefined : it.parentName;
const name = getTrackName({name: rawName, kind});
const parentTrackId = it.parentId;
- const maxDepth = it.maxDepth;
let trackGroup = SCROLLING_TRACK_GROUP;
- // If there are no slices in this track, skip it.
- if (maxDepth === null) {
- continue;
- }
-
if (parentTrackId !== null) {
const groupId = parentIdToGroupId.get(parentTrackId);
if (groupId === undefined) {
@@ -261,11 +232,11 @@
// Only add a gpu freq track if we have
// gpu freq data.
const freqExistsResult = await engine.query(`
- select *
- from gpu_counter_track
- where name = 'gpufreq' and gpu_id = ${gpu}
- limit 1;
- `);
+ select *
+ from gpu_counter_track
+ where name = 'gpufreq' and gpu_id = ${gpu}
+ limit 1;
+ `);
if (freqExistsResult.numRows() > 0) {
this.tracksToAdd.push({
uri: `perfetto.Counter#gpu_freq${gpu}`,
@@ -638,14 +609,14 @@
async addThreadStateTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with ts_distinct as materialized (select distinct utid from thread_state)
select
utid,
upid,
tid,
thread.name as threadName
from thread
- where utid != 0 and utid in ts_distinct`);
+ join _sched_summary using (utid)
+ `);
const it = result.iter({
utid: NUM,
@@ -726,16 +697,16 @@
async addThreadCounterTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- select
- thread_counter_track.name as trackName,
- utid,
- upid,
- tid,
- thread.name as threadName,
- thread_counter_track.id as trackId
- from thread_counter_track
- join thread using(utid)
- where thread_counter_track.name != 'thread_time'
+ select
+ thread_counter_track.name as trackName,
+ utid,
+ upid,
+ tid,
+ thread.name as threadName,
+ thread_counter_track.id as trackId
+ from thread_counter_track
+ join thread using(utid)
+ where thread_counter_track.name != 'thread_time'
`);
const it = result.iter({
@@ -776,27 +747,15 @@
async addProcessAsyncSliceTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where
- process_track.name is null or
- process_track.name not like "% Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
+ upid,
+ t.name as trackName,
+ t.track_ids as trackIds,
+ process.name as processName,
+ process.pid as pid
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name is null or t.name not glob "* Timeline"
`);
const it = result.iter({
@@ -805,7 +764,6 @@
trackIds: STR,
processName: STR_NULL,
pid: NUM_NULL,
- maxDepth: NUM_NULL,
});
for (; it.valid(); it.next()) {
const upid = it.upid;
@@ -813,14 +771,8 @@
const rawTrackIds = it.trackIds;
const processName = it.processName;
const pid = it.pid;
- const maxDepth = it.maxDepth;
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
- const uuid = this.getUuid(0, upid);
+ const uuid = this.getUuid(null, upid);
const name = getTrackName({
name: trackName,
upid,
@@ -840,37 +792,18 @@
async addUserAsyncSliceTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with tracks_with_slices as materialized (
- select distinct track_id
- from slice
- ),
- global_tracks as (
- select
- uid_track.name,
- uid_track.uid,
- group_concat(uid_track.id) as trackIds,
- count(uid_track.id) as trackCount
- from uid_track
- join tracks_with_slices
- where tracks_with_slices.track_id == uid_track.id
- group by uid_track.uid
- )
select
t.name as name,
t.uid as uid,
- package_list.package_name as package_name,
- t.trackIds as trackIds,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from global_tracks t
- join package_list
- where t.uid = package_list.uid
- group by t.uid
- `);
+ package_list.package_name as packageName
+ from _uid_track_track_summary_by_uid_and_name t
+ join package_list using (uid)
+ `);
const it = result.iter({
name: STR_NULL,
uid: NUM_NULL,
- package_name: STR_NULL,
+ packageName: STR_NULL,
});
// Map From [name] -> [uuid, key]
@@ -882,8 +815,7 @@
}
const rawName = it.name;
const uid = it.uid === null ? undefined : it.uid;
- const userName =
- it.package_name === null ? `UID: ${uid}` : it.package_name;
+ const userName = it.packageName === null ? `UID: ${uid}` : it.packageName;
const groupUuid = `uid-track-group${rawName}`;
if (groupMap.get(rawName) === undefined) {
@@ -910,48 +842,29 @@
async addActualFramesTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where process_track.name = "Actual Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
+ upid,
+ t.name as trackName,
+ process.name as processName,
+ process.pid as pid
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name = "Actual Timeline"
+ `);
const it = result.iter({
upid: NUM,
trackName: STR_NULL,
processName: STR_NULL,
pid: NUM_NULL,
- maxDepth: NUM_NULL,
});
for (; it.valid(); it.next()) {
const upid = it.upid;
const trackName = it.trackName;
const processName = it.processName;
const pid = it.pid;
- const maxDepth = it.maxDepth;
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
- const uuid = this.getUuid(0, upid);
-
+ const uuid = this.getUuid(null, upid);
const kind = ACTUAL_FRAMES_SLICE_TRACK_KIND;
const name = getTrackName({
name: trackName,
@@ -972,33 +885,21 @@
async addExpectedFramesTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where process_track.name = "Expected Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
+ upid,
+ t.name as trackName,
+ process.name as processName,
+ process.pid as pid
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name = "Expected Timeline"
+ `);
const it = result.iter({
upid: NUM,
trackName: STR_NULL,
processName: STR_NULL,
pid: NUM_NULL,
- maxDepth: NUM_NULL,
});
for (; it.valid(); it.next()) {
@@ -1006,15 +907,8 @@
const trackName = it.trackName;
const processName = it.processName;
const pid = it.pid;
- const maxDepth = it.maxDepth;
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
- const uuid = this.getUuid(0, upid);
-
+ const uuid = this.getUuid(null, upid);
const kind = EXPECTED_FRAMES_SLICE_TRACK_KIND;
const name = getTrackName({
name: trackName,
@@ -1035,7 +929,6 @@
async addThreadSliceTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- with slice_track as materialized (select distinct track_id from slice)
select
thread_track.utid as utid,
thread_track.id as trackId,
@@ -1046,8 +939,8 @@
thread.name as threadName,
thread.upid as upid
from thread_track
+ join _slice_track_summary using (id)
join thread using(utid)
- join slice_track on thread_track.id = slice_track.track_id
`);
const it = result.iter({
@@ -1091,14 +984,14 @@
async addProcessCounterTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- select
- process_counter_track.id as trackId,
- process_counter_track.name as trackName,
- upid,
- process.pid,
- process.name as processName
- from process_counter_track
- join process using(upid);
+ select
+ process_counter_track.id as trackId,
+ process_counter_track.name as trackName,
+ upid,
+ process.pid,
+ process.name as processName
+ from process_counter_track
+ join process using(upid);
`);
const it = result.iter({
trackId: NUM,
@@ -1113,7 +1006,7 @@
const trackId = it.trackId;
const trackName = it.trackName;
const processName = it.processName;
- const uuid = this.getUuid(0, upid);
+ const uuid = this.getUuid(null, upid);
const name = getTrackName({
name: trackName,
upid,
@@ -1135,13 +1028,13 @@
async addProcessHeapProfileTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- select distinct(upid) from heap_profile_allocation
- union
- select distinct(upid) from heap_graph_object
+ select upid
+ from _process_available_info_summary
+ where allocation_count > 0 or graph_object_count > 0
`);
for (const it = result.iter({upid: NUM}); it.valid(); it.next()) {
const upid = it.upid;
- const uuid = this.getUuid(0, upid);
+ const uuid = this.getUuid(null, upid);
this.tracksToAdd.push({
uri: `perfetto.HeapProfile#${upid}`,
trackSortKey: PrimaryTrackSortKey.HEAP_PROFILE_TRACK,
@@ -1153,14 +1046,15 @@
async addProcessPerfSamplesTracks(engine: EngineProxy): Promise<void> {
const result = await engine.query(`
- select distinct upid, pid
- from perf_sample join thread using (utid) join process using (upid)
- where callsite_id is not null
+ select upid, pid
+ from _process_available_info_summary
+ join process using (upid)
+ where perf_sample_count > 0
`);
for (const it = result.iter({upid: NUM, pid: NUM}); it.valid(); it.next()) {
const upid = it.upid;
const pid = it.pid;
- const uuid = this.getUuid(0, upid);
+ const uuid = this.getUuid(null, upid);
this.tracksToAdd.push({
uri: `perfetto.PerfSamplesProfile#${upid}`,
trackSortKey: PrimaryTrackSortKey.PERF_SAMPLES_PROFILE_TRACK,
@@ -1170,22 +1064,22 @@
}
}
- getUuidUnchecked(utid: number, upid: number | null) {
+ getUuidUnchecked(utid: number | null, upid: number | null) {
return upid === null
- ? this.utidToUuid.get(utid)
+ ? this.utidToUuid.get(utid!)
: this.upidToUuid.get(upid);
}
- getUuid(utid: number, upid: number | null) {
+ getUuid(utid: number | null, upid: number | null) {
return assertExists(this.getUuidUnchecked(utid, upid));
}
- getOrCreateUuid(utid: number, upid: number | null) {
+ getOrCreateUuid(utid: number | null, upid: number | null) {
let uuid = this.getUuidUnchecked(utid, upid);
if (uuid === undefined) {
uuid = uuidv4();
if (upid === null) {
- this.utidToUuid.set(utid, uuid);
+ this.utidToUuid.set(utid!, uuid);
} else {
this.upidToUuid.set(upid, uuid);
}
@@ -1274,181 +1168,155 @@
// thread name
// utid
const result = await engine.query(`
- with candidateThreadsAndProcesses as materialized (
- select upid, 0 as utid from process_track
- union
- select upid, 0 as utid from process_counter_track
- union
- select upid, utid from thread_counter_track join thread using(utid)
- union
- select upid, utid from thread_track join thread using(utid)
- union
- select upid, utid from (
- select distinct utid from sched
- ) join thread using(utid) group by utid
- union
- select upid, 0 as utid from (
- select distinct utid from perf_sample where callsite_id is not null
- ) join thread using (utid)
- union
- select upid, utid from (
- select distinct utid from cpu_profile_stack_sample
- ) join thread using(utid)
- union
- select upid as upid, 0 as utid from heap_profile_allocation
- union
- select upid as upid, 0 as utid from heap_graph_object
- ),
- schedSum as materialized (
- select upid, sum(thread_total_dur) as total_dur
- from (
- select utid, sum(dur) as thread_total_dur
- from sched where dur != -1 and utid != 0
- group by utid
+ with processGroups as (
+ select
+ upid,
+ process.pid as pid,
+ process.name as processName,
+ sum_running_dur as sumRunningDur,
+ thread_slice_count + process_slice_count as sliceCount,
+ perf_sample_count as perfSampleCount,
+ allocation_count as heapProfileAllocationCount,
+ graph_object_count as heapGraphObjectCount,
+ (
+ select group_concat(string_value)
+ from args
+ where
+ process.arg_set_id is not null and
+ arg_set_id = process.arg_set_id and
+ flat_key = 'chrome.process_label'
+ ) chromeProcessLabels,
+ case process.name
+ when 'Browser' then 3
+ when 'Gpu' then 2
+ when 'Renderer' then 1
+ else 0
+ end as chromeProcessRank
+ from _process_available_info_summary
+ join process using(upid)
+ ),
+ threadGroups as (
+ select
+ utid,
+ tid,
+ thread.name as threadName,
+ sum_running_dur as sumRunningDur,
+ slice_count as sliceCount,
+ perf_sample_count as perfSampleCount
+ from _thread_available_info_summary
+ join thread using (utid)
+ where upid is null
)
- join thread using (utid)
- group by upid
- ),
- sliceSum as materialized (
- select
- process.upid as upid,
- sum(cnt) as sliceCount
- from (select track_id, count(*) as cnt from slice group by track_id)
- left join thread_track on track_id = thread_track.id
- left join thread on thread_track.utid = thread.utid
- left join process_track on track_id = process_track.id
- join process on process.upid = thread.upid
- or process_track.upid = process.upid
- where process.upid is not null
- group by process.upid
- )
- select
- the_tracks.upid,
- the_tracks.utid,
- total_dur as hasSched,
- hasHeapProfiles,
- process.pid as pid,
- thread.tid as tid,
- process.name as processName,
- thread.name as threadName,
- package_list.debuggable as isDebuggable,
- ifnull((
- select group_concat(string_value)
- from args
- where
- process.arg_set_id is not null and
- arg_set_id = process.arg_set_id and
- flat_key = 'chrome.process_label'
- ), '') AS chromeProcessLabels,
- (case process.name
- when 'Browser' then 3
- when 'Gpu' then 2
- when 'Renderer' then 1
- else 0
- end) as chromeProcessRank
- from candidateThreadsAndProcesses the_tracks
- left join schedSum using(upid)
- left join (
- select
- distinct(upid) as upid,
- true as hasHeapProfiles
- from heap_profile_allocation
- union
- select
- distinct(upid) as upid,
- true as hasHeapProfiles
- from heap_graph_object
- ) using (upid)
- left join (
- select
- thread.upid as upid,
- sum(cnt) as perfSampleCount
+ select *
from (
- select utid, count(*) as cnt
- from perf_sample where callsite_id is not null
- group by utid
- ) join thread using (utid)
- group by thread.upid
- ) using (upid)
- left join sliceSum using (upid)
- left join thread using(utid)
- left join process using(upid)
- left join package_list using(uid)
- order by
- chromeProcessRank desc,
- hasHeapProfiles desc,
- perfSampleCount desc,
- total_dur desc,
- sliceCount desc,
- processName asc nulls last,
- the_tracks.upid asc nulls last,
- threadName asc nulls last,
- the_tracks.utid asc nulls last;
+ select
+ upid,
+ null as utid,
+ pid,
+ null as tid,
+ processName,
+ null as threadName,
+ sumRunningDur > 0 as hasSched,
+ heapProfileAllocationCount > 0
+ or heapGraphObjectCount > 0 as hasHeapInfo,
+ ifnull(chromeProcessLabels, '') as chromeProcessLabels
+ from processGroups
+ order by
+ chromeProcessRank desc,
+ heapProfileAllocationCount desc,
+ heapGraphObjectCount desc,
+ perfSampleCount desc,
+ sumRunningDur desc,
+ sliceCount desc,
+ processName asc,
+ upid asc
+ )
+ union all
+ select *
+ from (
+ select
+ null,
+ utid,
+ null as pid,
+ tid,
+ null as processName,
+ threadName,
+ sumRunningDur > 0 as hasSched,
+ 0 as hasHeapInfo,
+ '' as chromeProcessLabels
+ from threadGroups
+ order by
+ perfSampleCount desc,
+ sumRunningDur desc,
+ sliceCount desc,
+ threadName asc,
+ utid asc
+ )
`);
const it = result.iter({
- utid: NUM,
upid: NUM_NULL,
- tid: NUM_NULL,
+ utid: NUM_NULL,
pid: NUM_NULL,
- threadName: STR_NULL,
+ tid: NUM_NULL,
processName: STR_NULL,
+ threadName: STR_NULL,
hasSched: NUM_NULL,
- hasHeapProfiles: NUM_NULL,
+ hasHeapInfo: NUM_NULL,
chromeProcessLabels: STR,
});
for (; it.valid(); it.next()) {
const utid = it.utid;
- const tid = it.tid;
const upid = it.upid;
const pid = it.pid;
+ const tid = it.tid;
const threadName = it.threadName;
const processName = it.processName;
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const hasSched = !!it.hasSched;
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
- const hasHeapProfiles = !!it.hasHeapProfiles;
+ const hasHeapInfo = !!it.hasHeapInfo;
- // Group by upid if present else by utid.
- let pUuid =
- upid === null ? this.utidToUuid.get(utid) : this.upidToUuid.get(upid);
- // These should only happen once for each track group.
- if (pUuid === undefined) {
- pUuid = this.getOrCreateUuid(utid, upid);
- const summaryTrackKey = uuidv4();
- const type = hasSched ? 'schedule' : 'summary';
- const uri = `perfetto.ProcessScheduling#${upid}.${utid}.${type}`;
+ const summaryTrackKey = uuidv4();
+ const type = hasSched ? 'schedule' : 'summary';
+ const uri = `perfetto.ProcessScheduling#${upid}.${utid}.${type}`;
- this.tracksToAdd.push({
- uri,
- key: summaryTrackKey,
- trackSortKey: hasSched
- ? PrimaryTrackSortKey.PROCESS_SCHEDULING_TRACK
- : PrimaryTrackSortKey.PROCESS_SUMMARY_TRACK,
- name: `${upid === null ? tid : pid} summary`,
- labels: it.chromeProcessLabels.split(','),
- });
-
- const name = getTrackName({
- utid,
- processName,
- pid,
- threadName,
- tid,
- upid,
- });
- const addTrackGroup = Actions.addTrackGroup({
- summaryTrackKey,
- name,
- id: pUuid,
- // Perf profiling tracks remain collapsed, otherwise we would have too
- // many expanded process tracks for some perf traces, leading to
- // jankyness.
- collapsed: !hasHeapProfiles,
- });
-
- this.addTrackGroupActions.push(addTrackGroup);
+ // If previous groupings (e.g. kernel threads) picked up there tracks,
+ // don't try to regroup them.
+ const pUuid =
+ upid === null ? this.utidToUuid.get(utid!) : this.upidToUuid.get(upid);
+ if (pUuid !== undefined) {
+ continue;
}
+
+ this.tracksToAdd.push({
+ uri,
+ key: summaryTrackKey,
+ trackSortKey: hasSched
+ ? PrimaryTrackSortKey.PROCESS_SCHEDULING_TRACK
+ : PrimaryTrackSortKey.PROCESS_SUMMARY_TRACK,
+ name: `${upid === null ? tid : pid} summary`,
+ labels: it.chromeProcessLabels.split(','),
+ });
+
+ const name = getTrackName({
+ utid,
+ processName,
+ pid,
+ threadName,
+ tid,
+ upid,
+ });
+ const addTrackGroup = Actions.addTrackGroup({
+ summaryTrackKey,
+ name,
+ id: this.getOrCreateUuid(utid, upid),
+ // Perf profiling tracks remain collapsed, otherwise we would have too
+ // many expanded process tracks for some perf traces, leading to
+ // jankyness.
+ collapsed: !hasHeapInfo,
+ });
+ this.addTrackGroupActions.push(addTrackGroup);
}
}
diff --git a/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts b/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
index d7a37d8..b9127f0 100644
--- a/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
+++ b/ui/src/plugins/org.kernel.LinuxKernelDevices/index.ts
@@ -27,23 +27,11 @@
class LinuxKernelDevices implements Plugin {
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
- with
- slices_tracks as materialized (
- select distinct track_id
- from slice
- ),
- tracks as (
- select
- linux_device_track.id as track_id,
- linux_device_track.name
- from linux_device_track
- join slices_tracks on
- slices_tracks.track_id = linux_device_track.id
- )
select
- t.name,
- t.track_id as trackId
- from tracks as t
+ t.id as trackId,
+ t.name
+ from linux_device_track t
+ join _slice_track_summary using (id)
order by t.name;
`);
diff --git a/ui/src/public/utils.ts b/ui/src/public/utils.ts
index 60c4487..f5d3d7a 100644
--- a/ui/src/public/utils.ts
+++ b/ui/src/public/utils.ts
@@ -22,7 +22,7 @@
export function getTrackName(
args: Partial<{
name: string | null;
- utid: number;
+ utid: number | null;
processName: string | null;
pid: number | null;
threadName: string | null;
diff --git a/ui/src/tracks/async_slices/index.ts b/ui/src/tracks/async_slices/index.ts
index 2e8b3d5..18883d9 100644
--- a/ui/src/tracks/async_slices/index.ts
+++ b/ui/src/tracks/async_slices/index.ts
@@ -30,77 +30,41 @@
async addGlobalAsyncTracks(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const rawGlobalAsyncTracks = await engine.query(`
- with tracks_with_slices as materialized (
- select distinct track_id
- from slice
- ),
- global_tracks as (
- select
- track.parent_id as parent_id,
- track.id as track_id,
- track.name as name
- from track
- join tracks_with_slices on tracks_with_slices.track_id = track.id
- where
- track.type = "track"
- or track.type = "gpu_track"
- or track.type = "cpu_track"
- ),
- global_tracks_grouped as (
+ with global_tracks_grouped as (
select
parent_id,
name,
- group_concat(track_id) as trackIds,
- count(track_id) as trackCount
- from global_tracks track
+ group_concat(id) as trackIds,
+ count() as trackCount
+ from track t
+ join _slice_track_summary using (id)
+ where t.type in ('track', 'gpu_track', 'cpu_track')
group by parent_id, name
)
select
- t.parent_id as parentId,
- p.name as parentName,
t.name as name,
+ t.parent_id as parentId,
t.trackIds as trackIds,
__max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from global_tracks_grouped AS t
- left join track p on (t.parent_id = p.id)
- order by p.name, t.name;
+ from global_tracks_grouped t
`);
const it = rawGlobalAsyncTracks.iter({
name: STR_NULL,
- parentName: STR_NULL,
parentId: NUM_NULL,
trackIds: STR,
- maxDepth: NUM_NULL,
+ maxDepth: NUM,
});
- // let scrollJankRendered = false;
-
for (; it.valid(); it.next()) {
const rawName = it.name === null ? undefined : it.name;
- // const rawParentName = it.parentName === null ? undefined :
- // it.parentName;
const displayName = getTrackName({
name: rawName,
kind: ASYNC_SLICE_TRACK_KIND,
});
const rawTrackIds = it.trackIds;
const trackIds = rawTrackIds.split(',').map((v) => Number(v));
- // const parentTrackId = it.parentId;
const maxDepth = it.maxDepth;
- // If there are no slices in this track, skip it.
- if (maxDepth === null) {
- continue;
- }
-
- // if (ENABLE_SCROLL_JANK_PLUGIN_V2.get() && !scrollJankRendered &&
- // name.includes(INPUT_LATENCY_TRACK)) {
- // // This ensures that the scroll jank tracks render above the tracks
- // // for GestureScrollUpdate.
- // await this.addScrollJankTracks(this.engine);
- // scrollJankRendered = true;
- // }
-
ctx.registerTrack({
uri: `perfetto.AsyncSlices#${rawName}.${it.parentId}`,
displayName,
@@ -115,27 +79,16 @@
async addProcessAsyncSliceTracks(ctx: PluginContextTrace): Promise<void> {
const result = await ctx.engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where
- process_track.name is null or
- process_track.name not like "% Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
+ upid,
+ t.name as trackName,
+ t.track_ids as trackIds,
+ process.name as processName,
+ process.pid as pid,
+ __max_layout_depth(t.track_count, t.track_ids) as maxDepth
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name is null or t.name not glob "* Timeline"
`);
const it = result.iter({
@@ -144,7 +97,7 @@
trackIds: STR,
processName: STR_NULL,
pid: NUM_NULL,
- maxDepth: NUM_NULL,
+ maxDepth: NUM,
});
for (; it.valid(); it.next()) {
const upid = it.upid;
@@ -155,11 +108,6 @@
const pid = it.pid;
const maxDepth = it.maxDepth;
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
const kind = ASYNC_SLICE_TRACK_KIND;
const displayName = getTrackName({
name: trackName,
@@ -188,37 +136,20 @@
async addUserAsyncSliceTracks(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
- with tracks_with_slices as materialized (
- select distinct track_id
- from slice
- ),
- global_tracks as (
- select
- uid_track.name,
- uid_track.uid,
- group_concat(uid_track.id) as trackIds,
- count(uid_track.id) as trackCount
- from uid_track
- join tracks_with_slices
- where tracks_with_slices.track_id == uid_track.id
- group by uid_track.uid
- )
select
t.name as name,
t.uid as uid,
- package_list.package_name as package_name,
- t.trackIds as trackIds,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from global_tracks t
- join package_list
- where t.uid = package_list.uid
- group by t.uid
- `);
+ package_list.package_name as packageName,
+ t.track_ids as trackIds,
+ __max_layout_depth(t.track_count, t.track_ids) as maxDepth
+ from _uid_track_track_summary_by_uid_and_name t
+ join package_list using (uid)
+ `);
const it = result.iter({
name: STR_NULL,
uid: NUM_NULL,
- package_name: STR_NULL,
+ packageName: STR_NULL,
trackIds: STR,
maxDepth: NUM_NULL,
});
@@ -226,7 +157,7 @@
for (; it.valid(); it.next()) {
const kind = ASYNC_SLICE_TRACK_KIND;
const rawName = it.name === null ? undefined : it.name;
- const userName = it.package_name === null ? undefined : it.package_name;
+ const userName = it.packageName === null ? undefined : it.packageName;
const uid = it.uid === null ? undefined : it.uid;
const rawTrackIds = it.trackIds;
const trackIds = rawTrackIds.split(',').map((v) => Number(v));
diff --git a/ui/src/tracks/frames/index.ts b/ui/src/tracks/frames/index.ts
index 47e88ff..2cc877f 100644
--- a/ui/src/tracks/frames/index.ts
+++ b/ui/src/tracks/frames/index.ts
@@ -31,26 +31,17 @@
async addExpectedFrames(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where process_track.name = "Expected Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
+ upid,
+ t.name as trackName,
+ t.track_ids as trackIds,
+ process.name as processName,
+ process.pid as pid,
+ __max_layout_depth(t.track_count, t.track_ids) as maxDepth
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name = "Expected Timeline"
+ `);
const it = result.iter({
upid: NUM,
@@ -58,7 +49,7 @@
trackIds: STR,
processName: STR_NULL,
pid: NUM_NULL,
- maxDepth: NUM_NULL,
+ maxDepth: NUM,
});
for (; it.valid(); it.next()) {
@@ -70,11 +61,6 @@
const pid = it.pid;
const maxDepth = it.maxDepth;
- if (maxDepth === null) {
- // If there are no slices in this track, skip it.
- continue;
- }
-
const displayName = getTrackName({
name: trackName,
upid,
@@ -103,26 +89,17 @@
async addActualFrames(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
- with process_async_tracks as materialized (
- select
- process_track.upid as upid,
- process_track.name as trackName,
- process.name as processName,
- process.pid as pid,
- group_concat(process_track.id) as trackIds,
- count(1) as trackCount
- from process_track
- join process using(upid)
- where process_track.name = "Actual Timeline"
- group by
- process_track.upid,
- process_track.name
- )
select
- t.*,
- __max_layout_depth(t.trackCount, t.trackIds) as maxDepth
- from process_async_tracks t;
- `);
+ upid,
+ t.name as trackName,
+ t.track_ids as trackIds,
+ process.name as processName,
+ process.pid as pid,
+ __max_layout_depth(t.track_count, t.track_ids) as maxDepth
+ from _process_track_summary_by_upid_and_name t
+ join process using(upid)
+ where t.name = "Actual Timeline"
+ `);
const it = result.iter({
upid: NUM,
diff --git a/ui/src/tracks/process_summary/index.ts b/ui/src/tracks/process_summary/index.ts
index 47a93b0..3f53335 100644
--- a/ui/src/tracks/process_summary/index.ts
+++ b/ui/src/tracks/process_summary/index.ts
@@ -12,14 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {v4 as uuidv4} from 'uuid';
-
import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {
LONG_NULL,
NUM,
NUM_NULL,
- STR,
STR_NULL,
} from '../../trace_processor/query_result';
import {assertExists} from '../../base/logging';
@@ -37,166 +34,61 @@
// This plugin now manages both process "scheduling" and "summary" tracks.
class ProcessSummaryPlugin implements Plugin {
- private upidToUuid = new Map<number, string>();
- private utidToUuid = new Map<number, string>();
-
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
await this.addProcessTrackGroups(ctx);
await this.addKernelThreadSummary(ctx);
}
private async addProcessTrackGroups(ctx: PluginContextTrace): Promise<void> {
- this.upidToUuid.clear();
- this.utidToUuid.clear();
-
- // We want to create groups of tracks in a specific order.
- // The tracks should be grouped:
- // by upid
- // or (if upid is null) by utid
- // the groups should be sorted by:
- // Chrome-based process rank based on process names (e.g. Browser)
- // has a heap profile or not
- // total cpu time *for the whole parent process*
- // process name
- // upid
- // thread name
- // utid
const result = await ctx.engine.query(`
- with candidateThreadsAndProcesses as materialized (
- select upid, 0 as utid from process_track
- union
- select upid, 0 as utid from process_counter_track
- union
- select upid, utid from thread_counter_track join thread using(utid)
- union
- select upid, utid from thread_track join thread using(utid)
- union
- select upid, utid from (
- select distinct utid from sched
- ) join thread using(utid) group by utid
- union
- select upid, 0 as utid from (
- select distinct utid from perf_sample where callsite_id is not null
- ) join thread using (utid)
- union
- select upid, utid from (
- select distinct utid from cpu_profile_stack_sample
- ) join thread using(utid)
- union
- select upid as upid, 0 as utid from heap_profile_allocation
- union
- select upid as upid, 0 as utid from heap_graph_object
- ),
- schedSummary as materialized (
- select
- upid,
- sum(thread_total_dur) as total_dur,
- max(thread_max_dur) as total_max_dur,
- sum(thread_event_count) as total_event_count
+ select *
from (
select
- utid,
- sum(dur) as thread_total_dur,
- max(dur) as thread_max_dur,
- count() as thread_event_count
- from sched where dur != -1 and utid != 0
- group by utid
+ _process_available_info_summary.upid,
+ null as utid,
+ pid,
+ null as tid,
+ process.name as processName,
+ null as threadName,
+ sum_running_dur > 0 as hasSched,
+ max_running_dur as maxRunningDur,
+ running_count as runningCount,
+ android_process_metadata.debuggable as isDebuggable
+ from _process_available_info_summary
+ join process using(upid)
+ left join android_process_metadata using(upid)
)
- join thread using (utid)
- group by upid
- ),
- sliceSum as materialized (
- select
- process.upid as upid,
- sum(cnt) as sliceCount
- from (select track_id, count(*) as cnt from slice group by track_id)
- left join thread_track on track_id = thread_track.id
- left join thread on thread_track.utid = thread.utid
- left join process_track on track_id = process_track.id
- join process on process.upid = thread.upid
- or process_track.upid = process.upid
- where process.upid is not null
- group by process.upid
- )
- select
- the_tracks.upid,
- the_tracks.utid,
- total_dur as hasSched,
- total_max_dur as schedMaxDur,
- total_event_count as schedEventCount,
- hasHeapProfiles,
- process.pid as pid,
- thread.tid as tid,
- process.name as processName,
- thread.name as threadName,
- package_list.debuggable as isDebuggable,
- ifnull((
- select group_concat(string_value)
- from args
- where
- process.arg_set_id is not null and
- arg_set_id = process.arg_set_id and
- flat_key = 'chrome.process_label'
- ), '') AS chromeProcessLabels,
- (case process.name
- when 'Browser' then 3
- when 'Gpu' then 2
- when 'Renderer' then 1
- else 0
- end) as chromeProcessRank
- from candidateThreadsAndProcesses the_tracks
- left join schedSummary using(upid)
- left join (
- select
- distinct(upid) as upid,
- true as hasHeapProfiles
- from heap_profile_allocation
- union
- select
- distinct(upid) as upid,
- true as hasHeapProfiles
- from heap_graph_object
- ) using (upid)
- left join (
- select
- thread.upid as upid,
- sum(cnt) as perfSampleCount
+ union all
+ select *
from (
- select utid, count(*) as cnt
- from perf_sample where callsite_id is not null
- group by utid
- ) join thread using (utid)
- group by thread.upid
- ) using (upid)
- left join sliceSum using (upid)
- left join thread using(utid)
- left join process using(upid)
- left join package_list using(uid)
- order by
- chromeProcessRank desc,
- hasHeapProfiles desc,
- perfSampleCount desc,
- total_dur desc,
- sliceCount desc,
- processName asc nulls last,
- the_tracks.upid asc nulls last,
- threadName asc nulls last,
- the_tracks.utid asc nulls last;
+ select
+ null,
+ utid,
+ null as pid,
+ tid,
+ null as processName,
+ thread.name threadName,
+ sum_running_dur > 0 as hasSched,
+ max_running_dur as maxRunningDur,
+ running_count as runningCount,
+ 0 as isDebuggable
+ from _thread_available_info_summary
+ join thread using (utid)
+ where upid is null
+ )
`);
const it = result.iter({
- utid: NUM,
upid: NUM_NULL,
- tid: NUM_NULL,
+ utid: NUM_NULL,
pid: NUM_NULL,
- threadName: STR_NULL,
+ tid: NUM_NULL,
processName: STR_NULL,
+ threadName: STR_NULL,
hasSched: NUM_NULL,
- schedMaxDur: LONG_NULL,
- schedEventCount: NUM_NULL,
- hasHeapProfiles: NUM_NULL,
+ maxRunningDur: LONG_NULL,
+ runningCount: NUM_NULL,
isDebuggable: NUM_NULL,
- chromeProcessLabels: STR,
});
for (; it.valid(); it.next()) {
const utid = it.utid;
@@ -204,59 +96,52 @@
const upid = it.upid;
const pid = it.pid;
const hasSched = Boolean(it.hasSched);
- const schedMaxDur = it.schedMaxDur;
- const schedEventCount = it.schedEventCount;
+ const maxRunningDur = it.maxRunningDur;
+ const runningCount = it.runningCount;
const isDebuggable = Boolean(it.isDebuggable);
- // Group by upid if present else by utid.
- let pUuid =
- upid === null ? this.utidToUuid.get(utid) : this.upidToUuid.get(upid);
- // These should only happen once for each track group.
- if (pUuid === undefined) {
- pUuid = this.getOrCreateUuid(utid, upid);
- const pidForColor = pid ?? tid ?? upid ?? utid ?? 0;
- const type = hasSched ? 'schedule' : 'summary';
- const uri = `perfetto.ProcessScheduling#${upid}.${utid}.${type}`;
+ const pidForColor = pid ?? tid ?? upid ?? utid ?? 0;
+ const type = hasSched ? 'schedule' : 'summary';
+ const uri = `perfetto.ProcessScheduling#${upid}.${utid}.${type}`;
- if (hasSched) {
- const config: ProcessSchedulingTrackConfig = {
- pidForColor,
- upid,
- utid,
- };
+ if (hasSched) {
+ const config: ProcessSchedulingTrackConfig = {
+ pidForColor,
+ upid,
+ utid,
+ };
- ctx.registerTrack({
- uri,
- displayName: `${upid === null ? tid : pid} schedule`,
- kind: PROCESS_SCHEDULING_TRACK_KIND,
- tags: {
- isDebuggable,
- },
- trackFactory: () =>
- new ProcessSchedulingTrack(
- ctx.engine,
- config,
- assertExists(schedMaxDur),
- assertExists(schedEventCount),
- ),
- });
- } else {
- const config: ProcessSummaryTrackConfig = {
- pidForColor,
- upid,
- utid,
- };
+ ctx.registerTrack({
+ uri,
+ displayName: `${upid === null ? tid : pid} schedule`,
+ kind: PROCESS_SCHEDULING_TRACK_KIND,
+ tags: {
+ isDebuggable,
+ },
+ trackFactory: () =>
+ new ProcessSchedulingTrack(
+ ctx.engine,
+ config,
+ assertExists(maxRunningDur),
+ assertExists(runningCount),
+ ),
+ });
+ } else {
+ const config: ProcessSummaryTrackConfig = {
+ pidForColor,
+ upid,
+ utid,
+ };
- ctx.registerTrack({
- uri,
- displayName: `${upid === null ? tid : pid} summary`,
- kind: PROCESS_SUMMARY_TRACK,
- tags: {
- isDebuggable,
- },
- trackFactory: () => new ProcessSummaryTrack(ctx.engine, config),
- });
- }
+ ctx.registerTrack({
+ uri,
+ displayName: `${upid === null ? tid : pid} summary`,
+ kind: PROCESS_SUMMARY_TRACK,
+ tags: {
+ isDebuggable,
+ },
+ trackFactory: () => new ProcessSummaryTrack(ctx.engine, config),
+ });
}
}
}
@@ -313,25 +198,6 @@
trackFactory: () => new ProcessSummaryTrack(ctx.engine, config),
});
}
-
- private getOrCreateUuid(utid: number, upid: number | null) {
- let uuid = this.getUuidUnchecked(utid, upid);
- if (uuid === undefined) {
- uuid = uuidv4();
- if (upid === null) {
- this.utidToUuid.set(utid, uuid);
- } else {
- this.upidToUuid.set(upid, uuid);
- }
- }
- return uuid;
- }
-
- getUuidUnchecked(utid: number, upid: number | null) {
- return upid === null
- ? this.utidToUuid.get(utid)
- : this.upidToUuid.get(upid);
- }
}
export const plugin: PluginDescriptor = {
diff --git a/ui/src/tracks/process_summary/process_scheduling_track.ts b/ui/src/tracks/process_summary/process_scheduling_track.ts
index 07400ca..64fe72c 100644
--- a/ui/src/tracks/process_summary/process_scheduling_track.ts
+++ b/ui/src/tracks/process_summary/process_scheduling_track.ts
@@ -50,8 +50,8 @@
export interface Config {
pidForColor: number;
- upid: null | number;
- utid: number;
+ upid: number | null;
+ utid: number | null;
}
export class ProcessSchedulingTrack implements Track {
diff --git a/ui/src/tracks/process_summary/process_summary_track.ts b/ui/src/tracks/process_summary/process_summary_track.ts
index 6a8e687..f556728 100644
--- a/ui/src/tracks/process_summary/process_summary_track.ts
+++ b/ui/src/tracks/process_summary/process_summary_track.ts
@@ -37,7 +37,7 @@
export interface Config {
pidForColor: number;
upid: number | null;
- utid: number;
+ utid: number | null;
}
const MARGIN_TOP = 5;
diff --git a/ui/src/tracks/thread_state/index.ts b/ui/src/tracks/thread_state/index.ts
index b38eb1d..73e2faf 100644
--- a/ui/src/tracks/thread_state/index.ts
+++ b/ui/src/tracks/thread_state/index.ts
@@ -32,14 +32,14 @@
async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
const {engine} = ctx;
const result = await engine.query(`
- with ts_distinct as materialized (select distinct utid from thread_state)
select
utid,
upid,
tid,
thread.name as threadName
from thread
- where utid != 0 and utid in ts_distinct`);
+ join _sched_summary using (utid)
+ `);
const it = result.iter({
utid: NUM,