• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2020 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 {ColumnDef, Sorting, ThreadStateExtra} from '../../public/aggregation';
16import {AreaSelection} from '../../public/selection';
17import {Engine} from '../../trace_processor/engine';
18import {
19  LONG,
20  NUM,
21  NUM_NULL,
22  STR,
23  STR_NULL,
24} from '../../trace_processor/query_result';
25import {AreaSelectionAggregator} from '../../public/selection';
26import {Dataset} from '../../trace_processor/dataset';
27import {translateState} from '../../components/sql_utils/thread_state';
28
29export class ThreadStateSelectionAggregator implements AreaSelectionAggregator {
30  readonly id = 'thread_state_aggregation';
31
32  readonly schema = {
33    dur: LONG,
34    io_wait: NUM_NULL,
35    state: STR,
36    utid: NUM,
37  } as const;
38
39  async createAggregateView(
40    engine: Engine,
41    area: AreaSelection,
42    dataset?: Dataset,
43  ) {
44    if (dataset === undefined) return false;
45
46    await engine.query(`
47      create or replace perfetto table ${this.id} as
48      select
49        process.name as process_name,
50        process.pid,
51        thread.name as thread_name,
52        thread.tid,
53        tstate.state || ',' || ifnull(tstate.io_wait, 'NULL') as concat_state,
54        sum(tstate.dur) AS total_dur,
55        sum(tstate.dur) / count() as avg_dur,
56        count() as occurrences
57      from (${dataset.query()}) tstate
58      join thread using (utid)
59      left join process using (upid)
60      where
61        ts + dur > ${area.start}
62        and ts < ${area.end}
63      group by utid, concat_state
64    `);
65
66    return true;
67  }
68
69  async getExtra(
70    engine: Engine,
71    area: AreaSelection,
72    dataset?: Dataset,
73  ): Promise<ThreadStateExtra | void> {
74    if (dataset === undefined) return;
75
76    const query = `
77      select
78        state,
79        io_wait as ioWait,
80        sum(dur) as totalDur
81      from (${dataset.query()}) tstate
82      join thread using (utid)
83      where tstate.ts + tstate.dur > ${area.start}
84        and tstate.ts < ${area.end}
85      group by state, io_wait
86    `;
87    const result = await engine.query(query);
88
89    const it = result.iter({
90      state: STR_NULL,
91      ioWait: NUM_NULL,
92      totalDur: NUM,
93    });
94
95    let totalMs = 0;
96    const values = new Float64Array(result.numRows());
97    const states = [];
98    for (let i = 0; it.valid(); ++i, it.next()) {
99      const state = it.state == null ? undefined : it.state;
100      const ioWait = it.ioWait === null ? undefined : it.ioWait > 0;
101      states.push(translateState(state, ioWait));
102      const ms = it.totalDur / 1000000;
103      values[i] = ms;
104      totalMs += ms;
105    }
106    return {
107      kind: 'THREAD_STATE',
108      states,
109      values,
110      totalMs,
111    };
112  }
113
114  getColumnDefinitions(): ColumnDef[] {
115    return [
116      {
117        title: 'Process',
118        kind: 'STRING',
119        columnConstructor: Uint16Array,
120        columnId: 'process_name',
121      },
122      {
123        title: 'PID',
124        kind: 'NUMBER',
125        columnConstructor: Uint16Array,
126        columnId: 'pid',
127      },
128      {
129        title: 'Thread',
130        kind: 'STRING',
131        columnConstructor: Uint16Array,
132        columnId: 'thread_name',
133      },
134      {
135        title: 'TID',
136        kind: 'NUMBER',
137        columnConstructor: Uint16Array,
138        columnId: 'tid',
139      },
140      {
141        title: 'State',
142        kind: 'STATE',
143        columnConstructor: Uint16Array,
144        columnId: 'concat_state',
145      },
146      {
147        title: 'Wall duration (ms)',
148        kind: 'TIMESTAMP_NS',
149        columnConstructor: Float64Array,
150        columnId: 'total_dur',
151        sum: true,
152      },
153      {
154        title: 'Avg Wall duration (ms)',
155        kind: 'TIMESTAMP_NS',
156        columnConstructor: Float64Array,
157        columnId: 'avg_dur',
158      },
159      {
160        title: 'Occurrences',
161        kind: 'NUMBER',
162        columnConstructor: Uint16Array,
163        columnId: 'occurrences',
164        sum: true,
165      },
166    ];
167  }
168
169  getTabName() {
170    return 'Thread States';
171  }
172
173  getDefaultSorting(): Sorting {
174    return {column: 'total_dur', direction: 'DESC'};
175  }
176}
177