Updated Profiler OVERVIEW
Brian Vaughn committed
Mar 7, 2019 at 14:15 UTC
20b613dcdef149248ab2bfac77e72bbd3efb3d3d
1 file changed
+113
-163
OVERVIEW.md
+113
-163
@@ -165,207 +165,157 @@ while (index !== currentWeight) {
165
166
## Profiler
167
168
-The Profiler UI is a powerful tool for identifying and fixing performance problems. The primary goal of the new profiler is to minimize the impact of running it (so that it doesn't interfere with the application beign profiled). This can be accomplished by:
168
+The Profiler UI is a powerful tool for identifying and fixing performance problems. The primary goal of the new profiler is to minimize its impact (CPU usage) while profiling is active. This can be accomplished by:
169
* Minimizing bridge traffic.
170
-* Efficiently serializing bridge messages.
170
+* Making expensive computations lazy.
171
172
-All profiling information is stored on the backend. The backend push-notifies the frontend of when profiling starts ("_profilingStarted_") and stops ("_profilingStopped_"). All other profiling information is lazy and must be requested by the backend.
172
+Profiling information is stored on the backend. The backend push-notifies the frontend of when profiling starts ("_profilingStarted_") and stops ("_profilingStopped_").
173
174
-### Profiling summary
174
+When profiling begins, the frontend takes a snapshot/copy of each root. This snapshot includes the id, name, key, and child IDs for each node in the tree. (This information is already present on the frontend, so it does not require any additional bridge traffic.) While profiling is active, each time React commits– the frontend also stores a copy of the "_operations_" message (described above). Once profiling has finished, the frontend can use the original snapshot along with each of the stored "_operations_" messages to reconstruct the tree for each of the profiled commits.
175
+
176
+While profiling is in progress, the backend also stores some information <sup>1</sup> about each commit:
177
+* Commit time and duration
178
+* Which elements were rendered during that commit.
179
+* Which interactions (if any) were part of the commit.
180
176
-When the user opens the profiling tab, the frontend asks the backend if it has any profiling data for the currently-selected root. This is done by sending a "_profileSummary_" message with an id that identifies the root.
181
+This information is kept on the backend until requested by the frontend (as described below).
182
178
-The response is a typed array summarizing the profiling session for that. It consists of the following values:
183
+<sup>1</sup> In the future, the backend may also store additional metadata (e.g. which props/states changed between rendered for a given component).
184
+
185
+### Profiling summary
186
180
-1. root id
181
-1. number of interactions for the root in this profiling session
182
-1. number of commits for the root in this profiling session
187
+The profiling tab shows information for the currently-selected React root. When profiling completes (or when a new root is selected) the frontend first checks to see if there is any profiling data for the selected root. (Has it cached any "_operations_"?)
188
184
-Followed by a series of tuples for each commit:
189
+If so, then it sends a "_profileSummary_" message with an id that identifies the root. The backend then returns the following information:
190
186
-1. timestamp (relative to when profiling was started)
187
-1. duration of commit
191
+* root id (to match request and response)
192
+* number of interactions that were traced for this root
193
+* the commits (each consisting of a timestamp and duration) that were profiled for the root
194
195
This is the minimal information required to render the main Profiler interface.
196
191
-Here is an example profiler summary:
197
+Here is an example profile summary:
198
```js
193
-[
194
- 1, // root id
195
- 0, // no interactions were logged during this session
196
- 3, // number of commits
197
- 210, // first commit started 210ms after profiling began
198
- 10, // and took 10ms
199
- 284, // second commit started 284ms after profiling began
200
- 13, // and took 13ms
201
- 303, // third commit started 303ms after profiling began
202
- 5, // and took 5ms
199
+{
200
+ rootID: 1,
201
+ interactionCount: 2,
202
+ commits: [
203
+ [
204
+ 210, // first commit started 210ms after profiling began
205
+ 10, // and took 10ms
206
+ ],
207
+ [
208
+ 284, // second commit started 284ms after profiling began
209
+ 13, // and took 13ms
210
+ ]
211
+ [
212
+ 303, // third commit started 303ms after profiling began
213
+ 5, // and took 5ms
214
+ ]
215
+ ]
216
]
217
```
218
206
-Additional information (e.g. which components were part of a specific commit, which interactions were logged) must be lazily requested by the frontend as a user interacts with the Profiler UI.
219
+Additional information (e.g. which components were part of a specific commit, which interactions were logged) are lazily requested by the frontend as a user interacts with the Profiler UI.
220
221
### Commit details
222
210
-When a particular commit is selected, the frontend polls the backend for the information necessary to display the ["flame chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#flame-chart) and ["ranked chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#ranked-chart) views. This information includes the time and duration of the commit, any interactions that were part of the commit, and a tree representing the state of the React application as of that commit.
211
-
212
-The frontend sends a "_profileCommitDetails_" message specifying which root and commit (index) it is interested in. The backend sends a response to fill in missing details about the commit.
223
+When a commit is selected in the profiling view, the frontend needs to reconstruct the tree at that point in time using the snapshot and the "_operations_" it has cached.
224
214
-The response always beginning with 3 values:
225
+In addition to this, it also needs to ask the backend for some additional information needed to display the ["flame chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#flame-chart) and ["ranked chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#ranked-chart) views. The frontend sends a "_profileCommitDetails_" message specifying which root and commit (index) it is interested in. The backend sends a response to fill in missing details about the commit:
226
216
-1. root id
217
-1. commit index (which commit this describes)
218
-1. number of interactions
227
+* root id and commit index (to match request and response)
228
+* which elements were rendered during the commit and how long did they take
229
+* which interactions were part of the commit
230
220
-Next is a series of interactions (depending on the number specified previously) consisting of:
221
-
222
-1. interaction id
223
-1. timestamp (when the interaction was traced relative to when profiling started)
224
-1. UTF encoded interaction display name size
225
- * (followed by this number of encoded values)
226
-
227
-Finally a flattened representation of the React tree as of this commit operation:
228
-
229
-1. element id
230
-1. parent id
231
-1. base duration
232
-1. self duration
233
-1. actual duration
234
-1. UTF encoded display name size
235
- * (followed by this number of encoded values)
236
-
237
-Here is an example commit containing two interactions and a tree of three React components:
231
+Here is an example commit in which two elements were rendered and one interaction was traced:
232
233
```js
240
-[
241
- 1, // root id
242
- 0, // commit index (the first commit)
243
- 2, // the number of interactions (represented below)
244
-
245
- 1, // first interaction id
246
- 4, // time when interaction was first traced
247
- 3, // encoded interaction name size
248
- 70, // "F"
249
- 111, // "o"
250
- 111, // "o"
251
-
252
- 1, // second interaction id
253
- 5, // time when interaction was first traced
254
- 3, // encoded interaction name size
255
- 66, // "B"
256
- 97, // "a"
257
- 114, // "r"
258
-
259
- 1, // root fiber id
260
- -1, // parent id (signifies the fiber is a root)
261
- 15, // base duration
262
- 4, // self duration
263
- 15, // actual duration
264
- 4, // UTF encoded display name size
265
- 76, // "L"
266
- 105, // "i"
267
- 115, // "s"
268
- 116, // "t"
269
-
270
- 2, // fiber id
271
- 1, // parent id
272
- 11, // base duration
273
- 8, // self duration
274
- 11, // actual duration
275
- 4, // UTF encoded display name size
276
- 73, // "I"
277
- 116, // "t"
278
- 101, // "e"
279
- 109, // "m"
280
-
281
- 2, // fiber id
282
- 1, // parent id
283
- 8, // base duration
284
- 0, // self duration
285
- 0, // actual duration (this component didn't render during this commit)
286
- 4, // UTF encoded display name size
287
- 73, // "I"
288
- 116, // "t"
289
- 101, // "e"
290
- 109, // "m"
291
-]
234
+{
235
+ rootID: 1,
236
+ commitIndex: 0,
237
+
238
+ // Map of interaction ID to interaction.
239
+ interactions: {
240
+ 1: {
241
+ timestamp: 4,
242
+ name: "Foo"
243
+ },
244
+ 2: {
245
+ timestamp: 4,
246
+ name: "Bar"
247
+ }
248
+ },
249
+
250
+ // Map of element ID to render durations (ms).
251
+ // Elements not in this map were not rendered during the commit.
252
+ nodes: {
253
+ 1: {,
254
+ baseDuration: 15,
255
+ selfDuration: 4,
256
+ actualDuration: 15
257
+ },
258
+ 2: {
259
+ baseDuration: 11,
260
+ selfDuration: 8,
261
+ actualDuration: 11
262
+ }
263
+ }
264
+}
265
```
266
267
### Component commits
268
296
-When a particular component (fiber) is selected, the frontend polls the backend for the aggregate data required to render the ["component chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#component-chart) view. This information includes each time the component rendered and how long it took.
297
-
298
-The frontend sends a "_profileComponentDetails_" message specifying which root and commit number it is interested in. The backend sends a response that is serialized in a similar fashion as the Elements tree (above).
299
-
300
-The response consists of the following values:
301
-
302
-1. root id
303
-1. fiber id
304
-1. UTF encoded display name size
305
- * (followed by this number of encoded values)
306
-
307
-Followed by a series of tuples for each time the fiber was committed. The tuples consist of:
269
+When a particular component (fiber) is selected, the frontend polls the backend for the aggregate data required to render the ["component chart"](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#component-chart) view. The frontend sends a "_profileComponentDetails_" message specifying which root and component (id) it is interested in. The backend sends a response that includes:
270
309
-1. commit index
310
-1. duration of time spent rendering the component in this commit
271
+* root and component ids (to match request and response)
272
+* which commits was the component rendered in and how long did each take
273
312
-Here is an example of a fiber that committed twice during a profiling session:
274
+Here is an example of a component that committed twice during a profiling session:
275
276
```js
315
-[
316
- 1, // root id
317
- 2, // fiber id
318
- 4, // UTF encoded display name size
319
- 73, // "I"
320
- 116, // "t"
321
- 101, // "e"
322
- 109, // "m"
323
-
324
- 0, // commit index 0
325
- 11, // actual duration for this fiber in commit 0
326
-
327
- 3, // commit index 3
328
- 7, // actual duration for this fiber in commit 3
329
-]
277
+{
278
+ rootID: 1,
279
+ id: 2,
280
+
281
+ // Map of commit index to render duration (ms)
282
+ commits: {
283
+ 0: 11,
284
+ 3: 7
285
+ }
286
+}
287
```
288
289
### Interactions
290
334
-The [Interactions chart](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#interactions) shows a time series for every interaction that was traced in the recent profiler session. The frontend sends a "_profileInteractions_" message specifying which root it would like interaction data for. The backend sends a typed array as a response.
291
+The [Interactions chart](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#interactions) shows a time series for every interaction that was traced in the recent profiler session. The frontend sends a "_profileInteractions_" message specifying which root it would like interaction data for. The backend sends the following response:
292
336
-The response always begins with an id that identifies which root the interactions are associated with:
337
-
338
-1. root id
339
-
340
-Next is a series of interactions, consisting of:
341
-
342
-1. interaction id
343
-1. UTF encoded display name size
344
- * (followed by this number of encoded values)
345
-1. Number of commits this interaction was associated with
346
- * (followed by the index of each commit)
293
+* root id (to match request and response)
294
+* interaction metadata
295
296
Here is an example of a profiling session consisting of two interactions:
297
298
```js
351
-[
352
- 1, // root id
299
+{
300
+ rootID: 1,
301
+
302
+ // Map of ID to interaction:
303
+ interactions: {
304
+ 1: {
305
+ name: "Foo",
306
+ commits: [
307
+ 0, // index of first commit
308
+ 3 // index of second commit
309
+ ]
310
+ },
311
+ 2: {
312
+ name: "Bar",
313
+ commits: [
314
+ 0 // index of first commit
315
+ ]
316
+ }
317
+ }
318
+}
319
+```
320
354
- 1, // first interaction id
355
- 3, // encoded interaction name size
356
- 70, // "F"
357
- 111, // "o"
358
- 111, // "o"
359
- 2, // number of commits this interaction was associated with
360
- 0, // index of first commit
361
- 3, // index of second commit
362
-
363
- 1, // second interaction id
364
- 3, // encoded interaction name size
365
- 66, // "B"
366
- 97, // "a"
367
- 114, // "r"
368
- 1, // number of commits this interaction was associated with
369
- 0, // index of first commit
370
-]
371
-```
\ No newline at end of file
321
+The backend does not need to resend the timestamp for each of the commits because that was already sent as part of the "_profileSummary_" message.
\ No newline at end of file