xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.ThreadState/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 {THREAD_STATE_TRACK_KIND} from '../../public/track_kinds';
16import {Trace} from '../../public/trace';
17import {PerfettoPlugin} from '../../public/plugin';
18import {getThreadUriPrefix, getTrackName} from '../../public/utils';
19import {NUM, NUM_NULL, STR_NULL} from '../../trace_processor/query_result';
20import {ThreadStateTrack} from './thread_state_track';
21import {removeFalsyValues} from '../../base/array_utils';
22import {TrackNode} from '../../public/workspace';
23import {ThreadStateSelectionAggregator} from './thread_state_selection_aggregator';
24import ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups';
25
26function uriForThreadStateTrack(upid: number | null, utid: number): string {
27  return `${getThreadUriPrefix(upid, utid)}_state`;
28}
29
30export default class implements PerfettoPlugin {
31  static readonly id = 'dev.perfetto.ThreadState';
32  static readonly dependencies = [ProcessThreadGroupsPlugin];
33
34  async onTraceLoad(ctx: Trace): Promise<void> {
35    const {engine} = ctx;
36
37    ctx.selection.registerAreaSelectionAggregator(
38      new ThreadStateSelectionAggregator(),
39    );
40
41    const result = await engine.query(`
42      include perfetto module viz.threads;
43      include perfetto module viz.summary.threads;
44
45      select
46        utid,
47        t.upid,
48        tid,
49        t.name as threadName,
50        is_main_thread as isMainThread,
51        is_kernel_thread as isKernelThread
52      from _threads_with_kernel_flag t
53      join _sched_summary using (utid)
54    `);
55
56    const it = result.iter({
57      utid: NUM,
58      upid: NUM_NULL,
59      tid: NUM_NULL,
60      threadName: STR_NULL,
61      isMainThread: NUM_NULL,
62      isKernelThread: NUM,
63    });
64    for (; it.valid(); it.next()) {
65      const {utid, upid, tid, threadName, isMainThread, isKernelThread} = it;
66      const title = getTrackName({
67        utid,
68        tid,
69        threadName,
70        kind: THREAD_STATE_TRACK_KIND,
71      });
72
73      const uri = uriForThreadStateTrack(upid, utid);
74      ctx.tracks.registerTrack({
75        uri,
76        title,
77        tags: {
78          kind: THREAD_STATE_TRACK_KIND,
79          utid,
80          upid: upid ?? undefined,
81          ...(isKernelThread === 1 && {kernelThread: true}),
82        },
83        chips: removeFalsyValues([
84          isKernelThread === 0 && isMainThread === 1 && 'main thread',
85        ]),
86        track: new ThreadStateTrack(ctx, uri, utid),
87      });
88
89      const group = ctx.plugins
90        .getPlugin(ProcessThreadGroupsPlugin)
91        .getGroupForThread(utid);
92      const track = new TrackNode({uri, title, sortOrder: 10});
93      group?.addChildInOrder(track);
94    }
95
96    ctx.selection.registerSqlSelectionResolver({
97      sqlTableName: 'thread_state',
98      callback: async (id: number) => {
99        const result = await ctx.engine.query(`
100          select
101            thread_state.utid,
102            thread.upid
103          from
104            thread_state
105            join thread on thread_state.utid = thread.id
106          where thread_state.id = ${id}
107        `);
108
109        const {upid, utid} = result.firstRow({
110          upid: NUM_NULL,
111          utid: NUM,
112        });
113
114        return {
115          eventId: id,
116          trackUri: uriForThreadStateTrack(upid, utid),
117        };
118      },
119    });
120  }
121}
122