blob: c26371d221cea9f8d0829b5eba447dad38b2db98 [file] [log] [blame]
// Copyright (C) 2022 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 {PerfettoMetatrace, Trace, TracePacket} from '../common/protos';
import {perfetto} from '../gen/protos';
import {featureFlags} from './feature_flags';
import {toNs} from './time';
const METATRACING_BUFFER_SIZE = 100000;
const JS_THREAD_ID = 2;
import MetatraceCategories = perfetto.protos.MetatraceCategories;
const AOMT_FLAG = featureFlags.register({
id: 'alwaysOnMetatracing',
name: 'Enable always-on-metatracing',
description: 'Enables trace events in the UI and trace processor',
defaultValue: false,
});
const AOMT_DETAILED_FLAG = featureFlags.register({
id: 'alwaysOnMetatracing_detailed',
name: 'Detailed always-on-metatracing',
description: 'Enables recording additional events for trace event',
defaultValue: false,
});
function getInitialCategories(): MetatraceCategories|undefined {
if (!AOMT_FLAG.get()) return undefined;
if (AOMT_DETAILED_FLAG.get()) return MetatraceCategories.ALL;
return MetatraceCategories.TOPLEVEL;
}
let enabledCategories: MetatraceCategories|undefined = getInitialCategories();
export function enableMetatracing(categories?: MetatraceCategories) {
enabledCategories = categories || MetatraceCategories.ALL;
}
export function disableMetatracingAndGetTrace(): Uint8Array {
enabledCategories = undefined;
return readMetatrace();
}
export function isMetatracingEnabled(): boolean {
return enabledCategories !== undefined;
}
export function getEnabledMetatracingCategories(): MetatraceCategories|
undefined {
return enabledCategories;
}
interface TraceEvent {
eventName: string;
startNs: number;
durNs: number;
}
const traceEvents: TraceEvent[] = [];
function readMetatrace(): Uint8Array {
const eventToPacket = (e: TraceEvent): TracePacket => {
return TracePacket.create({
timestamp: e.startNs,
timestampClockId: 1,
perfettoMetatrace: PerfettoMetatrace.create({
eventName: e.eventName,
threadId: JS_THREAD_ID,
eventDurationNs: e.durNs,
}),
});
};
const packets: TracePacket[] = [];
for (const event of traceEvents) {
packets.push(eventToPacket(event));
}
const trace = Trace.create({
packet: packets,
});
return Trace.encode(trace).finish();
}
export type TraceEventScope = {
startNs: number, eventName: string;
};
const correctedTimeOrigin = new Date().getTime() - performance.now();
function now(): number {
return toNs((correctedTimeOrigin + performance.now()) / 1000);
}
export function traceEventBegin(eventName: string): TraceEventScope {
return {
eventName,
startNs: now(),
};
}
export function traceEventEnd(traceEvent: TraceEventScope) {
if (!isMetatracingEnabled()) return;
traceEvents.push({
eventName: traceEvent.eventName,
startNs: traceEvent.startNs,
durNs: now() - traceEvent.startNs,
});
while (traceEvents.length > METATRACING_BUFFER_SIZE) {
traceEvents.shift();
}
}