// 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 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(); const colNamesToDedupe = new Set(); 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, RawQueryArgs, RawQueryResult, StatCounters, StatusResult, SysStatsConfig, TraceConfig, VmstatCounters, };