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

Stop creating Owner Stacks if many have been created recently #32529

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

eps1lon
Copy link
Collaborator

@eps1lon eps1lon commented Mar 5, 2025

Summary

Adding Owner Stacks in development adds some non-negligible performance overhead.
This is shared roughly equally between the work required for captureOwnerStack to work and tasks being visible in runtimes that support console.createTask.

We now stop this work after a some amount of elements were created. Though we do reset that limit occasionally so that one-off updates on not too large trees do get complete Owner Stacks.

Chances are that you probably don't need Owner Stacks on large, frequent updates.

Stopping after 10.000 elements caps a large update at 500ms where uncapped would've taken 3.000ms (see attached fixture).

I added separate, dynamic feature flags to control when we cut off and how frequent we reset so that Meta can experiment with different values.

How did you test this change?

  • added tests
  • verified performance gains for a single, large update: 500ms (down from 3.000ms)

@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Mar 5, 2025
@react-sizebot
Copy link

react-sizebot commented Mar 5, 2025

Comparing: 6b1ae49...0fff6c5

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 518.43 kB 518.43 kB = 92.44 kB 92.44 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 589.19 kB 589.24 kB +0.02% 104.91 kB 104.93 kB
facebook-www/ReactDOM-prod.classic.js = 642.65 kB 642.65 kB = 113.00 kB 113.00 kB
facebook-www/ReactDOM-prod.modern.js = 632.96 kB 632.96 kB = 111.44 kB 111.44 kB
oss-stable-semver/react/cjs/react.react-server.development.js +12.62% 28.84 kB 32.48 kB +9.98% 6.91 kB 7.60 kB
oss-stable/react/cjs/react.react-server.development.js +12.61% 28.86 kB 32.50 kB +9.95% 6.94 kB 7.63 kB
facebook-react-native/react/cjs/JSXRuntime-dev.js +11.86% 11.26 kB 12.59 kB +5.41% 3.09 kB 3.26 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +10.67% 11.32 kB 12.52 kB +4.25% 3.13 kB 3.26 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +10.67% 11.32 kB 12.52 kB +4.25% 3.13 kB 3.26 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +10.53% 11.47 kB 12.67 kB +4.20% 3.17 kB 3.30 kB
oss-experimental/react/cjs/react.react-server.development.js +10.12% 35.90 kB 39.53 kB +8.11% 8.48 kB 9.16 kB
oss-stable-semver/react/cjs/react.development.js +8.28% 45.18 kB 48.92 kB +7.04% 10.26 kB 10.98 kB
oss-stable/react/cjs/react.development.js +8.28% 45.21 kB 48.95 kB +6.98% 10.28 kB 11.00 kB
oss-experimental/react/cjs/react.development.js +7.97% 46.95 kB 50.69 kB +6.85% 10.65 kB 11.38 kB
oss-stable-semver/react/cjs/react-jsx-runtime.react-server.development.js +7.59% 11.94 kB 12.85 kB +3.97% 3.25 kB 3.38 kB
oss-stable/react/cjs/react-jsx-runtime.react-server.development.js +7.59% 11.94 kB 12.85 kB +3.97% 3.25 kB 3.38 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.58% 11.95 kB 12.85 kB +3.96% 3.26 kB 3.39 kB
oss-stable/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.58% 11.95 kB 12.85 kB +3.96% 3.26 kB 3.39 kB
oss-experimental/react/cjs/react-jsx-runtime.react-server.development.js +7.49% 12.09 kB 13.00 kB +3.88% 3.30 kB 3.42 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.49% 12.09 kB 13.00 kB +3.91% 3.30 kB 3.43 kB
facebook-react-native/react/cjs/JSXDEVRuntime-dev.js +5.34% 11.06 kB 11.65 kB +5.34% 3.07 kB 3.23 kB
facebook-www/JSXDEVRuntime-dev.classic.js +4.42% 12.64 kB 13.20 kB +4.24% 3.42 kB 3.57 kB
facebook-www/JSXDEVRuntime-dev.modern.js +4.42% 12.64 kB 13.20 kB +4.24% 3.42 kB 3.57 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +4.37% 11.12 kB 11.61 kB +4.15% 3.11 kB 3.24 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +4.37% 11.12 kB 11.61 kB +4.15% 3.11 kB 3.24 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.development.js +4.31% 11.27 kB 11.75 kB +4.09% 3.15 kB 3.28 kB
facebook-react-native/react/cjs/React-dev.js +2.57% 51.03 kB 52.34 kB +2.05% 11.36 kB 11.59 kB
facebook-www/React-dev.modern.js +2.39% 55.41 kB 56.74 kB +2.21% 12.07 kB 12.33 kB
facebook-www/React-dev.classic.js +2.39% 55.41 kB 56.74 kB +2.21% 12.07 kB 12.34 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react/cjs/react.react-server.development.js +12.62% 28.84 kB 32.48 kB +9.98% 6.91 kB 7.60 kB
oss-stable/react/cjs/react.react-server.development.js +12.61% 28.86 kB 32.50 kB +9.95% 6.94 kB 7.63 kB
facebook-react-native/react/cjs/JSXRuntime-dev.js +11.86% 11.26 kB 12.59 kB +5.41% 3.09 kB 3.26 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +10.67% 11.32 kB 12.52 kB +4.25% 3.13 kB 3.26 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +10.67% 11.32 kB 12.52 kB +4.25% 3.13 kB 3.26 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +10.53% 11.47 kB 12.67 kB +4.20% 3.17 kB 3.30 kB
oss-experimental/react/cjs/react.react-server.development.js +10.12% 35.90 kB 39.53 kB +8.11% 8.48 kB 9.16 kB
oss-stable-semver/react/cjs/react.development.js +8.28% 45.18 kB 48.92 kB +7.04% 10.26 kB 10.98 kB
oss-stable/react/cjs/react.development.js +8.28% 45.21 kB 48.95 kB +6.98% 10.28 kB 11.00 kB
oss-experimental/react/cjs/react.development.js +7.97% 46.95 kB 50.69 kB +6.85% 10.65 kB 11.38 kB
oss-stable-semver/react/cjs/react-jsx-runtime.react-server.development.js +7.59% 11.94 kB 12.85 kB +3.97% 3.25 kB 3.38 kB
oss-stable/react/cjs/react-jsx-runtime.react-server.development.js +7.59% 11.94 kB 12.85 kB +3.97% 3.25 kB 3.38 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.58% 11.95 kB 12.85 kB +3.96% 3.26 kB 3.39 kB
oss-stable/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.58% 11.95 kB 12.85 kB +3.96% 3.26 kB 3.39 kB
oss-experimental/react/cjs/react-jsx-runtime.react-server.development.js +7.49% 12.09 kB 13.00 kB +3.88% 3.30 kB 3.42 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.react-server.development.js +7.49% 12.09 kB 13.00 kB +3.91% 3.30 kB 3.43 kB
facebook-react-native/react/cjs/JSXDEVRuntime-dev.js +5.34% 11.06 kB 11.65 kB +5.34% 3.07 kB 3.23 kB
facebook-www/JSXDEVRuntime-dev.classic.js +4.42% 12.64 kB 13.20 kB +4.24% 3.42 kB 3.57 kB
facebook-www/JSXDEVRuntime-dev.modern.js +4.42% 12.64 kB 13.20 kB +4.24% 3.42 kB 3.57 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +4.37% 11.12 kB 11.61 kB +4.15% 3.11 kB 3.24 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +4.37% 11.12 kB 11.61 kB +4.15% 3.11 kB 3.24 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.development.js +4.31% 11.27 kB 11.75 kB +4.09% 3.15 kB 3.28 kB
facebook-react-native/react/cjs/React-dev.js +2.57% 51.03 kB 52.34 kB +2.05% 11.36 kB 11.59 kB
facebook-www/React-dev.modern.js +2.39% 55.41 kB 56.74 kB +2.21% 12.07 kB 12.33 kB
facebook-www/React-dev.classic.js +2.39% 55.41 kB 56.74 kB +2.21% 12.07 kB 12.34 kB
facebook-react-native/react/cjs/React-prod.js +0.87% 19.52 kB 19.69 kB +1.06% 5.08 kB 5.13 kB
facebook-react-native/react/cjs/React-profiling.js +0.85% 19.95 kB 20.12 kB +1.03% 5.16 kB 5.21 kB
facebook-www/React-prod.modern.js +0.61% 21.03 kB 21.16 kB +0.71% 5.38 kB 5.42 kB
facebook-www/React-prod.classic.js +0.61% 21.03 kB 21.16 kB +0.71% 5.38 kB 5.42 kB
facebook-www/React-profiling.modern.js +0.60% 21.47 kB 21.59 kB +0.68% 5.46 kB 5.50 kB
facebook-www/React-profiling.classic.js +0.60% 21.47 kB 21.59 kB +0.68% 5.46 kB 5.50 kB
oss-stable-semver/react/cjs/react.react-server.production.js +0.44% 13.31 kB 13.37 kB +0.65% 3.67 kB 3.69 kB
oss-stable/react/cjs/react.react-server.production.js +0.44% 13.33 kB 13.39 kB +0.65% 3.69 kB 3.71 kB
oss-stable-semver/react/cjs/react.production.js +0.35% 17.08 kB 17.13 kB +0.63% 4.46 kB 4.48 kB
oss-stable/react/cjs/react.production.js +0.35% 17.10 kB 17.16 kB +0.58% 4.48 kB 4.51 kB
oss-experimental/react/cjs/react.react-server.production.js +0.32% 18.50 kB 18.56 kB +0.57% 4.92 kB 4.95 kB
oss-experimental/react/cjs/react.production.js +0.32% 18.54 kB 18.60 kB +0.58% 4.80 kB 4.83 kB

