or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-scheduling.mdindex.mdpriority-management.mdprofiling.mdtesting-utilities.mdtiming-yielding.md

profiling.mddocs/

0

# Profiling

1

2

Performance monitoring and event logging capabilities for development and debugging of scheduler-based applications.

3

4

The profiling system provides detailed insights into task execution, timing, and scheduler behavior through structured event logging.

5

6

## Capabilities

7

8

### Profiling Interface

9

10

The main profiling interface provides methods to start and stop profiling event collection.

11

12

```javascript { .api }

13

/**

14

* Profiling interface for performance monitoring

15

* Available only in profiling builds, null in production builds

16

*/

17

const unstable_Profiling: {

18

/** Start collecting profiling events */

19

startLoggingProfilingEvents(): void;

20

/** Stop collecting events and return logged data */

21

stopLoggingProfilingEvents(): ArrayBuffer | null;

22

} | null;

23

```

24

25

**Usage Examples:**

26

27

```javascript

28

import { unstable_Profiling } from "scheduler";

29

30

// Check if profiling is available

31

if (unstable_Profiling !== null) {

32

// Start profiling

33

unstable_Profiling.startLoggingProfilingEvents();

34

35

// Perform operations to profile

36

performScheduledWork();

37

38

// Stop profiling and get data

39

const profilingData = unstable_Profiling.stopLoggingProfilingEvents();

40

41

if (profilingData) {

42

// Process profiling data (ArrayBuffer)

43

analyzeProfilingData(profilingData);

44

}

45

} else {

46

console.log("Profiling not available in this build");

47

}

48

49

// Conditional profiling wrapper

50

function withProfiling(operation, name) {

51

const profilingEnabled = unstable_Profiling !== null;

52

53

if (profilingEnabled) {

54

unstable_Profiling.startLoggingProfilingEvents();

55

}

56

57

try {

58

return operation();

59

} finally {

60

if (profilingEnabled) {

61

const data = unstable_Profiling.stopLoggingProfilingEvents();

62

console.log(`Profiling data for ${name}:`, data);

63

}

64

}

65

}

66

```

67

68

### Profiling Data Format

69

70

The profiling system logs events as structured data in an ArrayBuffer. Events are logged as 32-bit integers with the following format:

71

72

- **Event Type** (1 byte): Type of event that occurred

73

- **Timestamp** (4 bytes): Microsecond timestamp when event occurred

74

- **Task ID** (4 bytes): Unique identifier for the task

75

- **Additional Data** (varies): Priority level, run ID, or other event-specific data

76

77

**Event Types:**

78

79

```javascript { .api }

80

// Event type constants (internal)

81

const TaskStartEvent = 1; // Task added to queue

82

const TaskCompleteEvent = 2; // Task finished successfully

83

const TaskErrorEvent = 3; // Task threw an error

84

const TaskCancelEvent = 4; // Task was cancelled

85

const TaskRunEvent = 5; // Task started executing

86

const TaskYieldEvent = 6; // Task yielded control

87

const SchedulerSuspendEvent = 7; // Scheduler became idle

88

const SchedulerResumeEvent = 8; // Scheduler resumed work

89

```

90

91

## Profiling Events

92

93

The scheduler automatically logs various events during task execution when profiling is enabled:

94

95

### Task Lifecycle Events

96

97

- **Task Start**: When a task is scheduled and added to the queue

98

- **Task Run**: When a task begins executing

99

- **Task Yield**: When a task yields control back to scheduler

100

- **Task Complete**: When a task finishes successfully

101

- **Task Error**: When a task throws an exception

102

- **Task Cancel**: When a task is cancelled before completion

103

104

### Scheduler Events

105

106

- **Scheduler Suspend**: When scheduler becomes idle (no pending work)

107

- **Scheduler Resume**: When scheduler resumes after being idle

108

109

## Advanced Usage

110

111

### Profiling Specific Operations

112

113

```javascript

114

import {

115

unstable_Profiling,

116

unstable_scheduleCallback,

117

unstable_NormalPriority

118

} from "scheduler";

119

120

async function profileTaskExecution() {

121

if (!unstable_Profiling) return;

122

123

unstable_Profiling.startLoggingProfilingEvents();

124

125

// Schedule multiple tasks to profile

126

const tasks = [];

127

for (let i = 0; i < 10; i++) {

128

const task = unstable_scheduleCallback(unstable_NormalPriority, (didTimeout) => {

129

// Simulate work

130

const start = performance.now();

131

while (performance.now() - start < 5) {

132

// Busy wait for 5ms

133

}

134

135

if (i % 3 === 0) {

136

// Some tasks yield

137

return (didTimeout) => {

138

console.log(`Task ${i} continuation, timeout: ${didTimeout}`);

139

};

140

}

141

});

142

tasks.push(task);

143

}

144

145

// Let tasks execute, then collect profiling data

146

setTimeout(() => {

147

const profilingData = unstable_Profiling.stopLoggingProfilingEvents();

148

console.log("Profiling completed, data size:", profilingData?.byteLength);

149

}, 1000);

150

}

151

```

