jest: Calls to Math are several orders of magnitude slower than when run outside of Jest
It appears that at least some calls to Math (only tested abs
and acos
) are several orders of magnitude slower than when run outside of the Jest environment.
See this repo and follow the first list of instructions to reproduce the issue. Running Math.abs
ten million times takes about 10ms
outside of Jest, but increases to about 2000ms
within a Jest environment.
OS: macOS High Sierra 10.13.2 Jest: 21.2.1 Node: 8.9.1 NPM: 5.5.1
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 11
- Comments: 27 (10 by maintainers)
@mattblang thanks so much for providing a focused repo and instructions so I didn’t have to guess what to run and what to time 👍 .
I digged into this a little 🕵️♀️:
Unfortunately, it’s the normal overhead that comes from using the vm module. The vm module uses interceptors for every global property and the interceptors are not cheap. If the code heavily uses global variables, the slowdown is larger. It’s not specific to
Math
, you see the slowdown for any global object.Jest uses the vm module. If the vm module doesn’t find a property, e.g.,
Math
, in the sandboxed context, it has to go on and search the global context. Here’s the relevant line of code: if the property is not on the sandbox, go on and check the global context. I think that’s why @SimenB sees the 50% speed up, because it’s one instead of two look ups. Here’s a bit of background information if you want to understand the vm implementation on a high level.I’m assuming you opened this issue because that slowdown is a real world problem for
Math
heavy applications like pngjs? If needed, one could introduce a--math
mode to Jest: If you know that the code you want to test heavily usesMath
, Jest could wrap all content in a function that hasMath
as a local variable. With a dirty hack that brings the tests back to20ms
instead of2000ms
(1000ms
ifMath
is injected in the sandboxed context).I added one line to script_transformer.js:
Using jest 24 and the option added in #7454, these are the numbers I’m seeing with the repro in the OP:
vs without changes:
Diff:
@thymikee Well, we understand the cause now but it is still a problem that renders stuff like jest-image-snapshot almost unusable. Should this issue be left open?
@ajhsu this was solved in v2.0.0 that was released awhile back, so taking 2 minutes to compare is not normal. Either way can you open an issue in jest- image-snapshot? Let’s not spam this jest issue.
Using
runInBand
(which disabled parallelization) doesn’t make a differencefor me - not really. I will dig into it at weekends
paeth predictor is that
Math.abs
heavy userhttps://github.com/lukeapage/pngjs/blob/master/lib/paeth-predictor.js#L3
Yup comment https://github.com/facebook/jest/issues/5163#issuecomment-355509597 tells about it
@fhinkel If understand properly, there is no way to resolve this issue - because of lookup of global variable?
I don’t know of an obvious reason why
Math.abs
should be slower in a vm context. But I think @mattblang said in comment that he doesn’t observe the slowdown when comparing regular to vm runs?This is really interesting… It went from 2000ms to 1000ms by just injecting
Math
from parent context, but it’s still a lot slower (and we don’t want to do that anyways).I think we somehow hit some deoptimisation, but I’m not sure how to debug that.
Thanks for the focused reproduction!