feat(benchpress): Add extension for ff metrics reporting

Closes #1976
This commit is contained in:
Hank Duan 2015-05-18 18:10:30 -07:00 committed by Tobias Bosch
parent 79f564be46
commit b390f441a1
9 changed files with 197 additions and 0 deletions

View File

@ -9,6 +9,7 @@
"license": "<%= packageJson.license %>",
"dependencies": {
"angular2": "<%= packageJson.version %>",
"firefox-profile": "<%= packageJson.dependencies['firefox-profile'] %>",
"rtts_assert": "<%= packageJson.version %>",
"traceur": "<%= packageJson.dependencies.traceur %>",
"selenium-webdriver": "<%= packageJson.dependencies['selenium-webdriver'] %>"

View File

@ -0,0 +1,2 @@
*.xpi
addon-sdk*

View File

@ -0,0 +1,12 @@
exportFunction(function() {
self.port.emit('startProfiler');
}, unsafeWindow, {defineAs: "startProfiler"});
exportFunction(function(filePath) {
self.port.emit('stopAndRecord', filePath);
}, unsafeWindow, {defineAs: "stopAndRecord"});
exportFunction(function() {
self.port.emit('forceGC');
}, unsafeWindow, {defineAs: "forceGC"});

View File

@ -0,0 +1,61 @@
var file = require('sdk/io/file');
var {Cc,Ci,Cu} = require("chrome");
function Profiler() {
this._profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
};
Profiler.prototype = {
start: function(entries, interval, features) {
this._profiler.StartProfiler(entries, interval, features, features.length);
},
stop: function(cb) {
this._profiler.StopProfiler();
// this.gcStats.clear();
},
getProfileData: function() {
return this._profiler.getProfileData();
}
};
function saveToFile(savePath, str) {
var textWriter = file.open(savePath, 'w');
textWriter.write(str);
textWriter.close();
}
function forceGC() {
Cu.forceGC();
var os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
os.notifyObservers(null, "child-gc-request", null);
}
var profiler = new Profiler();
function startProfiler() {
profiler.start(/* = profiler memory */ 10000000, 1, ['leaf', 'js', "stackwalk", 'gc']);
};
function stopAndRecord(filePath) {
var profileData = profiler.getProfileData();
profiler.stop();
saveToFile(filePath, JSON.stringify(profileData, null, 2));
};
var mod = require("sdk/page-mod");
var data = require("sdk/self").data;
mod.PageMod({
include: ['*'],
contentScriptFile: data.url("installed_script.js"),
onAttach: function(worker) {
worker.port.on('startProfiler', function() {
startProfiler();
});
worker.port.on('stopAndRecord', function(filePath) {
stopAndRecord(filePath);
});
worker.port.on('forceGC', function() {
forceGC();
});
}
});

View File

@ -0,0 +1,47 @@
var q = require('q');
var FirefoxProfile = require('firefox-profile');
var jpm = require('jpm/lib/xpi');
var pathUtil = require('path');
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path) {
var normalizedPath = pathUtil.normalize(path);
if (pathUtil.resolve(normalizedPath) == normalizedPath) {
// Already absolute path
return normalizedPath;
} else {
return pathUtil.join(__dirname, normalizedPath);
}
};
exports.getFirefoxProfile = function(extensionPath) {
var deferred = q.defer();
var firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], function() {
firefoxProfile.encoded(function(encodedProfile) {
var multiCapabilities = [{
browserName: 'firefox',
firefox_profile : encodedProfile
}];
deferred.resolve(multiCapabilities);
});
});
return deferred.promise;
};
exports.getFirefoxProfileWithExtension = function() {
var absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
var packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
var savedCwd = process.cwd();
process.chdir(absPackageJsonDir);
return jpm(packageJson).then(function(xpiPath) {
process.chdir(savedCwd);
return exports.getFirefoxProfile(xpiPath);
});
};

View File

@ -0,0 +1,5 @@
{
"version": "0.0.1",
"main": "lib/main.js",
"name": "ffperf-addon"
}

View File

@ -0,0 +1,18 @@
var testHelper = require('../../src/firefox_extension/lib/test_helper.js');
// Where to save profile results (parent folder must exist)
var PROFILE_SAVE_PATH = './perfProfile.json';
exports.config = {
seleniumAddress: 'http://127.0.0.1:4444/wd/hub',
specs: ['spec.js'],
getMultiCapabilities: function() {
return testHelper.getFirefoxProfileWithExtension();
},
params: {
profileSavePath: testHelper.getAbsolutePath(PROFILE_SAVE_PATH)
}
};

View File

@ -0,0 +1,50 @@
var fs = require('fs');
var validateFile = function() {
try {
var content = fs.readFileSync(browser.params.profileSavePath, 'utf8');
// TODO(hankduan): This check not very useful. Ideally we want to validate
// that the file contains all the events that we are looking for. Pending
// on data transformer.
expect(content).toContain('forceGC');
// Delete file
fs.unlinkSync(browser.params.profileSavePath);
} catch (err) {
if (err.code === 'ENOENT') {
// If files doesn't exist
console.error('Error: firefox extension did not save profile JSON');
} else {
console.error('Error: ' + err);
}
throw err;
}
};
describe('firefox extension', function() {
it ('should measure performance', function() {
browser.sleep(3000); // wait for extension to load
browser.driver.get('http://www.angularjs.org');
browser.executeScript('window.startProfiler()').then(function() {
console.log('started measuring perf');
});
browser.executeScript('window.forceGC()');
// Run some commands
element(by.model('yourName')).sendKeys('Hank');
expect(element(by.binding('yourName')).getText()).toEqual('Hello Hank!');
browser.executeScript('window.forceGC()');
var script =
'window.stopAndRecord("' + browser.params.profileSavePath + '")';
browser.executeScript(script).then(function() {
console.log('stopped measuring perf');
});
// wait for it to finish, then validate file.
browser.sleep(3000).then(validateFile);
})
});

View File

@ -25,6 +25,7 @@
},
"dependencies": {
"es6-module-loader": "^0.9.2",
"firefox-profile": "0.3.4",
"googleapis": "1.0.x",
"gulp-insert": "^0.4.0",
"gulp-modify": "0.0.5",