| // Copyright (C) 2018 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| import * as protos from '../gen/protos'; |
| import {slowlyCountRows} from './query_iterator'; |
| |
| // Aliases protos to avoid the super nested namespaces. |
| // See https://www.typescriptlang.org/docs/handbook/namespaces.html#aliases |
| import AndroidLogConfig = protos.perfetto.protos.AndroidLogConfig; |
| import AndroidPowerConfig = protos.perfetto.protos.AndroidPowerConfig; |
| import AndroidLogId = protos.perfetto.protos.AndroidLogId; |
| import BatteryCounters = |
| protos.perfetto.protos.AndroidPowerConfig.BatteryCounters; |
| import BufferConfig = protos.perfetto.protos.TraceConfig.BufferConfig; |
| import ChromeConfig = protos.perfetto.protos.ChromeConfig; |
| import ConsumerPort = protos.perfetto.protos.ConsumerPort; |
| import NativeContinuousDumpConfig = |
| protos.perfetto.protos.HeapprofdConfig.ContinuousDumpConfig; |
| import JavaContinuousDumpConfig = |
| protos.perfetto.protos.JavaHprofConfig.ContinuousDumpConfig; |
| import DataSourceConfig = protos.perfetto.protos.DataSourceConfig; |
| import FtraceConfig = protos.perfetto.protos.FtraceConfig; |
| import HeapprofdConfig = protos.perfetto.protos.HeapprofdConfig; |
| import JavaHprofConfig = protos.perfetto.protos.JavaHprofConfig; |
| import IAndroidPowerConfig = protos.perfetto.protos.IAndroidPowerConfig; |
| import IBufferConfig = protos.perfetto.protos.TraceConfig.IBufferConfig; |
| import IProcessStatsConfig = protos.perfetto.protos.IProcessStatsConfig; |
| import ISysStatsConfig = protos.perfetto.protos.ISysStatsConfig; |
| import ITraceConfig = protos.perfetto.protos.ITraceConfig; |
| import MeminfoCounters = protos.perfetto.protos.MeminfoCounters; |
| import ProcessStatsConfig = protos.perfetto.protos.ProcessStatsConfig; |
| import StatCounters = protos.perfetto.protos.SysStatsConfig.StatCounters; |
| import SysStatsConfig = protos.perfetto.protos.SysStatsConfig; |
| import TraceConfig = protos.perfetto.protos.TraceConfig; |
| import VmstatCounters = protos.perfetto.protos.VmstatCounters; |
| |
| // Trace Processor protos. |
| import IRawQueryArgs = protos.perfetto.protos.IRawQueryArgs; |
| import QueryArgs = protos.perfetto.protos.QueryArgs; |
| import RawQueryArgs = protos.perfetto.protos.RawQueryArgs; |
| import RawQueryResult = protos.perfetto.protos.RawQueryResult; |
| import StatusResult = protos.perfetto.protos.StatusResult; |
| import ComputeMetricArgs = protos.perfetto.protos.ComputeMetricArgs; |
| import ComputeMetricResult = protos.perfetto.protos.ComputeMetricResult; |
| |
| // TODO(hjd): Maybe these should go in their own file. |
| export interface Row { [key: string]: number|string; } |
| |
| const COLUMN_TYPE_STR = RawQueryResult.ColumnDesc.Type.STRING; |
| const COLUMN_TYPE_DOUBLE = RawQueryResult.ColumnDesc.Type.DOUBLE; |
| const COLUMN_TYPE_LONG = RawQueryResult.ColumnDesc.Type.LONG; |
| |
| function getCell(result: RawQueryResult, column: number, row: number): number| |
| string|null { |
| const values = result.columns[column]; |
| if (values.isNulls![row]) return null; |
| switch (result.columnDescriptors[column].type) { |
| case COLUMN_TYPE_LONG: |
| return +values.longValues![row]; |
| case COLUMN_TYPE_DOUBLE: |
| return +values.doubleValues![row]; |
| case COLUMN_TYPE_STR: |
| return values.stringValues![row]; |
| default: |
| throw new Error('Unhandled type!'); |
| } |
| } |
| |
| export function rawQueryResultColumns(result: RawQueryResult): string[] { |
| // Two columns can conflict on the same name, e.g. |
| // select x.foo, y.foo from x join y. In that case store them using the |
| // full table.column notation. |
| const res = [] as string[]; |
| const uniqColNames = new Set<string>(); |
| const colNamesToDedupe = new Set<string>(); |
| for (const col of result.columnDescriptors) { |
| const colName = col.name || ''; |
| if (uniqColNames.has(colName)) { |
| colNamesToDedupe.add(colName); |
| } |
| uniqColNames.add(colName); |
| } |
| for (let i = 0; i < result.columnDescriptors.length; i++) { |
| const colName = result.columnDescriptors[i].name || ''; |
| if (colNamesToDedupe.has(colName)) { |
| res.push(`${colName}.${i + 1}`); |
| } else { |
| res.push(colName); |
| } |
| } |
| return res; |
| } |
| |
| export function* rawQueryResultIter(result: RawQueryResult) { |
| const columns: Array<[string, number]> = rawQueryResultColumns(result).map( |
| (name, i): [string, number] => [name, i]); |
| for (let rowNum = 0; rowNum < slowlyCountRows(result); rowNum++) { |
| const row: Row = {}; |
| for (const [name, colNum] of columns) { |
| const cell = getCell(result, colNum, rowNum); |
| row[name] = cell === null ? '[NULL]' : cell; |
| } |
| yield row; |
| } |
| } |
| |
| export { |
| AndroidLogConfig, |
| AndroidLogId, |
| AndroidPowerConfig, |
| BatteryCounters, |
| BufferConfig, |
| ChromeConfig, |
| ConsumerPort, |
| ComputeMetricArgs, |
| ComputeMetricResult, |
| DataSourceConfig, |
| FtraceConfig, |
| HeapprofdConfig, |
| IAndroidPowerConfig, |
| IBufferConfig, |
| IProcessStatsConfig, |
| IRawQueryArgs, |
| ISysStatsConfig, |
| ITraceConfig, |
| JavaContinuousDumpConfig, |
| JavaHprofConfig, |
| MeminfoCounters, |
| NativeContinuousDumpConfig, |
| ProcessStatsConfig, |
| QueryArgs, |
| RawQueryArgs, |
| RawQueryResult, |
| StatCounters, |
| StatusResult, |
| SysStatsConfig, |
| TraceConfig, |
| VmstatCounters, |
| }; |