91 lines
3.4 KiB
TypeScript
91 lines
3.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
/**
|
|
* @param {Object} perfProfile The perf profile JSON object.
|
|
* @return {Object[]} An array of recognized events that are captured
|
|
* within the perf profile.
|
|
*/
|
|
export function convertPerfProfileToEvents(perfProfile: any): any[] {
|
|
var inProgressEvents = new Map(); // map from event name to start time
|
|
var finishedEvents = []; // Event[] finished events
|
|
var addFinishedEvent = function(eventName, startTime, endTime) {
|
|
var categorizedEventName = categorizeEvent(eventName);
|
|
var args = undefined;
|
|
if (categorizedEventName == 'gc') {
|
|
// TODO: We cannot measure heap size at the moment
|
|
args = {usedHeapSize: 0};
|
|
}
|
|
if (startTime == endTime) {
|
|
// Finished instantly
|
|
finishedEvents.push({ph: 'X', ts: startTime, name: categorizedEventName, args: args});
|
|
} else {
|
|
// Has duration
|
|
finishedEvents.push({ph: 'B', ts: startTime, name: categorizedEventName, args: args});
|
|
finishedEvents.push({ph: 'E', ts: endTime, name: categorizedEventName, args: args});
|
|
}
|
|
};
|
|
|
|
var samples = perfProfile.threads[0].samples;
|
|
// In perf profile, firefox samples all the frames in set time intervals. Here
|
|
// we go through all the samples and construct the start and end time for each
|
|
// event.
|
|
for (var i = 0; i < samples.length; ++i) {
|
|
var sample = samples[i];
|
|
var sampleTime = sample.time;
|
|
|
|
// Add all the frames into a set so it's easier/faster to find the set
|
|
// differences
|
|
var sampleFrames = new Set();
|
|
sample.frames.forEach(function(frame) { sampleFrames.add(frame.location); });
|
|
|
|
// If an event is in the inProgressEvents map, but not in the current sample,
|
|
// then it must have just finished. We add this event to the finishedEvents
|
|
// array and remove it from the inProgressEvents map.
|
|
var previousSampleTime = (i == 0 ? /* not used */ -1 : samples[i - 1].time);
|
|
inProgressEvents.forEach(function(startTime, eventName) {
|
|
if (!(sampleFrames.has(eventName))) {
|
|
addFinishedEvent(eventName, startTime, previousSampleTime);
|
|
inProgressEvents.delete(eventName);
|
|
}
|
|
});
|
|
|
|
// If an event is in the current sample, but not in the inProgressEvents map,
|
|
// then it must have just started. We add this event to the inProgressEvents
|
|
// map.
|
|
sampleFrames.forEach(function(eventName) {
|
|
if (!(inProgressEvents.has(eventName))) {
|
|
inProgressEvents.set(eventName, sampleTime);
|
|
}
|
|
});
|
|
}
|
|
|
|
// If anything is still in progress, we need to included it as a finished event
|
|
// since recording ended.
|
|
var lastSampleTime = samples[samples.length - 1].time;
|
|
inProgressEvents.forEach(function(startTime, eventName) {
|
|
addFinishedEvent(eventName, startTime, lastSampleTime);
|
|
});
|
|
|
|
// Remove all the unknown categories.
|
|
return finishedEvents.filter(function(event) { return event.name != 'unknown'; });
|
|
}
|
|
|
|
// TODO: this is most likely not exhaustive.
|
|
export function categorizeEvent(eventName: string): string {
|
|
if (eventName.indexOf('PresShell::Paint') > -1) {
|
|
return 'render';
|
|
} else if (eventName.indexOf('FirefoxDriver.prototype.executeScript') > -1) {
|
|
return 'script';
|
|
} else if (eventName.indexOf('forceGC') > -1) {
|
|
return 'gc';
|
|
} else {
|
|
return 'unknown';
|
|
}
|
|
}
|