• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {NUM, STR_NULL} from '../../trace_processor/query_result';
16import {createTraceProcessorSliceTrack} from '../dev.perfetto.TraceProcessorTrack/trace_processor_slice_track';
17import {PerfettoPlugin} from '../../public/plugin';
18import {Trace} from '../../public/trace';
19import {TrackNode} from '../../public/workspace';
20import {SLICE_TRACK_KIND} from '../../public/track_kinds';
21import {SuspendResumeDetailsPanel} from './suspend_resume_details';
22import ThreadPlugin from '../dev.perfetto.Thread';
23import TraceProcessorTrackPlugin from '../dev.perfetto.TraceProcessorTrack';
24
25export default class implements PerfettoPlugin {
26  static readonly id = 'org.kernel.SuspendResumeLatency';
27  static readonly dependencies = [ThreadPlugin, TraceProcessorTrackPlugin];
28
29  async onTraceLoad(ctx: Trace): Promise<void> {
30    const threads = ctx.plugins.getPlugin(ThreadPlugin).getThreadMap();
31    const {engine} = ctx;
32    const rawGlobalAsyncTracks = await engine.query(`
33      with global_tracks_grouped as (
34        select
35          name,
36          group_concat(distinct t.id) as trackIds,
37          count() as trackCount
38        from track t
39        where t.name = "Suspend/Resume Latency"
40      )
41      select
42        t.trackIds as trackIds,
43        case
44          when
45            t.trackCount > 0
46          then
47            __max_layout_depth(t.trackCount, t.trackIds)
48          else 0
49        end as maxDepth
50      from global_tracks_grouped t
51    `);
52    const it = rawGlobalAsyncTracks.iter({
53      trackIds: STR_NULL,
54      maxDepth: NUM,
55    });
56    // If no Suspend/Resume tracks exist, then nothing to do.
57    if (it.trackIds == null) {
58      return;
59    }
60    const rawTrackIds = it.trackIds;
61    const trackIds = rawTrackIds.split(',').map((v) => Number(v));
62    const maxDepth = it.maxDepth;
63
64    const uri = `/suspend_resume_latency`;
65    const displayName = `Suspend/Resume Latency`;
66    ctx.tracks.registerTrack({
67      uri,
68      title: displayName,
69      tags: {
70        trackIds,
71        kind: SLICE_TRACK_KIND,
72      },
73      track: createTraceProcessorSliceTrack({
74        trace: ctx,
75        uri,
76        maxDepth,
77        trackIds,
78        detailsPanel: () => new SuspendResumeDetailsPanel(ctx, threads),
79      }),
80    });
81
82    // Display the track in the UI.
83    const track = new TrackNode({uri, title: displayName});
84    ctx.workspace.addChildInOrder(track);
85  }
86}
87