browsertime 17.8.0 → 17.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/bin/browsertime.js +22 -0
- package/lib/chrome/webdriver/chromium.js +5 -1
- package/lib/core/engine/collector.js +4 -1
- package/lib/core/engine/command/geckoProfiler.js +38 -0
- package/lib/core/engine/index.js +3 -1
- package/lib/core/engine/iteration.js +14 -0
- package/lib/firefox/geckoProfiler.js +31 -18
- package/lib/firefox/settings/geckoProfilerDefaults.js +7 -5
- package/lib/firefox/webdriver/firefox.js +8 -3
- package/lib/support/cli.js +17 -11
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
## 17.9.0 - 2022-04-19
|
|
4
|
+
### Added
|
|
5
|
+
* New command to start geckoprofiling when scripting using Firefox. Thank you [KS](https://github.com/92kns) for PR [#1934](https://github.com/sitespeedio/browsertime/pull/1934). This is probably only something you need if you work at Mozilla. There's also a follow PR [#1940](https://github.com/sitespeedio/browsertime/pull/1940) that fixes some of the issues I've been wanted to fix with the Geckoprofiler code.
|
|
6
|
+
|
|
7
|
+
* Use `--enableProfileRun` to make one extra run where metrics aren't collected but Geckoprofiler or Chromes timeline log is turned on. This useful if you are worrying about the trace causing overhead, but you still wan trace from the test/journey. It's a little rough at the moment so it will a follow up in the future [#1943](https://github.com/sitespeedio/browsertime/pull/1943).
|
|
8
|
+
|
|
9
|
+
## 17.8.1 - 2022-04-12
|
|
10
|
+
### Fixed
|
|
11
|
+
* Upgraded to Firefox HAR 0.0.10 [#1939](https://github.com/sitespeedio/browsertime/pull/1939).
|
|
3
12
|
## 17.8.0 - 2022-04-11
|
|
4
13
|
### Fixed
|
|
5
14
|
* Upgraded to Firefox HAR 0.0.8 [#1937](https://github.com/sitespeedio/browsertime/pull/1937).
|
package/bin/browsertime.js
CHANGED
|
@@ -122,6 +122,28 @@ async function run(urls, options) {
|
|
|
122
122
|
storageManager.writeJson(harName + '.har', result.har, useGzip)
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
if (options.enableProfileRun) {
|
|
127
|
+
log.info('Make one extra run to collect trace information');
|
|
128
|
+
options.iterations = 1;
|
|
129
|
+
if (options.browser === 'firefox') {
|
|
130
|
+
options.firefox.geckoProfiler = true;
|
|
131
|
+
} else if (options.browser === 'chrome') {
|
|
132
|
+
options.chrome.timeline = true;
|
|
133
|
+
options.cpu = true;
|
|
134
|
+
options.chrome.enableTraceScreenshots = true;
|
|
135
|
+
options.chrome.traceCategory = [
|
|
136
|
+
'disabled-by-default-v8.cpu_profiler'
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
options.video = false;
|
|
140
|
+
options.visualMetrics = false;
|
|
141
|
+
const traceEngine = new Engine(options);
|
|
142
|
+
await traceEngine.start();
|
|
143
|
+
await traceEngine.runMultiple(urls, scriptsByCategory);
|
|
144
|
+
await traceEngine.stop();
|
|
145
|
+
}
|
|
146
|
+
|
|
125
147
|
await Promise.all(saveOperations);
|
|
126
148
|
|
|
127
149
|
const resultDirectory = relative(process.cwd(), storageManager.directory);
|
|
@@ -331,7 +331,11 @@ export class Chromium {
|
|
|
331
331
|
|
|
332
332
|
if (this.collectTracingEvents) {
|
|
333
333
|
const trace = parse(this.events, result.url);
|
|
334
|
-
|
|
334
|
+
const name = this.options.enableProfileRun
|
|
335
|
+
? `trace-${index}-extra-run.json`
|
|
336
|
+
: `trace-${index}.json`;
|
|
337
|
+
result.extraJson[name] = trace;
|
|
338
|
+
|
|
335
339
|
const cpu = await parseCPUTrace(trace, result.url);
|
|
336
340
|
result.cpu = cpu;
|
|
337
341
|
|
|
@@ -503,8 +503,11 @@ export class Collector {
|
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
if (this.options.firefox && this.options.firefox.geckoProfiler) {
|
|
506
|
+
const name = this.options.enableProfileRun
|
|
507
|
+
? `geckoProfile-${index}-extra.json.gz`
|
|
508
|
+
: `geckoProfile-${index}.json.gz`;
|
|
506
509
|
results.files.geckoProfiles.push(
|
|
507
|
-
`${pathToFolder(url, this.options)}
|
|
510
|
+
`${pathToFolder(url, this.options)}${name}`
|
|
508
511
|
);
|
|
509
512
|
}
|
|
510
513
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
const log = intel.getLogger('browsertime.command.geckoprofiler');
|
|
3
|
+
export class GeckoProfiler {
|
|
4
|
+
constructor(GeckoProfiler, browser, index, options) {
|
|
5
|
+
this.GeckoProfiler = GeckoProfiler;
|
|
6
|
+
this.browser = browser;
|
|
7
|
+
this.index = index;
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async start() {
|
|
12
|
+
if (this.options.browser === 'firefox') {
|
|
13
|
+
if (this.options.firefox.geckoProfilerRecordingType === 'custom') {
|
|
14
|
+
return this.GeckoProfiler.start();
|
|
15
|
+
} else {
|
|
16
|
+
log.info(
|
|
17
|
+
'You need to set geckoProfilerRecordingType to custom to turn on the profiler in scripting'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
throw new Error('Geckoprofiler only works in Firefox');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async stop() {
|
|
26
|
+
if (this.options.browser === 'firefox') {
|
|
27
|
+
if (this.options.firefox.geckoProfilerRecordingType === 'custom') {
|
|
28
|
+
const url = await this.browser
|
|
29
|
+
.getDriver()
|
|
30
|
+
.executeScript('return document.documentURI;');
|
|
31
|
+
|
|
32
|
+
return this.GeckoProfiler.stop(this.index, url);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error('Geckoprofiler only works in Firefox');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/lib/core/engine/index.js
CHANGED
|
@@ -41,6 +41,8 @@ import { getNumberOfRunningProcesses } from '../../support/processes.js';
|
|
|
41
41
|
import { isAndroidConfigured, Android } from '../../android/index.js';
|
|
42
42
|
import { Scroll } from './command/scroll.js';
|
|
43
43
|
import { Navigation } from './command/navigation.js';
|
|
44
|
+
import { GeckoProfiler } from '../../firefox/geckoProfiler.js';
|
|
45
|
+
import { GeckoProfiler as GeckoProfilerCommand } from './command/geckoProfiler.js';
|
|
44
46
|
const log = intel.getLogger('browsertime');
|
|
45
47
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
46
48
|
|
|
@@ -147,6 +149,17 @@ export class Iteration {
|
|
|
147
149
|
options
|
|
148
150
|
);
|
|
149
151
|
|
|
152
|
+
const browserProfiler = new GeckoProfiler(
|
|
153
|
+
browser,
|
|
154
|
+
this.storageManager,
|
|
155
|
+
this.options
|
|
156
|
+
);
|
|
157
|
+
const profiler = new GeckoProfilerCommand(
|
|
158
|
+
browserProfiler,
|
|
159
|
+
browser,
|
|
160
|
+
index,
|
|
161
|
+
this.options
|
|
162
|
+
);
|
|
150
163
|
const cdp = new ChromeDevelopmentToolsProtocol(
|
|
151
164
|
engineDelegate,
|
|
152
165
|
options.browser
|
|
@@ -154,6 +167,7 @@ export class Iteration {
|
|
|
154
167
|
const android = new Android(options);
|
|
155
168
|
const debug = new Debug(browser, options);
|
|
156
169
|
const commands = {
|
|
170
|
+
profiler: profiler,
|
|
157
171
|
click: new Click(browser, this.pageCompleteCheck),
|
|
158
172
|
scroll: new Scroll(browser, options),
|
|
159
173
|
addText: new AddText(browser),
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import get from 'lodash.get';
|
|
3
3
|
import intel from 'intel';
|
|
4
|
-
import {
|
|
5
|
-
android_sampling_interval,
|
|
6
|
-
desktop_sampling_interval
|
|
7
|
-
} from './settings/geckoProfilerDefaults.js';
|
|
4
|
+
import { geckoProfilerDefaults } from './settings/geckoProfilerDefaults.js';
|
|
8
5
|
import { isAndroidConfigured, Android } from '../android/index.js';
|
|
9
6
|
import { pathToFolder } from '../support/pathToFolder.js';
|
|
10
7
|
import { BrowserError } from '../support/errors.js';
|
|
@@ -33,10 +30,10 @@ async function timeout(promise, ms, errorMessage) {
|
|
|
33
30
|
]);
|
|
34
31
|
}
|
|
35
32
|
export class GeckoProfiler {
|
|
36
|
-
constructor(runner, storageManager,
|
|
33
|
+
constructor(runner, storageManager, options) {
|
|
37
34
|
this.runner = runner;
|
|
38
35
|
this.storageManager = storageManager;
|
|
39
|
-
this.firefoxConfig =
|
|
36
|
+
this.firefoxConfig = options.firefox;
|
|
40
37
|
this.options = options;
|
|
41
38
|
}
|
|
42
39
|
|
|
@@ -44,14 +41,26 @@ export class GeckoProfiler {
|
|
|
44
41
|
const runner = this.runner;
|
|
45
42
|
const firefoxConfig = this.firefoxConfig;
|
|
46
43
|
const options = this.options;
|
|
47
|
-
const chosenFeatures =
|
|
48
|
-
firefoxConfig
|
|
44
|
+
const chosenFeatures = get(
|
|
45
|
+
firefoxConfig,
|
|
46
|
+
'geckoProfilerParams.features',
|
|
47
|
+
geckoProfilerDefaults.features
|
|
48
|
+
).split(',');
|
|
49
|
+
|
|
49
50
|
const featureString = '["' + chosenFeatures.join('","') + '"]';
|
|
50
51
|
|
|
51
|
-
const chosenThreads =
|
|
52
|
+
const chosenThreads = get(
|
|
53
|
+
firefoxConfig,
|
|
54
|
+
'geckoProfilerParams.threads',
|
|
55
|
+
geckoProfilerDefaults.threads
|
|
56
|
+
).split(',');
|
|
52
57
|
const threadString = '["' + chosenThreads.join('","') + '"]';
|
|
53
58
|
|
|
54
|
-
let interval =
|
|
59
|
+
let interval = get(
|
|
60
|
+
firefoxConfig,
|
|
61
|
+
'geckoProfilerParams.interval',
|
|
62
|
+
geckoProfilerDefaults.interval
|
|
63
|
+
);
|
|
55
64
|
|
|
56
65
|
// Set platform specific sampling intervals if not explicitly specified.
|
|
57
66
|
if (
|
|
@@ -59,11 +68,15 @@ export class GeckoProfiler {
|
|
|
59
68
|
!firefoxConfig.geckoProfilerParams.interval
|
|
60
69
|
) {
|
|
61
70
|
interval = isAndroidConfigured(options)
|
|
62
|
-
?
|
|
63
|
-
:
|
|
71
|
+
? geckoProfilerDefaults.androidSamplingInterval
|
|
72
|
+
: geckoProfilerDefaults.desktopSamplingInterval;
|
|
64
73
|
}
|
|
65
74
|
|
|
66
|
-
const bufferSize =
|
|
75
|
+
const bufferSize = get(
|
|
76
|
+
firefoxConfig,
|
|
77
|
+
'geckoProfilerParams.bufferSize',
|
|
78
|
+
geckoProfilerDefaults.bufferSize
|
|
79
|
+
);
|
|
67
80
|
|
|
68
81
|
// Firefox 69 and above has a slightly different API for StartProfiler
|
|
69
82
|
// See nsIProfiler::StartProfiler in tools/profiler/gecko/nsIProfiler.idl
|
|
@@ -121,6 +134,7 @@ export class GeckoProfiler {
|
|
|
121
134
|
const runner = this.runner;
|
|
122
135
|
const storageManager = this.storageManager;
|
|
123
136
|
const options = this.options;
|
|
137
|
+
|
|
124
138
|
let profileDir = await storageManager.createSubDataDir(
|
|
125
139
|
join(pathToFolder(url, options))
|
|
126
140
|
);
|
|
@@ -171,12 +185,11 @@ export class GeckoProfiler {
|
|
|
171
185
|
|
|
172
186
|
// GZIP the profile and remove the old file
|
|
173
187
|
log.info('Gzip file the profile.');
|
|
188
|
+
const name = this.options.enableProfileRun
|
|
189
|
+
? `geckoProfile-${index}-extra.json.gz`
|
|
190
|
+
: `geckoProfile-${index}.json.gz`;
|
|
174
191
|
await timeout(
|
|
175
|
-
storageManager.gzip(
|
|
176
|
-
destinationFilename,
|
|
177
|
-
join(profileDir, `geckoProfile-${index}.json.gz`),
|
|
178
|
-
true
|
|
179
|
-
),
|
|
192
|
+
storageManager.gzip(destinationFilename, join(profileDir, name), true),
|
|
180
193
|
300_000, // 5 minutes
|
|
181
194
|
'Could not gzip the profile.'
|
|
182
195
|
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
export const geckoProfilerDefaults = {
|
|
2
|
+
features: 'js,stackwalk,leaf',
|
|
3
|
+
threads: 'GeckoMain,Compositor,Renderer',
|
|
4
|
+
desktopSamplingInterval: 1,
|
|
5
|
+
androidSamplingInterval: 4,
|
|
6
|
+
bufferSize: 13_107_200 // 100MB
|
|
7
|
+
};
|
|
@@ -101,11 +101,13 @@ export class Firefox {
|
|
|
101
101
|
await this.android.resetPowerUsage();
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
if (
|
|
104
|
+
if (
|
|
105
|
+
this.firefoxConfig.geckoProfiler &&
|
|
106
|
+
this.firefoxConfig.geckoProfilerRecordingType !== 'custom'
|
|
107
|
+
) {
|
|
105
108
|
this.geckoProfiler = new GeckoProfiler(
|
|
106
109
|
runner,
|
|
107
110
|
this.storageManager,
|
|
108
|
-
this.firefoxConfig,
|
|
109
111
|
this.options
|
|
110
112
|
);
|
|
111
113
|
|
|
@@ -133,7 +135,10 @@ export class Firefox {
|
|
|
133
135
|
);
|
|
134
136
|
}
|
|
135
137
|
|
|
136
|
-
if (
|
|
138
|
+
if (
|
|
139
|
+
this.firefoxConfig.geckoProfiler &&
|
|
140
|
+
this.firefoxConfig.geckoProfilerRecordingType !== 'custom'
|
|
141
|
+
) {
|
|
137
142
|
await this.geckoProfiler.stop(index, url);
|
|
138
143
|
}
|
|
139
144
|
|
package/lib/support/cli.js
CHANGED
|
@@ -14,13 +14,7 @@ import {
|
|
|
14
14
|
xvfbDisplay
|
|
15
15
|
} from '../video/defaults.js';
|
|
16
16
|
import { screenshotDefaults } from '../screenshot/defaults.js';
|
|
17
|
-
import {
|
|
18
|
-
features,
|
|
19
|
-
threads as _threads,
|
|
20
|
-
desktop_sampling_interval,
|
|
21
|
-
android_sampling_interval,
|
|
22
|
-
bufferSize
|
|
23
|
-
} from '../firefox/settings/geckoProfilerDefaults.js';
|
|
17
|
+
import { geckoProfilerDefaults } from '../firefox/settings/geckoProfilerDefaults.js';
|
|
24
18
|
|
|
25
19
|
const configPath = findUpSync(['.browsertime.json']);
|
|
26
20
|
|
|
@@ -472,26 +466,33 @@ export function parseCommandLine() {
|
|
|
472
466
|
type: 'boolean',
|
|
473
467
|
group: 'firefox'
|
|
474
468
|
})
|
|
469
|
+
.option('firefox.geckoProfilerRecordingType', {
|
|
470
|
+
describe: 'Expose the start/stop commands for the gecko profiler',
|
|
471
|
+
default: 'pageload',
|
|
472
|
+
choices: ['pageload', 'custom'],
|
|
473
|
+
type: 'string',
|
|
474
|
+
group: 'firefox'
|
|
475
|
+
})
|
|
475
476
|
.option('firefox.geckoProfilerParams.features', {
|
|
476
477
|
describe: 'Enabled features during gecko profiling',
|
|
477
|
-
default: features,
|
|
478
|
+
default: geckoProfilerDefaults.features,
|
|
478
479
|
type: 'string',
|
|
479
480
|
group: 'firefox'
|
|
480
481
|
})
|
|
481
482
|
.option('firefox.geckoProfilerParams.threads', {
|
|
482
483
|
describe: 'Threads to profile.',
|
|
483
|
-
default:
|
|
484
|
+
default: geckoProfilerDefaults.threads,
|
|
484
485
|
type: 'string',
|
|
485
486
|
group: 'firefox'
|
|
486
487
|
})
|
|
487
488
|
.option('firefox.geckoProfilerParams.interval', {
|
|
488
|
-
describe: `Sampling interval in ms. Defaults to ${
|
|
489
|
+
describe: `Sampling interval in ms. Defaults to ${geckoProfilerDefaults.desktopSamplingInterval} on desktop, and ${geckoProfilerDefaults.androidSamplingInterval} on android.`,
|
|
489
490
|
type: 'number',
|
|
490
491
|
group: 'firefox'
|
|
491
492
|
})
|
|
492
493
|
.option('firefox.geckoProfilerParams.bufferSize', {
|
|
493
494
|
describe: 'Buffer size in elements. Default is ~90MB.',
|
|
494
|
-
default: bufferSize,
|
|
495
|
+
default: geckoProfilerDefaults.bufferSize,
|
|
495
496
|
type: 'number',
|
|
496
497
|
group: 'firefox'
|
|
497
498
|
})
|
|
@@ -578,6 +579,11 @@ export function parseCommandLine() {
|
|
|
578
579
|
'URL to a running Selenium server (e.g. to run a browser on another machine).',
|
|
579
580
|
group: 'selenium'
|
|
580
581
|
})
|
|
582
|
+
.option('enableProfileRun', {
|
|
583
|
+
type: 'boolean',
|
|
584
|
+
describe:
|
|
585
|
+
'Make one extra run that collects the profiling trace log (no other metrics is collected). For Chrome it will collect the timeline trace, for Firefox it will get the Geckoprofiler trace. This means you do not need to get the trace for all runs and can skip the overhead it produces.'
|
|
586
|
+
})
|
|
581
587
|
.option('video', {
|
|
582
588
|
type: 'boolean',
|
|
583
589
|
describe:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browsertime",
|
|
3
3
|
"description": "Get performance metrics from your web page using Browsertime.",
|
|
4
|
-
"version": "17.
|
|
4
|
+
"version": "17.9.0",
|
|
5
5
|
"bin": "./bin/browsertime.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"dependencies": {
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"@sitespeed.io/geckodriver": "0.33.0",
|
|
13
13
|
"@sitespeed.io/throttle": "5.0.0",
|
|
14
14
|
"@sitespeed.io/tracium": "0.3.3",
|
|
15
|
-
"ff-test-bidi-har-export": "0.0.
|
|
15
|
+
"ff-test-bidi-har-export": "0.0.10",
|
|
16
16
|
"btoa": "1.2.1",
|
|
17
17
|
"chrome-har": "0.13.1",
|
|
18
|
-
"chrome-remote-interface": "0.32.
|
|
18
|
+
"chrome-remote-interface": "0.32.2",
|
|
19
19
|
"dayjs": "1.11.7",
|
|
20
|
-
"execa": "7.
|
|
20
|
+
"execa": "7.1.1",
|
|
21
21
|
"fast-stats": "0.0.6",
|
|
22
22
|
"find-up": "6.3.0",
|
|
23
23
|
"get-port": "6.1.2",
|