• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use size 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 * as m from 'mithril';
16
17import {Actions} from '../common/actions';
18import {drawDoubleHeadedArrow} from '../common/canvas_utils';
19import {translateState} from '../common/thread_state';
20import {timeToCode, toNs} from '../common/time';
21
22import {globals, SliceDetails, ThreadDesc} from './globals';
23import {PanelSize} from './panel';
24import {scrollToTrackAndTs} from './scroll_helper';
25import {SlicePanel} from './slice_panel';
26
27export class SliceDetailsPanel extends SlicePanel {
28  view() {
29    const sliceInfo = globals.sliceDetails;
30    if (sliceInfo.utid === undefined) return;
31    const threadInfo = globals.threads.get(sliceInfo.utid);
32
33    return m(
34        '.details-panel',
35        m('.details-panel-heading',
36          m('h2.split', `Slice Details`),
37          (sliceInfo.wakeupTs && sliceInfo.wakerUtid) ?
38              m('h2.split', 'Scheduling Latency') :
39              ''),
40        this.getDetails(sliceInfo, threadInfo));
41  }
42
43  getDetails(sliceInfo: SliceDetails, threadInfo: ThreadDesc|undefined) {
44    if (!threadInfo || sliceInfo.ts === undefined ||
45        sliceInfo.dur === undefined) {
46      return null;
47    } else {
48      const tableRows = [
49        m('tr',
50          m('th', `Process`),
51          m('td', `${threadInfo.procName} [${threadInfo.pid}]`)),
52        m('tr',
53          m('th', `Thread`),
54          m('td',
55            `${threadInfo.threadName} [${threadInfo.tid}]`,
56            m('i.material-icons.grey',
57              {onclick: () => this.goToThread(), title: 'Go to thread'},
58              'call_made'))),
59        m('tr', m('th', `Cmdline`), m('td', threadInfo.cmdline)),
60        m('tr', m('th', `Start time`), m('td', `${timeToCode(sliceInfo.ts)}`)),
61        m('tr',
62          m('th', `Duration`),
63          m('td', this.computeDuration(sliceInfo.ts, sliceInfo.dur))),
64        (sliceInfo.thread_dur === undefined ||
65         sliceInfo.thread_ts === undefined) ?
66            '' :
67            m('tr',
68              m('th', 'Thread duration'),
69              m('td',
70                this.computeDuration(
71                    sliceInfo.thread_ts, sliceInfo.thread_dur))),
72        m('tr', m('th', `Prio`), m('td', `${sliceInfo.priority}`)),
73        m('tr',
74          m('th', `End State`),
75          m('td', translateState(sliceInfo.endState))),
76        m('tr',
77          m('th', `Slice ID`),
78          m('td', sliceInfo.id ? sliceInfo.id.toString() : 'Unknown'))
79      ];
80
81      for (const [key, value] of this.getProcessThreadDetails(sliceInfo)) {
82        if (value !== undefined) {
83          tableRows.push(m('tr', m('th', key), m('td', value)));
84        }
85      }
86
87      return m(
88          '.details-table',
89          m('table.half-width', tableRows),
90      );
91    }
92  }
93
94  goToThread() {
95    const sliceInfo = globals.sliceDetails;
96    if (sliceInfo.utid === undefined) return;
97    const threadInfo = globals.threads.get(sliceInfo.utid);
98
99    if (sliceInfo.id === undefined || sliceInfo.ts === undefined ||
100        sliceInfo.dur === undefined || sliceInfo.cpu === undefined ||
101        threadInfo === undefined) {
102      return;
103    }
104
105    let trackId: string|number|undefined;
106    for (const track of Object.values(globals.state.tracks)) {
107      if (track.kind === 'ThreadStateTrack' &&
108          (track.config as {utid: number}).utid === threadInfo.utid) {
109        trackId = track.id;
110      }
111    }
112
113    if (trackId && sliceInfo.threadStateId) {
114      globals.makeSelection(Actions.selectThreadState({
115        id: sliceInfo.threadStateId,
116        trackId: trackId.toString(),
117      }));
118
119      scrollToTrackAndTs(
120          trackId, toNs(sliceInfo.ts + globals.state.traceTime.startSec), true);
121    }
122  }
123
124
125  renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
126    const details = globals.sliceDetails;
127    // Show expanded details on the scheduling of the currently selected slice.
128    if (details.wakeupTs && details.wakerUtid !== undefined) {
129      const threadInfo = globals.threads.get(details.wakerUtid);
130      // Draw diamond and vertical line.
131      const startDraw = {x: size.width / 2 + 20, y: 52};
132      ctx.beginPath();
133      ctx.moveTo(startDraw.x, startDraw.y + 28);
134      ctx.fillStyle = 'black';
135      ctx.lineTo(startDraw.x + 6, startDraw.y + 20);
136      ctx.lineTo(startDraw.x, startDraw.y + 12);
137      ctx.lineTo(startDraw.x - 6, startDraw.y + 20);
138      ctx.fill();
139      ctx.closePath();
140      ctx.fillRect(startDraw.x - 1, startDraw.y, 2, 100);
141
142      // Wakeup explanation text.
143      ctx.font = '13px Roboto Condensed';
144      ctx.fillStyle = '#3c4b5d';
145      if (threadInfo) {
146        const displayText = `Wakeup @ ${
147            timeToCode(
148                details.wakeupTs - globals.state.traceTime.startSec)} on CPU ${
149            details.wakerCpu} by`;
150        const processText = `P: ${threadInfo.procName} [${threadInfo.pid}]`;
151        const threadText = `T: ${threadInfo.threadName} [${threadInfo.tid}]`;
152        ctx.fillText(displayText, startDraw.x + 20, startDraw.y + 20);
153        ctx.fillText(processText, startDraw.x + 20, startDraw.y + 37);
154        ctx.fillText(threadText, startDraw.x + 20, startDraw.y + 55);
155      }
156
157      // Draw latency arrow and explanation text.
158      drawDoubleHeadedArrow(ctx, startDraw.x, startDraw.y + 80, 60, true);
159      if (details.ts) {
160        const displayLatency = `Scheduling latency: ${
161            timeToCode(
162                details.ts -
163                (details.wakeupTs - globals.state.traceTime.startSec))}`;
164        ctx.fillText(displayLatency, startDraw.x + 70, startDraw.y + 86);
165        const explain1 =
166            'This is the interval from when the task became eligible to run';
167        const explain2 =
168            '(e.g. because of notifying a wait queue it was suspended on) to';
169        const explain3 = 'when it started running.';
170        ctx.font = '10px Roboto Condensed';
171        ctx.fillText(explain1, startDraw.x + 70, startDraw.y + 86 + 16);
172        ctx.fillText(explain2, startDraw.x + 70, startDraw.y + 86 + 16 + 12);
173        ctx.fillText(explain3, startDraw.x + 70, startDraw.y + 86 + 16 + 24);
174      }
175    }
176  }
177}
178