ui: Replace query with queryV2
Change-Id: I4d043e24ff4409eefe6c47e0d33b87b424ac013a
diff --git a/ui/src/controller/aggregation/aggregation_controller.ts b/ui/src/controller/aggregation/aggregation_controller.ts
index 96c91f9..d699b46 100644
--- a/ui/src/controller/aggregation/aggregation_controller.ts
+++ b/ui/src/controller/aggregation/aggregation_controller.ts
@@ -19,7 +19,7 @@
ThreadStateExtra,
} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
-import {NUM, slowlyCountRows} from '../../common/query_iterator';
+import {NUM, NUM_NULL, STR_NULL} from '../../common/query_result';
import {Area, Sorting} from '../../common/state';
import {Controller} from '../controller';
import {globals} from '../globals';
@@ -115,9 +115,9 @@
sorting = `${pref.sorting.column} ${pref.sorting.direction}`;
}
const query = `select ${colIds} from ${this.kind} order by ${sorting}`;
- const result = await this.args.engine.query(query);
+ const result = await this.args.engine.queryV2(query);
- const numRows = slowlyCountRows(result);
+ const numRows = result.numRows();
const columns = defs.map(def => this.columnFromColumnDef(def, numRows));
const columnSums = await Promise.all(defs.map(def => this.getSum(def)));
const extraData = await this.getExtra(this.args.engine, area);
@@ -135,20 +135,29 @@
return idx;
}
- for (let row = 0; row < numRows; row++) {
- const cols = result.columns;
- for (let col = 0; col < result.columns.length; col++) {
- if (cols[col].stringValues && cols[col].stringValues!.length > 0) {
- data.columns[col].data[row] =
- internString(cols[col].stringValues![row]);
- } else if (cols[col].longValues && cols[col].longValues!.length > 0) {
- data.columns[col].data[row] = cols[col].longValues![row];
- } else if (
- cols[col].doubleValues && cols[col].doubleValues!.length > 0) {
- data.columns[col].data[row] = cols[col].doubleValues![row];
+ const spec: {[k: string]: string|number|null} = {};
+ for (const column of columns) {
+ if (column.kind === 'STRING') {
+ spec[column.columnId] = STR_NULL;
+ } else {
+ spec[column.columnId] = NUM_NULL;
+ }
+ }
+
+ const it = result.iter(spec);
+ for (let i = 0; it.valid(); it.next(), ++i) {
+ for (const column of data.columns) {
+ const item = it.get(column.columnId);
+ if (item === null) {
+ column.data[i] = column.kind === 'STRING' ? internString('NULL') : 0;
+ } else if (typeof item === 'string') {
+ column.data[i] = internString(item);
+ } else {
+ column.data[i] = item;
}
}
}
+
return data;
}
diff --git a/ui/src/controller/aggregation/thread_aggregation_controller.ts b/ui/src/controller/aggregation/thread_aggregation_controller.ts
index 3fe9dac..b9c15fb 100644
--- a/ui/src/controller/aggregation/thread_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/thread_aggregation_controller.ts
@@ -14,7 +14,7 @@
import {ColumnDef, ThreadStateExtra} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
-import {slowlyCountRows} from '../../common/query_iterator';
+import {NUM, NUM_NULL, STR} from '../../common/query_result';
import {Area, Sorting} from '../../common/state';
import {translateState} from '../../common/thread_state';
import {toNs} from '../../common/time';
@@ -73,31 +73,37 @@
this.setThreadStateUtids(area.tracks);
if (this.utids === undefined || this.utids.length === 0) return;
- const query = `select state, io_wait, sum(dur) as total_dur from process
+ const query =
+ `select state, io_wait as ioWait, sum(dur) as totalDur from process
JOIN thread USING(upid)
JOIN thread_state USING(utid)
WHERE utid IN (${this.utids}) AND thread_state.ts + thread_state.dur > ${
- toNs(area.startSec)} AND
+ toNs(area.startSec)} AND
thread_state.ts < ${toNs(area.endSec)}
GROUP BY state, io_wait`;
- const result = await engine.query(query);
- const numRows = slowlyCountRows(result);
+ const result = await engine.queryV2(query);
+
+ const it = result.iter({
+ state: STR,
+ ioWait: NUM_NULL,
+ totalDur: NUM,
+ });
const summary: ThreadStateExtra = {
kind: 'THREAD_STATE',
states: [],
- values: new Float64Array(numRows),
+ values: new Float64Array(result.numRows()),
totalMs: 0
};
- for (let row = 0; row < numRows; row++) {
- const state = result.columns[0].stringValues![row];
- const ioWait = result.columns[1].isNulls![row] ?
- undefined :
- !!result.columns[1].longValues![row];
+ summary.totalMs = 0;
+ for (let i = 0; it.valid(); ++i, it.next()) {
+ const state = it.state;
+ const ioWait = it.ioWait === null ? undefined : it.ioWait > 0;
summary.states.push(translateState(state, ioWait));
- summary.values[row] = result.columns[2].longValues![row] / 1000000; // ms
+ const ms = it.totalDur / 1000000;
+ summary.values[i] = ms;
+ summary.totalMs += ms;
}
- summary.totalMs = summary.values.reduce((a, b) => a + b, 0);
return summary;
}
diff --git a/ui/src/controller/cpu_profile_controller.ts b/ui/src/controller/cpu_profile_controller.ts
index 05e03e9..34834d3 100644
--- a/ui/src/controller/cpu_profile_controller.ts
+++ b/ui/src/controller/cpu_profile_controller.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {Engine} from '../common/engine';
-import {slowlyCountRows} from '../common/query_iterator';
+import {NUM, STR} from '../common/query_result';
import {CallsiteInfo, CpuProfileSampleSelection} from '../common/state';
import {CpuProfileDetails} from '../frontend/globals';
@@ -106,7 +106,7 @@
// 5. Sort the query by the depth of the callstack frames.
const sampleQuery = `
SELECT
- samples.id,
+ samples.id as id,
IFNULL(
(
SELECT name
@@ -115,8 +115,8 @@
LIMIT 1
),
spf.name
- ) AS frame_name,
- spm.name AS mapping_name
+ ) AS name,
+ spm.name AS mapping
FROM cpu_profile_stack_sample AS samples
LEFT JOIN (
SELECT
@@ -141,26 +141,28 @@
ORDER BY callsites.depth;
`;
- const callsites = await this.args.engine.query(sampleQuery);
+ const callsites = await this.args.engine.queryV2(sampleQuery);
- if (slowlyCountRows(callsites) < 1) {
+ if (callsites.numRows() === 0) {
return undefined;
}
- const sampleData: CallsiteInfo[] = new Array();
- for (let i = 0; i < slowlyCountRows(callsites); i++) {
- const id = +callsites.columns[0].longValues![i];
- const name = callsites.columns[1].stringValues![i];
- const mapping = callsites.columns[2].stringValues![i];
+ const it = callsites.iter({
+ id: NUM,
+ name: STR,
+ mapping: STR,
+ });
+ const sampleData: CallsiteInfo[] = new Array();
+ for (; it.valid(); it.next()) {
sampleData.push({
- id,
+ id: it.id,
totalSize: 0,
depth: 0,
parentId: 0,
- name,
+ name: it.name,
selfSize: 0,
- mapping,
+ mapping: it.mapping,
merged: false,
highlighted: false
});
diff --git a/ui/src/controller/flow_events_controller.ts b/ui/src/controller/flow_events_controller.ts
index 87dd298..90b8254 100644
--- a/ui/src/controller/flow_events_controller.ts
+++ b/ui/src/controller/flow_events_controller.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {Engine} from '../common/engine';
-import {slowlyCountRows} from '../common/query_iterator';
+import {NUM, STR_NULL} from '../common/query_result';
import {Area} from '../common/state';
import {fromNs, toNs} from '../common/time';
import {Flow} from '../frontend/globals';
@@ -43,34 +43,53 @@
}
queryFlowEvents(query: string, callback: (flows: Flow[]) => void) {
- this.args.engine.query(query).then(res => {
+ this.args.engine.queryV2(query).then(result => {
const flows: Flow[] = [];
- for (let i = 0; i < slowlyCountRows(res); i++) {
- const beginSliceId = res.columns[0].longValues![i];
- const beginTrackId = res.columns[1].longValues![i];
- const beginSliceName = res.columns[2].stringValues![i];
- const beginSliceCategory = res.columns[3].stringValues![i];
- const beginSliceStartTs = fromNs(res.columns[4].longValues![i]);
- const beginSliceEndTs = fromNs(res.columns[5].longValues![i]);
- const beginDepth = res.columns[6].longValues![i];
+ const it = result.iter({
+ beginSliceId: NUM,
+ beginTrackId: NUM,
+ beginSliceName: STR_NULL,
+ beginSliceCategory: STR_NULL,
+ beginSliceStartTs: NUM,
+ beginSliceEndTs: NUM,
+ beginDepth: NUM,
+ endSliceId: NUM,
+ endTrackId: NUM,
+ endSliceName: STR_NULL,
+ endSliceCategory: STR_NULL,
+ endSliceStartTs: NUM,
+ endSliceEndTs: NUM,
+ endDepth: NUM,
+ name: STR_NULL,
+ category: STR_NULL,
+ id: NUM,
+ });
+ for (; it.valid(); it.next()) {
+ const beginSliceId = it.beginSliceId;
+ const beginTrackId = it.beginTrackId;
+ const beginSliceName =
+ it.beginSliceName === null ? 'NULL' : it.beginSliceName;
+ const beginSliceCategory =
+ it.beginSliceCategory === null ? 'NULL' : it.beginSliceCategory;
+ const beginSliceStartTs = fromNs(it.beginSliceStartTs);
+ const beginSliceEndTs = fromNs(it.beginSliceEndTs);
+ const beginDepth = it.beginDepth;
- const endSliceId = res.columns[7].longValues![i];
- const endTrackId = res.columns[8].longValues![i];
- const endSliceName = res.columns[9].stringValues![i];
- const endSliceCategory = res.columns[10].stringValues![i];
- const endSliceStartTs = fromNs(res.columns[11].longValues![i]);
- const endSliceEndTs = fromNs(res.columns[12].longValues![i]);
- const endDepth = res.columns[13].longValues![i];
+ const endSliceId = it.endSliceId;
+ const endTrackId = it.endTrackId;
+ const endSliceName =
+ it.endSliceName === null ? 'NULL' : it.endSliceName;
+ const endSliceCategory =
+ it.endSliceCategory === null ? 'NULL' : it.endSliceCategory;
+ const endSliceStartTs = fromNs(it.endSliceStartTs);
+ const endSliceEndTs = fromNs(it.endSliceEndTs);
+ const endDepth = it.endDepth;
// Category and name present only in version 1 flow events
// It is most likelly NULL for all other versions
- const category = res.columns[14].isNulls![i] ?
- undefined :
- res.columns[14].stringValues![i];
- const name = res.columns[15].isNulls![i] ?
- undefined :
- res.columns[15].stringValues![i];
- const id = res.columns[16].longValues![i];
+ const category = it.category === null ? undefined : it.category;
+ const name = it.name === null ? undefined : it.name;
+ const id = it.id;
flows.push({
id,
@@ -110,13 +129,23 @@
const query = `
select
- f.slice_out, t1.track_id, t1.name,
- t1.category, t1.ts, (t1.ts+t1.dur), t1.depth,
- f.slice_in, t2.track_id, t2.name,
- t2.category, t2.ts, (t2.ts+t2.dur), t2.depth,
- extract_arg(f.arg_set_id, 'cat'),
- extract_arg(f.arg_set_id, 'name'),
- f.id
+ f.slice_out as beginSliceId,
+ t1.track_id as beginTrackId,
+ t1.name as beginSliceName,
+ t1.category as beginSliceCategory,
+ t1.ts as beginSliceStartTs,
+ (t1.ts+t1.dur) as beginSliceEndTs,
+ t1.depth as beginDepth,
+ f.slice_in as endSliceId,
+ t2.track_id as endTrackId,
+ t2.name as endSliceName,
+ t2.category as endSliceCategory,
+ t2.ts as endSliceStartTs,
+ (t2.ts+t2.dur) as endSliceEndTs,
+ t2.depth as endDepth,
+ extract_arg(f.arg_set_id, 'cat') as category,
+ extract_arg(f.arg_set_id, 'name') as name,
+ f.id as id
from directly_connected_flow(${sliceId}) f
join slice t1 on f.slice_out = t1.slice_id
join slice t2 on f.slice_in = t2.slice_id
@@ -161,13 +190,23 @@
const query = `
select
- f.slice_out, t1.track_id, t1.name,
- t1.category, t1.ts, (t1.ts+t1.dur), t1.depth,
- f.slice_in, t2.track_id, t2.name,
- t2.category, t2.ts, (t2.ts+t2.dur), t2.depth,
- extract_arg(f.arg_set_id, 'cat'),
- extract_arg(f.arg_set_id, 'name'),
- f.id
+ f.slice_out as beginSliceId,
+ t1.track_id as beginTrackId,
+ t1.name as beginSliceName,
+ t1.category as beginSliceCategory,
+ t1.ts as beginSliceStartTs,
+ (t1.ts+t1.dur) as beginSliceEndTs,
+ t1.depth as beginDepth,
+ f.slice_in as endSliceId,
+ t2.track_id as endTrackId,
+ t2.name as endSliceName,
+ t2.category as endSliceCategory,
+ t2.ts as endSliceStartTs,
+ (t2.ts+t2.dur) as endSliceEndTs,
+ t2.depth as endDepth,
+ extract_arg(f.arg_set_id, 'cat') as category,
+ extract_arg(f.arg_set_id, 'name') as name,
+ f.id as id
from flow f
join slice t1 on f.slice_out = t1.slice_id
join slice t2 on f.slice_in = t2.slice_id
diff --git a/ui/src/controller/heap_profile_controller.ts b/ui/src/controller/heap_profile_controller.ts
index 82f4b7e..b2d07f7 100644
--- a/ui/src/controller/heap_profile_controller.ts
+++ b/ui/src/controller/heap_profile_controller.ts
@@ -23,7 +23,7 @@
OBJECTS_ALLOCATED_NOT_FREED_KEY,
SPACE_MEMORY_ALLOCATED_NOT_FREED_KEY
} from '../common/flamegraph_util';
-import {slowlyCountRows} from '../common/query_iterator';
+import {NUM, STR} from '../common/query_result';
import {CallsiteInfo, HeapProfileFlamegraph} from '../common/state';
import {fromNs} from '../common/time';
import {HeapProfileDetails} from '../frontend/globals';
@@ -57,7 +57,7 @@
// TODO(hjd): This should be LRU.
if (this.cache.size > this.cacheSizeLimit) {
for (const name of this.cache.values()) {
- await this.engine.query(`drop table ${name}`);
+ await this.engine.queryV2(`drop table ${name}`);
}
this.cache.clear();
}
@@ -228,8 +228,9 @@
tableName: string, viewingOption = DEFAULT_VIEWING_OPTION,
focusRegex: string) {
let orderBy = '';
- let sizeIndex = 4;
- let selfIndex = 9;
+ let totalColumnName: 'cumulativeSize'|'cumulativeAllocSize'|
+ 'cumulativeCount'|'cumulativeAllocCount' = 'cumulativeSize';
+ let selfColumnName: 'size'|'count' = 'size';
// TODO(fmayer): Improve performance so this is no longer necessary.
// Alternatively consider collapsing frames of the same label.
const maxDepth = 100;
@@ -238,73 +239,97 @@
orderBy = `where cumulative_size > 0 and depth < ${
maxDepth} order by depth, parent_id,
cumulative_size desc, name`;
- sizeIndex = 4;
- selfIndex = 9;
+ totalColumnName = 'cumulativeSize';
+ selfColumnName = 'size';
break;
case ALLOC_SPACE_MEMORY_ALLOCATED_KEY:
orderBy = `where cumulative_alloc_size > 0 and depth < ${
maxDepth} order by depth, parent_id,
cumulative_alloc_size desc, name`;
- sizeIndex = 5;
- selfIndex = 9;
+ totalColumnName = 'cumulativeAllocSize';
+ selfColumnName = 'size';
break;
case OBJECTS_ALLOCATED_NOT_FREED_KEY:
orderBy = `where cumulative_count > 0 and depth < ${
maxDepth} order by depth, parent_id,
cumulative_count desc, name`;
- sizeIndex = 6;
- selfIndex = 10;
+ totalColumnName = 'cumulativeCount';
+ selfColumnName = 'count';
break;
case OBJECTS_ALLOCATED_KEY:
orderBy = `where cumulative_alloc_count > 0 and depth < ${
maxDepth} order by depth, parent_id,
cumulative_alloc_count desc, name`;
- sizeIndex = 7;
- selfIndex = 10;
+ totalColumnName = 'cumulativeAllocCount';
+ selfColumnName = 'count';
break;
default:
break;
}
- const callsites = await this.args.engine.query(
- `SELECT id, IFNULL(DEMANGLE(name), name), IFNULL(parent_id, -1), depth,
- cumulative_size, cumulative_alloc_size, cumulative_count,
- cumulative_alloc_count, map_name, size, count,
- IFNULL(source_file, ''), IFNULL(line_number, -1)
+ const callsites = await this.args.engine.queryV2(`
+ SELECT
+ id as hash,
+ IFNULL(DEMANGLE(name), name) as name,
+ IFNULL(parent_id, -1) as parentHash,
+ depth,
+ cumulative_size as cumulativeSize,
+ cumulative_alloc_size as cumulativeAllocSize,
+ cumulative_count as cumulativeCount,
+ cumulative_alloc_count as cumulativeAllocCount,
+ map_name as mapping,
+ size,
+ count,
+ IFNULL(source_file, '') as sourceFile,
+ IFNULL(line_number, -1) as lineNumber
from ${tableName} ${orderBy}`);
const flamegraphData: CallsiteInfo[] = new Array();
const hashToindex: Map<number, number> = new Map();
- for (let i = 0; i < slowlyCountRows(callsites); i++) {
- const hash = callsites.columns[0].longValues![i];
- let name = callsites.columns[1].stringValues![i];
- const parentHash = callsites.columns[2].longValues![i];
- const depth = +callsites.columns[3].longValues![i];
- const totalSize = +callsites.columns[sizeIndex].longValues![i];
- const mapping = callsites.columns[8].stringValues![i];
- const selfSize = +callsites.columns[selfIndex].longValues![i];
+ const it = callsites.iter({
+ hash: NUM,
+ name: STR,
+ parentHash: NUM,
+ depth: NUM,
+ cumulativeSize: NUM,
+ cumulativeAllocSize: NUM,
+ cumulativeCount: NUM,
+ cumulativeAllocCount: NUM,
+ mapping: STR,
+ sourceFile: STR,
+ lineNumber: NUM,
+ size: NUM,
+ count: NUM,
+ });
+ for (let i = 0; it.valid(); ++i, it.next()) {
+ const hash = it.hash;
+ let name = it.name;
+ const parentHash = it.parentHash;
+ const depth = it.depth;
+ const totalSize = it[totalColumnName];
+ const selfSize = it[selfColumnName];
+ const mapping = it.mapping;
const highlighted = focusRegex !== '' &&
name.toLocaleLowerCase().includes(focusRegex.toLocaleLowerCase());
const parentId =
hashToindex.has(+parentHash) ? hashToindex.get(+parentHash)! : -1;
let location: string|undefined;
- if (callsites.columns[11].stringValues != null &&
- /[a-zA-Z]/i.test(callsites.columns[11].stringValues[i])) {
- location = callsites.columns[11].stringValues[i];
- if (callsites.columns[12].longValues != null &&
- callsites.columns[12].longValues[i] !== -1) {
- location += `:${callsites.columns[12].longValues[i].toString()}`;
+ if (/[a-zA-Z]/i.test(it.sourceFile)) {
+ location = it.sourceFile;
+ if (it.lineNumber !== -1) {
+ location += `:${it.lineNumber}`;
}
}
if (depth === maxDepth - 1) {
name += ' [tree truncated]';
}
- hashToindex.set(+hash, i);
// Instead of hash, we will store index of callsite in this original array
// as an id of callsite. That way, we have quicker access to parent and it
- // will stay unique.
+ // will stay unique:
+ hashToindex.set(hash, i);
+
flamegraphData.push({
id: i,
totalSize,
@@ -361,9 +386,9 @@
// Collecting data for more information about heap profile, such as:
// total memory allocated, memory that is allocated and not freed.
- const pidValue = await this.args.engine.query(
+ const result = await this.args.engine.queryV2(
`select pid from process where upid = ${upid}`);
- const pid = pidValue.columns[0].longValues![0];
+ const pid = result.firstRow({pid: NUM}).pid;
const startTime = fromNs(ts) - globals.state.traceTime.startSec;
return {ts: startTime, tsNs: ts, pid, upid, type};
}
diff --git a/ui/src/controller/logs_controller.ts b/ui/src/controller/logs_controller.ts
index fb1ba62..d70e25a 100644
--- a/ui/src/controller/logs_controller.ts
+++ b/ui/src/controller/logs_controller.ts
@@ -20,7 +20,7 @@
LogEntriesKey,
LogExistsKey
} from '../common/logs';
-import {NUM, slowlyCountRows} from '../common/query_iterator';
+import {NUM, STR} from '../common/query_result';
import {fromNs, TimeSpan, toNsCeil, toNsFloor} from '../common/time';
import {Controller} from './controller';
@@ -76,25 +76,23 @@
const vizSqlBounds = `ts >= ${vizStartNs} and ts <= ${vizEndNs}`;
const rowsResult =
- await engine.query(`select ts, prio, tag, msg from android_logs
+ await engine.queryV2(`select ts, prio, tag, msg from android_logs
where ${vizSqlBounds}
order by ts
limit ${pagination.start}, ${pagination.count}`);
- if (!slowlyCountRows(rowsResult)) {
- return {
- offset: pagination.start,
- timestamps: [],
- priorities: [],
- tags: [],
- messages: [],
- };
- }
+ const timestamps = [];
+ const priorities = [];
+ const tags = [];
+ const messages = [];
- const timestamps = rowsResult.columns[0].longValues!;
- const priorities = rowsResult.columns[1].longValues!;
- const tags = rowsResult.columns[2].stringValues!;
- const messages = rowsResult.columns[3].stringValues!;
+ const it = rowsResult.iter({ts: NUM, prio: NUM, tag: STR, msg: STR});
+ for (; it.valid(); it.next()) {
+ timestamps.push(it.ts);
+ priorities.push(it.prio);
+ tags.push(it.tag);
+ messages.push(it.msg);
+ }
return {
offset: pagination.start,
diff --git a/ui/src/controller/metrics_controller.ts b/ui/src/controller/metrics_controller.ts
index 6d0e835..b179d65 100644
--- a/ui/src/controller/metrics_controller.ts
+++ b/ui/src/controller/metrics_controller.ts
@@ -14,7 +14,7 @@
import {Actions} from '../common/actions';
import {Engine, QueryError} from '../common/engine';
-import {iter, STR} from '../common/query_iterator';
+import {STR} from '../common/query_result';
import {Controller} from './controller';
import {globals} from './globals';
@@ -33,13 +33,10 @@
private async getMetricNames() {
const metrics = [];
- const it = iter(
- {
- name: STR,
- },
- await this.engine.query('select name from trace_metrics'));
+ const result = await this.engine.queryV2('select name from trace_metrics');
+ const it = result.iter({name: STR});
for (; it.valid(); it.next()) {
- metrics.push(it.row.name);
+ metrics.push(it.name);
}
return metrics;
}
diff --git a/ui/src/controller/query_controller.ts b/ui/src/controller/query_controller.ts
index 2247884..7ac7857 100644
--- a/ui/src/controller/query_controller.ts
+++ b/ui/src/controller/query_controller.ts
@@ -15,8 +15,8 @@
import {assertExists} from '../base/logging';
import {Actions} from '../common/actions';
import {Engine} from '../common/engine';
-import {Row} from '../common/protos';
import {QueryResponse} from '../common/queries';
+import {Row} from '../common/query_result';
import {Controller} from './controller';
import {globals} from './globals';
diff --git a/ui/src/controller/selection_controller.ts b/ui/src/controller/selection_controller.ts
index 02be3db..1c5c375 100644
--- a/ui/src/controller/selection_controller.ts
+++ b/ui/src/controller/selection_controller.ts
@@ -17,10 +17,10 @@
import {Engine} from '../common/engine';
import {
NUM,
- singleRow,
- slowlyCountRows,
- STR
-} from '../common/query_iterator';
+ NUM_NULL,
+ STR,
+ STR_NULL,
+} from '../common/query_result';
import {ChromeSliceSelection} from '../common/state';
import {translateState} from '../common/thread_state';
import {fromNs, toNs} from '../common/time';
@@ -101,23 +101,23 @@
promisedDescription = Promise.resolve(new Map());
promisedArgs = Promise.resolve(new Map());
} else {
- const typeResult = singleRow(
- {
- leafTable: STR,
- argSetId: NUM,
- },
- await this.args.engine.query(`
+ const result = await this.args.engine.queryV2(`
SELECT
type as leafTable,
arg_set_id as argSetId
- FROM slice WHERE id = ${selectedId}`));
+ FROM slice WHERE id = ${selectedId}`);
- if (typeResult === undefined) {
+ if (result.numRows() === 0) {
return;
}
- leafTable = typeResult.leafTable;
- const argSetId = typeResult.argSetId;
+ const row = result.firstRow({
+ leafTable: STR,
+ argSetId: NUM,
+ });
+
+ leafTable = row.leafTable;
+ const argSetId = row.argSetId;
promisedDescription = this.describeSlice(selectedId);
promisedArgs = this.getArgs(argSetId);
}
@@ -186,14 +186,17 @@
const map = new Map<string, string>();
if (id === -1) return map;
const query = `
- select description, doc_link
+ select
+ ifnull(description, '') as description,
+ ifnull(doc_link, '') as docLink
from describe_slice
where slice_id = ${id}
`;
- const result = await this.args.engine.query(query);
- for (let i = 0; i < slowlyCountRows(result); i++) {
- const description = result.columns[0].stringValues![i];
- const docLink = result.columns[1].stringValues![i];
+ const result = await this.args.engine.queryV2(query);
+ const it = result.iter({description: STR, docLink: STR});
+ for (; it.valid(); it.next()) {
+ const description = it.description;
+ const docLink = it.docLink;
map.set('Description', description);
map.set('Documentation', docLink);
}
@@ -209,10 +212,14 @@
FROM args
WHERE arg_set_id = ${argId}
`;
- const result = await this.args.engine.query(query);
- for (let i = 0; i < slowlyCountRows(result); i++) {
- const name = result.columns[0].stringValues![i];
- const value = result.columns[1].stringValues![i];
+ const result = await this.args.engine.queryV2(query);
+ const it = result.iter({
+ name: STR,
+ value: STR,
+ });
+ for (; it.valid(); it.next()) {
+ const name = it.name;
+ const value = it.value;
if (name === 'destination slice id' && !isNaN(Number(value))) {
const destTrackId = await this.getDestTrackId(value);
args.set(
@@ -226,10 +233,10 @@
}
async getDestTrackId(sliceId: string): Promise<string> {
- const trackIdQuery = `select track_id from slice
+ const trackIdQuery = `select track_id as trackId from slice
where slice_id = ${sliceId}`;
- const destResult = await this.args.engine.query(trackIdQuery);
- const trackIdTp = destResult.columns[0].longValues![0];
+ const result = await this.args.engine.queryV2(trackIdQuery);
+ const trackIdTp = result.firstRow({trackId: NUM}).trackId;
// TODO(hjd): If we had a consistent mapping from TP track_id
// UI track id for slice tracks this would be unnecessary.
let trackId = '';
@@ -247,95 +254,114 @@
const query = `
SELECT
ts,
- thread_state.dur,
+ thread_state.dur as dur,
state,
- io_wait,
- thread_state.utid,
- thread_state.cpu,
- sched.id,
- thread_state.blocked_function
+ io_wait as ioWait,
+ thread_state.utid as utid,
+ thread_state.cpu as cpu,
+ sched.id as id,
+ thread_state.blocked_function as blockedFunction
from thread_state
left join sched using(ts) where thread_state.id = ${id}
`;
- this.args.engine.query(query).then(result => {
- const selection = globals.state.currentSelection;
- const cols = result.columns;
- if (slowlyCountRows(result) === 1 && selection) {
- const ts = cols[0].longValues![0];
- const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
- const dur = fromNs(cols[1].longValues![0]);
- const stateStr = cols[2].stringValues![0];
- const ioWait =
- cols[3].isNulls![0] ? undefined : !!cols[3].longValues![0];
- const state = translateState(stateStr, ioWait);
- const utid = cols[4].longValues![0];
- const cpu = cols[5].isNulls![0] ? undefined : cols[5].longValues![0];
- const sliceId =
- cols[6].isNulls![0] ? undefined : cols[6].longValues![0];
- const blockedFunction =
- cols[7].isNulls![0] ? undefined : cols[7].stringValues![0];
- const selected: ThreadStateDetails = {
- ts: timeFromStart,
- dur,
- state,
- utid,
- cpu,
- sliceId,
- blockedFunction
- };
- globals.publish('ThreadStateDetails', selected);
- }
- });
+ const result = await this.args.engine.queryV2(query);
+
+ const selection = globals.state.currentSelection;
+ if (result.numRows() > 0 && selection) {
+ const row = result.firstRow({
+ ts: NUM,
+ dur: NUM,
+ state: STR,
+ ioWait: NUM_NULL,
+ utid: NUM,
+ cpu: NUM_NULL,
+ id: NUM_NULL,
+ blockedFunction: STR_NULL,
+ });
+ const ts = row.ts;
+ const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
+ const dur = fromNs(row.dur);
+ const ioWait = row.ioWait === null ? undefined : row.ioWait > 0;
+ const state = translateState(row.state, ioWait);
+ const utid = row.utid;
+ const cpu = row.cpu === null ? undefined : row.cpu;
+ const sliceId = row.id === null ? undefined : row.id;
+ const blockedFunction =
+ row.blockedFunction === null ? undefined : row.blockedFunction;
+ const selected: ThreadStateDetails =
+ {ts: timeFromStart, dur, state, utid, cpu, sliceId, blockedFunction};
+ globals.publish('ThreadStateDetails', selected);
+ }
}
async sliceDetails(id: number) {
- const sqlQuery = `SELECT ts, dur, priority, end_state, utid, cpu,
- thread_state.id FROM sched join thread_state using(ts, utid, dur, cpu)
+ const sqlQuery = `SELECT
+ ts,
+ dur,
+ priority,
+ end_state as endState,
+ utid,
+ cpu,
+ thread_state.id as threadStateId
+ FROM sched join thread_state using(ts, utid, dur, cpu)
WHERE sched.id = ${id}`;
- this.args.engine.query(sqlQuery).then(result => {
- // Check selection is still the same on completion of query.
- const selection = globals.state.currentSelection;
- if (slowlyCountRows(result) === 1 && selection) {
- const ts = result.columns[0].longValues![0];
- const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
- const dur = fromNs(result.columns[1].longValues![0]);
- const priority = result.columns[2].longValues![0];
- const endState = result.columns[3].stringValues![0];
- const utid = result.columns[4].longValues![0];
- const cpu = result.columns[5].longValues![0];
- const threadStateId = result.columns[6].longValues![0];
- const selected: SliceDetails = {
- ts: timeFromStart,
- dur,
- priority,
- endState,
- cpu,
- id,
- utid,
- threadStateId
- };
- this.schedulingDetails(ts, utid)
- .then(wakeResult => {
- Object.assign(selected, wakeResult);
- })
- .finally(() => {
- globals.publish('SliceDetails', selected);
- });
- }
- });
+ const result = await this.args.engine.queryV2(sqlQuery);
+ // Check selection is still the same on completion of query.
+ const selection = globals.state.currentSelection;
+ if (result.numRows() > 0 && selection) {
+ const row = result.firstRow({
+ ts: NUM,
+ dur: NUM,
+ priority: NUM,
+ endState: STR,
+ utid: NUM,
+ cpu: NUM,
+ threadStateId: NUM,
+ });
+ const ts = row.ts;
+ const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
+ const dur = fromNs(row.dur);
+ const priority = row.priority;
+ const endState = row.endState;
+ const utid = row.utid;
+ const cpu = row.cpu;
+ const threadStateId = row.threadStateId;
+ const selected: SliceDetails = {
+ ts: timeFromStart,
+ dur,
+ priority,
+ endState,
+ cpu,
+ id,
+ utid,
+ threadStateId
+ };
+ this.schedulingDetails(ts, utid)
+ .then(wakeResult => {
+ Object.assign(selected, wakeResult);
+ })
+ .finally(() => {
+ globals.publish('SliceDetails', selected);
+ });
+ }
}
async counterDetails(ts: number, rightTs: number, id: number) {
- const counter = await this.args.engine.query(
- `SELECT value, track_id FROM counter WHERE id = ${id}`);
- const value = counter.columns[0].doubleValues![0];
- const trackId = counter.columns[1].longValues![0];
+ const counter = await this.args.engine.queryV2(
+ `SELECT value, track_id as trackId FROM counter WHERE id = ${id}`);
+ const row = counter.iter({
+ value: NUM,
+ trackId: NUM,
+ });
+ const value = row.value;
+ const trackId = row.trackId;
// Finding previous value. If there isn't previous one, it will return 0 for
// ts and value.
- const previous = await this.args.engine.query(
- `SELECT MAX(ts), value FROM counter WHERE ts < ${ts} and track_id = ${
- trackId}`);
- const previousValue = previous.columns[1].doubleValues![0];
+ const previous = await this.args.engine.queryV2(`SELECT
+ MAX(ts),
+ IFNULL(value, 0)
+ FROM counter WHERE ts < ${ts} and track_id = ${trackId}`);
+ const previousValue = previous.firstRow({value: NUM}).value;
const endTs =
rightTs !== -1 ? rightTs : toNs(globals.state.traceTime.endSec);
const delta = value - previousValue;
@@ -346,12 +372,12 @@
async schedulingDetails(ts: number, utid: number|Long) {
let event = 'sched_waking';
- const waking = await this.args.engine.query(
+ const waking = await this.args.engine.queryV2(
`select * from instants where name = 'sched_waking' limit 1`);
- const wakeup = await this.args.engine.query(
+ const wakeup = await this.args.engine.queryV2(
`select * from instants where name = 'sched_wakeup' limit 1`);
- if (slowlyCountRows(waking) === 0) {
- if (slowlyCountRows(wakeup) === 0) return undefined;
+ if (waking.numRows() === 0) {
+ if (wakeup.numRows() === 0) return undefined;
// Only use sched_wakeup if waking is not in the trace.
event = 'sched_wakeup';
}
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index b2d38a9..f9b3e44 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -23,7 +23,7 @@
import {TRACE_MARGIN_TIME_S} from '../common/constants';
import {Engine, QueryError} from '../common/engine';
import {HttpRpcEngine} from '../common/http_rpc_engine';
-import {iter, NUM, slowlyCountRows, STR} from '../common/query_iterator';
+import {NUM, NUM_NULL, STR, STR_NULL} from '../common/query_result';
import {EngineMode} from '../common/state';
import {TimeSpan, toNs, toNsCeil, toNsFloor} from '../common/time';
import {WasmEngineProxy} from '../common/wasm_engine_proxy';
@@ -336,8 +336,8 @@
// of the limit 1, and instead delegate the filtering to the iterator.
const query = `select '_' as _ from raw
where cpu + 1 > 1 or utid + 1 > 1 limit 1`;
- const result = await assertExists(this.engine).query(query);
- const hasFtrace = !!slowlyCountRows(result);
+ const result = await assertExists(this.engine).queryV2(query);
+ const hasFtrace = result.numRows() > 0;
globals.publish('HasFtrace', hasFtrace);
}
@@ -355,11 +355,12 @@
union
select distinct(graph_sample_ts) as ts, 'graph' as type, upid from
heap_graph_object) order by ts limit 1`;
- const profile = await assertExists(this.engine).query(query);
- if (profile.numRecords !== 1) return;
- const ts = profile.columns[0].longValues![0];
- const type = profile.columns[1].stringValues![0];
- const upid = profile.columns[2].longValues![0];
+ const profile = await assertExists(this.engine).queryV2(query);
+ if (profile.numRows() !== 1) return;
+ const row = profile.firstRow({ts: NUM, type: STR, upid: NUM});
+ const ts = row.ts;
+ const type = row.type;
+ const upid = row.upid;
globals.dispatch(Actions.selectHeapProfile({id: 0, upid, ts, type}));
}
@@ -372,25 +373,37 @@
private async listThreads() {
this.updateStatus('Reading thread list');
- const sqlQuery = `select utid, tid, pid, thread.name,
+ const query = `select
+ utid,
+ tid,
+ pid,
+ ifnull(thread.name, '') as threadName,
ifnull(
case when length(process.name) > 0 then process.name else null end,
- thread.name),
- process.cmdline
+ thread.name) as procName,
+ process.cmdline as cmdline
from (select * from thread order by upid) as thread
left join (select * from process order by upid) as process
using(upid)`;
- const threadRows = await assertExists(this.engine).query(sqlQuery);
+ const result = await assertExists(this.engine).queryV2(query);
const threads: ThreadDesc[] = [];
- for (let i = 0; i < slowlyCountRows(threadRows); i++) {
- const utid = threadRows.columns[0].longValues![i];
- const tid = threadRows.columns[1].longValues![i];
- const pid = threadRows.columns[2].longValues![i];
- const threadName = threadRows.columns[3].stringValues![i];
- const procName = threadRows.columns[4].stringValues![i];
- const cmdline = threadRows.columns[5].stringValues![i];
+ const it = result.iter({
+ utid: NUM,
+ tid: NUM,
+ pid: NUM_NULL,
+ threadName: STR,
+ procName: STR_NULL,
+ cmdline: STR_NULL,
+ });
+ for (; it.valid(); it.next()) {
+ const utid = it.utid;
+ const tid = it.tid;
+ const pid = it.pid === null ? undefined : it.pid;
+ const threadName = it.threadName;
+ const procName = it.procName === null ? undefined : it.procName;
+ const cmdline = it.cmdline === null ? undefined : it.cmdline;
threads.push({utid, tid, threadName, pid, procName, cmdline});
- } // for (record ...)
+ }
globals.publish('Threads', threads);
}
@@ -409,19 +422,20 @@
const endNs = toNsCeil(endSec);
// Sched overview.
- const schedRows = await engine.query(
- `select sum(dur)/${stepSec}/1e9, cpu from sched ` +
+ const schedResult = await engine.queryV2(
+ `select sum(dur)/${stepSec}/1e9 as load, cpu from sched ` +
`where ts >= ${startNs} and ts < ${endNs} and utid != 0 ` +
'group by cpu order by cpu');
const schedData: {[key: string]: QuantizedLoad} = {};
- for (let i = 0; i < slowlyCountRows(schedRows); i++) {
- const load = schedRows.columns[0].doubleValues![i];
- const cpu = schedRows.columns[1].longValues![i];
+ const it = schedResult.iter({load: NUM, cpu: NUM});
+ for (; it.valid(); it.next()) {
+ const load = it.load;
+ const cpu = it.cpu;
schedData[cpu] = {startSec, endSec, load};
hasSchedOverview = true;
- } // for (record ...)
+ }
globals.publish('OverviewData', schedData);
- } // for (step ...)
+ }
if (hasSchedOverview) {
return;
@@ -430,10 +444,10 @@
// Slices overview.
const traceStartNs = toNs(traceTime.start);
const stepSecNs = toNs(stepSec);
- const sliceSummaryQuery = await engine.query(`select
+ const sliceResult = await engine.queryV2(`select
bucket,
upid,
- sum(utid_sum) / cast(${stepSecNs} as float) as upid_sum
+ sum(utid_sum) / cast(${stepSecNs} as float) as load
from thread
inner join (
select
@@ -447,10 +461,11 @@
group by bucket, upid`);
const slicesData: {[key: string]: QuantizedLoad[]} = {};
- for (let i = 0; i < slowlyCountRows(sliceSummaryQuery); i++) {
- const bucket = sliceSummaryQuery.columns[0].longValues![i];
- const upid = sliceSummaryQuery.columns[1].longValues![i];
- const load = sliceSummaryQuery.columns[2].doubleValues![i];
+ const it = sliceResult.iter({bucket: NUM, upid: NUM, load: NUM});
+ for (; it.valid(); it.next()) {
+ const bucket = it.bucket;
+ const upid = it.upid;
+ const load = it.load;
const startSec = traceTime.start + stepSec * bucket;
const endSec = startSec + stepSec;
@@ -467,13 +482,12 @@
private async cacheCurrentTrace() {
const engine = assertExists(this.engine);
- const query = await engine.query(`select str_value from metadata
+ const result = await engine.queryV2(`select str_value as uuid from metadata
where name = 'trace_uuid'`);
- const it = iter({'str_value': STR}, query);
- if (!it.valid()) {
+ if (result.numRows() === 0) {
throw new Error('metadata.trace_uuid could not be found.');
}
- const traceUuid = it.row.str_value;
+ const traceUuid = result.firstRow({uuid: STR}).uuid;
const engineConfig = assertExists(Object.values(globals.state.engines)[0]);
cacheTrace(engineConfig.source, traceUuid);
globals.dispatch(Actions.setTraceUuid({traceUuid}));
@@ -555,13 +569,15 @@
this.updateStatus(`Inserting data for ${metric} metric`);
try {
- const result = await engine.query(`pragma table_info(${metric}_event)`);
+ const result =
+ await engine.queryV2(`pragma table_info(${metric}_event)`);
let hasSliceName = false;
let hasDur = false;
let hasUpid = false;
let hasValue = false;
- for (let i = 0; i < slowlyCountRows(result); i++) {
- const name = result.columns[1].stringValues![i];
+ const it = result.iter({name: STR});
+ for (; it.valid(); it.next()) {
+ const name = it.name;
hasSliceName = hasSliceName || name === 'slice_name';
hasDur = hasDur || name === 'dur';
hasUpid = hasUpid || name === 'upid';
diff --git a/ui/src/controller/trace_error_controller.ts b/ui/src/controller/trace_error_controller.ts
index 4f6eaa7..09e3380 100644
--- a/ui/src/controller/trace_error_controller.ts
+++ b/ui/src/controller/trace_error_controller.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {Engine} from '../common/engine';
-import {NUM} from '../common/query_iterator';
+import {NUM} from '../common/query_result';
import {Controller} from './controller';
import {globals} from './globals';
diff --git a/ui/src/controller/track_controller.ts b/ui/src/controller/track_controller.ts
index de05b94..c0dfc8c 100644
--- a/ui/src/controller/track_controller.ts
+++ b/ui/src/controller/track_controller.ts
@@ -113,11 +113,6 @@
return resolution >= 0.0008;
}
- protected async query(query: string) {
- const result = await this.engine.query(query);
- return result;
- }
-
protected async queryV2(query: string) {
const result = await this.engine.queryV2(query);
return result;
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index dd69835..84aa565 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -26,7 +26,7 @@
NUM_NULL,
STR,
STR_NULL,
-} from '../common/query_iterator';
+} from '../common/query_result';
import {SCROLLING_TRACK_GROUP, TrackKindPriority} from '../common/state';
import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../tracks/actual_frames/common';
import {ANDROID_LOGS_TRACK_KIND} from '../tracks/android_log/common';