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 {createThreadStateTrack} 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'; 25import {createAggregationToTabAdaptor} from '../../components/aggregation_adapter'; 26 27function uriForThreadStateTrack(upid: number | null, utid: number): string { 28 return `${getThreadUriPrefix(upid, utid)}_state`; 29} 30 31export default class implements PerfettoPlugin { 32 static readonly id = 'dev.perfetto.ThreadState'; 33 static readonly dependencies = [ProcessThreadGroupsPlugin]; 34 35 async onTraceLoad(ctx: Trace): Promise<void> { 36 const {engine} = ctx; 37 38 ctx.selection.registerAreaSelectionTab( 39 createAggregationToTabAdaptor(ctx, new ThreadStateSelectionAggregator()), 40 ); 41 42 const result = await engine.query(` 43 include perfetto module viz.threads; 44 include perfetto module viz.summary.threads; 45 46 select 47 utid, 48 t.upid, 49 tid, 50 t.name as threadName, 51 is_main_thread as isMainThread, 52 is_kernel_thread as isKernelThread 53 from _threads_with_kernel_flag t 54 join _sched_summary using (utid) 55 `); 56 57 const it = result.iter({ 58 utid: NUM, 59 upid: NUM_NULL, 60 tid: NUM_NULL, 61 threadName: STR_NULL, 62 isMainThread: NUM_NULL, 63 isKernelThread: NUM, 64 }); 65 for (; it.valid(); it.next()) { 66 const {utid, upid, tid, threadName, isMainThread, isKernelThread} = it; 67 const title = getTrackName({ 68 utid, 69 tid, 70 threadName, 71 kind: THREAD_STATE_TRACK_KIND, 72 }); 73 74 const uri = uriForThreadStateTrack(upid, utid); 75 ctx.tracks.registerTrack({ 76 uri, 77 title, 78 tags: { 79 kind: THREAD_STATE_TRACK_KIND, 80 utid, 81 upid: upid ?? undefined, 82 ...(isKernelThread === 1 && {kernelThread: true}), 83 }, 84 chips: removeFalsyValues([ 85 isKernelThread === 0 && isMainThread === 1 && 'main thread', 86 ]), 87 track: createThreadStateTrack(ctx, uri, utid), 88 }); 89 90 const group = ctx.plugins 91 .getPlugin(ProcessThreadGroupsPlugin) 92 .getGroupForThread(utid); 93 const track = new TrackNode({uri, title, sortOrder: 10}); 94 group?.addChildInOrder(track); 95 } 96 } 97} 98