diff --git a/packages/benchpress/src/firefox_extension/.gitignore b/packages/benchpress/src/firefox_extension/.gitignore deleted file mode 100644 index fc1a520a40..0000000000 --- a/packages/benchpress/src/firefox_extension/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.xpi -addon-sdk* diff --git a/packages/benchpress/src/firefox_extension/data/installed_script.ts b/packages/benchpress/src/firefox_extension/data/installed_script.ts deleted file mode 100644 index 1e14d5cc6b..0000000000 --- a/packages/benchpress/src/firefox_extension/data/installed_script.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @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 - */ - -declare var exportFunction: any; -declare var unsafeWindow: any; - -exportFunction(function() { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('startProfiler', curTime); -}, unsafeWindow, {defineAs: 'startProfiler'}); - -exportFunction(function() { - (self).port.emit('stopProfiler'); -}, unsafeWindow, {defineAs: 'stopProfiler'}); - -exportFunction(function(cb: Function) { - (self).port.once('perfProfile', cb); - (self).port.emit('getProfile'); -}, unsafeWindow, {defineAs: 'getProfile'}); - -exportFunction(function() { - (self).port.emit('forceGC'); -}, unsafeWindow, {defineAs: 'forceGC'}); - -exportFunction(function(name: string) { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('markStart', name, curTime); -}, unsafeWindow, {defineAs: 'markStart'}); - -exportFunction(function(name: string) { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('markEnd', name, curTime); -}, unsafeWindow, {defineAs: 'markEnd'}); diff --git a/packages/benchpress/src/firefox_extension/lib/main.ts b/packages/benchpress/src/firefox_extension/lib/main.ts deleted file mode 100644 index 348014637c..0000000000 --- a/packages/benchpress/src/firefox_extension/lib/main.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @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 - */ - -const {Cc, Ci, Cu} = require('chrome'); -const os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService); -const ParserUtil = require('./parser_util'); - -class Profiler { - private _profiler: any; - // TODO(issue/24571): remove '!'. - private _markerEvents !: any[]; - // TODO(issue/24571): remove '!'. - private _profilerStartTime !: number; - - constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); } - - start(entries: any, interval: any, features: any, timeStarted: any) { - this._profiler.StartProfiler(entries, interval, features, features.length); - this._profilerStartTime = timeStarted; - this._markerEvents = []; - } - - stop() { this._profiler.StopProfiler(); } - - getProfilePerfEvents() { - const profileData = this._profiler.getProfileData(); - let perfEvents = ParserUtil.convertPerfProfileToEvents(profileData); - perfEvents = this._mergeMarkerEvents(perfEvents); - perfEvents.sort(function(event1: any, event2: any) { - return event1.ts - event2.ts; - }); // Sort by ts - return perfEvents; - } - - /** @internal */ - private _mergeMarkerEvents(perfEvents: any[]): any[] { - this._markerEvents.forEach(function(markerEvent) { perfEvents.push(markerEvent); }); - return perfEvents; - } - - addStartEvent(name: string, timeStarted: number) { - this._markerEvents.push({ph: 'B', ts: timeStarted - this._profilerStartTime, name: name}); - } - - addEndEvent(name: string, timeEnded: number) { - this._markerEvents.push({ph: 'E', ts: timeEnded - this._profilerStartTime, name: name}); - } -} - -function forceGC() { - Cu.forceGC(); - os.notifyObservers(null, 'child-gc-request', null); -} - -const mod = require('sdk/page-mod'); -const data = require('sdk/self').data; -const profiler = new Profiler(); -mod.PageMod({ - include: ['*'], - contentScriptFile: data.url('installed_script.js'), - onAttach: (worker: any) => { - worker.port.on( - 'startProfiler', - (timeStarted: any) => profiler.start( - /* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted)); - worker.port.on('stopProfiler', () => profiler.stop()); - worker.port.on( - 'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents())); - worker.port.on('forceGC', forceGC); - worker.port.on( - 'markStart', (name: string, timeStarted: any) => profiler.addStartEvent(name, timeStarted)); - worker.port.on( - 'markEnd', (name: string, timeEnded: any) => profiler.addEndEvent(name, timeEnded)); - } -}); diff --git a/packages/benchpress/src/firefox_extension/lib/parser_util.ts b/packages/benchpress/src/firefox_extension/lib/parser_util.ts deleted file mode 100644 index 6bccc3c876..0000000000 --- a/packages/benchpress/src/firefox_extension/lib/parser_util.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @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[] { - const inProgressEvents = new Map(); // map from event name to start time - const finishedEvents: {[key: string]: any}[] = []; // Event[] finished events - const addFinishedEvent = function(eventName: string, startTime: number, endTime: number) { - const categorizedEventName = categorizeEvent(eventName); - let args: {[key: string]: any}|undefined = 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}); - } - }; - - const 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 (let i = 0; i < samples.length; ++i) { - const sample = samples[i]; - const sampleTime = sample.time; - - // Add all the frames into a set so it's easier/faster to find the set - // differences - const sampleFrames = new Set(); - sample.frames.forEach(function(frame: {[key: string]: any}) { - 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. - const 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. - const 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'; - } -} diff --git a/packages/benchpress/src/firefox_extension/lib/test_helper.ts b/packages/benchpress/src/firefox_extension/lib/test_helper.ts deleted file mode 100644 index 97cfd2519d..0000000000 --- a/packages/benchpress/src/firefox_extension/lib/test_helper.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @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 - */ - -const q = require('q'); -const FirefoxProfile = require('firefox-profile'); -const jpm = require('jpm/lib/xpi'); -const pathUtil = require('path'); - -const PERF_ADDON_PACKAGE_JSON_DIR = '..'; - -exports.getAbsolutePath = function(path: string) { - const normalizedPath = pathUtil.normalize(path); - if (pathUtil.resolve(normalizedPath) == normalizedPath) { - // Already absolute path - return normalizedPath; - } else { - return pathUtil.join(__dirname, normalizedPath); - } -}; - -exports.getFirefoxProfile = function(extensionPath: string) { - const deferred = q.defer(); - - const firefoxProfile = new FirefoxProfile(); - firefoxProfile.addExtensions([extensionPath], () => { - firefoxProfile.encoded((err: any, encodedProfile: string) => { - const multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}]; - deferred.resolve(multiCapabilities); - }); - }); - - return deferred.promise; -}; - -exports.getFirefoxProfileWithExtension = function() { - const absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR); - const packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json')); - - const savedCwd = process.cwd(); - process.chdir(absPackageJsonDir); - - return jpm(packageJson).then((xpiPath: string) => { - process.chdir(savedCwd); - return exports.getFirefoxProfile(xpiPath); - }); -}; diff --git a/packages/benchpress/src/firefox_extension/package.json b/packages/benchpress/src/firefox_extension/package.json deleted file mode 100644 index f3e5ca2608..0000000000 --- a/packages/benchpress/src/firefox_extension/package.json +++ /dev/null @@ -1 +0,0 @@ -{ "version" : "0.0.1", "main" : "lib/main.js", "name" : "ffperf-addon" } diff --git a/packages/benchpress/test/firefox_extension/conf.ts b/packages/benchpress/test/firefox_extension/conf.ts deleted file mode 100644 index 4be1898f2b..0000000000 --- a/packages/benchpress/test/firefox_extension/conf.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @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 - */ - -require('core-js'); -require('reflect-metadata'); -const testHelper = require('../../src/firefox_extension/lib/test_helper.js'); - -exports.config = { - specs: ['spec.js', 'sample_benchmark.js'], - - framework: 'jasmine2', - - jasmineNodeOpts: {showColors: true, defaultTimeoutInterval: 1200000}, - - getMultiCapabilities: function() { return testHelper.getFirefoxProfileWithExtension(); } -}; diff --git a/packages/benchpress/test/firefox_extension/parser_util_spec.ts b/packages/benchpress/test/firefox_extension/parser_util_spec.ts deleted file mode 100644 index 1669d07036..0000000000 --- a/packages/benchpress/test/firefox_extension/parser_util_spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @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 - */ - -import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser_util'; - -function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) { - expect(actualEvents.length == expectedEvents.length); - for (let i = 0; i < actualEvents.length; ++i) { - const actualEvent = actualEvents[i]; - const expectedEvent = expectedEvents[i]; - for (const key in actualEvent) { - expect(actualEvent[key]).toEqual(expectedEvent[key]); - } - } -} - -{ - describe('convertPerfProfileToEvents', function() { - it('should convert single instantaneous event', function() { - const profileData = { - threads: [ - {samples: [{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}]} - ] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]); - }); - - it('should convert single non-instantaneous event', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 100, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual( - perfEvents, [{ph: 'B', ts: 1, name: 'script'}, {ph: 'E', ts: 100, name: 'script'}]); - }); - - it('should convert multiple instantaneous events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'PresShell::Paint'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual( - perfEvents, [{ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}]); - }); - - it('should convert multiple mixed events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'PresShell::Paint'}]}, - {time: 5, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 10, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [ - {ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}, - {ph: 'B', ts: 5, name: 'script'}, {ph: 'E', ts: 10, name: 'script'} - ]); - }); - - it('should add args to gc events', function() { - const profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]}; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'gc', args: {usedHeapSize: 0}}]); - }); - - it('should skip unknown events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'foo'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]); - }); - }); -} diff --git a/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts b/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts deleted file mode 100644 index 2657a2347a..0000000000 --- a/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @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 - */ - -import {$, browser} from 'protractor'; - -const benchpress = require('../../index.js'); - -// TODO: this test is currnetly failing. it seems that it didn't run on the ci for a while -xdescribe('deep tree baseline', function() { - const runner = new benchpress.Runner([ - // use protractor as Webdriver client - benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS, - // use RegressionSlopeValidator to validate samples - benchpress.Validator.bind(benchpress.RegressionSlopeValidator), - // use 10 samples to calculate slope regression - benchpress.bind(benchpress.RegressionSlopeValidator.SAMPLE_SIZE).toValue(20), - // use the script metric to calculate slope regression - benchpress.bind(benchpress.RegressionSlopeValidator.METRIC).toValue('scriptTime'), - benchpress.bind(benchpress.Options.FORCE_GC).toValue(true) - ]); - - - it('should be fast!', function(done) { - browser.ignoreSynchronization = true; - browser.get('http://localhost:8001/playground/src/benchpress/'); - - /* - * Tell benchpress to click the buttons to destroy and re-create the tree for each sample. - * Benchpress will log the collected metrics after each sample is collected, and will stop - * sampling as soon as the calculated regression slope for last 20 samples is stable. - */ - runner - .sample({ - id: 'baseline', - execute: function() { $('button').click(); }, - providers: [benchpress.bind(benchpress.Options.SAMPLE_DESCRIPTION).toValue({depth: 9})] - }) - .then(done, done.fail); - }); -}); diff --git a/packages/benchpress/test/firefox_extension/spec.ts b/packages/benchpress/test/firefox_extension/spec.ts deleted file mode 100644 index 754ea37212..0000000000 --- a/packages/benchpress/test/firefox_extension/spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @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 - */ - -/* tslint:disable:no-console */ -import {browser} from 'protractor'; - -const assertEventsContainsName = function(events: any[], eventName: string) { - let found = false; - for (let i = 0; i < events.length; ++i) { - if (events[i].name == eventName) { - found = true; - break; - } - } - expect(found).toBeTruthy(); -}; - -// TODO: this test is currnetly failing. it seems that it didn't run on the ci for a while -xdescribe('firefox extension', function() { - const TEST_URL = 'http://localhost:8001/playground/src/hello_world/index.html'; - - it('should measure performance', function() { - browser.sleep(3000); // wait for extension to load - - browser.driver.get(TEST_URL); - - browser.executeScript('window.startProfiler()').then(function() { - console.log('started measuring perf'); - }); - - browser.executeAsyncScript('setTimeout(arguments[0], 1000);'); - browser.executeScript('window.forceGC()'); - - browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);') - .then(function(profile: any) { - assertEventsContainsName(profile, 'gc'); - assertEventsContainsName(profile, 'script'); - }); - }); -});