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

Merged
merged 9 commits into from
Mar 23, 2025

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 during render so that one-off updates on not too large trees do get complete Owner Stacks. A new render will always start fresh.

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).

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: da996a1...54e6c53

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 +0.05% 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 515.14 kB 515.14 kB = 91.74 kB 91.74 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.11% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 615.53 kB 615.53 kB = 108.89 kB 108.89 kB
facebook-www/ReactDOM-prod.classic.js = 651.48 kB 651.48 kB = 114.89 kB 114.89 kB
facebook-www/ReactDOM-prod.modern.js = 641.76 kB 641.76 kB = 113.31 kB 113.31 kB
oss-stable-semver/react/cjs/react-jsx-runtime.react-server.development.js +8.45% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable/react/cjs/react-jsx-runtime.react-server.development.js +8.45% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.44% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.44% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-experimental/react/cjs/react-jsx-runtime.react-server.development.js +8.34% 12.21 kB 13.23 kB +4.45% 3.33 kB 3.48 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.34% 12.22 kB 13.24 kB +4.47% 3.33 kB 3.48 kB
facebook-react-native/react/cjs/JSXRuntime-dev.js +7.48% 11.67 kB 12.54 kB +4.68% 3.20 kB 3.35 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +6.99% 11.44 kB 12.24 kB +4.56% 3.16 kB 3.30 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +6.99% 11.44 kB 12.24 kB +4.56% 3.16 kB 3.30 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +6.90% 11.59 kB 12.39 kB +4.53% 3.20 kB 3.34 kB
facebook-react-native/react/cjs/JSXDEVRuntime-dev.js +5.76% 11.47 kB 12.13 kB +4.65% 3.18 kB 3.33 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +5.33% 11.25 kB 11.84 kB +4.52% 3.14 kB 3.29 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +5.33% 11.25 kB 11.84 kB +4.52% 3.14 kB 3.29 kB
facebook-www/JSXDEVRuntime-dev.classic.js +5.26% 12.77 kB 13.44 kB +4.43% 3.45 kB 3.61 kB
facebook-www/JSXDEVRuntime-dev.modern.js +5.26% 12.77 kB 13.44 kB +4.43% 3.45 kB 3.61 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.development.js +5.26% 11.39 kB 11.99 kB +4.49% 3.18 kB 3.33 kB
facebook-react-native/react/cjs/React-dev.js +2.48% 50.48 kB 51.73 kB +1.57% 11.31 kB 11.49 kB
facebook-www/React-dev.modern.js +2.36% 54.28 kB 55.56 kB +1.59% 11.92 kB 12.11 kB
facebook-www/React-dev.classic.js +2.36% 54.28 kB 55.56 kB +1.59% 11.92 kB 12.11 kB
oss-stable-semver/react/cjs/react.react-server.development.js +2.28% 28.11 kB 28.75 kB +2.13% 6.82 kB 6.96 kB
oss-stable/react/cjs/react.react-server.development.js +2.27% 28.13 kB 28.77 kB +2.13% 6.84 kB 6.99 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-jsx-runtime.react-server.development.js +8.45% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable/react/cjs/react-jsx-runtime.react-server.development.js +8.45% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.44% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-stable/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.44% 12.07 kB 13.09 kB +4.50% 3.29 kB 3.44 kB
oss-experimental/react/cjs/react-jsx-runtime.react-server.development.js +8.34% 12.21 kB 13.23 kB +4.45% 3.33 kB 3.48 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.react-server.development.js +8.34% 12.22 kB 13.24 kB +4.47% 3.33 kB 3.48 kB
facebook-react-native/react/cjs/JSXRuntime-dev.js +7.48% 11.67 kB 12.54 kB +4.68% 3.20 kB 3.35 kB
oss-stable-semver/react/cjs/react-jsx-runtime.development.js +6.99% 11.44 kB 12.24 kB +4.56% 3.16 kB 3.30 kB
oss-stable/react/cjs/react-jsx-runtime.development.js +6.99% 11.44 kB 12.24 kB +4.56% 3.16 kB 3.30 kB
oss-experimental/react/cjs/react-jsx-runtime.development.js +6.90% 11.59 kB 12.39 kB +4.53% 3.20 kB 3.34 kB
facebook-react-native/react/cjs/JSXDEVRuntime-dev.js +5.76% 11.47 kB 12.13 kB +4.65% 3.18 kB 3.33 kB
oss-stable-semver/react/cjs/react-jsx-dev-runtime.development.js +5.33% 11.25 kB 11.84 kB +4.52% 3.14 kB 3.29 kB
oss-stable/react/cjs/react-jsx-dev-runtime.development.js +5.33% 11.25 kB 11.84 kB +4.52% 3.14 kB 3.29 kB
facebook-www/JSXDEVRuntime-dev.classic.js +5.26% 12.77 kB 13.44 kB +4.43% 3.45 kB 3.61 kB
facebook-www/JSXDEVRuntime-dev.modern.js +5.26% 12.77 kB 13.44 kB +4.43% 3.45 kB 3.61 kB
oss-experimental/react/cjs/react-jsx-dev-runtime.development.js +5.26% 11.39 kB 11.99 kB +4.49% 3.18 kB 3.33 kB
facebook-react-native/react/cjs/React-dev.js +2.48% 50.48 kB 51.73 kB +1.57% 11.31 kB 11.49 kB
facebook-www/React-dev.modern.js +2.36% 54.28 kB 55.56 kB +1.59% 11.92 kB 12.11 kB
facebook-www/React-dev.classic.js +2.36% 54.28 kB 55.56 kB +1.59% 11.92 kB 12.11 kB
oss-stable-semver/react/cjs/react.react-server.development.js +2.28% 28.11 kB 28.75 kB +2.13% 6.82 kB 6.96 kB
oss-stable/react/cjs/react.react-server.development.js +2.27% 28.13 kB 28.77 kB +2.13% 6.84 kB 6.99 kB
oss-experimental/react/cjs/react.react-server.development.js +1.77% 35.12 kB 35.74 kB +1.65% 8.38 kB 8.52 kB
oss-stable-semver/react/cjs/react.development.js +1.31% 44.45 kB 45.03 kB +1.25% 10.16 kB 10.28 kB
oss-stable/react/cjs/react.development.js +1.31% 44.48 kB 45.06 kB +1.28% 10.18 kB 10.31 kB
oss-experimental/react/cjs/react.development.js +1.26% 46.17 kB 46.75 kB +1.24% 10.54 kB 10.67 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +1.16% 137.84 kB 139.44 kB +0.91% 25.69 kB 25.92 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +1.16% 137.84 kB 139.44 kB +0.91% 25.69 kB 25.92 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +1.13% 141.67 kB 143.27 kB +0.95% 26.29 kB 26.54 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +1.13% 141.67 kB 143.27 kB +0.95% 26.29 kB 26.54 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.12% 142.26 kB 143.85 kB +0.90% 26.57 kB 26.81 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.12% 142.26 kB 143.85 kB +0.90% 26.57 kB 26.81 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.12% 142.28 kB 143.88 kB +0.86% 26.55 kB 26.78 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.12% 142.28 kB 143.88 kB +0.86% 26.55 kB 26.78 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.browser.development.js +1.11% 144.84 kB 146.44 kB +0.89% 26.89 kB 27.13 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +1.10% 145.58 kB 147.18 kB +0.90% 26.99 kB 27.23 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +1.10% 145.58 kB 147.18 kB +0.90% 26.99 kB 27.23 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +1.10% 146.12 kB 147.73 kB +0.90% 27.11 kB 27.36 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +1.10% 146.12 kB 147.73 kB +0.90% 27.11 kB 27.36 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.edge.development.js +1.07% 149.30 kB 150.90 kB +0.88% 27.62 kB 27.87 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.07% 149.45 kB 151.05 kB +0.92% 27.59 kB 27.85 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.07% 149.45 kB 151.05 kB +0.92% 27.59 kB 27.85 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.07% 148.95 kB 150.55 kB +0.87% 27.59 kB 27.83 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.07% 148.95 kB 150.55 kB +0.87% 27.59 kB 27.83 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.07% 149.51 kB 151.11 kB +0.92% 27.60 kB 27.86 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.07% 149.51 kB 151.11 kB +0.92% 27.60 kB 27.86 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1.07% 149.55 kB 151.15 kB +0.91% 27.84 kB 28.10 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +1.07% 149.57 kB 151.17 kB +0.89% 27.86 kB 28.10 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.06% 150.09 kB 151.69 kB +0.86% 27.86 kB 28.09 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.06% 150.09 kB 151.69 kB +0.86% 27.86 kB 28.09 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.06% 150.16 kB 151.75 kB +0.86% 27.87 kB 28.11 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.06% 150.16 kB 151.75 kB +0.86% 27.87 kB 28.11 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.browser.development.js +1.05% 152.58 kB 154.18 kB +0.97% 28.21 kB 28.49 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js +1.05% 153.12 kB 154.72 kB +1.01% 28.34 kB 28.62 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1.02% 156.24 kB 157.84 kB +0.93% 28.92 kB 29.18 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +1.02% 157.08 kB 158.68 kB +0.89% 28.98 kB 29.23 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +1.02% 157.14 kB 158.75 kB +0.89% 28.99 kB 29.24 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +1.01% 157.38 kB 158.98 kB +0.87% 29.21 kB 29.47 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +1.01% 157.45 kB 159.04 kB +0.87% 29.22 kB 29.48 kB
oss-stable-semver/react-server/cjs/react-server-flight.development.js +0.66% 99.87 kB 100.53 kB +0.94% 18.49 kB 18.67 kB
oss-stable/react-server/cjs/react-server-flight.development.js +0.66% 99.87 kB 100.53 kB +0.94% 18.49 kB 18.67 kB
oss-experimental/react-server/cjs/react-server-flight.development.js +0.62% 106.85 kB 107.51 kB +0.87% 19.74 kB 19.91 kB
oss-stable-semver/react-server/cjs/react-server.development.js +0.38% 171.08 kB 171.74 kB +0.48% 30.75 kB 30.89 kB
oss-stable/react-server/cjs/react-server.development.js +0.38% 171.08 kB 171.74 kB +0.48% 30.75 kB 30.89 kB
oss-experimental/react-server/cjs/react-server.development.js +0.35% 188.08 kB 188.73 kB +0.44% 32.84 kB 32.99 kB
oss-experimental/react-markup/cjs/react-markup.react-server.development.js +0.21% 532.15 kB 533.26 kB +0.22% 95.33 kB 95.54 kB

