blob: e412f7cb4222e320fc02f974a90e0c1e5ab97e71 [file] [log] [blame]
// Copyright (C) 2024 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 {createPerfettoTable} from '../../../trace_processor/sql_utils';
import {Trace} from '../../trace';
import {sqlNameSafe} from '../../../base/string_utils';
import {
BaseCounterTrack,
CounterOptions,
} from '../../../frontend/base_counter_track';
import {Engine} from '../../../trace_processor/engine';
export interface QueryCounterTrackArgs {
// The trace object used to run queries.
readonly trace: Trace;
// A unique, reproducible ID for this track.
readonly uri: string;
// The query and optional column remapping.
readonly data: SqlDataSource;
// Optional: Which columns should be used for ts, and value. If omitted,
// the defaults 'ts', and 'value' will be used.
readonly columns?: Partial<CounterColumnMapping>;
// Optional: Display options for the counter track.
readonly options?: Partial<CounterOptions>;
}
export interface SqlDataSource {
// SQL source selecting the necessary data.
readonly sqlSource: string;
// Optional: Rename columns from the query result.
// If omitted, original column names from the query are used instead.
// The caller is responsible for ensuring that the number of items in this
// list matches the number of columns returned by sqlSource.
readonly columns?: string[];
}
export interface CounterColumnMapping {
readonly ts: string;
readonly value: string;
}
/**
* Creates a counter track based on a query.
*
* The query must provide the following columns:
* - ts: INTEGER - The timestamp of each sample.
* - value: REAL | INTEGER - The value of each sample.
*
* The column names don't have to be 'ts' and 'value', and can be remapped if
* convenient using the config.columns parameter.
*/
export async function createQueryCounterTrack(args: QueryCounterTrackArgs) {
const tableName = `__query_counter_track_${sqlNameSafe(args.uri)}`;
await createPerfettoTableForTrack(
args.trace.engine,
tableName,
args.data,
args.columns,
);
return new SqlTableCounterTrack(
args.trace,
args.uri,
tableName,
args.options,
);
}
async function createPerfettoTableForTrack(
engine: Engine,
tableName: string,
data: SqlDataSource,
columnMapping: Partial<CounterColumnMapping> = {},
) {
const {ts = 'ts', value = 'value'} = columnMapping;
const query = `
with data as (
${data.sqlSource}
)
select
${ts} as ts,
${value} as value
from data
order by ts
`;
return await createPerfettoTable(engine, tableName, query);
}
class SqlTableCounterTrack extends BaseCounterTrack {
constructor(
trace: Trace,
uri: string,
private readonly sqlTableName: string,
options?: Partial<CounterOptions>,
) {
super(trace, uri, options);
}
getSqlSource(): string {
return `select * from ${this.sqlTableName}`;
}
}