blob: 22f83f08c1e8d0f67be0639fd2b06e7f39bcfc6b [file] [edit]
// Copyright (C) 2025 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 m from 'mithril';
import type {Engine} from '../../../trace_processor/engine';
import {
NUM_NULL,
STR_NULL,
UNKNOWN,
} from '../../../trace_processor/query_result';
import {Section} from '../../../widgets/section';
import {CodeSnippet} from '../../../widgets/code_snippet';
import {EmptyState} from '../../../widgets/empty_state';
import {getTraceInfos} from '../utils';
export interface ConfigEntry {
readonly traceId?: number;
readonly traceIndex?: number;
readonly sessionName?: string;
readonly configText: string;
}
export interface ConfigData {
readonly configs: ReadonlyArray<ConfigEntry>;
}
export async function loadConfigData(engine: Engine): Promise<ConfigData> {
const configResult = await engine.query(`
INCLUDE PERFETTO MODULE std.traceinfo.trace;
SELECT
trace_id as traceId,
extract_metadata_for_trace(trace_id, 'trace_config_pbtxt') as configText,
unique_session_name as sessionName
FROM _metadata_by_trace
WHERE configText IS NOT NULL
ORDER BY traceId;
`);
const traceInfos = await getTraceInfos(engine);
const configs: ConfigEntry[] = [];
const it = configResult.iter({
traceId: NUM_NULL,
configText: UNKNOWN,
sessionName: STR_NULL,
});
for (; it.valid(); it.next()) {
const traceId = it.traceId;
const info = traceId !== null ? traceInfos.get(traceId) : undefined;
configs.push({
traceId: traceId ?? undefined,
traceIndex: info?.traceIndex ?? undefined,
configText: String(it.configText),
sessionName: it.sessionName ?? undefined,
});
}
return {configs};
}
export interface ConfigTabAttrs {
data: ConfigData;
}
export class ConfigTab implements m.ClassComponent<ConfigTabAttrs> {
view({attrs}: m.CVnode<ConfigTabAttrs>) {
const configs = attrs.data.configs;
if (configs.length === 0) {
return m(
'.pf-trace-info-page__tab-content',
m(
Section,
{
title: 'Trace Configuration',
subtitle: 'TraceConfig protobuf used to record this trace',
},
m(EmptyState, {
icon: 'settings',
title: 'No trace configuration available',
}),
),
);
}
return m(
'.pf-trace-info-page__tab-content',
configs.map((config, index) => {
let title = 'Trace Configuration';
if (
configs.length > 1 ||
config.sessionName ||
config.traceIndex !== undefined
) {
const indexPart =
config.traceIndex !== undefined ? ` ${config.traceIndex}` : '';
const namePart = config.sessionName ? `: ${config.sessionName}` : '';
title = `Trace Configuration${indexPart}${namePart}`;
}
return m(
Section,
{
key: config.traceId ?? index,
title,
subtitle: 'TraceConfig protobuf used to record this trace',
},
m(CodeSnippet, {
text: config.configText,
language: 'prototext',
downloadFileName:
config.traceIndex !== undefined
? `config_${config.traceIndex}.txtpb`
: 'config.txtpb',
}),
);
}),
);
}
}