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