Generated by 🚫 dangerJS against 54e6c53


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?

Comment on lines 256 to 259
// 1 for the timeout
// And since we haven't committed yet, we continue to reset the Owner Stack
// limit periodically.
pendingTimers: 2,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is where Fiber differs from Fizz and Flight. prepareFreshStack isn't called when we render from a ping if we never committed. Fizz and Flight will stop at this point in the test though.

kdckhanpur

This comment was marked as resolved.


import ReactSharedInternals from 'shared/ReactSharedInternals';

let resetOwnerStackIntervalId: mixed = null;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

each renderer has its own interval now. Should we just move this timeout ID into isomorphic React?

} else {
const localDate = Date;
const initialTime = localDate.now();
getCurrentTime = () => localDate.now() - initialTime;
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't need the initialTime offset here. That's just something scheduler does for consistency with performance.now and you can't rely on it.

jackpope and others added 8 commits March 23, 2025 15:31
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.
This reverts commit 97ffdbb.
No longer needed now that we stop resetting outside render.
Has the benefit of not suddenly resetting in the middle of render
@eps1lon eps1lon force-pushed the sebbie/owner-stack-cutoff branch from d615a3d to 54e6c53 Compare March 23, 2025 22:34
@eps1lon eps1lon merged commit 4a9df08 into facebook:main Mar 23, 2025
240 of 241 checks passed
@eps1lon eps1lon deleted the sebbie/owner-stack-cutoff branch March 23, 2025 22:52
github-actions bot pushed a commit that referenced this pull request Mar 23, 2025
github-actions bot pushed a commit that referenced this pull request Mar 23, 2025
jackpope pushed a commit that referenced this pull request Mar 26, 2025
#32529 added a dynamic flag for
this, but that breaks tests since the flags are not defined everywhere.

However, this is a static value and the flag is only for supporting
existing tests. So we can override it in the test config, and make it
static at built time instead.
github-actions bot pushed a commit that referenced this pull request Mar 26, 2025
#32529 added a dynamic flag for
this, but that breaks tests since the flags are not defined everywhere.

However, this is a static value and the flag is only for supporting
existing tests. So we can override it in the test config, and make it
static at built time instead.

DiffTrain build for [f99c9fe](f99c9fe)
github-actions bot pushed a commit that referenced this pull request Mar 26, 2025
#32529 added a dynamic flag for
this, but that breaks tests since the flags are not defined everywhere.

However, this is a static value and the flag is only for supporting
existing tests. So we can override it in the test config, and make it
static at built time instead.

DiffTrain build for [f99c9fe](f99c9fe)
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.

7 participants