• 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 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 {Engine} from '../common/engine';
16import {fromNs} from '../common/time';
17import {SliceDetails} from '../frontend/globals';
18
19import {Controller} from './controller';
20import {globals} from './globals';
21
22export interface SelectionControllerArgs {
23  engine: Engine;
24}
25
26// This class queries the TP for the details on a specific slice that has
27// been clicked.
28export class SelectionController extends Controller<'main'> {
29  private lastSelectedSlice?: number;
30  constructor(private args: SelectionControllerArgs) {
31    super('main');
32  }
33
34  run() {
35    const selection = globals.state.currentSelection;
36    if (selection === null ||
37        selection.kind !== 'SLICE' ||
38        selection.id === this.lastSelectedSlice) {
39      return;
40    }
41    const selectedSlice = selection.id;
42    this.lastSelectedSlice = selectedSlice;
43
44    if (selectedSlice !== undefined) {
45      const sqlQuery = `SELECT ts, dur, priority, end_state, utid FROM sched
46                        WHERE row_id = ${selectedSlice}`;
47      this.args.engine.query(sqlQuery).then(result => {
48        // Check selection is still the same on completion of query.
49        const selection = globals.state.currentSelection;
50        if (result.numRecords === 1 &&
51            selection &&
52            selection.kind === 'SLICE' &&
53            selection.id === selectedSlice) {
54          const ts = result.columns[0].longValues![0] as number;
55          const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
56          const dur = fromNs(result.columns[1].longValues![0] as number);
57          const priority = result.columns[2].longValues![0] as number;
58          const endState = result.columns[3].stringValues![0];
59          const selected:
60              SliceDetails = {ts: timeFromStart, dur, priority, endState};
61          const utid = result.columns[4].longValues![0];
62          this.schedulingDetails(ts, utid).then(wakeResult => {
63            Object.assign(selected, wakeResult);
64            globals.publish('SliceDetails', selected);
65          });
66        }
67      });
68    }
69  }
70
71  async schedulingDetails(ts: number, utid: number|Long) {
72    // Find the ts of the first sched_wakeup before the current slice.
73    const queryWakeupTs = `select ts from instants where name = 'sched_wakeup'
74    and ref = ${utid} and ts < ${ts} order by ts desc limit 1`;
75    const wakeupRow = await this.args.engine.queryOneRow(queryWakeupTs);
76    // Find the previous sched slice for the current utid.
77    const queryPrevSched = `select ts from sched where utid = ${utid}
78    and ts < ${ts} order by ts desc limit 1`;
79    const prevSchedRow = await this.args.engine.queryOneRow(queryPrevSched);
80    // If this is the first sched slice for this utid or if the wakeup found
81    // was after the previous slice then we know the wakeup was for this slice.
82    if (prevSchedRow[0] && wakeupRow[0] < prevSchedRow[0]) {
83      return undefined;
84    }
85    const wakeupTs = wakeupRow[0];
86    // Find the sched slice with the utid of the waker running when the
87    // sched wakeup occurred. This is the waker.
88    const queryWaker = `select utid, cpu from sched where utid =
89    (select utid from raw where name = 'sched_wakeup' and ts = ${wakeupTs})
90    and ts < ${wakeupTs} and ts + dur >= ${wakeupTs};`;
91    const wakerRow = await this.args.engine.queryOneRow(queryWaker);
92    if (wakerRow) {
93      return {
94        wakeupTs: fromNs(wakeupTs),
95        wakerUtid: wakerRow[0],
96        wakerCpu: wakerRow[1]
97      };
98    } else {
99      return undefined;
100    }
101  }
102}
103