From d5ba33fa7571dbbb54764cf57caa1063402212e6 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Tue, 15 Oct 2024 16:48:12 +0000 Subject: [PATCH] Add a plugin for Desktop Windowing statsd atoms. Parse desktop window events into a stdlib table, and create a plugin that registers a command that will create a timeline track and pin it. Bug: 370730027 Test: tools/diff_test_trace_processor.py out/linux/trace_processor_shell --name-filter '.*desktop_mode.*' Change-Id: Ic8e20529b802c3a25fb0c6858800048f75beb2fc --- Android.bp | 1 + BUILD | 1 + .../perfetto_sql/stdlib/android/BUILD.gn | 1 + .../stdlib/android/desktop_mode.sql | 72 ++++++++++++++ .../multiple_window_only_update.pb.sha256 | 1 + ...ltiple_windows_add_update_remove.pb.sha256 | 1 + ...ngle_window_add_update_no_remove.pb.sha256 | 1 + .../single_window_add_update_remove.pb.sha256 | 1 + ...ngle_window_no_add_update_remove.pb.sha256 | 1 + .../single_window_only_update.pb.sha256 | 1 + .../diff_tests/include_index.py | 2 + .../stdlib/android/desktop_mode_tests.py | 96 +++++++++++++++++++ .../dev.perfetto.AndroidDesktopMode/OWNERS | 2 + .../dev.perfetto.AndroidDesktopMode/index.ts | 81 ++++++++++++++++ 14 files changed, 262 insertions(+) create mode 100644 src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql create mode 100644 test/data/android_desktop_mode/multiple_window_only_update.pb.sha256 create mode 100644 test/data/android_desktop_mode/multiple_windows_add_update_remove.pb.sha256 create mode 100644 test/data/android_desktop_mode/single_window_add_update_no_remove.pb.sha256 create mode 100644 test/data/android_desktop_mode/single_window_add_update_remove.pb.sha256 create mode 100644 test/data/android_desktop_mode/single_window_no_add_update_remove.pb.sha256 create mode 100644 test/data/android_desktop_mode/single_window_only_update.pb.sha256 create mode 100644 test/trace_processor/diff_tests/stdlib/android/desktop_mode_tests.py create mode 100644 ui/src/plugins/dev.perfetto.AndroidDesktopMode/OWNERS create mode 100644 ui/src/plugins/dev.perfetto.AndroidDesktopMode/index.ts diff --git a/Android.bp b/Android.bp index f724ada739..861d8efbe0 100644 --- a/Android.bp +++ b/Android.bp @@ -13532,6 +13532,7 @@ genrule { "src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql", "src/trace_processor/perfetto_sql/stdlib/android/cpu/cluster_type.sql", "src/trace_processor/perfetto_sql/stdlib/android/critical_blocking_calls.sql", + "src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql", "src/trace_processor/perfetto_sql/stdlib/android/device.sql", "src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql", "src/trace_processor/perfetto_sql/stdlib/android/frames/jank_type.sql", diff --git a/BUILD b/BUILD index efe83c86a5..19d13b1c43 100644 --- a/BUILD +++ b/BUILD @@ -2814,6 +2814,7 @@ perfetto_filegroup( "src/trace_processor/perfetto_sql/stdlib/android/binder_breakdown.sql", "src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql", "src/trace_processor/perfetto_sql/stdlib/android/critical_blocking_calls.sql", + "src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql", "src/trace_processor/perfetto_sql/stdlib/android/device.sql", "src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql", "src/trace_processor/perfetto_sql/stdlib/android/freezer.sql", diff --git a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn index 40320fa2b8..14a1560162 100644 --- a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn +++ b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn @@ -33,6 +33,7 @@ perfetto_sql_source_set("android") { "binder_breakdown.sql", "broadcasts.sql", "critical_blocking_calls.sql", + "desktop_mode.sql", "device.sql", "dvfs.sql", "freezer.sql", diff --git a/src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql b/src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql new file mode 100644 index 0000000000..de4729b612 --- /dev/null +++ b/src/trace_processor/perfetto_sql/stdlib/android/desktop_mode.sql @@ -0,0 +1,72 @@ +-- +-- 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 android.statsd; + +-- Desktop Windows with durations they were open. +CREATE PERFETTO TABLE android_desktop_mode_windows ( +-- Window add timestamp; NULL if no add event in the trace. +raw_add_ts INT, +-- Window remove timestamp; NULL if no remove event in the trace. +raw_remove_ts INT, +-- timestamp that the window was added; or trace_start() if no add event in the trace. +ts INT, +-- duration the window was open; or until trace_end() if no remove event in the trace. +dur INT, +-- Desktop Window instance ID - unique per window. +instance_id INT, +-- UID of the app running in the window. +uid INT +) AS +WITH + atoms AS ( + SELECT + ts, + extract_arg(arg_set_id, 'field_1') AS type, + extract_arg(arg_set_id, 'field_2') AS instance_id, + extract_arg(arg_set_id, 'field_3') AS uid + FROM android_statsd_atoms + WHERE name = 'atom_819'), + dw_statsd_events_add AS ( + SELECT * + FROM atoms + WHERE type = 1), + dw_statsd_events_remove AS ( + SELECT * FROM atoms + WHERE type = 2), + dw_statsd_events_update_by_instance AS ( + SELECT instance_id, min(uid) AS uid FROM atoms + WHERE type = 3 GROUP BY instance_id), + dw_windows AS ( + SELECT + a.ts AS raw_add_ts, + r.ts AS raw_remove_ts, + ifnull(a.ts, trace_start()) AS ts, -- Assume trace_start() if no add event found. + ifnull(r.ts, trace_end()) - ifnull(a.ts, trace_start()) AS dur, -- Assume trace_end() if no remove event found. + ifnull(a.instance_id, r.instance_id) AS instance_id, + ifnull(a.uid, r.uid) AS uid + FROM dw_statsd_events_add a + FULL JOIN dw_statsd_events_remove r ON a.instance_id = r.instance_id), + -- Assume window was open for the entire trace if we only see change events for the instance ID. + dw_windows_with_update_events AS ( + SELECT * FROM dw_windows + UNION + SELECT NULL, NULL, trace_start(), trace_end() - trace_start(), instance_id, uid + FROM dw_statsd_events_update_by_instance + WHERE + instance_id NOT IN (SELECT instance_id FROM dw_windows)) +SELECT * FROM dw_windows_with_update_events; + diff --git a/test/data/android_desktop_mode/multiple_window_only_update.pb.sha256 b/test/data/android_desktop_mode/multiple_window_only_update.pb.sha256 new file mode 100644 index 0000000000..939c9861f3 --- /dev/null +++ b/test/data/android_desktop_mode/multiple_window_only_update.pb.sha256 @@ -0,0 +1 @@ +de2c99d57ebec6ab843bc56047eb12dbedc3d08a8a1d989d9b3302ed30057286 \ No newline at end of file diff --git a/test/data/android_desktop_mode/multiple_windows_add_update_remove.pb.sha256 b/test/data/android_desktop_mode/multiple_windows_add_update_remove.pb.sha256 new file mode 100644 index 0000000000..5866d07e7c --- /dev/null +++ b/test/data/android_desktop_mode/multiple_windows_add_update_remove.pb.sha256 @@ -0,0 +1 @@ +0967fdf494167fe47e5ddf4c540fcc7cc0b22e36ddafa4b4c1172fe3c171b3d6 \ No newline at end of file diff --git a/test/data/android_desktop_mode/single_window_add_update_no_remove.pb.sha256 b/test/data/android_desktop_mode/single_window_add_update_no_remove.pb.sha256 new file mode 100644 index 0000000000..f4656e4b93 --- /dev/null +++ b/test/data/android_desktop_mode/single_window_add_update_no_remove.pb.sha256 @@ -0,0 +1 @@ +0bb09b4c68a125a09b6856879af92cd47dd980c2dcaa1513c370b9b6a7b575d1 \ No newline at end of file diff --git a/test/data/android_desktop_mode/single_window_add_update_remove.pb.sha256 b/test/data/android_desktop_mode/single_window_add_update_remove.pb.sha256 new file mode 100644 index 0000000000..3496183a29 --- /dev/null +++ b/test/data/android_desktop_mode/single_window_add_update_remove.pb.sha256 @@ -0,0 +1 @@ +bab0c50523ac903872cd11f3fdd4a9ecda98e937573d17011eb877636e82c3c3 \ No newline at end of file diff --git a/test/data/android_desktop_mode/single_window_no_add_update_remove.pb.sha256 b/test/data/android_desktop_mode/single_window_no_add_update_remove.pb.sha256 new file mode 100644 index 0000000000..3c01fec63a --- /dev/null +++ b/test/data/android_desktop_mode/single_window_no_add_update_remove.pb.sha256 @@ -0,0 +1 @@ +7f63f17b65a0fca4bc5ccd75c9a7eb854779585b20cb91fcf371e7892642327e \ No newline at end of file diff --git a/test/data/android_desktop_mode/single_window_only_update.pb.sha256 b/test/data/android_desktop_mode/single_window_only_update.pb.sha256 new file mode 100644 index 0000000000..20f7be35ab --- /dev/null +++ b/test/data/android_desktop_mode/single_window_only_update.pb.sha256 @@ -0,0 +1 @@ +ee1172b8ad0eaf856e2776575b861f44663bb98f1d40d7d4e66ee0f532220568 \ No newline at end of file diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py index f13fbb62a2..9062b8e266 100644 --- a/test/trace_processor/diff_tests/include_index.py +++ b/test/trace_processor/diff_tests/include_index.py @@ -108,6 +108,7 @@ from diff_tests.parser.ufs.tests import Ufs from diff_tests.parser.zip.tests import Zip from diff_tests.stdlib.android.cpu_cluster_tests import CpuClusters +from diff_tests.stdlib.android.desktop_mode_tests import DesktopMode from diff_tests.stdlib.android.frames_tests import Frames from diff_tests.stdlib.android.gpu import AndroidGpu from diff_tests.stdlib.android.heap_graph_tests import HeapGraph @@ -295,6 +296,7 @@ def fetch_all_diff_tests(index_path: str) -> List['testing.TestCase']: *AndroidGpu(index_path, 'stdlib/android', 'AndroidGpu').fetch(), *AndroidStdlib(index_path, 'stdlib/android', 'AndroidStdlib').fetch(), *CpuClusters(index_path, 'stdlib/android', 'CpuClusters').fetch(), + *DesktopMode(index_path, 'stdlib/android', 'DesktopMode').fetch(), *LinuxCpu(index_path, 'stdlib/linux/cpu', 'LinuxCpu').fetch(), *LinuxTests(index_path, 'stdlib/linux', 'LinuxTests').fetch(), *DominatorTree(index_path, 'stdlib/graphs', 'DominatorTree').fetch(), diff --git a/test/trace_processor/diff_tests/stdlib/android/desktop_mode_tests.py b/test/trace_processor/diff_tests/stdlib/android/desktop_mode_tests.py new file mode 100644 index 0000000000..0ef52a4608 --- /dev/null +++ b/test/trace_processor/diff_tests/stdlib/android/desktop_mode_tests.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# Copyright (C) 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 a +# +# 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. + +from python.generators.diff_tests.testing import DataPath +from python.generators.diff_tests.testing import Csv +from python.generators.diff_tests.testing import DiffTestBlueprint +from python.generators.diff_tests.testing import TestSuite + +class DesktopMode(TestSuite): + + def test_android_desktop_mode_windows_statsd_events(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/single_window_add_update_remove.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + 1112172132337,1115098491388,1112172132337,2926359051,22,10211 + """)) + + def test_android_desktop_mode_windows_statsd_events_multiple_windows(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/multiple_windows_add_update_remove.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + 1340951146935,1347096280320,1340951146935,6145133385,24,10211 + 1342507511641,1345461733688,1342507511641,2954222047,26,10183 + """)) + + def test_android_desktop_mode_windows_statsd_events_add_no_remove(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/single_window_add_update_no_remove.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + 1552558346094,"[NULL]",1552558346094,1620521485,27,10211 + """)) + + def test_android_desktop_mode_windows_statsd_events_no_add_update_remove(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/single_window_no_add_update_remove.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + "[NULL]",1696520389866,1695387563286,1132826580,29,10211 + """)) + + def test_android_desktop_mode_windows_statsd_events_only_update(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/single_window_only_update.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + "[NULL]","[NULL]",1852548597746,3663403770,31,10211 + """)) + + def test_android_desktop_mode_windows_statsd_events_multiple_windows_update_only(self): + return DiffTestBlueprint( + trace=DataPath('android_desktop_mode/multiple_window_only_update.pb'), + query=""" + INCLUDE PERFETTO MODULE android.desktop_mode; + SELECT * FROM android_desktop_mode_windows; + """, + out=Csv(""" + "raw_add_ts","raw_remove_ts","ts","dur","instance_id","uid" + "[NULL]","[NULL]",2137135290268,4737314089,33,10211 + "[NULL]","[NULL]",2137135290268,4737314089,35,10183 + """)) + diff --git a/ui/src/plugins/dev.perfetto.AndroidDesktopMode/OWNERS b/ui/src/plugins/dev.perfetto.AndroidDesktopMode/OWNERS new file mode 100644 index 0000000000..d0be0ccd53 --- /dev/null +++ b/ui/src/plugins/dev.perfetto.AndroidDesktopMode/OWNERS @@ -0,0 +1,2 @@ +benm@google.com + diff --git a/ui/src/plugins/dev.perfetto.AndroidDesktopMode/index.ts b/ui/src/plugins/dev.perfetto.AndroidDesktopMode/index.ts new file mode 100644 index 0000000000..c4fead227e --- /dev/null +++ b/ui/src/plugins/dev.perfetto.AndroidDesktopMode/index.ts @@ -0,0 +1,81 @@ +// Copyright (C) 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 +// +// 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 { + SimpleSliceTrack, + SimpleSliceTrackConfig, +} from '../../frontend/simple_slice_track'; +import {PerfettoPlugin, PluginDescriptor} from '../../public/plugin'; +import {Trace} from '../../public/trace'; +import {TrackNode} from '../../public/workspace'; + +const INCLUDE_DESKTOP_MODULE_QUERY = `INCLUDE PERFETTO MODULE android.desktop_mode`; + +const QUERY = ` +SELECT + ROW_NUMBER() OVER (ORDER BY ts) AS id, + ts, + dur, + ifnull(p.package_name, 'uid=' || dw.uid) AS name +FROM android_desktop_mode_windows dw +LEFT JOIN package_list p ON CAST (dw.uid AS INT) % 100000 = p.uid AND p.uid != 1000 +`; + +const COLUMNS = ['id', 'ts', 'dur', 'name']; +const TRACK_NAME = 'Desktop Mode Windows'; +const TRACK_URI = '/desktop_windows'; + +class AndroidDesktopMode implements PerfettoPlugin { + async onTraceReady(_ctx: Trace): Promise { + await _ctx.engine.query(INCLUDE_DESKTOP_MODULE_QUERY); + this.registerTrack( + _ctx, + QUERY, + ); + _ctx.commands.registerCommand({ + id: 'dev.perfetto.DesktopMode#AddTrackDesktopWindowss', + name: 'Add Track: ' + TRACK_NAME, + callback: () => this.addSimpleTrack(_ctx), + }); + } + + registerTrack(_ctx: Trace, sql: string) { + const config: SimpleSliceTrackConfig = { + data: { + sqlSource: sql, + columns: COLUMNS, + }, + columns: {ts: 'ts', dur: 'dur', name: 'name'}, + argColumns: [], + }; + const track = new SimpleSliceTrack(_ctx, {trackUri: TRACK_URI}, config); + _ctx.tracks.registerTrack({ + uri: TRACK_URI, + title: TRACK_NAME, + track, + }); + } + + addSimpleTrack(_ctx: Trace) { + const trackNode = new TrackNode({uri: TRACK_URI, title: TRACK_NAME}); + _ctx.workspace.addChildInOrder(trackNode); + trackNode.pin(); + } +} + +export const plugin: PluginDescriptor = { + pluginId: 'dev.perfetto.AndroidDesktopMode', + plugin: AndroidDesktopMode, +}; +