main
js 187 lines 4.39 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import type {PriorityLevel} from './SchedulerPriorities';
11 import {enableProfiling} from './SchedulerFeatureFlags';
12
13 let runIdCounter: number = 0;
14 let mainThreadIdCounter: number = 0;
15
16 // Bytes per element is 4
17 const INITIAL_EVENT_LOG_SIZE = 131072;
18 const MAX_EVENT_LOG_SIZE = 524288; // Equivalent to 2 megabytes
19
20 let eventLogSize = 0;
21 let eventLogBuffer = null;
22 let eventLog = null;
23 let eventLogIndex = 0;
24
25 const TaskStartEvent = 1;
26 const TaskCompleteEvent = 2;
27 const TaskErrorEvent = 3;
28 const TaskCancelEvent = 4;
29 const TaskRunEvent = 5;
30 const TaskYieldEvent = 6;
31 const SchedulerSuspendEvent = 7;
32 const SchedulerResumeEvent = 8;
33
34 function logEvent(entries: Array<number | PriorityLevel>) {
35 if (eventLog !== null) {
36 const offset = eventLogIndex;
37 eventLogIndex += entries.length;
38 if (eventLogIndex + 1 > eventLogSize) {
39 eventLogSize *= 2;
40 if (eventLogSize > MAX_EVENT_LOG_SIZE) {
41 // Using console['error'] to evade Babel and ESLint
42 console['error'](
43 "Scheduler Profiling: Event log exceeded maximum size. Don't " +
44 'forget to call `stopLoggingProfilingEvents()`.',
45 );
46 stopLoggingProfilingEvents();
47 return;
48 }
49 const newEventLog = new Int32Array(eventLogSize * 4);
50 // $FlowFixMe[incompatible-type] found when upgrading Flow
51 newEventLog.set(eventLog);
52 eventLogBuffer = newEventLog.buffer;
53 eventLog = newEventLog;
54 }
55 eventLog.set(entries, offset);
56 }
57 }
58
59 export function startLoggingProfilingEvents(): void {
60 eventLogSize = INITIAL_EVENT_LOG_SIZE;
61 eventLogBuffer = new ArrayBuffer(eventLogSize * 4);
62 eventLog = new Int32Array(eventLogBuffer);
63 eventLogIndex = 0;
64 }
65
66 export function stopLoggingProfilingEvents(): ArrayBuffer | null {
67 const buffer = eventLogBuffer;
68 eventLogSize = 0;
69 eventLogBuffer = null;
70 eventLog = null;
71 eventLogIndex = 0;
72 return buffer;
73 }
74
75 export function markTaskStart(
76 task: {
77 id: number,
78 priorityLevel: PriorityLevel,
79 ...
80 },
81 ms: number,
82 ) {
83 // $FlowFixMe[constant-condition]
84 if (enableProfiling) {
85 if (eventLog !== null) {
86 // performance.now returns a float, representing milliseconds. When the
87 // event is logged, it's coerced to an int. Convert to microseconds to
88 // maintain extra degrees of precision.
89 logEvent([TaskStartEvent, ms * 1000, task.id, task.priorityLevel]);
90 }
91 }
92 }
93
94 export function markTaskCompleted(
95 task: {
96 id: number,
97 priorityLevel: PriorityLevel,
98 ...
99 },
100 ms: number,
101 ) {
102 // $FlowFixMe[constant-condition]
103 if (enableProfiling) {
104 if (eventLog !== null) {
105 logEvent([TaskCompleteEvent, ms * 1000, task.id]);
106 }
107 }
108 }
109
110 export function markTaskCanceled(
111 task: {
112 id: number,
113 priorityLevel: PriorityLevel,
114 ...
115 },
116 ms: number,
117 ) {
118 // $FlowFixMe[constant-condition]
119 if (enableProfiling) {
120 if (eventLog !== null) {
121 logEvent([TaskCancelEvent, ms * 1000, task.id]);
122 }
123 }
124 }
125
126 export function markTaskErrored(
127 task: {
128 id: number,
129 priorityLevel: PriorityLevel,
130 ...
131 },
132 ms: number,
133 ) {
134 // $FlowFixMe[constant-condition]
135 if (enableProfiling) {
136 if (eventLog !== null) {
137 logEvent([TaskErrorEvent, ms * 1000, task.id]);
138 }
139 }
140 }
141
142 export function markTaskRun(
143 task: {
144 id: number,
145 priorityLevel: PriorityLevel,
146 ...
147 },
148 ms: number,
149 ) {
150 // $FlowFixMe[constant-condition]
151 if (enableProfiling) {
152 runIdCounter++;
153
154 if (eventLog !== null) {
155 logEvent([TaskRunEvent, ms * 1000, task.id, runIdCounter]);
156 }
157 }
158 }
159
160 export function markTaskYield(task: {id: number, ...}, ms: number) {
161 // $FlowFixMe[constant-condition]
162 if (enableProfiling) {
163 if (eventLog !== null) {
164 logEvent([TaskYieldEvent, ms * 1000, task.id, runIdCounter]);
165 }
166 }
167 }
168
169 export function markSchedulerSuspended(ms: number) {
170 // $FlowFixMe[constant-condition]
171 if (enableProfiling) {
172 mainThreadIdCounter++;
173
174 if (eventLog !== null) {
175 logEvent([SchedulerSuspendEvent, ms * 1000, mainThreadIdCounter]);
176 }
177 }
178 }
179
180 export function markSchedulerUnsuspended(ms: number) {
181 // $FlowFixMe[constant-condition]
182 if (enableProfiling) {
183 if (eventLog !== null) {
184 logEvent([SchedulerResumeEvent, ms * 1000, mainThreadIdCounter]);
185 }
186 }
187 }