152

153

### Profiling Data Analysis

154

155

```javascript

156

function analyzeProfilingData(arrayBuffer) {

157

if (!arrayBuffer || arrayBuffer.byteLength === 0) {

158

console.log("No profiling data available");

159

return;

160

}

161

162

const view = new Int32Array(arrayBuffer);

163

const events = [];

164

165

// Parse events from the buffer

166

for (let i = 0; i < view.length; i += 4) {

167

const eventType = view[i];

168

const timestamp = view[i + 1];

169

const taskId = view[i + 2];

170

const extraData = view[i + 3];

171

172

events.push({

173

type: getEventTypeName(eventType),

174

timestamp: timestamp / 1000, // Convert microseconds to milliseconds

175

taskId,

176

extraData

177

});

178

}

179

180

// Analyze the events

181

console.log(`Collected ${events.length} profiling events`);

182

183

const taskMetrics = calculateTaskMetrics(events);

184

console.log("Task metrics:", taskMetrics);

185

}

186

187

function getEventTypeName(eventType) {

188

const names = {

189

1: "TaskStart",

190

2: "TaskComplete",

191

3: "TaskError",

192

4: "TaskCancel",

193

5: "TaskRun",

194

6: "TaskYield",

195

7: "SchedulerSuspend",

196

8: "SchedulerResume"

197

};

198

return names[eventType] || "Unknown";

199

}

200

201

function calculateTaskMetrics(events) {

202

const taskStats = new Map();

203

204

events.forEach(event => {

205

if (!taskStats.has(event.taskId)) {

206

taskStats.set(event.taskId, {

207

startTime: null,

208

endTime: null,

209

runTime: null,

210

yields: 0,

211

errors: 0

212

});

213

}

214

215

const stats = taskStats.get(event.taskId);

216

217

switch (event.type) {

218

case "TaskStart":

219

stats.startTime = event.timestamp;

220

break;

221

case "TaskRun":

222

stats.runTime = event.timestamp;

223

break;

224

case "TaskComplete":

225

stats.endTime = event.timestamp;

226

break;

227

case "TaskYield":

228

stats.yields++;

229

break;

230

case "TaskError":

231

stats.errors++;

232

break;

233

}

234

});

235

236

return {

237

totalTasks: taskStats.size,

238

avgExecutionTime: calculateAverageExecutionTime(taskStats),

239

totalYields: Array.from(taskStats.values()).reduce((sum, stats) => sum + stats.yields, 0),

240

totalErrors: Array.from(taskStats.values()).reduce((sum, stats) => sum + stats.errors, 0)

241

};

242

}

243

```

244

245

### Integration with Development Tools

246

247

```javascript

248

// Development-only profiling wrapper

249

function createProfilingWrapper() {

250

if (process.env.NODE_ENV !== "development" || !unstable_Profiling) {

251

return {

252

start: () => {},

253

end: () => {},

254

wrap: (fn) => fn

255

};

256

}

257

258

let isActive = false;

259

260

return {

261

start(label = "operation") {

262

if (isActive) return;

263

isActive = true;

264

console.log(`Starting profiling: ${label}`);

265

unstable_Profiling.startLoggingProfilingEvents();

266

},

267

268

end(label = "operation") {

269

if (!isActive) return;

270

isActive = false;

271

const data = unstable_Profiling.stopLoggingProfilingEvents();

272

console.log(`Profiling completed: ${label}`, data);

273

},

274

275

wrap(fn, label) {

276

return (...args) => {

277

this.start(label);

278

try {

279

return fn(...args);

280

} finally {

281

this.end(label);

282

}

283

};

284

}

285

};

286

}

287

288

// Usage

289

const profiler = createProfilingWrapper();

290

291

const profiledFunction = profiler.wrap(

292

() => {

293

// Scheduled work

294

performComplexOperation();

295

},

296

"complex-operation"

297

);

298

```

299

300

## Build Configuration

301

302

Profiling is controlled at build time through feature flags:

303

304

- **Development builds**: Profiling typically enabled

305

- **Production builds**: Profiling disabled (`unstable_Profiling` is `null`)

306

- **Profiling builds**: Special builds with profiling always enabled

307

308

The profiling system adds minimal overhead when disabled, but can impact performance when enabled due to event logging overhead.

309

310

## Limitations

311

312

1. **Build Dependency**: Only available in builds with profiling enabled

313

2. **Memory Usage**: Profiling data accumulates in memory until stopped

314

3. **Performance Impact**: Event logging adds overhead to task execution

315

4. **Data Size Limits**: Maximum event log size is limited (2MB by default)

316

5. **Binary Format**: Profiling data is in binary format requiring parsing

317

318

## Best Practices

319

320

- Enable profiling only during development and debugging

321

- Stop profiling collection regularly to prevent memory buildup

322

- Use profiling to identify performance bottlenecks in task scheduling

323

- Combine with browser DevTools for comprehensive performance analysis

324

- Profile both individual operations and complete workflows