1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport {removeFalsyValues} from '../../base/array_utils'; 16*6dbdd20aSAndroid Build Coastguard Workerimport {TrackNode} from '../../public/workspace'; 17*6dbdd20aSAndroid Build Coastguard Workerimport {SLICE_TRACK_KIND} from '../../public/track_kinds'; 18*6dbdd20aSAndroid Build Coastguard Workerimport {Trace} from '../../public/trace'; 19*6dbdd20aSAndroid Build Coastguard Workerimport {PerfettoPlugin} from '../../public/plugin'; 20*6dbdd20aSAndroid Build Coastguard Workerimport {getThreadUriPrefix, getTrackName} from '../../public/utils'; 21*6dbdd20aSAndroid Build Coastguard Workerimport {NUM, NUM_NULL, STR, STR_NULL} from '../../trace_processor/query_result'; 22*6dbdd20aSAndroid Build Coastguard Workerimport {AsyncSliceTrack} from './async_slice_track'; 23*6dbdd20aSAndroid Build Coastguard Workerimport {exists} from '../../base/utils'; 24*6dbdd20aSAndroid Build Coastguard Workerimport {assertExists, assertTrue} from '../../base/logging'; 25*6dbdd20aSAndroid Build Coastguard Workerimport {SliceSelectionAggregator} from './slice_selection_aggregator'; 26*6dbdd20aSAndroid Build Coastguard Workerimport ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups'; 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Workerexport default class implements PerfettoPlugin { 29*6dbdd20aSAndroid Build Coastguard Worker static readonly id = 'dev.perfetto.AsyncSlices'; 30*6dbdd20aSAndroid Build Coastguard Worker static readonly dependencies = [ProcessThreadGroupsPlugin]; 31*6dbdd20aSAndroid Build Coastguard Worker 32*6dbdd20aSAndroid Build Coastguard Worker async onTraceLoad(ctx: Trace): Promise<void> { 33*6dbdd20aSAndroid Build Coastguard Worker const trackIdsToUris = new Map<number, string>(); 34*6dbdd20aSAndroid Build Coastguard Worker 35*6dbdd20aSAndroid Build Coastguard Worker await this.addGlobalAsyncTracks(ctx, trackIdsToUris); 36*6dbdd20aSAndroid Build Coastguard Worker await this.addProcessAsyncSliceTracks(ctx, trackIdsToUris); 37*6dbdd20aSAndroid Build Coastguard Worker await this.addThreadAsyncSliceTracks(ctx, trackIdsToUris); 38*6dbdd20aSAndroid Build Coastguard Worker 39*6dbdd20aSAndroid Build Coastguard Worker ctx.selection.registerSqlSelectionResolver({ 40*6dbdd20aSAndroid Build Coastguard Worker sqlTableName: 'slice', 41*6dbdd20aSAndroid Build Coastguard Worker callback: async (id: number) => { 42*6dbdd20aSAndroid Build Coastguard Worker // Locate the track for a given id in the slice table 43*6dbdd20aSAndroid Build Coastguard Worker const result = await ctx.engine.query(` 44*6dbdd20aSAndroid Build Coastguard Worker select 45*6dbdd20aSAndroid Build Coastguard Worker track_id as trackId 46*6dbdd20aSAndroid Build Coastguard Worker from 47*6dbdd20aSAndroid Build Coastguard Worker slice 48*6dbdd20aSAndroid Build Coastguard Worker where slice.id = ${id} 49*6dbdd20aSAndroid Build Coastguard Worker `); 50*6dbdd20aSAndroid Build Coastguard Worker 51*6dbdd20aSAndroid Build Coastguard Worker if (result.numRows() === 0) { 52*6dbdd20aSAndroid Build Coastguard Worker return undefined; 53*6dbdd20aSAndroid Build Coastguard Worker } 54*6dbdd20aSAndroid Build Coastguard Worker 55*6dbdd20aSAndroid Build Coastguard Worker const {trackId} = result.firstRow({ 56*6dbdd20aSAndroid Build Coastguard Worker trackId: NUM, 57*6dbdd20aSAndroid Build Coastguard Worker }); 58*6dbdd20aSAndroid Build Coastguard Worker 59*6dbdd20aSAndroid Build Coastguard Worker const trackUri = trackIdsToUris.get(trackId); 60*6dbdd20aSAndroid Build Coastguard Worker if (!trackUri) { 61*6dbdd20aSAndroid Build Coastguard Worker return undefined; 62*6dbdd20aSAndroid Build Coastguard Worker } 63*6dbdd20aSAndroid Build Coastguard Worker 64*6dbdd20aSAndroid Build Coastguard Worker return { 65*6dbdd20aSAndroid Build Coastguard Worker trackUri, 66*6dbdd20aSAndroid Build Coastguard Worker eventId: id, 67*6dbdd20aSAndroid Build Coastguard Worker }; 68*6dbdd20aSAndroid Build Coastguard Worker }, 69*6dbdd20aSAndroid Build Coastguard Worker }); 70*6dbdd20aSAndroid Build Coastguard Worker 71*6dbdd20aSAndroid Build Coastguard Worker ctx.selection.registerAreaSelectionAggregator( 72*6dbdd20aSAndroid Build Coastguard Worker new SliceSelectionAggregator(), 73*6dbdd20aSAndroid Build Coastguard Worker ); 74*6dbdd20aSAndroid Build Coastguard Worker } 75*6dbdd20aSAndroid Build Coastguard Worker 76*6dbdd20aSAndroid Build Coastguard Worker async addGlobalAsyncTracks( 77*6dbdd20aSAndroid Build Coastguard Worker ctx: Trace, 78*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris: Map<number, string>, 79*6dbdd20aSAndroid Build Coastguard Worker ): Promise<void> { 80*6dbdd20aSAndroid Build Coastguard Worker const {engine} = ctx; 81*6dbdd20aSAndroid Build Coastguard Worker // TODO(stevegolton): The track exclusion logic is currently a hack. This will be replaced 82*6dbdd20aSAndroid Build Coastguard Worker // by a mechanism for more specific plugins to override tracks from more generic plugins. 83*6dbdd20aSAndroid Build Coastguard Worker const suspendResumeLatencyTrackName = 'Suspend/Resume Latency'; 84*6dbdd20aSAndroid Build Coastguard Worker const rawGlobalAsyncTracks = await engine.query(` 85*6dbdd20aSAndroid Build Coastguard Worker include perfetto module graphs.search; 86*6dbdd20aSAndroid Build Coastguard Worker include perfetto module viz.summary.tracks; 87*6dbdd20aSAndroid Build Coastguard Worker 88*6dbdd20aSAndroid Build Coastguard Worker with global_tracks_grouped as ( 89*6dbdd20aSAndroid Build Coastguard Worker select 90*6dbdd20aSAndroid Build Coastguard Worker t.parent_id, 91*6dbdd20aSAndroid Build Coastguard Worker t.name, 92*6dbdd20aSAndroid Build Coastguard Worker group_concat(t.id) as trackIds, 93*6dbdd20aSAndroid Build Coastguard Worker count() as trackCount, 94*6dbdd20aSAndroid Build Coastguard Worker ifnull(min(a.order_id), 0) as order_id 95*6dbdd20aSAndroid Build Coastguard Worker from track t 96*6dbdd20aSAndroid Build Coastguard Worker join _slice_track_summary using (id) 97*6dbdd20aSAndroid Build Coastguard Worker left join _track_event_tracks_ordered a USING (id) 98*6dbdd20aSAndroid Build Coastguard Worker where 99*6dbdd20aSAndroid Build Coastguard Worker t.type in ('__intrinsic_track', 'gpu_track', '__intrinsic_cpu_track') 100*6dbdd20aSAndroid Build Coastguard Worker and (name != '${suspendResumeLatencyTrackName}' or name is null) 101*6dbdd20aSAndroid Build Coastguard Worker and classification not in ( 102*6dbdd20aSAndroid Build Coastguard Worker 'linux_rpm', 103*6dbdd20aSAndroid Build Coastguard Worker 'linux_device_frequency', 104*6dbdd20aSAndroid Build Coastguard Worker 'irq_counter', 105*6dbdd20aSAndroid Build Coastguard Worker 'softirq_counter', 106*6dbdd20aSAndroid Build Coastguard Worker 'android_energy_estimation_breakdown', 107*6dbdd20aSAndroid Build Coastguard Worker 'android_energy_estimation_breakdown_per_uid' 108*6dbdd20aSAndroid Build Coastguard Worker ) 109*6dbdd20aSAndroid Build Coastguard Worker group by parent_id, name 110*6dbdd20aSAndroid Build Coastguard Worker order by parent_id, order_id 111*6dbdd20aSAndroid Build Coastguard Worker ), 112*6dbdd20aSAndroid Build Coastguard Worker intermediate_groups as ( 113*6dbdd20aSAndroid Build Coastguard Worker select 114*6dbdd20aSAndroid Build Coastguard Worker t.name, 115*6dbdd20aSAndroid Build Coastguard Worker t.id, 116*6dbdd20aSAndroid Build Coastguard Worker t.parent_id, 117*6dbdd20aSAndroid Build Coastguard Worker ifnull(a.order_id, 0) as order_id 118*6dbdd20aSAndroid Build Coastguard Worker from graph_reachable_dfs!( 119*6dbdd20aSAndroid Build Coastguard Worker ( 120*6dbdd20aSAndroid Build Coastguard Worker select id as source_node_id, parent_id as dest_node_id 121*6dbdd20aSAndroid Build Coastguard Worker from track 122*6dbdd20aSAndroid Build Coastguard Worker where parent_id is not null 123*6dbdd20aSAndroid Build Coastguard Worker ), 124*6dbdd20aSAndroid Build Coastguard Worker ( 125*6dbdd20aSAndroid Build Coastguard Worker select distinct parent_id as node_id 126*6dbdd20aSAndroid Build Coastguard Worker from global_tracks_grouped 127*6dbdd20aSAndroid Build Coastguard Worker where parent_id is not null 128*6dbdd20aSAndroid Build Coastguard Worker ) 129*6dbdd20aSAndroid Build Coastguard Worker ) g 130*6dbdd20aSAndroid Build Coastguard Worker join track t on g.node_id = t.id 131*6dbdd20aSAndroid Build Coastguard Worker left join _track_event_tracks_ordered a USING (id) 132*6dbdd20aSAndroid Build Coastguard Worker ) 133*6dbdd20aSAndroid Build Coastguard Worker select 134*6dbdd20aSAndroid Build Coastguard Worker t.name as name, 135*6dbdd20aSAndroid Build Coastguard Worker t.parent_id as parentId, 136*6dbdd20aSAndroid Build Coastguard Worker t.trackIds as trackIds, 137*6dbdd20aSAndroid Build Coastguard Worker t.order_id as orderId, 138*6dbdd20aSAndroid Build Coastguard Worker __max_layout_depth(t.trackCount, t.trackIds) as maxDepth 139*6dbdd20aSAndroid Build Coastguard Worker from global_tracks_grouped t 140*6dbdd20aSAndroid Build Coastguard Worker union all 141*6dbdd20aSAndroid Build Coastguard Worker select 142*6dbdd20aSAndroid Build Coastguard Worker t.name as name, 143*6dbdd20aSAndroid Build Coastguard Worker t.parent_id as parentId, 144*6dbdd20aSAndroid Build Coastguard Worker cast_string!(t.id) as trackIds, 145*6dbdd20aSAndroid Build Coastguard Worker t.order_id as orderId, 146*6dbdd20aSAndroid Build Coastguard Worker NULL as maxDepth 147*6dbdd20aSAndroid Build Coastguard Worker from intermediate_groups t 148*6dbdd20aSAndroid Build Coastguard Worker left join _slice_track_summary s using (id) 149*6dbdd20aSAndroid Build Coastguard Worker where s.id is null 150*6dbdd20aSAndroid Build Coastguard Worker order by parentId, orderId 151*6dbdd20aSAndroid Build Coastguard Worker `); 152*6dbdd20aSAndroid Build Coastguard Worker const it = rawGlobalAsyncTracks.iter({ 153*6dbdd20aSAndroid Build Coastguard Worker name: STR_NULL, 154*6dbdd20aSAndroid Build Coastguard Worker parentId: NUM_NULL, 155*6dbdd20aSAndroid Build Coastguard Worker trackIds: STR, 156*6dbdd20aSAndroid Build Coastguard Worker orderId: NUM, 157*6dbdd20aSAndroid Build Coastguard Worker maxDepth: NUM_NULL, 158*6dbdd20aSAndroid Build Coastguard Worker }); 159*6dbdd20aSAndroid Build Coastguard Worker 160*6dbdd20aSAndroid Build Coastguard Worker // Create a map of track nodes by id 161*6dbdd20aSAndroid Build Coastguard Worker const trackMap = new Map< 162*6dbdd20aSAndroid Build Coastguard Worker number, 163*6dbdd20aSAndroid Build Coastguard Worker {parentId: number | null; trackNode: TrackNode} 164*6dbdd20aSAndroid Build Coastguard Worker >(); 165*6dbdd20aSAndroid Build Coastguard Worker 166*6dbdd20aSAndroid Build Coastguard Worker for (; it.valid(); it.next()) { 167*6dbdd20aSAndroid Build Coastguard Worker const rawName = it.name === null ? undefined : it.name; 168*6dbdd20aSAndroid Build Coastguard Worker const title = getTrackName({ 169*6dbdd20aSAndroid Build Coastguard Worker name: rawName, 170*6dbdd20aSAndroid Build Coastguard Worker kind: SLICE_TRACK_KIND, 171*6dbdd20aSAndroid Build Coastguard Worker }); 172*6dbdd20aSAndroid Build Coastguard Worker const rawTrackIds = it.trackIds; 173*6dbdd20aSAndroid Build Coastguard Worker const trackIds = rawTrackIds.split(',').map((v) => Number(v)); 174*6dbdd20aSAndroid Build Coastguard Worker const maxDepth = it.maxDepth; 175*6dbdd20aSAndroid Build Coastguard Worker 176*6dbdd20aSAndroid Build Coastguard Worker if (maxDepth === null) { 177*6dbdd20aSAndroid Build Coastguard Worker assertTrue(trackIds.length == 1); 178*6dbdd20aSAndroid Build Coastguard Worker const trackNode = new TrackNode({title, sortOrder: -25}); 179*6dbdd20aSAndroid Build Coastguard Worker trackMap.set(trackIds[0], {parentId: it.parentId, trackNode}); 180*6dbdd20aSAndroid Build Coastguard Worker } else { 181*6dbdd20aSAndroid Build Coastguard Worker const uri = `/async_slices_${rawName}_${it.parentId}`; 182*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 183*6dbdd20aSAndroid Build Coastguard Worker uri, 184*6dbdd20aSAndroid Build Coastguard Worker title, 185*6dbdd20aSAndroid Build Coastguard Worker tags: { 186*6dbdd20aSAndroid Build Coastguard Worker trackIds, 187*6dbdd20aSAndroid Build Coastguard Worker kind: SLICE_TRACK_KIND, 188*6dbdd20aSAndroid Build Coastguard Worker scope: 'global', 189*6dbdd20aSAndroid Build Coastguard Worker }, 190*6dbdd20aSAndroid Build Coastguard Worker track: new AsyncSliceTrack(ctx, uri, maxDepth, trackIds), 191*6dbdd20aSAndroid Build Coastguard Worker }); 192*6dbdd20aSAndroid Build Coastguard Worker const trackNode = new TrackNode({ 193*6dbdd20aSAndroid Build Coastguard Worker uri, 194*6dbdd20aSAndroid Build Coastguard Worker title, 195*6dbdd20aSAndroid Build Coastguard Worker sortOrder: it.orderId, 196*6dbdd20aSAndroid Build Coastguard Worker }); 197*6dbdd20aSAndroid Build Coastguard Worker trackIds.forEach((id) => { 198*6dbdd20aSAndroid Build Coastguard Worker trackMap.set(id, {parentId: it.parentId, trackNode}); 199*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris.set(id, uri); 200*6dbdd20aSAndroid Build Coastguard Worker }); 201*6dbdd20aSAndroid Build Coastguard Worker } 202*6dbdd20aSAndroid Build Coastguard Worker } 203*6dbdd20aSAndroid Build Coastguard Worker 204*6dbdd20aSAndroid Build Coastguard Worker // Attach track nodes to parents / or the workspace if they have no parent 205*6dbdd20aSAndroid Build Coastguard Worker trackMap.forEach(({parentId, trackNode}) => { 206*6dbdd20aSAndroid Build Coastguard Worker if (exists(parentId)) { 207*6dbdd20aSAndroid Build Coastguard Worker const parent = assertExists(trackMap.get(parentId)); 208*6dbdd20aSAndroid Build Coastguard Worker parent.trackNode.addChildInOrder(trackNode); 209*6dbdd20aSAndroid Build Coastguard Worker } else { 210*6dbdd20aSAndroid Build Coastguard Worker ctx.workspace.addChildInOrder(trackNode); 211*6dbdd20aSAndroid Build Coastguard Worker } 212*6dbdd20aSAndroid Build Coastguard Worker }); 213*6dbdd20aSAndroid Build Coastguard Worker } 214*6dbdd20aSAndroid Build Coastguard Worker 215*6dbdd20aSAndroid Build Coastguard Worker async addProcessAsyncSliceTracks( 216*6dbdd20aSAndroid Build Coastguard Worker ctx: Trace, 217*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris: Map<number, string>, 218*6dbdd20aSAndroid Build Coastguard Worker ): Promise<void> { 219*6dbdd20aSAndroid Build Coastguard Worker const result = await ctx.engine.query(` 220*6dbdd20aSAndroid Build Coastguard Worker select 221*6dbdd20aSAndroid Build Coastguard Worker upid, 222*6dbdd20aSAndroid Build Coastguard Worker t.name as trackName, 223*6dbdd20aSAndroid Build Coastguard Worker t.track_ids as trackIds, 224*6dbdd20aSAndroid Build Coastguard Worker process.name as processName, 225*6dbdd20aSAndroid Build Coastguard Worker process.pid as pid, 226*6dbdd20aSAndroid Build Coastguard Worker t.parent_id as parentId, 227*6dbdd20aSAndroid Build Coastguard Worker __max_layout_depth(t.track_count, t.track_ids) as maxDepth 228*6dbdd20aSAndroid Build Coastguard Worker from _process_track_summary_by_upid_and_parent_id_and_name t 229*6dbdd20aSAndroid Build Coastguard Worker join process using (upid) 230*6dbdd20aSAndroid Build Coastguard Worker where t.name is null or t.name not glob "* Timeline" 231*6dbdd20aSAndroid Build Coastguard Worker `); 232*6dbdd20aSAndroid Build Coastguard Worker 233*6dbdd20aSAndroid Build Coastguard Worker const it = result.iter({ 234*6dbdd20aSAndroid Build Coastguard Worker upid: NUM, 235*6dbdd20aSAndroid Build Coastguard Worker parentId: NUM_NULL, 236*6dbdd20aSAndroid Build Coastguard Worker trackName: STR_NULL, 237*6dbdd20aSAndroid Build Coastguard Worker trackIds: STR, 238*6dbdd20aSAndroid Build Coastguard Worker processName: STR_NULL, 239*6dbdd20aSAndroid Build Coastguard Worker pid: NUM_NULL, 240*6dbdd20aSAndroid Build Coastguard Worker maxDepth: NUM, 241*6dbdd20aSAndroid Build Coastguard Worker }); 242*6dbdd20aSAndroid Build Coastguard Worker 243*6dbdd20aSAndroid Build Coastguard Worker const trackMap = new Map< 244*6dbdd20aSAndroid Build Coastguard Worker number, 245*6dbdd20aSAndroid Build Coastguard Worker {parentId: number | null; upid: number; trackNode: TrackNode} 246*6dbdd20aSAndroid Build Coastguard Worker >(); 247*6dbdd20aSAndroid Build Coastguard Worker 248*6dbdd20aSAndroid Build Coastguard Worker for (; it.valid(); it.next()) { 249*6dbdd20aSAndroid Build Coastguard Worker const upid = it.upid; 250*6dbdd20aSAndroid Build Coastguard Worker const trackName = it.trackName; 251*6dbdd20aSAndroid Build Coastguard Worker const rawTrackIds = it.trackIds; 252*6dbdd20aSAndroid Build Coastguard Worker const trackIds = rawTrackIds.split(',').map((v) => Number(v)); 253*6dbdd20aSAndroid Build Coastguard Worker const processName = it.processName; 254*6dbdd20aSAndroid Build Coastguard Worker const pid = it.pid; 255*6dbdd20aSAndroid Build Coastguard Worker const maxDepth = it.maxDepth; 256*6dbdd20aSAndroid Build Coastguard Worker 257*6dbdd20aSAndroid Build Coastguard Worker const kind = SLICE_TRACK_KIND; 258*6dbdd20aSAndroid Build Coastguard Worker const title = getTrackName({ 259*6dbdd20aSAndroid Build Coastguard Worker name: trackName, 260*6dbdd20aSAndroid Build Coastguard Worker upid, 261*6dbdd20aSAndroid Build Coastguard Worker pid, 262*6dbdd20aSAndroid Build Coastguard Worker processName, 263*6dbdd20aSAndroid Build Coastguard Worker kind, 264*6dbdd20aSAndroid Build Coastguard Worker }); 265*6dbdd20aSAndroid Build Coastguard Worker 266*6dbdd20aSAndroid Build Coastguard Worker const uri = `/process_${upid}/async_slices_${rawTrackIds}`; 267*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 268*6dbdd20aSAndroid Build Coastguard Worker uri, 269*6dbdd20aSAndroid Build Coastguard Worker title, 270*6dbdd20aSAndroid Build Coastguard Worker tags: { 271*6dbdd20aSAndroid Build Coastguard Worker trackIds, 272*6dbdd20aSAndroid Build Coastguard Worker kind: SLICE_TRACK_KIND, 273*6dbdd20aSAndroid Build Coastguard Worker scope: 'process', 274*6dbdd20aSAndroid Build Coastguard Worker upid, 275*6dbdd20aSAndroid Build Coastguard Worker }, 276*6dbdd20aSAndroid Build Coastguard Worker track: new AsyncSliceTrack(ctx, uri, maxDepth, trackIds), 277*6dbdd20aSAndroid Build Coastguard Worker }); 278*6dbdd20aSAndroid Build Coastguard Worker const track = new TrackNode({uri, title, sortOrder: 30}); 279*6dbdd20aSAndroid Build Coastguard Worker trackIds.forEach((id) => { 280*6dbdd20aSAndroid Build Coastguard Worker trackMap.set(id, {trackNode: track, parentId: it.parentId, upid}); 281*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris.set(id, uri); 282*6dbdd20aSAndroid Build Coastguard Worker }); 283*6dbdd20aSAndroid Build Coastguard Worker } 284*6dbdd20aSAndroid Build Coastguard Worker 285*6dbdd20aSAndroid Build Coastguard Worker // Attach track nodes to parents / or the workspace if they have no parent 286*6dbdd20aSAndroid Build Coastguard Worker trackMap.forEach((t) => { 287*6dbdd20aSAndroid Build Coastguard Worker const parent = exists(t.parentId) && trackMap.get(t.parentId); 288*6dbdd20aSAndroid Build Coastguard Worker if (parent !== false && parent !== undefined) { 289*6dbdd20aSAndroid Build Coastguard Worker parent.trackNode.addChildInOrder(t.trackNode); 290*6dbdd20aSAndroid Build Coastguard Worker } else { 291*6dbdd20aSAndroid Build Coastguard Worker const processGroup = ctx.plugins 292*6dbdd20aSAndroid Build Coastguard Worker .getPlugin(ProcessThreadGroupsPlugin) 293*6dbdd20aSAndroid Build Coastguard Worker .getGroupForProcess(t.upid); 294*6dbdd20aSAndroid Build Coastguard Worker processGroup?.addChildInOrder(t.trackNode); 295*6dbdd20aSAndroid Build Coastguard Worker } 296*6dbdd20aSAndroid Build Coastguard Worker }); 297*6dbdd20aSAndroid Build Coastguard Worker } 298*6dbdd20aSAndroid Build Coastguard Worker 299*6dbdd20aSAndroid Build Coastguard Worker async addThreadAsyncSliceTracks( 300*6dbdd20aSAndroid Build Coastguard Worker ctx: Trace, 301*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris: Map<number, string>, 302*6dbdd20aSAndroid Build Coastguard Worker ): Promise<void> { 303*6dbdd20aSAndroid Build Coastguard Worker const result = await ctx.engine.query(` 304*6dbdd20aSAndroid Build Coastguard Worker include perfetto module viz.summary.slices; 305*6dbdd20aSAndroid Build Coastguard Worker include perfetto module viz.summary.threads; 306*6dbdd20aSAndroid Build Coastguard Worker include perfetto module viz.threads; 307*6dbdd20aSAndroid Build Coastguard Worker 308*6dbdd20aSAndroid Build Coastguard Worker select 309*6dbdd20aSAndroid Build Coastguard Worker t.utid, 310*6dbdd20aSAndroid Build Coastguard Worker t.parent_id as parentId, 311*6dbdd20aSAndroid Build Coastguard Worker thread.upid, 312*6dbdd20aSAndroid Build Coastguard Worker t.name as trackName, 313*6dbdd20aSAndroid Build Coastguard Worker thread.name as threadName, 314*6dbdd20aSAndroid Build Coastguard Worker thread.tid as tid, 315*6dbdd20aSAndroid Build Coastguard Worker t.track_ids as trackIds, 316*6dbdd20aSAndroid Build Coastguard Worker __max_layout_depth(t.track_count, t.track_ids) as maxDepth, 317*6dbdd20aSAndroid Build Coastguard Worker k.is_main_thread as isMainThread, 318*6dbdd20aSAndroid Build Coastguard Worker k.is_kernel_thread AS isKernelThread 319*6dbdd20aSAndroid Build Coastguard Worker from _thread_track_summary_by_utid_and_name t 320*6dbdd20aSAndroid Build Coastguard Worker join _threads_with_kernel_flag k using(utid) 321*6dbdd20aSAndroid Build Coastguard Worker join thread using (utid) 322*6dbdd20aSAndroid Build Coastguard Worker `); 323*6dbdd20aSAndroid Build Coastguard Worker 324*6dbdd20aSAndroid Build Coastguard Worker const it = result.iter({ 325*6dbdd20aSAndroid Build Coastguard Worker utid: NUM, 326*6dbdd20aSAndroid Build Coastguard Worker parentId: NUM_NULL, 327*6dbdd20aSAndroid Build Coastguard Worker upid: NUM_NULL, 328*6dbdd20aSAndroid Build Coastguard Worker trackName: STR_NULL, 329*6dbdd20aSAndroid Build Coastguard Worker trackIds: STR, 330*6dbdd20aSAndroid Build Coastguard Worker maxDepth: NUM, 331*6dbdd20aSAndroid Build Coastguard Worker isMainThread: NUM_NULL, 332*6dbdd20aSAndroid Build Coastguard Worker isKernelThread: NUM, 333*6dbdd20aSAndroid Build Coastguard Worker threadName: STR_NULL, 334*6dbdd20aSAndroid Build Coastguard Worker tid: NUM_NULL, 335*6dbdd20aSAndroid Build Coastguard Worker }); 336*6dbdd20aSAndroid Build Coastguard Worker 337*6dbdd20aSAndroid Build Coastguard Worker const trackMap = new Map< 338*6dbdd20aSAndroid Build Coastguard Worker number, 339*6dbdd20aSAndroid Build Coastguard Worker {parentId: number | null; utid: number; trackNode: TrackNode} 340*6dbdd20aSAndroid Build Coastguard Worker >(); 341*6dbdd20aSAndroid Build Coastguard Worker 342*6dbdd20aSAndroid Build Coastguard Worker for (; it.valid(); it.next()) { 343*6dbdd20aSAndroid Build Coastguard Worker const { 344*6dbdd20aSAndroid Build Coastguard Worker utid, 345*6dbdd20aSAndroid Build Coastguard Worker parentId, 346*6dbdd20aSAndroid Build Coastguard Worker upid, 347*6dbdd20aSAndroid Build Coastguard Worker trackName, 348*6dbdd20aSAndroid Build Coastguard Worker isMainThread, 349*6dbdd20aSAndroid Build Coastguard Worker isKernelThread, 350*6dbdd20aSAndroid Build Coastguard Worker maxDepth, 351*6dbdd20aSAndroid Build Coastguard Worker threadName, 352*6dbdd20aSAndroid Build Coastguard Worker tid, 353*6dbdd20aSAndroid Build Coastguard Worker } = it; 354*6dbdd20aSAndroid Build Coastguard Worker const rawTrackIds = it.trackIds; 355*6dbdd20aSAndroid Build Coastguard Worker const trackIds = rawTrackIds.split(',').map((v) => Number(v)); 356*6dbdd20aSAndroid Build Coastguard Worker const title = getTrackName({ 357*6dbdd20aSAndroid Build Coastguard Worker name: trackName, 358*6dbdd20aSAndroid Build Coastguard Worker utid, 359*6dbdd20aSAndroid Build Coastguard Worker tid, 360*6dbdd20aSAndroid Build Coastguard Worker threadName, 361*6dbdd20aSAndroid Build Coastguard Worker kind: 'Slices', 362*6dbdd20aSAndroid Build Coastguard Worker }); 363*6dbdd20aSAndroid Build Coastguard Worker 364*6dbdd20aSAndroid Build Coastguard Worker const uri = `/${getThreadUriPrefix(upid, utid)}_slice_${rawTrackIds}`; 365*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 366*6dbdd20aSAndroid Build Coastguard Worker uri, 367*6dbdd20aSAndroid Build Coastguard Worker title, 368*6dbdd20aSAndroid Build Coastguard Worker tags: { 369*6dbdd20aSAndroid Build Coastguard Worker trackIds, 370*6dbdd20aSAndroid Build Coastguard Worker kind: SLICE_TRACK_KIND, 371*6dbdd20aSAndroid Build Coastguard Worker scope: 'thread', 372*6dbdd20aSAndroid Build Coastguard Worker utid, 373*6dbdd20aSAndroid Build Coastguard Worker upid: upid ?? undefined, 374*6dbdd20aSAndroid Build Coastguard Worker ...(isKernelThread === 1 && {kernelThread: true}), 375*6dbdd20aSAndroid Build Coastguard Worker }, 376*6dbdd20aSAndroid Build Coastguard Worker chips: removeFalsyValues([ 377*6dbdd20aSAndroid Build Coastguard Worker isKernelThread === 0 && isMainThread === 1 && 'main thread', 378*6dbdd20aSAndroid Build Coastguard Worker ]), 379*6dbdd20aSAndroid Build Coastguard Worker track: new AsyncSliceTrack(ctx, uri, maxDepth, trackIds), 380*6dbdd20aSAndroid Build Coastguard Worker }); 381*6dbdd20aSAndroid Build Coastguard Worker const track = new TrackNode({uri, title, sortOrder: 20}); 382*6dbdd20aSAndroid Build Coastguard Worker trackIds.forEach((id) => { 383*6dbdd20aSAndroid Build Coastguard Worker trackMap.set(id, {trackNode: track, parentId, utid}); 384*6dbdd20aSAndroid Build Coastguard Worker trackIdsToUris.set(id, uri); 385*6dbdd20aSAndroid Build Coastguard Worker }); 386*6dbdd20aSAndroid Build Coastguard Worker } 387*6dbdd20aSAndroid Build Coastguard Worker 388*6dbdd20aSAndroid Build Coastguard Worker // Attach track nodes to parents / or the workspace if they have no parent 389*6dbdd20aSAndroid Build Coastguard Worker trackMap.forEach((t) => { 390*6dbdd20aSAndroid Build Coastguard Worker const parent = exists(t.parentId) && trackMap.get(t.parentId); 391*6dbdd20aSAndroid Build Coastguard Worker if (parent !== false && parent !== undefined) { 392*6dbdd20aSAndroid Build Coastguard Worker parent.trackNode.addChildInOrder(t.trackNode); 393*6dbdd20aSAndroid Build Coastguard Worker } else { 394*6dbdd20aSAndroid Build Coastguard Worker const group = ctx.plugins 395*6dbdd20aSAndroid Build Coastguard Worker .getPlugin(ProcessThreadGroupsPlugin) 396*6dbdd20aSAndroid Build Coastguard Worker .getGroupForThread(t.utid); 397*6dbdd20aSAndroid Build Coastguard Worker group?.addChildInOrder(t.trackNode); 398*6dbdd20aSAndroid Build Coastguard Worker } 399*6dbdd20aSAndroid Build Coastguard Worker }); 400*6dbdd20aSAndroid Build Coastguard Worker } 401*6dbdd20aSAndroid Build Coastguard Worker} 402