Generated by 🚫 dangerJS against dbaf445


let recentlyCreatedOwnerStacks = 0;
let recentlyCreatedDebugTasks = 0;
setInterval(() => {
Copy link
Member

Choose a reason for hiding this comment

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

Can we move the counter and timer to isomorphic react?

It would also be good to reset the counter every commit (and reset the timer too, but maybe not start it until the next render).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do we not mean react with "isomorphic react"?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This interval will be duplicated across jsx and createElement since they're in separate bundles. So it's two.

However, that seems fine. If you have a run away number of elements you'll have that with either createElement or jsx.

Better than leaking this info outside the module and having to read it from an object.

The reason to do isomorphic would be if it was reset using commit or something in each renderer. Although if you have a bunch of frequent commits, maybe it's not so much better.

It does seem weird to have a this running all the time even when React isn't rendering though.

Also, this needs to be DEV-only gated and feature detected if setInterval exists.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It does seem weird to have a this running all the time even when React isn't rendering though.

That would require adding a dedicated method to internals, right? Should we just share a method to reset with renderers and they decide when to reset (timer-based, commit based etc.) or should it just be a a simple start/stop interval?

jackpope and others added 6 commits March 5, 2025 19:27
Add prestart
Adding Owner Stacks in development adds some non-negligible performance overhead.
This is shared roughly equally between the work required for `captureOwnerStack` to work and tasks being visible in runtimes that support `console.createTask`.

We now stop this work after a some amount of elements were created. Though we do reset that limit occasionally so that one-off updates on not too large trees do get complete Owner Stacks.

Chances are that you probably don't need Owner Stacks on large, frequent updates.

Stopping after 10.000 elements caps a large update at 500ms where uncapped would've taken 3.000ms (see attached fixture).

I added separate, dynamic feature flags to control when we cut off and how frequent we reset so that Meta can experiment with different values.
Not sure about this one. It'll point into React code i.e. node_modules and should be
ignore-listed by modern frameworks.
@eps1lon eps1lon force-pushed the sebbie/owner-stack-cutoff branch from c7fdaef to dbaf445 Compare March 5, 2025 18:27
@eps1lon eps1lon marked this pull request as ready for review March 5, 2025 20:33
@eps1lon eps1lon requested a review from sebmarkbage March 5, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants