Skip to content

Profiler actualDuration bugfix #13313

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

Merged
merged 4 commits into from
Aug 8, 2018
Merged

Conversation

bvaughn
Copy link
Contributor

@bvaughn bvaughn commented Aug 2, 2018

While testing the new DevTools profiler, I noticed that sometimes– in larger, more complicated applications– an incorrect value was being reported for actualDuration (often too large, occasionally negative).

Unfortunately I was unable to capture the problem in a test, but I believe it has something to do with the way I was tracking render times across different priorities and roots. So this PR replaces the old approach with a simpler one that I believe is more robust.

Anecdotally, the timing problems I was able to reproduce before in my test app(s) are no longer happening after this change. I think the code is also easier to read and reason about now.

Resolves #13309

@pull-bot
Copy link

pull-bot commented Aug 2, 2018

ReactDOM: size: 0.0%, gzip: -0.0%

Details of bundled changes.

Comparing: b179bae...ccc4f31

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js -0.5% -0.5% 643.19 KB 640.14 KB 151.05 KB 150.3 KB UMD_DEV
react-dom.production.min.js 0.0% -0.0% 96.27 KB 96.28 KB 31.21 KB 31.21 KB UMD_PROD
react-dom.development.js -0.5% -0.5% 639.33 KB 636.28 KB 149.88 KB 149.12 KB NODE_DEV
react-dom.production.min.js 0.0% 0.0% 96.26 KB 96.27 KB 30.74 KB 30.74 KB NODE_PROD
ReactDOM-dev.js -0.5% -0.5% 646.57 KB 643.45 KB 148.19 KB 147.38 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.3% 0.0% 278.1 KB 278.89 KB 52.2 KB 52.22 KB FB_WWW_PROD
react-dom.profiling.min.js +0.1% 0.0% 97.39 KB 97.48 KB 31.14 KB 31.15 KB NODE_PROFILING
ReactDOM-profiling.js -0.0% -0.1% 281.39 KB 281.31 KB 52.92 KB 52.86 KB FB_WWW_PROFILING

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js -0.7% -0.8% 435.55 KB 432.5 KB 98.71 KB 97.93 KB UMD_DEV
react-art.production.min.js -0.0% -0.0% 85.17 KB 85.16 KB 26.42 KB 26.41 KB UMD_PROD
react-art.development.js -0.8% -1.0% 368.06 KB 365.02 KB 81.64 KB 80.86 KB NODE_DEV
react-art.production.min.js -0.0% -0.1% 50.16 KB 50.15 KB 15.79 KB 15.78 KB NODE_PROD
ReactART-dev.js -0.9% -1.0% 358.57 KB 355.45 KB 76.52 KB 75.78 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.1% 🔺+0.1% 152.95 KB 153.13 KB 26.36 KB 26.39 KB FB_WWW_PROD

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js -0.8% -1.0% 363.96 KB 360.91 KB 80.05 KB 79.27 KB UMD_DEV
react-test-renderer.development.js -0.8% -1.0% 360.09 KB 357.04 KB 79.07 KB 78.29 KB NODE_DEV
ReactTestRenderer-dev.js -0.9% -0.9% 365.23 KB 362.12 KB 78 KB 77.27 KB FB_WWW_DEV

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js -0.9% -1.0% 349.08 KB 346.03 KB 75.67 KB 74.89 KB NODE_DEV
react-reconciler.production.min.js 0.0% -0.0% 47.71 KB 47.72 KB 14.47 KB 14.46 KB NODE_PROD
react-reconciler-persistent.development.js -0.9% -1.0% 347.69 KB 344.65 KB 75.12 KB 74.34 KB NODE_DEV
react-reconciler-persistent.production.min.js 0.0% -0.0% 47.72 KB 47.73 KB 14.47 KB 14.47 KB NODE_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js -0.6% -0.7% 483.4 KB 480.28 KB 106.86 KB 106.08 KB RN_FB_DEV
ReactNativeRenderer-prod.js -0.4% -0.2% 214.2 KB 213.28 KB 37.54 KB 37.48 KB RN_FB_PROD
ReactNativeRenderer-dev.js -0.6% -0.7% 483.13 KB 480.01 KB 106.8 KB 106.03 KB RN_OSS_DEV
ReactNativeRenderer-prod.js -0.4% -0.2% 204.24 KB 203.33 KB 35.92 KB 35.86 KB RN_OSS_PROD
ReactFabric-dev.js -0.7% -0.8% 473.61 KB 470.49 KB 104.43 KB 103.64 KB RN_FB_DEV
ReactFabric-prod.js 🔺+0.1% -0.0% 195.36 KB 195.6 KB 34.36 KB 34.35 KB RN_FB_PROD
ReactFabric-dev.js -0.7% -0.7% 473.65 KB 470.53 KB 104.44 KB 103.66 KB RN_OSS_DEV
ReactFabric-prod.js 🔺+0.1% -0.0% 195.39 KB 195.64 KB 34.37 KB 34.36 KB RN_OSS_PROD
ReactNativeRenderer-profiling.js -0.5% -0.3% 207.75 KB 206.75 KB 36.62 KB 36.5 KB RN_OSS_PROFILING
ReactFabric-profiling.js +0.1% -0.2% 198.41 KB 198.6 KB 35 KB 34.92 KB RN_OSS_PROFILING
ReactNativeRenderer-profiling.js -0.5% -0.3% 217.67 KB 216.67 KB 38.24 KB 38.12 KB RN_FB_PROFILING
ReactFabric-profiling.js +0.1% -0.2% 198.37 KB 198.56 KB 34.98 KB 34.9 KB RN_FB_PROFILING

