|  | // Copyright (C) 2019 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use size file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | import * as m from 'mithril'; | 
|  |  | 
|  | import {Actions} from '../common/actions'; | 
|  | import {timeToCode, toNs} from '../common/time'; | 
|  |  | 
|  | import {globals} from './globals'; | 
|  | import {Panel, PanelSize} from './panel'; | 
|  | import {scrollToTrackAndTs} from './scroll_helper'; | 
|  |  | 
|  |  | 
|  | export class ThreadStatePanel extends Panel { | 
|  | view() { | 
|  | const threadState = globals.threadStateDetails; | 
|  | if (threadState === undefined || threadState.utid === undefined || | 
|  | threadState.ts === undefined || threadState.dur === undefined || | 
|  | threadState.state === undefined) { | 
|  | return m('.details-panel'); | 
|  | } | 
|  | const threadInfo = globals.threads.get(threadState.utid); | 
|  | if (threadInfo) { | 
|  | return m( | 
|  | '.details-panel', | 
|  | m('.details-panel-heading', m('h2', 'Thread State')), | 
|  | m('.details-table', [m('table.half-width', [ | 
|  | m('tr', | 
|  | m('th', `Start time`), | 
|  | m('td', `${timeToCode(threadState.ts)}`)), | 
|  | m('tr', | 
|  | m('th', `Duration`), | 
|  | m( | 
|  | 'td', | 
|  | `${timeToCode(threadState.dur)} `, | 
|  | )), | 
|  | m('tr', | 
|  | m('th', `State`), | 
|  | m('td', | 
|  | this.getStateContent( | 
|  | threadState.state, | 
|  | threadState.cpu, | 
|  | threadState.sliceId, | 
|  | threadState.ts))), | 
|  | m('tr', | 
|  | m('th', `Process`), | 
|  | m('td', `${threadInfo.procName} [${threadInfo.pid}]`)), | 
|  | this.getBlockedFunctionContent(threadState.blockedFunction), | 
|  | ])])); | 
|  | } | 
|  | return m('.details-panel'); | 
|  | } | 
|  |  | 
|  | renderCanvas(_ctx: CanvasRenderingContext2D, _size: PanelSize) {} | 
|  |  | 
|  | // If it is the running state, we want to show which CPU and a button to | 
|  | // go to the sched slice. Otherwise, just show the state. | 
|  | getStateContent( | 
|  | state: string, cpu: number|undefined, sliceId: number|undefined, | 
|  | ts: number) { | 
|  | if (sliceId === undefined || cpu === undefined) { | 
|  | return [state]; | 
|  | } | 
|  |  | 
|  | return [ | 
|  | `${state} on CPU ${cpu}`, | 
|  | m( | 
|  | 'i.material-icons.grey', | 
|  | { | 
|  | onclick: () => { | 
|  | // TODO(hjd): Use trackId from TP. | 
|  | let trackId; | 
|  | for (const track of Object.values(globals.state.tracks)) { | 
|  | if (track.kind === 'CpuSliceTrack' && | 
|  | (track.config as {cpu: number}).cpu === cpu) { | 
|  | trackId = track.id; | 
|  | } | 
|  | } | 
|  | if (trackId) { | 
|  | globals.makeSelection( | 
|  | Actions.selectSlice({id: sliceId, trackId})); | 
|  | scrollToTrackAndTs( | 
|  | trackId, toNs(ts + globals.state.traceTime.startSec)); | 
|  | } | 
|  | }, | 
|  | title: 'Go to CPU slice' | 
|  | }, | 
|  | 'call_made') | 
|  | ]; | 
|  | } | 
|  |  | 
|  | getBlockedFunctionContent(blockedFunction: string|undefined) { | 
|  | if (blockedFunction === undefined) { | 
|  | return null; | 
|  | } | 
|  | return m('tr', m('th', `Blocked Function`), m('td', blockedFunction)); | 
|  | } | 
|  | } |