Skip to content
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

Top-level await leads to complexity explosion with cyclic imports #15767

Closed
andersk opened this issue May 4, 2022 · 5 comments
Closed

Top-level await leads to complexity explosion with cyclic imports #15767

andersk opened this issue May 4, 2022 · 5 comments

Comments

@andersk
Copy link

andersk commented May 4, 2022

Bug report

What is the current behavior?

In a project with cyclic imports, top-level await leads to a massive complexity explosion. On a complete graph of n nodes, the time and memory grows as Θ(n!), which gets very bad quickly.

If the current behavior is a bug, please provide the steps to reproduce.

  1. Create the following file as 0.js:

    export const c = await null;
  2. Create the following file as 1.js, and copy it to 2.js, 3.js, 4.js, 5.js, 6.js, 7.js, 8.js, 9.js and src.js:

    import "./0.js";
    import "./1.js";
    import "./2.js";
    import "./3.js";
    import "./4.js";
    import "./5.js";
    import "./6.js";
    import "./7.js";
    import "./8.js";
    import "./9.js";

    (Note that none of the import cycles pass through 0.js, so this should be fine.)

  3. Run webpack --mode=development --experiments-top-level-await. (No additional configuration file is needed.)

  4. Run 'time' node dist/main.js.

    $ 'time' node dist/main.js 
    7.57user 0.42system 0:07.53elapsed 106%CPU (0avgtext+0avgdata 1271408maxresident)k
    0inputs+0outputs (0major+333169minor)pagefaults 0swaps

As you can see, this takes over 7 seconds and 1.2 gigabytes of memory.

If you insert a console.log statement into the whenAll function in dist/main.js, you’ll see that it gets called exactly ⌊10! ⋅ e⌋ − 1 = 9864100 times.

What is the expected behavior?

This should run almost immediately with very little memory.

Other relevant information:
webpack version: 5.72.0
Node.js version: 16.15.0
Operating System: NixOS 22.05
Additional tools:

@vankop
Copy link
Member

vankop commented May 4, 2022

for me all works as expected
Screenshot 2022-05-04 at 12 00 50

please create a reproducible repo

@andersk
Copy link
Author

andersk commented May 4, 2022

@vankop Your screenshot shows that you’ve copied the 29-byte file ten times. The recipe I gave above has one 29-byte file, and ten copies of the 170-byte file. Like this:

https://gist.github.com/andersk/0af1a0654516fb53ba7b8e757be4db85

@andersk
Copy link
Author

andersk commented May 4, 2022

In fact, cyclic imports are not necessary to reproduce this. Here’s an example with 24 modules taking 12 seconds and 1.9 gigabytes, with 223 − 1 = 8388607 calls to whenAll.

https://gist.github.com/andersk/034cf3103f15f16f7088aae525f15496

$ webpack --mode=development --experiments-top-level-await
$ 'time' node dist/main.js
12.52user 0.72system 0:10.97elapsed 120%CPU (0avgtext+0avgdata 1890260maxresident)k
0inputs+0outputs (0major+536615minor)pagefaults 0swaps

@webpack-bot
Copy link
Contributor

This issue had no activity for at least three months.

It's subject to automatic issue closing if there is no activity in the next 15 days.

@andersk
Copy link
Author

andersk commented Aug 4, 2022

This seems to have been fixed in v5.73.0 by #15899.

@andersk andersk closed this as completed Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants