assert: fix slow error message generation for minified code - #62338
assert: fix slow error message generation for minified code#62338Felipeness wants to merge 1 commit into
Conversation
Do you have a reproduction case that demonstrates it taking minutes? I find that extremely difficult to believe. Specifically, acorn is generally quite fast and there are hard practical limits already in place that would prevent it from taking "minutes". I think at best this would shave a couple hundred milliseconds off an error path, which is of questionable value given the added complexity. |
jasnell
left a comment
There was a problem hiding this comment.
Not really seeing this as a valid optimization. See prior comment for reasoning.
|
Hey @jasnell, fair question. I'm working on putting together a proper reproduction case for the timing claim. Will update here once I have it. Been a bit sidetracked dealing with Windows build issues on another PR, but this is on my list. Thanks for the patience. |
|
@jasnell It's a valid known issue and merging would be highly appreciated. There is a repro here: #52677 (comment) Spent an hour trying to figure out why my console freezes for minutes while running my tests when I use There are a few issues based on this: |
getFirstExpression() tokenizes the whole source line to find the expression at the error column. In bundled or minified code that line is the entire file, so every failing assertion pays an O(line) tokenize, and the result is not cached. Extract a window around the target column for lines longer than 2048 characters, cutting at the previous statement boundary so acorn still receives usable input, and tolerate a window that starts mid-token. On a single 930KB line, 20 failing assertions go from 1118ms to 34ms. Refs: nodejs#52677 Refs: nodejs#52962
9279652 to
05010a4
Compare
|
I owed a repro since March and never delivered it. Here it is, with numbers. The repro is the one @elemental-mind linked: https://gist.github.com/martinjlowm/aa7d02905f7c49935be0a3bf4819a5f3 Both builds are from b328bf7, same commit, same config. The file is a single 930KB line with the assert call inside that line. "sparse" is semicolons, "dense" is minified code with real identifiers and calls. Each run touches
@jasnell your estimate is right for a single failure, it is 64ms here, not minutes. What I did not say in March is that the cost is paid per failure and is not cached. A suite with 1000 failing assertions on this file spends about 59s inside Assert tests pass, including I squashed the two commits into one and changed the prefix to |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #62338 +/- ##
==========================================
+ Coverage 89.68% 90.12% +0.44%
==========================================
Files 676 752 +76
Lines 206689 252250 +45561
Branches 39579 47458 +7879
==========================================
+ Hits 185370 227343 +41973
- Misses 13450 16220 +2770
- Partials 7869 8687 +818
🚀 New features to boost your workflow:
|
Summary
When
assert.ok(falsy)is called in minified/bundled code (common in Lambda deployments via Webpack/Terser), the error message generation can take seconds to minutes. ThegetFirstExpressionfunction inlib/internal/errors/error_source.jstokenizes the entire source line with acorn to extract the failing expression, but for minified single-line files the source line is the entire file (potentially megabytes).This PR fixes the performance issue by windowing the tokenization:
assert.ok) is preservedBenchmark results (tested manually)
Test plan
test/parallel/test-assert-long-line-perf.jswith two tests:assert.okdoes not hang on a large synthetic minified file (100K declarations + assert)ok(false))test-assert-first-line.jstest (which testsassert-long-line.js, a 9.4KB single-line fixture) still produces the correct error message with windowing enabledassert.ok(false),assert['ok'](false), and plain;-padded assert callsFixes: #52677
Jira: N/A (open source contribution)