Generated by 🚫 dangerJS

if (profilerStartTime >= 0) {
const elapsedTime = now() - profilerStartTime;
fiber.actualDuration += elapsedTime;
if (overrideBaseTime) {
Copy link
Contributor Author

@bvaughn bvaughn Aug 2, 2018

Choose a reason for hiding this comment

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

Base time is a little awkward to handle. Before, we were only including "begin" phase work in the base time value– and this PR continues that behavior, because I wasn't sure how to preserve the behavior we wanted otherwise (without adding an additional field).

The behavior is, essentially:

  • When cloning a fiber, copy the base time from the previous render.
  • If the fiber bails out, leave that value in place.
  • If the fiber renders, override the base time value.
  • When the fiber completes, bubble up base times from its children.

Since we are using a single timer to track both the "actual duration" and "base duration" values, and this timer wraps both the "begin" and "render" phases– I opted to only update base time during render (since we know definitively whether we have bailed out or not during that phase).

If this is silly for some reason, or you know of a better way to achieve this, let's chat! I don't think it's a very big deal, since completeWork doesn't really include any time spent in user component code.

@bvaughn bvaughn requested a review from sebmarkbage August 2, 2018 22:14
// If replayFailedUnitOfWorkWithInvokeGuardedCallback is enbaled, ThrowsError is replayed.
expect(mountCall[2]).toBe(flagEnabled && __DEV__ ? 27 : 17);
// We don't count the time spent in replaying the failed unit of work (ThrowsError)
expect(mountCall[2]).toBe(17);
Copy link
Contributor Author

@bvaughn bvaughn Aug 3, 2018

Choose a reason for hiding this comment

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

This PR changes the timing so that we override the actual time spent during the failure with the time spent while retrying it (only for that particular fiber)– but I think that's fine. This particular detail was kind of arbitrary anyway.

<AdvanceTime byAmount={10}>
<AdvanceTime byAmount={10} shouldComponentUpdate={false} />
<AdvanceTime byAmount={4}>
<AdvanceTime byAmount={7} shouldComponentUpdate={false} />
Copy link
Contributor Author

@bvaughn bvaughn Aug 3, 2018

Choose a reason for hiding this comment

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

This change was an unnecessary one but made the test a little stronger since 10 & 10 could give a false positive.

While testing the new DevTools profiler, I noticed that sometimes– in larger, more complicated applications– the actualDuration value was incorrect (either too large, or sometimes negative). I was not able to reproduce this in a smaller application or test (which sucks) but I assume it has something to do with the way I was tracking render times across priorities/roots. So this PR replaces the previous approach with a simpler one.
nextRenderExpirationTime,
);
if (enableProfilerTimer) {
if (workInProgress.mode & ProfileMode) {
Copy link
Collaborator

@acdlite acdlite Aug 3, 2018

Choose a reason for hiding this comment

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

Nit: Can you combine the enableProfilerTimer check with these inner checks? Or do we not trust the build system to strip out the dead code?

Copy link
Contributor Author

@bvaughn bvaughn Aug 3, 2018

Choose a reason for hiding this comment

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

Nope, this is just something subjective I've done because it seems to read more clearly that the outer conditional is a feature flag. Happy to combine them if you have a preference.

To be fair, there's precedent for this in a lot of other places– but again, I don't feel strongly about it. If you do, I will change it.

@bvaughn bvaughn force-pushed the profiler-timer-bugfix branch from cc714c4 to 6f996da Compare August 3, 2018 21:06
@bvaughn bvaughn changed the title Simplified profiler actualDuration timing Profiler actualDuration bugfix Aug 6, 2018
@bvaughn
Copy link
Contributor Author

bvaughn commented Aug 6, 2018

Friendly ping 😄

@bvaughn bvaughn requested a review from gaearon August 7, 2018 15:44
@bvaughn bvaughn merged commit 067cc24 into facebook:master Aug 8, 2018
@bvaughn bvaughn deleted the profiler-timer-bugfix branch August 8, 2018 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants