This folder contains the new trace engine that was first implemented for the Performance Insights panel and is now being repurposed as the primary trace engine that we use within DevTools.
Once you have an instance of the model, you can call the parse method to take a set of raw events and parse them. Once parsed, you then have to call the traceParsedData method, providing an index of the trace you want to have the data for. This is because any model can store a number of traces. Each trace is given an index, which starts at 0 and increments by one as a new trace is parsed.
If you are managing multiple traces, you should store them in some form of indexed data structure so you can easily know which index to use to fetch any data from the model. You may delete a trace with deleteTraceByIndex, which will then update the indexes of all other traces too.
When you call parse you have two options. You can await it, which will wait until the trace is fully parsed:
await this.model.parse();
But it's likely preferable to instead use events, to avoid blocking the UI whilst parsing is in progress. You can listen to the ModelUpdateEvent for updates:
this.model.addEventListener(Model.ModelUpdateEvent.eventName, event => {
const {data} = event as Model.ModelUpdateEvent;
if (data.data === 'done') {
// trace is complete
const newestData = this.model.traceParsedData(this.model.getRecordingsAvailable().length - 1);
} else {
// data.data will be an object: { index: X, total: Y}, which represents how many events (X) have been processed out of a total (Y).
// This can be used to show a progress bar, for example.
}
})
Trace Parsing is split into a series of Handlers. The trace processor loops over every event in the trace and calls each handler in turn (done this way so we only loop over the trace file once, rather than doing it once-per-handler). A Handler is a file that exposes a set of methods, most importantly handleEvent() and data(). The handleEvent function will be called for each event in the trace, and it is up to an individual handler to do something with that event if it needs to. The data method should return the final data that has been parsed and generated by the handler.
Each handler can be individually unit tested by feeding it events, and asserting on the final result of its data() function.
The final data object that is returned by the Processor contains the result of calling data() on each handler. The key of each item in the object will be the name of the handler. Once this data is returned, it is considered immutable and should not be changed.
When you create an instance of the Trace Model it will automatically create an instance of the trace worker. This worker is where the actual parsing is done. This is to ensure that parsing a large trace does not cause the main thread to freeze. The fact that the tracing occurs in a different thread is an implementation detail and should not impact how you interface with the trace model itself.
When you call parse(), the model will post a message to the worker. This starts processing, and sends messages back. models/trace/worker/Types.ts contains the messages that can be sent to and from the worker.
The model listens to these messages and will deal with them. If you want to listen out for updates from the model, you can listen to the ModelUpdateEvent, which will be emitted periodically with progress stats, and finally once a trace is complete.