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

perf(resolve-dependencies): avoid copying preferredVersions object #6735

Merged
merged 1 commit into from
Jun 29, 2023

Conversation

zxbodya
Copy link
Contributor

@zxbodya zxbodya commented Jun 29, 2023

Replacing object spread with a prototype chain, avoiding extra memory allocations in resolveDependencies

This becomes noticeable on relatively large monorepo(~2k packages) reducing memory usage and making it faster

Also in my case:

  1. allowing to complete pnpm install without --max_old_space_size=8192 (it is slower, but at least works without OOM crash)
  2. prevents OOM issue with auto-install-peers=true (for me this is crashing otherwise no matter max_old_space_size)

flame graph using pprof-it, running NODE_OPTIONS="--max_old_space_size=8192" pprof-it ../pnpm/pnpm/bin/pnpm.cjs install --offline --resolution-only

before:
Screenshot 2023-06-29 at 23 17 56

after:
Screenshot 2023-06-29 at 23 18 17

replacing object spread with a prototype chain,
avoiding extra memory allocations in resolveDependencies

this becomes noticeable on relatively large monorepo(~2k packages)
reducing memory usage and making it slightly faster

1. allowing to complete `pnpm install` without `--max_old_space_size=8192`
   (it is noticeably slower, but at least works)
2. prevents OOM issue with `auto-install-peers=true`
   (this is crashing otherwise no matter `max_old_space_size`)
@@ -522,7 +522,7 @@ export async function resolveDependencies (
postponedPeersResolutionQueue.push(postponedPeersResolution)
}
})
const newPreferredVersions = { ...preferredVersions }
const newPreferredVersions = Object.create(preferredVersions) as PreferredVersions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this means that when we replace a field in newPreferredVersions, the same field will also be replaced in preferredVersions, which is not what we want.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, looks like in this case we don't override existing fields in newPreferredVersions, only adding new ones. And the new ones will not appear in preferredVersions. So I guess it should work fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no change in this regard, when assigning the property to newPreferredVersions - it would affect only the new object created here (not a prototype of it)

the main difference is to be when reading the property - if it not found in newPreferredVersions, it would be read from the prototype (preferredVersions)

however, the opposite is true - changing properties of preferredVersions, if not overridden will be reflected on newPreferredVersions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

about the possibility of overrides in preferredVersions, just noticed in code below(for both - before and after the pr), not sure if that can cause issues:

    if (!newPreferredVersions[resolvedPackage.name]) {
      newPreferredVersions[resolvedPackage.name] = {}
    }
    if (!newPreferredVersions[resolvedPackage.name][resolvedPackage.version]) {
      newPreferredVersions[resolvedPackage.name][resolvedPackage.version] = 'version'
      // ^^ -- here the content of `preferredVersions[resolvedPackage.name][resolvedPackage.version]` is possibly modified
      // that will happen if `resolvedPackage.name` was already in `preferredVersions` ()
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think this should be fixed. It is probably causing some hard to reproduce issues.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created an issue from your comment #6737

Let me know if you want to work on it.

@zkochan zkochan merged commit e9684b5 into pnpm:main Jun 29, 2023
13 of 14 checks passed
@welcome
Copy link

welcome bot commented Jun 29, 2023

Congrats on merging your first pull request! 🎉🎉🎉

@zxbodya zxbodya deleted the perf-prefered-versions branch June 29, 2023 23:21
zkochan pushed a commit that referenced this pull request Jun 30, 2023
…6735)

replacing object spread with a prototype chain,
avoiding extra memory allocations in resolveDependencies

this becomes noticeable on relatively large monorepo(~2k packages)
reducing memory usage and making it slightly faster

1. allowing to complete `pnpm install` without `--max_old_space_size=8192`
   (it is noticeably slower, but at least works)
2. prevents OOM issue with `auto-install-peers=true`
   (this is crashing otherwise no matter `max_old_space_size`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants