chrome-devtools-frontend
Version:
Chrome DevTools UI
133 lines (114 loc) • 4.5 kB
text/typescript
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as SDK from '../../core/sdk/sdk.js';
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
import * as Protocol from '../../generated/protocol.js';
import type * as Types from './types/types.js';
export class TracingManager extends SDK.SDKModel.SDKModel<void> {
readonly #tracingAgent: ProtocolProxyApi.TracingApi;
#activeClient: TracingManagerClient|null;
#eventsRetrieved: number;
#finishing?: boolean;
constructor(target: SDK.Target.Target) {
super(target);
this.#tracingAgent = target.tracingAgent();
target.registerTracingDispatcher(new TracingDispatcher(this));
this.#activeClient = null;
this.#eventsRetrieved = 0;
}
bufferUsage(usage?: number, percentFull?: number): void {
if (this.#activeClient) {
this.#activeClient.tracingBufferUsage(usage || percentFull || 0);
}
}
eventsCollected(events: Types.Events.Event[]): void {
if (!this.#activeClient) {
return;
}
this.#activeClient.traceEventsCollected(events);
this.#eventsRetrieved += events.length;
// CDP no longer provides an approximate_event_count AKA eventCount. It's always 0.
// To give some idea of progress we'll compare to a large (900k event) trace.
// And we'll clamp both sides so the user sees some progress, and never maxed at 99%
const progress = Math.min((this.#eventsRetrieved / 900_000) + 0.15, 0.90);
this.#activeClient.eventsRetrievalProgress(progress);
}
tracingComplete(): void {
this.#eventsRetrieved = 0;
if (this.#activeClient) {
this.#activeClient.tracingComplete();
this.#activeClient = null;
}
this.#finishing = false;
}
async reset(): Promise<void> {
// If we have an active client, we should try to stop
// it before resetting it, else we will leave the
// backend in a broken state where it thinks we are in
// the middle of tracing, but we think we are not.
// Then, any subsequent attempts to record will fail
// because the backend will not let us start a second
// tracing session.
if (this.#activeClient) {
await this.#tracingAgent.invoke_end();
}
this.#eventsRetrieved = 0;
this.#activeClient = null;
this.#finishing = false;
}
async start(client: TracingManagerClient, categoryFilter: string): Promise<Protocol.ProtocolResponseWithError> {
if (this.#activeClient) {
throw new Error('Tracing is already started');
}
const bufferUsageReportingIntervalMs = 500;
this.#activeClient = client;
const args = {
bufferUsageReportingInterval: bufferUsageReportingIntervalMs,
transferMode: Protocol.Tracing.StartRequestTransferMode.ReportEvents,
traceConfig: {
recordMode: Protocol.Tracing.TraceConfigRecordMode.RecordUntilFull,
traceBufferSizeInKb: 1200 * 1000,
includedCategories: categoryFilter.split(','),
},
};
const response = await this.#tracingAgent.invoke_start(args);
if (response.getError()) {
this.#activeClient = null;
}
return response;
}
stop(): void {
if (!this.#activeClient) {
throw new Error('Tracing is not started');
}
if (this.#finishing) {
throw new Error('Tracing is already being stopped');
}
this.#finishing = true;
void this.#tracingAgent.invoke_end();
}
}
export interface TracingManagerClient {
traceEventsCollected(events: Types.Events.Event[]): void;
tracingComplete(): void;
tracingBufferUsage(usage: number): void;
eventsRetrievalProgress(progress: number): void;
}
class TracingDispatcher implements ProtocolProxyApi.TracingDispatcher {
readonly #tracingManager: TracingManager;
constructor(tracingManager: TracingManager) {
this.#tracingManager = tracingManager;
}
// `eventCount` will always be 0 as perfetto no longer calculates `approximate_event_count`
bufferUsage({value, percentFull}: Protocol.Tracing.BufferUsageEvent): void {
this.#tracingManager.bufferUsage(value, percentFull);
}
dataCollected({value}: Protocol.Tracing.DataCollectedEvent): void {
this.#tracingManager.eventsCollected(value);
}
tracingComplete(): void {
this.#tracingManager.tracingComplete();
}
}
SDK.SDKModel.SDKModel.register(TracingManager, {capabilities: SDK.Target.Capability.TRACING, autostart: false});