-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Poor performance while loading date-fns
#75
Comments
@nwalters512 Thanks for the excellent issue! Here is some playing of mine. First my "slow.js": const { Hook } = require('./'); // require-in-the-middle
const N = 1
for (var i = 0; i < N; i++) {
// How @opentelemetry/instrumentation uses RITM:
const moduleNames = null
const opts = { internals: true }
// // How elastic-apm-node uses RITM:
// const moduleNames = ['http', 'https', 'ioreds' /* ... */]
// const opts = {}
// // Nathan
// const moduleNames = null
// const opts = {}
new Hook(moduleNames, opts, function (exports, name, basedir) {
return exports;
});
}
const start = Date.now();
require('date-fns');
console.error(`loaded date-fns in ${Date.now() - start}ms`); baselineAs a baseline, here are a few runs without a Hook (i.e.
internals=trueA difference from your runs is that I'm setting With N=1 hook, no opts, as you were running:
With N=1 hook,
Your patch is still very effective for both cases. With N=1 hook, no opts, and your patch (see below):
With N=1 hook,
Here I'm assuming your patch is something like: diff --git a/index.js b/index.js
index bc1fddf..b0ad25b 100644
--- a/index.js
+++ b/index.js
@@ -236,6 +237,7 @@ function Hook (modules, options, onrequire) {
res = resolve.sync(moduleName, { basedir })
} catch (e) {
debug('could not resolve module: %s', moduleName)
+ self._cache.set(filename, exports, core) // XXX
return exports // abort if module could not be resolved (e.g. no main in package.json and no index.js file)
}
@@ -247,6 +249,7 @@ function Hook (modules, options, onrequire) {
debug('preparing to process require of internal file: %s', moduleName)
} else {
debug('ignoring require of non-main module file: %s', res)
+ self._cache.set(filename, exports, core) // XXX
return exports // abort if not main module file
}
} |
This can be a big perf win when using the Hook *without* the modules argument, e.g.: `new Hook(null, onrequire)`. Fixes: #75
I recently discovered that this package (via
@opentelemetry/*
) is causing significant slowdowns when loading packages that internally require a large number of files. I useddate-fns
as an example, as it's easy to reproduce the issue with it, but I believe it occurs for any package that internally uses a large number of files, or that loads the same files over and over again from other files.Reproduction
In the root of this repository, install
date-fns
:Create the following
slow.js
file in the root of this repository:Run this script with
node slow.js
and observe how long it takes to load; on my machine, it's ~100ms.Now, add a no-op require hook that doesn't filter modules:
Run the script again, and observe that the runtime has more than tripled (it's ~330ms on my machine).
Now, add more hooks to simulate a worst-case scenario like that described in open-telemetry/opentelemetry-js-contrib#1566, where you inadvertently end up with many hooks installed:
Observe that the runtime has increased yet again, this time to ~1.7 seconds, just to load a single module!
Potential fix
I noticed that there's an cache for resolved modules. However, it's unused in two cases that
date-fns
seems to hit frequently:I added
self._cache.set(filename, exports, core)
before each of thosereturn exports
statements, and with 7 hooks installed, that brought the time to loaddate-fns
down from ~1.7 seconds to just 338ms! This still isn't nearly as fast as loading it without therequire-in-the-middle
hooks, but it's a significant improvement.I don't know how safe this is; maybe there's a good reason the exports cache isn't used in these code paths! However, if y'all think this would be safe, I'd be happy to open a PR with this improvement.
The text was updated successfully, but these errors were encountered: