Skip to content

Commit

Permalink
Added separate feature flag for scheduler tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Vaughn committed May 15, 2019
1 parent daf9abf commit fa0d5b1
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 55 deletions.
12 changes: 10 additions & 2 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
enableSchedulerTracing,
enableProfilerTimer,
enableSuspenseServerRenderer,
enableUpdateSchedulerTracking,
enableEventAPI,
} from 'shared/ReactFeatureFlags';
import {
Expand Down Expand Up @@ -1334,11 +1335,18 @@ function commitSuspenseComponent(
}
thenables.forEach(thenable => {
// Memoize using the boundary fiber to prevent redundant listeners.
let retry = resolveRetryThenable.bind(null, finishedWork, thenable);
let retry = resolveRetryThenable.bind(
null,
finishedWork,
thenable,
finishedRoot,
committedExpirationTime,
);
if (!retryCache.has(thenable)) {
if (enableSchedulerTracing) {
retry = Schedule_tracing_wrap(retry);

}
if (enableUpdateSchedulerTracking) {
// If we have pending work still, restore the original schedulers
restorePendingSchedulers(finishedRoot, committedExpirationTime);
}
Expand Down
15 changes: 12 additions & 3 deletions packages/react-reconciler/src/ReactFiberRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import type {Interaction} from 'scheduler/src/Tracing';
import {noTimeout} from './ReactFiberHostConfig';
import {createHostRootFiber} from './ReactFiber';
import {NoWork} from './ReactFiberExpirationTime';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
import {
enableSchedulerTracing,
enableUpdateSchedulerTracking,
} from 'shared/ReactFeatureFlags';
import {unstable_getThreadID} from 'scheduler/tracing';

// TODO: This should be lifted into the renderer.
Expand Down Expand Up @@ -84,9 +87,11 @@ type ProfilingOnlyFiberRootProperties = {|
interactionThreadID: number,
memoizedInteractions: Set<Interaction>,
pendingInteractionMap: PendingInteractionMap,
|};

// Used to enable DevTools Profiler UI to show which Fibers scheduled a given commit.
// May also be useful in the future to expose via the Profiler API somehow?
// The following attributes are only used by DevTools and are only present in DEV builds.
// They enable DevTools Profiler UI to show which Fiber(s) scheduled a given commit.
type SchedulerTrackingOnlyFiberRootProperties = {|
memoizedSchedulers: Set<Fiber>,
pendingSchedulersMap: PendingSchedulersMap,
|};
Expand All @@ -99,6 +104,7 @@ type ProfilingOnlyFiberRootProperties = {|
export type FiberRoot = {
...BaseFiberRootProperties,
...ProfilingOnlyFiberRootProperties,
...SchedulerTrackingOnlyFiberRootProperties,
};

function FiberRootNode(containerInfo, tag, hydrate) {
Expand All @@ -124,6 +130,9 @@ function FiberRootNode(containerInfo, tag, hydrate) {
this.interactionThreadID = unstable_getThreadID();
this.memoizedInteractions = new Set();
this.pendingInteractionMap = new Map();
}

if (enableUpdateSchedulerTracking) {
this.memoizedSchedulers = new Set();
this.pendingSchedulersMap = new Map();
}
Expand Down
89 changes: 48 additions & 41 deletions packages/react-reconciler/src/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {Interaction} from 'scheduler/src/Tracing';
import {
warnAboutDeprecatedLifecycles,
enableUserTimingAPI,
enableUpdateSchedulerTracking,
enableSuspenseServerRenderer,
replayFailedUnitOfWorkWithInvokeGuardedCallback,
enableProfilerTimer,
Expand Down Expand Up @@ -336,7 +337,7 @@ export function scheduleUpdateOnFiber(
return;
}

if (enableSchedulerTracing) {
if (enableUpdateSchedulerTracking) {
const pendingSchedulersMap = root.pendingSchedulersMap;
let schedulers = pendingSchedulersMap.get(expirationTime);
if (schedulers == null) {
Expand Down Expand Up @@ -2179,6 +2180,10 @@ export function restorePendingSchedulers(
root: FiberRoot,
expirationTime: ExpirationTime,
): void {
if (!enableUpdateSchedulerTracking) {
return;
}

const pendingSchedulersMap = root.pendingSchedulersMap;
let schedulers = pendingSchedulersMap.get(expirationTime);
if (schedulers == null) {
Expand Down Expand Up @@ -2306,52 +2311,54 @@ function schedulePendingInteraction(root, expirationTime) {

function startWorkOnPendingInteraction(root, expirationTime) {
// This is called when new work is started on a root.
if (!enableSchedulerTracing) {
return;
}

// Determine which interactions this batch of work currently includes, So that
// we can accurately attribute time spent working on it, And so that cascading
// work triggered during the render phase will be associated with it.
const interactions: Set<Interaction> = new Set();
root.pendingInteractionMap.forEach(
(scheduledInteractions, scheduledExpirationTime) => {
if (enableUpdateSchedulerTracking) {
const memoizedSchedulers: Set<Fiber> = new Set();
const pendingSchedulersMap = root.pendingSchedulersMap;
pendingSchedulersMap.forEach((schedulers, scheduledExpirationTime) => {
if (scheduledExpirationTime >= expirationTime) {
scheduledInteractions.forEach(interaction =>
interactions.add(interaction),
);
pendingSchedulersMap.delete(scheduledExpirationTime);
schedulers.forEach(fiber => memoizedSchedulers.add(fiber));
}
},
);
});

const memoizedSchedulers: Set<Fiber> = new Set();
const pendingSchedulersMap = root.pendingSchedulersMap;
pendingSchedulersMap.forEach((schedulers, scheduledExpirationTime) => {
if (scheduledExpirationTime >= expirationTime) {
pendingSchedulersMap.delete(scheduledExpirationTime);
schedulers.forEach(fiber => memoizedSchedulers.add(fiber));
}
});
root.memoizedSchedulers = memoizedSchedulers;
}

// Store the current set of interactions on the FiberRoot for a few reasons:
// We can re-use it in hot functions like renderRoot() without having to
// recalculate it. We will also use it in commitWork() to pass to any Profiler
// onRender() hooks. This also provides DevTools with a way to access it when
// the onCommitRoot() hook is called.
root.memoizedInteractions = interactions;
root.memoizedSchedulers = memoizedSchedulers;
if (enableSchedulerTracing) {
// Determine which interactions this batch of work currently includes, So that
// we can accurately attribute time spent working on it, And so that cascading
// work triggered during the render phase will be associated with it.
const interactions: Set<Interaction> = new Set();
root.pendingInteractionMap.forEach(
(scheduledInteractions, scheduledExpirationTime) => {
if (scheduledExpirationTime >= expirationTime) {
scheduledInteractions.forEach(interaction =>
interactions.add(interaction),
);
}
},
);

if (interactions.size > 0) {
const subscriber = __subscriberRef.current;
if (subscriber !== null) {
const threadID = computeThreadID(root, expirationTime);
try {
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// If the subscriber throws, rethrow it in a separate task
scheduleCallback(ImmediatePriority, () => {
throw error;
});
// Store the current set of interactions on the FiberRoot for a few reasons:
// We can re-use it in hot functions like renderRoot() without having to
// recalculate it. We will also use it in commitWork() to pass to any Profiler
// onRender() hooks. This also provides DevTools with a way to access it when
// the onCommitRoot() hook is called.
root.memoizedInteractions = interactions;

if (interactions.size > 0) {
const subscriber = __subscriberRef.current;
if (subscriber !== null) {
const threadID = computeThreadID(root, expirationTime);
try {
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// If the subscriber throws, rethrow it in a separate task
scheduleCallback(ImmediatePriority, () => {
throw error;
});
}
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions packages/react-reconciler/src/ReactFiberUnwindWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
import {
enableSchedulerTracing,
enableSuspenseServerRenderer,
enableUpdateSchedulerTracking,
enableEventAPI,
} from 'shared/ReactFeatureFlags';
import {NoMode, BatchedMode} from './ReactTypeOfMode';
Expand Down Expand Up @@ -187,7 +188,8 @@ function attachPingListener(
);
if (enableSchedulerTracing) {
ping = Schedule_tracing_wrap(ping);

}
if (enableUpdateSchedulerTracking) {
// If we have pending work still, restore the original schedulers
restorePendingSchedulers(root, renderExpirationTime);
}
Expand Down Expand Up @@ -319,10 +321,17 @@ function throwException(
// Memoize using the boundary fiber to prevent redundant listeners.
if (!retryCache.has(thenable)) {
retryCache.add(thenable);
let retry = resolveRetryThenable.bind(null, workInProgress, thenable);
let retry = resolveRetryThenable.bind(
null,
workInProgress,
thenable,
root,
renderExpirationTime,
);
if (enableSchedulerTracing) {
retry = Schedule_tracing_wrap(retry);

}
if (enableUpdateSchedulerTracking) {
// If we have pending work still, restore the original schedulers
restorePendingSchedulers(root, renderExpirationTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ let Scheduler;
let TestUtils;
let mockDevToolsHook;

function loadModules({
enableProfilerTimer = true,
enableSchedulerTracing = true,
} = {}) {
function loadModules(enableUpdateSchedulerTracking = true) {
jest.resetModules();

mockDevToolsHook = {
Expand All @@ -35,8 +32,7 @@ function loadModules({
);

ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer;
ReactFeatureFlags.enableSchedulerTracing = enableSchedulerTracing;
ReactFeatureFlags.enableUpdateSchedulerTracking = enableUpdateSchedulerTracking;

React = require('react');
ReactDOM = require('react-dom');
Expand Down
3 changes: 3 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export const enableProfilerTimer = __PROFILE__;
// Trace which interactions trigger each commit.
export const enableSchedulerTracing = __PROFILE__;

// Track which Fiber(s) schedule render work.
export const enableUpdateSchedulerTracking = __PROFILE__;

// Only used in www builds.
export const enableSuspenseServerRenderer = false; // TODO: __DEV__? Here it might just be false.

Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const {debugRenderPhaseSideEffects} = require('ReactFeatureFlags');
export const enableUserTimingAPI = __DEV__;
export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableUpdateSchedulerTracking = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const enableStableConcurrentModeAPIs = false;
export const warnAboutShorthandPropertyCollision = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
export const warnAboutDeprecatedLifecycles = true;
export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableUpdateSchedulerTracking = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
export const disableYielding = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.persistent.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const warnAboutDeprecatedLifecycles = true;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableUpdateSchedulerTracking = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
export const disableYielding = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const warnAboutDeprecatedLifecycles = false;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
export const enableProfilerTimer = false;
export const enableSchedulerTracing = false;
export const enableUpdateSchedulerTracking = false;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
export const disableYielding = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const warnAboutDeprecatedLifecycles = true;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
export const enableProfilerTimer = false;
export const enableSchedulerTracing = false;
export const enableUpdateSchedulerTracking = false;
export const enableSuspenseServerRenderer = false;
export const enableStableConcurrentModeAPIs = false;
export const enableSchedulerDebugging = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export let enableUserTimingAPI = __DEV__;

export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableUpdateSchedulerTracking = __PROFILE__;
export const enableSchedulerDebugging = true;

export const enableStableConcurrentModeAPIs = false;
Expand Down

0 comments on commit fa0d5b1

Please sign in to comment.