Skip to content

RemoveParentModulesPlugin takes a long time with hundreds of chunks #6248

@filipesilva

Description

@filipesilva
Contributor

Do you want to request a feature or report a bug?
I want to report a performance bug.

What is the current behavior?
In projects with a lot of chunks, a lot of time is spent on RemoveParentModulesPlugin.

The original report (angular/angular-cli#5618 (comment)) detailed a 1h build time for a non-production (no uglify etc) build.

The project uses Angular CLI and contains around ~2700 source files. This project has 376 chunks.

A similar sized project (https://github.com/filipesilva/angular-cli-test-repo) takes only a few minutes to build using the same options.

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

The project is closed source so I do not have a source, but the owner is available for some remote debugging (angular/angular-cli#5618 (comment)).

He provided CPU profiles for the first ~10m with node 8.4.0 (here) and with node 9.3.0 (here).

Both profiles show the majority of time being spent in RemoveParentModulesPlugin, specifically within the hasModule function. Also see the "Other information" bit at the end for a comparison with Webpack 4.

What is the expected behavior?
RemoveParentModulesPlugin is optimized to allow having a lot of chunks without a big performance hit.

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

Node.js 8.4.0, Webpack 3.10.0. Unknown browser/OS.

Other information.

I've been looking at Webpack 4 and thought maybe it could help since there are a lot of performance improvements there. The plugin in question has suffered some changes:

It looks like there's a fair bit of optimizations changes there. But I'm not sure if the bottleneck has changed.

There's two places where time is being spent on the CPU profile:

  • a has call inside the hasModule function:
    image
  • a filter call inside the hasModule function:
    image

This function hasn't changed though so I don't think it would speed up in this case.

/cc @pleerock @TheLarkInn

Activity

ooflorent

ooflorent commented on Jan 5, 2018

@ooflorent
Member

I have an idea to fix this but I need a repo where the build is moderately long (from 10s to 5min) because of this plugin. Could someone provide it?

filipesilva

filipesilva commented on Jan 5, 2018

@filipesilva
ContributorAuthor

I don't have one, I'm sorry... Investigation on this was mostly from exchanges with @pleerock over at angular/angular-cli#5618 (he's the one that experiences the problem).

I'm guessing it's because of the chunk quantity but to be honest it might not be.

sokra

sokra commented on Jan 5, 2018

@sokra
Member

Please try webpack 4. There is a 80% chance that this has been fixed.

pleerock

pleerock commented on Jan 5, 2018

@pleerock

@filipesilva is it possible to use angular cli with webpack 4? (maybe with night builds) then I can check it?

ooflorent

ooflorent commented on Jan 5, 2018

@ooflorent
Member

I've opened a PR to attempt to fix this. Another maybe-solution could be to replace the Queue by a UniqueQueue to avoid processing the same chunk multiple times.

filipesilva

filipesilva commented on Jan 5, 2018

@filipesilva
ContributorAuthor

@pleerock I have angular/angular-cli#8611 but it probably will break on stuff. If you want to try it you'll have to link it to your project like detailed in https://github.com/angular/angular-cli#development-hints-for-working-on-angular-cli.

This might be a bit involved though. Happy to get on that screenshare you mentioned to help you set it up. Might have to disable stuff that uses plugins that don't yet work with webpack 4 as well.

pleerock

pleerock commented on Jan 10, 2018

@pleerock

@filipesilva I have new reports with your branch and webpack 4. First 10+ minutes of RemoveParentModulesPlugin execution without max_old_space_size being set:

screenshot 2018-01-10 12 52 10

webpack4_no_high_memory.cpuprofile.zip

First 10+ minutes of RemoveParentModulesPlugin execution with max_old_space_size being set:

screenshot 2018-01-10 13 10 01
webpack4_high_memory.cpuprofile.zip

This part of code:

while(queue.length > 0) {
  const chunk = queue.dequeue();
  let availableModules = availableModulesMap.get(chunk);
  let changed = false;
  for(const parent of chunk.parentsIterable) {
    const availableModulesInParent = availableModulesMap.get(parent);
    if(availableModulesInParent !== undefined) {
      // If we know the available modules in parent: process these
      if(availableModules === undefined) {
        // if we have not own info yet: create new entry
        availableModules = new Set(availableModulesInParent);
        for(const m of parent.modulesIterable)
          availableModules.add(m);
        availableModulesMap.set(chunk, availableModules);
        changed = true;
      } else {
        for(const m of availableModules) {
          if(!parent.containsModule(m) && !availableModulesInParent.has(m)) {
            availableModules.delete(m);
            changed = true;
          }
        }
      }
    }
  }
  if(changed) {
    // if something changed: enqueue our children
    for(const child of chunk.chunksIterable)
      queue.enqueue(child);
  }
}

Takes lot of loops. I didn't measure time but it was running like 50000 times each iteration took around half second. I wasn't successful in finishing this operation at all since don't know when. But I guess since node.js updation from 8 to 9 (as was recommended me before). I'll try to finish this operation and share reports how log it takes on node 9 and then run again on node 8 and compare results.

Also Im open to communication via skype, hangouts or similar service, just let me know how and when.

filipesilva

filipesilva commented on Jan 10, 2018

@filipesilva
ContributorAuthor

Great job on getting those CPU profiles @pleerock! I think the high memory CPU log is the most accurate one because the other will have a lot of time spent on GC, and that doesn't really help narrow down the problem.

It looks like the seal hook is running into a lot of error cases:
image

@sokra is this information useful for you? I can jump on a hangouts with @pleerock and try some more advanced debugging if you can give us some directions.

ooflorent

ooflorent commented on Jan 10, 2018

@ooflorent
Member

@pleerock @filipesilva have you tried the fix in my PR?

filipesilva

filipesilva commented on Jan 10, 2018

@filipesilva
ContributorAuthor

I have not, no. I don't have access to the repo where the problem manifests. @pleerock can you try manually patching your local webpack node_modules with https://github.com/webpack/webpack/pull/6249/files?

pleerock

pleerock commented on Jan 10, 2018

@pleerock

@filipesilva I will. btw it was running since I posted my message (over 3hrs) and Im going to stop execution since I don't see the end (last time I run it with webpack3 and node9 was over 6hrs and I stopped execution as well)

pleerock

pleerock commented on Jan 10, 2018

@pleerock

So, its same with provided code. Problem is still in while cycle. In 10+ minutes it run 2500 cycles each iteration took 200ms in average. Profile results:

screenshot 2018-01-10 17 11 10
webpack4_extra_changes.cpuprofile.zip

pleerock

pleerock commented on Jan 10, 2018

@pleerock

Okay, I downgraded node from 9.3.0 to 8.9.4 and same while cycle iteration now takes ~50ms. As I previously told I wasn't able to finish serve process at all since I upgraded to node 9.

Results of running 10 minutes with node8:

screenshot 2018-01-10 17 41 38
webpack4_node8.cpuprofile.zip

44 remaining items

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @kenotron@ooflorent@sokra@pleerock@sibelius

        Issue actions

          RemoveParentModulesPlugin takes a long time with hundreds of chunks · Issue #6248 · webpack/webpack