Skip to content

Add option and scripts to display and compare performance timings - #2045

Merged
lukastaegert merged 10 commits into
masterfrom
enable-perf-display
Mar 14, 2018
Merged

Add option and scripts to display and compare performance timings#2045
lukastaegert merged 10 commits into
masterfrom
enable-perf-display

Conversation

@lukastaegert

@lukastaegert lukastaegert commented Mar 11, 2018

Copy link
Copy Markdown
Member

With the growing need to get reliable performance metrics, this PR aims to provide a comprehensive solution.

  1. The JavaScript API receives a new perf: true/false option. When this option is supplied, performance information is gathered and the bundle receives a new getTimings function that can be used to query all accumulated timings up to a certain point
  2. If perf: true is used, in addition to timing rollup's own code, timing information will also gathered for most plugin hooks individually by plugin.
  3. If the option is not supplied, all timing functions present in the code will be replaced with empty functions.
  4. If perf: true is used via the config file interface (or --perf via the CLI), gathered timings will be displayed after the run. Timings are identified via labels that use a markdown-like syntax to receive some formatting.
  5. A new perf:init script has been added to the package.json file. This script receives a <Github username>/<repo name> or <Github username>/<repo name>#<branch> string as parameter to identify a repo that will be checked out into the /perf folder. The repo needs to contain a rollup.config.js file at the top level (you can use e.g. rollup/rollup) and can be used as a base for performance measurements.
  6. A new perf script has been added to the package.json file. This script will use the current version of rollup in /dist and use it via the JavaScript API to bundle the code in the /perf folder. If there are several configurations present, only the first input and output configuration is used.
  7. If the script is run for the first time, a new file /perf/rollup.perf.json is created to store the current measurements. If this file is already present, it will not be overwritten. Instead, deviations from the previous run will be displayed.
  8. As measurements can be very volatile, "npm run perf" by default bundles the repo 6 times and discards for each timing label the 3 largest results. The rest will then be averaged. You can control this behaviour by e.g. running "npm run perf 8 2" to do 8 runs with 2 discarded results instead.
  9. To get even better code-level performance information, "npm run perf:debug" will instead run rollup in e.g. Chrome devtools.

Otherwise I think the best way to get a feeling for this, try it our yourself! Run

npm run perf:init rollup/rollup
npm run perf
npm run perf

and see what happens.

@guybedford guybedford left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work - this will be an awesome base to work on performance further!

Comment thread scripts/perf-init.js
if (process.argv.length !== 3 || !VALID_REPO.test(repo)) {
console.error(
'You need to provide a GitHub repo in the form <username>/<repo>, e.g. ' +
'"npm run perf:init rollup/rollup"'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thought I'd mention - it could be useful to support npm run perf:init rollup/rollup#branch-name where the branch becomes -b ${branchName} in the git clone when provided.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Even though the intention is to test is your current installation of rollup and not what you install in the perf folder, this feature could also be used to easily work on and debug rollup problems with branches in repos.

Comment thread scripts/perf-init.js Outdated
.catch(error => {
console.error(error);
process.exit(1);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This context could be a good excuse to use async/await...

Comment thread src/Chunk.ts Outdated

const TIME_RENDER_MODULES = '- render modules';
const TIME_RENDER_FORMAT = '- render format';
const TIME_SOURCEMAP = '- sourcemap';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps have the names without the - and add this in the timers utility code rather?

Comment thread src/rollup/index.ts Outdated

if (optionError) inputOptions.onwarn({ message: optionError, code: 'UNKNOWN_OPTION' });
const TIME_BUILD = '# BUILD';
const TIME_GENERATE = '# GENERATE';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see you included the markers to distinguish hierarchy at this level.

Perhaps timeStart can take a second argument representing the heading number?

Comment thread scripts/perf.js Outdated
await buildAndGetTimings(config);
console.info('Completed initial run (Discarded).');
const timings = await buildAndGetTimings(config);
console.info('Completed run 1.');

@guybedford guybedford Mar 12, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be useful to have some basic timing information as these show for quick perf testing when one doesn't want to wait for all the runs to complete (think eg ping).

@guybedford

Copy link
Copy Markdown
Contributor

I've been testing this out and there still appears to be quite a bit of variation in the timings.

Perhaps run a manual GC call between runs to help avoid GC randomness?

This can be done with node --expose-gc wrapper for the main execution thread and a gc() call between runs.

@lukastaegert

Copy link
Copy Markdown
Member Author

@guybedford I have implemented all suggestions and did some further changes:

  • The npm script will now garbage collect before each run
  • Instead of discarding outliers, we are discarding the largest results each
  • While gathering timings, current top level results are displayed after each run (already doing some of the discarding/averaging)

Maybe you want to have another look so that we can merge this soon.

@guybedford

Copy link
Copy Markdown
Contributor

Looks great to me, please do go ahead with the merge.

@lukastaegert lukastaegert added this to the 0.57.0 milestone Mar 14, 2018
@lukastaegert
lukastaegert merged commit bbd8289 into master Mar 14, 2018
@lukastaegert
lukastaegert deleted the enable-perf-display branch March 14, 2018 05:16
@mourner

mourner commented Mar 14, 2018

Copy link
Copy Markdown
Contributor

@lukastaegert trying this out on mapbox/mapbox-gl-js, I'm getting:

(node:70891) UnhandledPromiseRejectionWarning: Error: Could not resolve entry (src/index.js)
    at error (/Users/mourner/projects/rollup/dist/rollup.js:168:15)
    at /Users/mourner/projects/rollup/dist/rollup.js:21174:17
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
    at Function.Module.runMain (module.js:695:11)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3
(node:70891) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:70891) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Any clues?

@mourner

mourner commented Mar 14, 2018

Copy link
Copy Markdown
Contributor

Nevermind, forgot to npm install after pulling in the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants