Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Commit 8657869

Browse files
authored
Separate Tracks for Components and Phases (#31525)
Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. <img width="1352" alt="Screenshot 2024-11-12 at 8 26 05 PM" src="https://github.com/user-attachments/assets/590bc6d3-3540-4ee4-b474-5d733b8d8d8d"> That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. <img width="1277" alt="Screenshot 2024-11-12 at 8 26 16 PM" src="https://github.com/user-attachments/assets/4fc39e35-10ec-4452-ad32-c1c2e6b5e1a8">
1 parent b15135b commit 8657869

1 file changed

Lines changed: 65 additions & 53 deletions

File tree

‎packages/react-reconciler/src/ReactFiberPerformanceTrack.js‎

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ const supportsUserTiming =
2121
// $FlowFixMe[method-unbinding]
2222
typeofperformance.measure==='function';
2323

24-
constTRACK_GROUP='Components ⚛';
24+
constCOMPONENTS_TRACK='Components ⚛';
2525

2626
// Reused to avoid thrashing the GC.
2727
constreusableComponentDevToolDetails={
2828
dataType: 'track-entry',
2929
color: 'primary',
30-
track: 'Blocking',// Lane
31-
trackGroup: TRACK_GROUP,
30+
track: COMPONENTS_TRACK,
3231
};
3332
constreusableComponentOptions={
3433
start: -0,
@@ -38,9 +37,24 @@ const reusableComponentOptions = {
3837
},
3938
};
4039

40+
constLANES_TRACK_GROUP='Scheduler ⚛';
41+
42+
constreusableLaneDevToolDetails={
43+
dataType: 'track-entry',
44+
color: 'primary',
45+
track: 'Blocking',// Lane
46+
trackGroup: LANES_TRACK_GROUP,
47+
};
48+
constreusableLaneOptions={
49+
start: -0,
50+
end: -0,
51+
detail: {
52+
devtools: reusableLaneDevToolDetails,
53+
},
54+
};
55+
4156
exportfunctionsetCurrentTrackFromLanes(lanes: number): void{
42-
reusableComponentDevToolDetails.track=
43-
getGroupNameOfHighestPriorityLane(lanes);
57+
reusableLaneDevToolDetails.track=getGroupNameOfHighestPriorityLane(lanes);
4458
}
4559

4660
exportfunctionlogComponentRender(
@@ -107,21 +121,20 @@ export function logBlockingStart(
107121
renderStartTime: number,
108122
): void{
109123
if(supportsUserTiming){
110-
reusableComponentDevToolDetails.track='Blocking';
124+
reusableLaneDevToolDetails.track='Blocking';
111125
if(eventTime>0&&eventType!==null){
112126
// Log the time from the event timeStamp until we called setState.
113-
reusableComponentDevToolDetails.color='secondary-dark';
114-
reusableComponentOptions.start=eventTime;
115-
reusableComponentOptions.end=
116-
updateTime>0 ? updateTime : renderStartTime;
117-
performance.measure(eventType,reusableComponentOptions);
127+
reusableLaneDevToolDetails.color='secondary-dark';
128+
reusableLaneOptions.start=eventTime;
129+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
130+
performance.measure(eventType,reusableLaneOptions);
118131
}
119132
if(updateTime>0){
120133
// Log the time from when we called setState until we started rendering.
121-
reusableComponentDevToolDetails.color='primary-light';
122-
reusableComponentOptions.start=updateTime;
123-
reusableComponentOptions.end=renderStartTime;
124-
performance.measure('Blocked',reusableComponentOptions);
134+
reusableLaneDevToolDetails.color='primary-light';
135+
reusableLaneOptions.start=updateTime;
136+
reusableLaneOptions.end=renderStartTime;
137+
performance.measure('Blocked',reusableLaneOptions);
125138
}
126139
}
127140
}
@@ -134,43 +147,42 @@ export function logTransitionStart(
134147
renderStartTime: number,
135148
): void{
136149
if(supportsUserTiming){
137-
reusableComponentDevToolDetails.track='Transition';
150+
reusableLaneDevToolDetails.track='Transition';
138151
if(eventTime>0&&eventType!==null){
139152
// Log the time from the event timeStamp until we started a transition.
140-
reusableComponentDevToolDetails.color='secondary-dark';
141-
reusableComponentOptions.start=eventTime;
142-
reusableComponentOptions.end=
153+
reusableLaneDevToolDetails.color='secondary-dark';
154+
reusableLaneOptions.start=eventTime;
155+
reusableLaneOptions.end=
143156
startTime>0
144157
? startTime
145158
: updateTime>0
146159
? updateTime
147160
: renderStartTime;
148-
performance.measure(eventType,reusableComponentOptions);
161+
performance.measure(eventType,reusableLaneOptions);
149162
}
150163
if(startTime>0){
151164
// Log the time from when we started an async transition until we called setState or started rendering.
152-
reusableComponentDevToolDetails.color='primary-dark';
153-
reusableComponentOptions.start=startTime;
154-
reusableComponentOptions.end=
155-
updateTime>0 ? updateTime : renderStartTime;
156-
performance.measure('Action',reusableComponentOptions);
165+
reusableLaneDevToolDetails.color='primary-dark';
166+
reusableLaneOptions.start=startTime;
167+
reusableLaneOptions.end=updateTime>0 ? updateTime : renderStartTime;
168+
performance.measure('Action',reusableLaneOptions);
157169
}
158170
if(updateTime>0){
159171
// Log the time from when we called setState until we started rendering.
160-
reusableComponentDevToolDetails.color='primary-light';
161-
reusableComponentOptions.start=updateTime;
162-
reusableComponentOptions.end=renderStartTime;
163-
performance.measure('Blocked',reusableComponentOptions);
172+
reusableLaneDevToolDetails.color='primary-light';
173+
reusableLaneOptions.start=updateTime;
174+
reusableLaneOptions.end=renderStartTime;
175+
performance.measure('Blocked',reusableLaneOptions);
164176
}
165177
}
166178
}
167179

168180
exportfunctionlogRenderPhase(startTime: number,endTime: number): void{
169181
if(supportsUserTiming){
170-
reusableComponentDevToolDetails.color='primary-dark';
171-
reusableComponentOptions.start=startTime;
172-
reusableComponentOptions.end=endTime;
173-
performance.measure('Render',reusableComponentOptions);
182+
reusableLaneDevToolDetails.color='primary-dark';
183+
reusableLaneOptions.start=startTime;
184+
reusableLaneOptions.end=endTime;
185+
performance.measure('Render',reusableLaneOptions);
174186
}
175187
}
176188

@@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase(
180192
): void{
181193
// This was inside a throttled Suspense boundary commit.
182194
if(supportsUserTiming){
183-
reusableComponentDevToolDetails.color='secondary-light';
184-
reusableComponentOptions.start=startTime;
185-
reusableComponentOptions.end=endTime;
186-
performance.measure('Throttled',reusableComponentOptions);
195+
reusableLaneDevToolDetails.color='secondary-light';
196+
reusableLaneOptions.start=startTime;
197+
reusableLaneOptions.end=endTime;
198+
performance.measure('Throttled',reusableLaneOptions);
187199
}
188200
}
189201

@@ -193,28 +205,28 @@ export function logSuspendedCommitPhase(
193205
): void{
194206
// This means the commit was suspended on CSS or images.
195207
if(supportsUserTiming){
196-
reusableComponentDevToolDetails.color='secondary-light';
197-
reusableComponentOptions.start=startTime;
198-
reusableComponentOptions.end=endTime;
199-
performance.measure('Suspended',reusableComponentOptions);
208+
reusableLaneDevToolDetails.color='secondary-light';
209+
reusableLaneOptions.start=startTime;
210+
reusableLaneOptions.end=endTime;
211+
performance.measure('Suspended',reusableLaneOptions);
200212
}
201213
}
202214

203215
exportfunctionlogCommitPhase(startTime: number,endTime: number): void{
204216
if(supportsUserTiming){
205-
reusableComponentDevToolDetails.color='secondary-dark';
206-
reusableComponentOptions.start=startTime;
207-
reusableComponentOptions.end=endTime;
208-
performance.measure('Commit',reusableComponentOptions);
217+
reusableLaneDevToolDetails.color='secondary-dark';
218+
reusableLaneOptions.start=startTime;
219+
reusableLaneOptions.end=endTime;
220+
performance.measure('Commit',reusableLaneOptions);
209221
}
210222
}
211223

212224
exportfunctionlogPaintYieldPhase(startTime: number,endTime: number): void{
213225
if(supportsUserTiming){
214-
reusableComponentDevToolDetails.color='secondary-light';
215-
reusableComponentOptions.start=startTime;
216-
reusableComponentOptions.end=endTime;
217-
performance.measure('Waiting for Paint',reusableComponentOptions);
226+
reusableLaneDevToolDetails.color='secondary-light';
227+
reusableLaneOptions.start=startTime;
228+
reusableLaneOptions.end=endTime;
229+
performance.measure('Waiting for Paint',reusableLaneOptions);
218230
}
219231
}
220232

@@ -223,9 +235,9 @@ export function logPassiveCommitPhase(
223235
endTime: number,
224236
): void{
225237
if(supportsUserTiming){
226-
reusableComponentDevToolDetails.color='secondary-dark';
227-
reusableComponentOptions.start=startTime;
228-
reusableComponentOptions.end=endTime;
229-
performance.measure('Remaining Effects',reusableComponentOptions);
238+
reusableLaneDevToolDetails.color='secondary-dark';
239+
reusableLaneOptions.start=startTime;
240+
reusableLaneOptions.end=endTime;
241+
performance.measure('Remaining Effects',reusableLaneOptions);
230242
}
231243
}

0 commit comments

Comments
 (0)