Skip to content

Commit b390f44

Browse files
hankduantbosch
authored andcommitted
feat(benchpress): Add extension for ff metrics reporting
Closes #1976
1 parent 79f564b commit b390f44

File tree

9 files changed

+197
-0
lines changed

9 files changed

+197
-0
lines changed

modules/benchpress/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"license": "<%= packageJson.license %>",
1010
"dependencies": {
1111
"angular2": "<%= packageJson.version %>",
12+
"firefox-profile": "<%= packageJson.dependencies['firefox-profile'] %>",
1213
"rtts_assert": "<%= packageJson.version %>",
1314
"traceur": "<%= packageJson.dependencies.traceur %>",
1415
"selenium-webdriver": "<%= packageJson.dependencies['selenium-webdriver'] %>"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.xpi
2+
addon-sdk*
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
exportFunction(function() {
2+
self.port.emit('startProfiler');
3+
}, unsafeWindow, {defineAs: "startProfiler"});
4+
5+
exportFunction(function(filePath) {
6+
self.port.emit('stopAndRecord', filePath);
7+
}, unsafeWindow, {defineAs: "stopAndRecord"});
8+
9+
exportFunction(function() {
10+
self.port.emit('forceGC');
11+
}, unsafeWindow, {defineAs: "forceGC"});
12+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
var file = require('sdk/io/file');
2+
var {Cc,Ci,Cu} = require("chrome");
3+
4+
function Profiler() {
5+
this._profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
6+
};
7+
8+
Profiler.prototype = {
9+
start: function(entries, interval, features) {
10+
this._profiler.StartProfiler(entries, interval, features, features.length);
11+
},
12+
stop: function(cb) {
13+
this._profiler.StopProfiler();
14+
// this.gcStats.clear();
15+
},
16+
getProfileData: function() {
17+
return this._profiler.getProfileData();
18+
}
19+
};
20+
21+
function saveToFile(savePath, str) {
22+
var textWriter = file.open(savePath, 'w');
23+
textWriter.write(str);
24+
textWriter.close();
25+
}
26+
27+
function forceGC() {
28+
Cu.forceGC();
29+
var os = Cc["@mozilla.org/observer-service;1"]
30+
.getService(Ci.nsIObserverService);
31+
os.notifyObservers(null, "child-gc-request", null);
32+
}
33+
34+
var profiler = new Profiler();
35+
function startProfiler() {
36+
profiler.start(/* = profiler memory */ 10000000, 1, ['leaf', 'js', "stackwalk", 'gc']);
37+
};
38+
function stopAndRecord(filePath) {
39+
var profileData = profiler.getProfileData();
40+
profiler.stop();
41+
saveToFile(filePath, JSON.stringify(profileData, null, 2));
42+
};
43+
44+
45+
var mod = require("sdk/page-mod");
46+
var data = require("sdk/self").data;
47+
mod.PageMod({
48+
include: ['*'],
49+
contentScriptFile: data.url("installed_script.js"),
50+
onAttach: function(worker) {
51+
worker.port.on('startProfiler', function() {
52+
startProfiler();
53+
});
54+
worker.port.on('stopAndRecord', function(filePath) {
55+
stopAndRecord(filePath);
56+
});
57+
worker.port.on('forceGC', function() {
58+
forceGC();
59+
});
60+
}
61+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
var q = require('q');
2+
var FirefoxProfile = require('firefox-profile');
3+
var jpm = require('jpm/lib/xpi');
4+
var pathUtil = require('path');
5+
6+
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
7+
8+
exports.getAbsolutePath = function(path) {
9+
var normalizedPath = pathUtil.normalize(path);
10+
if (pathUtil.resolve(normalizedPath) == normalizedPath) {
11+
// Already absolute path
12+
return normalizedPath;
13+
} else {
14+
return pathUtil.join(__dirname, normalizedPath);
15+
}
16+
};
17+
18+
exports.getFirefoxProfile = function(extensionPath) {
19+
var deferred = q.defer();
20+
21+
var firefoxProfile = new FirefoxProfile();
22+
firefoxProfile.addExtensions([extensionPath], function() {
23+
firefoxProfile.encoded(function(encodedProfile) {
24+
var multiCapabilities = [{
25+
browserName: 'firefox',
26+
firefox_profile : encodedProfile
27+
}];
28+
deferred.resolve(multiCapabilities);
29+
});
30+
});
31+
32+
return deferred.promise;
33+
};
34+
35+
exports.getFirefoxProfileWithExtension = function() {
36+
var absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
37+
var packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
38+
39+
var savedCwd = process.cwd();
40+
process.chdir(absPackageJsonDir);
41+
42+
return jpm(packageJson).then(function(xpiPath) {
43+
process.chdir(savedCwd);
44+
return exports.getFirefoxProfile(xpiPath);
45+
});
46+
};
47+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"version": "0.0.1",
3+
"main": "lib/main.js",
4+
"name": "ffperf-addon"
5+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var testHelper = require('../../src/firefox_extension/lib/test_helper.js');
2+
3+
// Where to save profile results (parent folder must exist)
4+
var PROFILE_SAVE_PATH = './perfProfile.json';
5+
6+
exports.config = {
7+
seleniumAddress: 'http://127.0.0.1:4444/wd/hub',
8+
9+
specs: ['spec.js'],
10+
11+
getMultiCapabilities: function() {
12+
return testHelper.getFirefoxProfileWithExtension();
13+
},
14+
15+
params: {
16+
profileSavePath: testHelper.getAbsolutePath(PROFILE_SAVE_PATH)
17+
}
18+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
var fs = require('fs');
2+
3+
var validateFile = function() {
4+
try {
5+
var content = fs.readFileSync(browser.params.profileSavePath, 'utf8');
6+
// TODO(hankduan): This check not very useful. Ideally we want to validate
7+
// that the file contains all the events that we are looking for. Pending
8+
// on data transformer.
9+
expect(content).toContain('forceGC');
10+
// Delete file
11+
fs.unlinkSync(browser.params.profileSavePath);
12+
} catch (err) {
13+
if (err.code === 'ENOENT') {
14+
// If files doesn't exist
15+
console.error('Error: firefox extension did not save profile JSON');
16+
} else {
17+
console.error('Error: ' + err);
18+
}
19+
throw err;
20+
}
21+
};
22+
23+
describe('firefox extension', function() {
24+
it ('should measure performance', function() {
25+
browser.sleep(3000); // wait for extension to load
26+
27+
browser.driver.get('http://www.angularjs.org');
28+
29+
browser.executeScript('window.startProfiler()').then(function() {
30+
console.log('started measuring perf');
31+
});
32+
33+
browser.executeScript('window.forceGC()');
34+
35+
// Run some commands
36+
element(by.model('yourName')).sendKeys('Hank');
37+
expect(element(by.binding('yourName')).getText()).toEqual('Hello Hank!');
38+
39+
browser.executeScript('window.forceGC()');
40+
41+
var script =
42+
'window.stopAndRecord("' + browser.params.profileSavePath + '")';
43+
browser.executeScript(script).then(function() {
44+
console.log('stopped measuring perf');
45+
});
46+
47+
// wait for it to finish, then validate file.
48+
browser.sleep(3000).then(validateFile);
49+
})
50+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
},
2626
"dependencies": {
2727
"es6-module-loader": "^0.9.2",
28+
"firefox-profile": "0.3.4",
2829
"googleapis": "1.0.x",
2930
"gulp-insert": "^0.4.0",
3031
"gulp-modify": "0.0.5",

0 commit comments

Comments
 (0)