xref: /aosp_15_r20/external/perfetto/ui/src/plugins/org.kernel.SuspendResumeLatency/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 {AsyncSliceTrack} from '../dev.perfetto.AsyncSlices/async_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 {Slice} from '../../public/track';
23import {OnSliceClickArgs} from '../../components/tracks/base_slice_track';
24import {ThreadMap} from '../dev.perfetto.Thread/threads';
25import ThreadPlugin from '../dev.perfetto.Thread';
26import AsyncSlicesPlugin from '../dev.perfetto.AsyncSlices';
27
28// SuspendResumeSliceTrack exists so as to override the `onSliceClick` function
29// in AsyncSliceTrack.
30// TODO(stevegolton): Remove this?
31class SuspendResumeSliceTrack extends AsyncSliceTrack {
32  constructor(
33    trace: Trace,
34    uri: string,
35    maxDepth: number,
36    trackIds: number[],
37    private readonly threads: ThreadMap,
38  ) {
39    super(trace, uri, maxDepth, trackIds);
40  }
41
42  onSliceClick(args: OnSliceClickArgs<Slice>) {
43    this.trace.selection.selectTrackEvent(this.uri, args.slice.id);
44  }
45
46  override detailsPanel() {
47    return new SuspendResumeDetailsPanel(this.trace, this.threads);
48  }
49}
50
51export default class implements PerfettoPlugin {
52  static readonly id = 'org.kernel.SuspendResumeLatency';
53  static readonly dependencies = [ThreadPlugin, AsyncSlicesPlugin];
54
55  async onTraceLoad(ctx: Trace): Promise<void> {
56    const threads = ctx.plugins.getPlugin(ThreadPlugin).getThreadMap();
57    const {engine} = ctx;
58    const rawGlobalAsyncTracks = await engine.query(`
59      with global_tracks_grouped as (
60        select
61          name,
62          group_concat(distinct t.id) as trackIds,
63          count() as trackCount
64        from track t
65        where t.name = "Suspend/Resume Latency"
66      )
67      select
68        t.trackIds as trackIds,
69        case
70          when
71            t.trackCount > 0
72          then
73            __max_layout_depth(t.trackCount, t.trackIds)
74          else 0
75        end as maxDepth
76      from global_tracks_grouped t
77    `);
78    const it = rawGlobalAsyncTracks.iter({
79      trackIds: STR_NULL,
80      maxDepth: NUM,
81    });
82    // If no Suspend/Resume tracks exist, then nothing to do.
83    if (it.trackIds == null) {
84      return;
85    }
86    const rawTrackIds = it.trackIds;
87    const trackIds = rawTrackIds.split(',').map((v) => Number(v));
88    const maxDepth = it.maxDepth;
89
90    const uri = `/suspend_resume_latency`;
91    const displayName = `Suspend/Resume Latency`;
92    ctx.tracks.registerTrack({
93      uri,
94      title: displayName,
95      tags: {
96        trackIds,
97        kind: SLICE_TRACK_KIND,
98      },
99      track: new SuspendResumeSliceTrack(ctx, uri, maxDepth, trackIds, threads),
100    });
101
102    // Display the track in the UI.
103    const track = new TrackNode({uri, title: displayName});
104    ctx.workspace.addChildInOrder(track);
105  }
106}
107