Skip to content

Commit

Permalink
Collect CPU consumption for Firefox. (#2046)
Browse files Browse the repository at this point in the history
  • Loading branch information
soulgalore authored Jan 2, 2024
1 parent c72d3a7 commit 0153b70
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 4 deletions.
11 changes: 11 additions & 0 deletions lib/core/engine/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,17 @@ export class Collector {
results.geckoPerfStats.push(data.perfStats);
}

// Add Firefox cpu power
if (data.powerConsumption) {
if (!results.powerConsumption) {
results.powerConsumption = [];
}
results.powerConsumption.push(data.powerConsumption);
statistics.addDeep({
powerConsumption: results.powerConsumption
});
}

// Add total memory
if (this.options.firefox && this.options.firefox.memoryReport) {
statistics.addDeep({
Expand Down
6 changes: 5 additions & 1 deletion lib/core/engine/command/geckoProfiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ export class GeckoProfiler {
async stop() {
if (this.options.browser === 'firefox') {
if (this.options.firefox.geckoProfilerRecordingType === 'custom') {
return this.GeckoProfiler.stop(this.index, this.result[0].url);
return this.GeckoProfiler.stop(
this.index,
this.result[0].url,
this.result
);
}
} else {
throw new Error('Geckoprofiler only works in Firefox');
Expand Down
50 changes: 49 additions & 1 deletion lib/firefox/geckoProfiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ import { BrowserError } from '../support/errors.js';
const delay = ms => new Promise(res => setTimeout(res, ms));
const log = intel.getLogger('browsertime.firefox');

// Return power usage in Wh
function computePowerSum(counter) {
let sum = 0;
// Older Firefoxes see https://github.com/sitespeedio/sitespeed.io/issues/3944#issuecomment-1871090793
if (counter.sample_groups) {
for (const groups of counter.sample_groups) {
const countIndex = groups.samples.schema.count;
for (const sample of groups.samples.data) {
sum += sample[countIndex];
}
}
} else {
const countIndex = counter.samples.schema.count;
for (const sample of counter.samples.data) {
sum += sample[countIndex];
}
}
return sum * 1e-12;
}

/**
* Timeout a promise after ms. Use promise.race to compete
* about the timeout and the promise.
Expand Down Expand Up @@ -130,7 +150,7 @@ export class GeckoProfiler {
return delay(firefoxConfig.geckoProfilerSettleTime || 3000);
}

async stop(index, url) {
async stop(index, url, result) {
const runner = this.runner;
const storageManager = this.storageManager;
const options = this.options;
Expand Down Expand Up @@ -183,6 +203,34 @@ export class GeckoProfiler {
await android._downloadFile(deviceProfileFilename, destinationFilename);
}

if (this.firefoxConfig.powerConsumption === true) {
const chosenFeatures = get(
this.firefoxConfig,
'geckoProfilerParams.features',
geckoProfilerDefaults.features
);
if (chosenFeatures.includes('power')) {
log.info('Collecting CPU power consumtion');
const profile = JSON.parse(
await storageManager.readData(
`geckoProfile-${index}.json`,
join(pathToFolder(url, options))
)
);
let power = 0;
for (const counter of profile.counters) {
if (counter.category === 'power') {
power += computePowerSum(counter);
}
}
result.powerConsumption = Number(power);
} else {
log.warning(
'Missing power setting in geckoProfilerParams.features so power will not be collected'
);
}
}

// GZIP the profile and remove the old file
log.info('Gzip file the profile.');
const name = this.options.enableProfileRun
Expand Down
2 changes: 1 addition & 1 deletion lib/firefox/webdriver/firefox.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class Firefox {
this.firefoxConfig.geckoProfiler &&
this.firefoxConfig.geckoProfilerRecordingType !== 'custom'
) {
await this.geckoProfiler.stop(index, url);
await this.geckoProfiler.stop(index, url, result);
}

if (this.firefoxConfig.perfStats) {
Expand Down
7 changes: 7 additions & 0 deletions lib/support/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ export function parseCommandLine() {
'need to specify the logs you wish to gather.',
group: 'firefox'
})
.option('firefox.powerConsumption', {
type: 'boolean',
default: false,
describe:
'Enable power consumption collection (in Wh). To get the consumption you also need to set firefox.geckoProfilerParams.features to include power.',
group: 'firefox'
})
.option('firefox.setMozLog', {
describe:
'Use in conjunction with firefox.collectMozLog to set MOZ_LOG to something ' +
Expand Down
12 changes: 11 additions & 1 deletion lib/support/statistics.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ function validateType(value, type, message) {
}
}

function hasDecimals(num) {
return num !== Math.floor(num);
}

function percentileName(percentile) {
if (percentile === 0) {
return 'min';
Expand Down Expand Up @@ -129,7 +133,7 @@ export class Statistics {
// https://en.wikipedia.org/wiki/Interquartile_range
stats = stats.iqr();
}
if (stats.median() < 1 && stats.median() > 0) {
if (stats.median() < 10 && stats.median() > 0) {
decimals = 4;
}
const node = {
Expand Down Expand Up @@ -165,6 +169,12 @@ export class Statistics {
}
if (stats.median() < 1 && stats.median() > 0) {
decimals = 4;
} else if (
hasDecimals(stats.median()) &&
stats.median() < 100 &&
stats.median() > 1
) {
decimals = 2;
}
const results = {
median: Number.parseFloat(stats.median().toFixed(decimals)),
Expand Down

0 comments on commit 0153b70

Please sign in to comment.