1// Copyright (C) 2018 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 * as protos from '../gen/protos';
16import {slowlyCountRows} from './query_iterator';
17
18// Aliases protos to avoid the super nested namespaces.
19// See https://www.typescriptlang.org/docs/handbook/namespaces.html#aliases
20import AndroidLogConfig = protos.perfetto.protos.AndroidLogConfig;
21import AndroidPowerConfig = protos.perfetto.protos.AndroidPowerConfig;
22import AndroidLogId = protos.perfetto.protos.AndroidLogId;
23import BatteryCounters =
24    protos.perfetto.protos.AndroidPowerConfig.BatteryCounters;
25import BufferConfig = protos.perfetto.protos.TraceConfig.BufferConfig;
26import ChromeConfig = protos.perfetto.protos.ChromeConfig;
27import ConsumerPort = protos.perfetto.protos.ConsumerPort;
28import NativeContinuousDumpConfig =
29    protos.perfetto.protos.HeapprofdConfig.ContinuousDumpConfig;
30import JavaContinuousDumpConfig =
31    protos.perfetto.protos.JavaHprofConfig.ContinuousDumpConfig;
32import DataSourceConfig = protos.perfetto.protos.DataSourceConfig;
33import FtraceConfig = protos.perfetto.protos.FtraceConfig;
34import HeapprofdConfig = protos.perfetto.protos.HeapprofdConfig;
35import JavaHprofConfig = protos.perfetto.protos.JavaHprofConfig;
36import IAndroidPowerConfig = protos.perfetto.protos.IAndroidPowerConfig;
37import IBufferConfig = protos.perfetto.protos.TraceConfig.IBufferConfig;
38import IProcessStatsConfig = protos.perfetto.protos.IProcessStatsConfig;
39import ISysStatsConfig = protos.perfetto.protos.ISysStatsConfig;
40import ITraceConfig = protos.perfetto.protos.ITraceConfig;
41import MeminfoCounters = protos.perfetto.protos.MeminfoCounters;
42import ProcessStatsConfig = protos.perfetto.protos.ProcessStatsConfig;
43import StatCounters = protos.perfetto.protos.SysStatsConfig.StatCounters;
44import SysStatsConfig = protos.perfetto.protos.SysStatsConfig;
45import TraceConfig = protos.perfetto.protos.TraceConfig;
46import VmstatCounters = protos.perfetto.protos.VmstatCounters;
47
48// Trace Processor protos.
49import IRawQueryArgs = protos.perfetto.protos.IRawQueryArgs;
50import RawQueryArgs = protos.perfetto.protos.RawQueryArgs;
51import RawQueryResult = protos.perfetto.protos.RawQueryResult;
52import StatusResult = protos.perfetto.protos.StatusResult;
53import ComputeMetricArgs = protos.perfetto.protos.ComputeMetricArgs;
54import ComputeMetricResult = protos.perfetto.protos.ComputeMetricResult;
55
56// TODO(hjd): Maybe these should go in their own file.
57export interface Row { [key: string]: number|string; }
58
59const COLUMN_TYPE_STR = RawQueryResult.ColumnDesc.Type.STRING;
60const COLUMN_TYPE_DOUBLE = RawQueryResult.ColumnDesc.Type.DOUBLE;
61const COLUMN_TYPE_LONG = RawQueryResult.ColumnDesc.Type.LONG;
62
63function getCell(result: RawQueryResult, column: number, row: number): number|
64    string|null {
65  const values = result.columns[column];
66  if (values.isNulls![row]) return null;
67  switch (result.columnDescriptors[column].type) {
68    case COLUMN_TYPE_LONG:
69      return +values.longValues![row];
70    case COLUMN_TYPE_DOUBLE:
71      return +values.doubleValues![row];
72    case COLUMN_TYPE_STR:
73      return values.stringValues![row];
74    default:
75      throw new Error('Unhandled type!');
76  }
77}
78
79export function rawQueryResultColumns(result: RawQueryResult): string[] {
80  // Two columns can conflict on the same name, e.g.
81  // select x.foo, y.foo from x join y. In that case store them using the
82  // full table.column notation.
83  const res = [] as string[];
84  const uniqColNames = new Set<string>();
85  const colNamesToDedupe = new Set<string>();
86  for (const col of result.columnDescriptors) {
87    const colName = col.name || '';
88    if (uniqColNames.has(colName)) {
89      colNamesToDedupe.add(colName);
90    }
91    uniqColNames.add(colName);
92  }
93  for (let i = 0; i < result.columnDescriptors.length; i++) {
94    const colName = result.columnDescriptors[i].name || '';
95    if (colNamesToDedupe.has(colName)) {
96      res.push(`${colName}.${i + 1}`);
97    } else {
98      res.push(colName);
99    }
100  }
101  return res;
102}
103
104export function* rawQueryResultIter(result: RawQueryResult) {
105  const columns: Array<[string, number]> = rawQueryResultColumns(result).map(
106      (name, i): [string, number] => [name, i]);
107  for (let rowNum = 0; rowNum < slowlyCountRows(result); rowNum++) {
108    const row: Row = {};
109    for (const [name, colNum] of columns) {
110      const cell = getCell(result, colNum, rowNum);
111      row[name] = cell === null ? '[NULL]' : cell;
112    }
113    yield row;
114  }
115}
116
117export {
118  AndroidLogConfig,
119  AndroidLogId,
120  AndroidPowerConfig,
121  BatteryCounters,
122  BufferConfig,
123  ChromeConfig,
124  ConsumerPort,
125  ComputeMetricArgs,
126  ComputeMetricResult,
127  DataSourceConfig,
128  FtraceConfig,
129  HeapprofdConfig,
130  IAndroidPowerConfig,
131  IBufferConfig,
132  IProcessStatsConfig,
133  IRawQueryArgs,
134  ISysStatsConfig,
135  ITraceConfig,
136  JavaContinuousDumpConfig,
137  JavaHprofConfig,
138  MeminfoCounters,
139  NativeContinuousDumpConfig,
140  ProcessStatsConfig,
141  RawQueryArgs,
142  RawQueryResult,
143  StatCounters,
144  StatusResult,
145  SysStatsConfig,
146  TraceConfig,
147  VmstatCounters,
148};
149