xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.PerfSamplesProfile/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2021 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 {TrackData} from '../../components/tracks/track_data';
16import {PERF_SAMPLES_PROFILE_TRACK_KIND} from '../../public/track_kinds';
17import {Trace} from '../../public/trace';
18import {PerfettoPlugin} from '../../public/plugin';
19import {NUM, NUM_NULL, STR_NULL} from '../../trace_processor/query_result';
20import {assertExists} from '../../base/logging';
21import {
22  ProcessPerfSamplesProfileTrack,
23  ThreadPerfSamplesProfileTrack,
24} from './perf_samples_profile_track';
25import {getThreadUriPrefix} from '../../public/utils';
26import {TrackNode} from '../../public/workspace';
27import ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups';
28
29export interface Data extends TrackData {
30  tsStarts: BigInt64Array;
31}
32
33function makeUriForProc(upid: number) {
34  return `/process_${upid}/perf_samples_profile`;
35}
36
37export default class implements PerfettoPlugin {
38  static readonly id = 'dev.perfetto.PerfSamplesProfile';
39  static readonly dependencies = [ProcessThreadGroupsPlugin];
40
41  async onTraceLoad(ctx: Trace): Promise<void> {
42    const pResult = await ctx.engine.query(`
43      select distinct upid
44      from perf_sample
45      join thread using (utid)
46      where callsite_id is not null and upid is not null
47    `);
48    for (const it = pResult.iter({upid: NUM}); it.valid(); it.next()) {
49      const upid = it.upid;
50      const uri = makeUriForProc(upid);
51      const title = `Process Callstacks`;
52      ctx.tracks.registerTrack({
53        uri,
54        title,
55        tags: {
56          kind: PERF_SAMPLES_PROFILE_TRACK_KIND,
57          upid,
58        },
59        track: new ProcessPerfSamplesProfileTrack(ctx, uri, upid),
60      });
61      const group = ctx.plugins
62        .getPlugin(ProcessThreadGroupsPlugin)
63        .getGroupForProcess(upid);
64      const track = new TrackNode({uri, title, sortOrder: -40});
65      group?.addChildInOrder(track);
66    }
67    const tResult = await ctx.engine.query(`
68      select distinct
69        utid,
70        tid,
71        thread.name as threadName,
72        upid
73      from perf_sample
74      join thread using (utid)
75      where callsite_id is not null
76    `);
77    for (
78      const it = tResult.iter({
79        utid: NUM,
80        tid: NUM,
81        threadName: STR_NULL,
82        upid: NUM_NULL,
83      });
84      it.valid();
85      it.next()
86    ) {
87      const {threadName, utid, tid, upid} = it;
88      const title =
89        threadName === null
90          ? `Thread Callstacks ${tid}`
91          : `${threadName} Callstacks ${tid}`;
92      const uri = `${getThreadUriPrefix(upid, utid)}_perf_samples_profile`;
93      ctx.tracks.registerTrack({
94        uri,
95        title,
96        tags: {
97          kind: PERF_SAMPLES_PROFILE_TRACK_KIND,
98          utid,
99          upid: upid ?? undefined,
100        },
101        track: new ThreadPerfSamplesProfileTrack(ctx, uri, utid),
102      });
103      const group = ctx.plugins
104        .getPlugin(ProcessThreadGroupsPlugin)
105        .getGroupForThread(utid);
106      const track = new TrackNode({uri, title, sortOrder: -50});
107      group?.addChildInOrder(track);
108    }
109
110    ctx.onTraceReady.addListener(async () => {
111      await selectPerfSample(ctx);
112    });
113  }
114}
115
116async function selectPerfSample(ctx: Trace) {
117  const profile = await assertExists(ctx.engine).query(`
118    select upid
119    from perf_sample
120    join thread using (utid)
121    where callsite_id is not null
122    order by ts desc
123    limit 1
124  `);
125  if (profile.numRows() !== 1) return;
126  const row = profile.firstRow({upid: NUM});
127  const upid = row.upid;
128
129  // Create an area selection over the first process with a perf samples track
130  ctx.selection.selectArea({
131    start: ctx.traceInfo.start,
132    end: ctx.traceInfo.end,
133    trackUris: [makeUriForProc(upid)],
134  });
135}
136