• 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 m from 'mithril';
16
17import {Actions} from '../common/actions';
18import {translateState} from '../common/thread_state';
19import {tpTimeToCode} from '../common/time';
20import {globals, SliceDetails, ThreadDesc} from './globals';
21import {scrollToTrackAndTs} from './scroll_helper';
22import {SlicePanel} from './slice_panel';
23
24export class SliceDetailsPanel extends SlicePanel {
25  view() {
26    const sliceInfo = globals.sliceDetails;
27    if (sliceInfo.utid === undefined) return;
28    const threadInfo = globals.threads.get(sliceInfo.utid);
29
30    return m(
31        '.details-panel',
32        m(
33            '.details-panel-heading',
34            m('h2.split', `Slice Details`),
35            this.hasSchedLatencyInfo(sliceInfo) &&
36                m('h2.split', 'Scheduling Latency'),
37            ),
38        this.renderDetails(sliceInfo, threadInfo));
39  }
40
41  private renderSchedLatencyInfo(sliceInfo: SliceDetails): m.Children {
42    if (!this.hasSchedLatencyInfo(sliceInfo)) {
43      return null;
44    }
45    return m(
46        '.half-width-panel.slice-details-latency-panel',
47        m('img.slice-details-image', {
48          src: `${globals.root}assets/scheduling_latency.png`,
49        }),
50        this.renderWakeupText(sliceInfo),
51        this.renderDisplayLatencyText(sliceInfo),
52    );
53  }
54
55  private renderWakeupText(sliceInfo: SliceDetails): m.Children {
56    if (sliceInfo.wakerUtid === undefined) {
57      return null;
58    }
59    const threadInfo = globals.threads.get(sliceInfo.wakerUtid!);
60    if (!threadInfo) {
61      return null;
62    }
63    const timestamp =
64        tpTimeToCode(sliceInfo.wakeupTs! - globals.state.traceTime.start);
65    return m(
66        '.slice-details-wakeup-text',
67        m('', `Wakeup @ ${timestamp} on CPU ${sliceInfo.wakerCpu} by`),
68        m('', `P: ${threadInfo.procName} [${threadInfo.pid}]`),
69        m('', `T: ${threadInfo.threadName} [${threadInfo.tid}]`),
70    );
71  }
72
73  private renderDisplayLatencyText(sliceInfo: SliceDetails): m.Children {
74    if (sliceInfo.ts === undefined || sliceInfo.wakeupTs === undefined) {
75      return null;
76    }
77
78    const latency = tpTimeToCode(sliceInfo.ts - sliceInfo.wakeupTs);
79    return m(
80        '.slice-details-latency-text',
81        m('', `Scheduling latency: ${latency}`),
82        m('.text-detail',
83          `This is the interval from when the task became eligible to run
84        (e.g. because of notifying a wait queue it was suspended on) to
85        when it started running.`),
86    );
87  }
88
89  private hasSchedLatencyInfo({wakeupTs, wakerUtid}: SliceDetails): boolean {
90    return wakeupTs !== undefined && wakerUtid !== undefined;
91  }
92
93  private renderDetails(sliceInfo: SliceDetails, threadInfo?: ThreadDesc):
94      m.Children {
95    if (!threadInfo || sliceInfo.ts === undefined ||
96        sliceInfo.dur === undefined) {
97      return null;
98    } else {
99      const tableRows = [
100        m('tr',
101          m('th', `Process`),
102          m('td', `${threadInfo.procName} [${threadInfo.pid}]`)),
103        m('tr',
104          m('th', `Thread`),
105          m('td',
106            `${threadInfo.threadName} [${threadInfo.tid}]`,
107            m('i.material-icons.grey',
108              {onclick: () => this.goToThread(), title: 'Go to thread'},
109              'call_made'))),
110        m('tr', m('th', `Cmdline`), m('td', threadInfo.cmdline)),
111        m('tr',
112          m('th', `Start time`),
113          m('td',
114            `${tpTimeToCode(sliceInfo.ts - globals.state.traceTime.start)}`)),
115        m('tr',
116          m('th', `Duration`),
117          m('td', this.computeDuration(sliceInfo.ts, sliceInfo.dur))),
118        (sliceInfo.threadDur === undefined ||
119         sliceInfo.threadTs === undefined) ?
120            '' :
121            m('tr',
122              m('th', 'Thread duration'),
123              m('td',
124                this.computeDuration(sliceInfo.threadTs, sliceInfo.threadDur))),
125        m('tr', m('th', `Prio`), m('td', `${sliceInfo.priority}`)),
126        m('tr',
127          m('th', `End State`),
128          m('td', translateState(sliceInfo.endState))),
129        m('tr',
130          m('th', `Slice ID`),
131          m('td',
132            (sliceInfo.id !== undefined) ? sliceInfo.id.toString() :
133                                           'Unknown')),
134      ];
135
136      for (const [key, value] of this.getProcessThreadDetails(sliceInfo)) {
137        if (value !== undefined) {
138          tableRows.push(m('tr', m('th', key), m('td', value)));
139        }
140      }
141
142      return m(
143          '.details-table-multicolumn',
144          m('table.half-width-panel', tableRows),
145          this.renderSchedLatencyInfo(sliceInfo),
146      );
147    }
148  }
149
150  goToThread() {
151    const sliceInfo = globals.sliceDetails;
152    if (sliceInfo.utid === undefined) return;
153    const threadInfo = globals.threads.get(sliceInfo.utid);
154
155    if (sliceInfo.id === undefined || sliceInfo.ts === undefined ||
156        sliceInfo.dur === undefined || sliceInfo.cpu === undefined ||
157        threadInfo === undefined) {
158      return;
159    }
160
161    let trackId: string|number|undefined;
162    for (const track of Object.values(globals.state.tracks)) {
163      if (track.kind === 'ThreadStateTrack' &&
164          (track.config as {utid: number}).utid === threadInfo.utid) {
165        trackId = track.id;
166      }
167    }
168
169    if (trackId && sliceInfo.threadStateId) {
170      globals.makeSelection(Actions.selectThreadState({
171        id: sliceInfo.threadStateId,
172        trackId: trackId.toString(),
173      }));
174
175      scrollToTrackAndTs(trackId, sliceInfo.ts, true);
176    }
177  }
178
179  renderCanvas() {}
180}
181