@contrail/util 1.1.15-alpha-5 → 1.1.15-alpha-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
const performance_util_1 = require("./performance-util");
|
|
4
13
|
function demonstrateStartEndSpan() {
|
|
@@ -16,21 +25,25 @@ function demonstrateStartEndSpan() {
|
|
|
16
25
|
(0, performance_util_1.startSpan)('Complete Task');
|
|
17
26
|
(0, performance_util_1.startSpan)('Initialization');
|
|
18
27
|
const start2 = performance.now();
|
|
19
|
-
while (performance.now() < start2 + 50) {
|
|
28
|
+
while (performance.now() < start2 + 50) {
|
|
29
|
+
}
|
|
20
30
|
(0, performance_util_1.endSpan)('Initialization');
|
|
21
31
|
(0, performance_util_1.startSpan)('Main Processing');
|
|
22
32
|
(0, performance_util_1.startSpan)('Sub-task 1');
|
|
23
33
|
const start3 = performance.now();
|
|
24
|
-
while (performance.now() < start3 + 30) {
|
|
34
|
+
while (performance.now() < start3 + 30) {
|
|
35
|
+
}
|
|
25
36
|
(0, performance_util_1.endSpan)('Sub-task 1');
|
|
26
37
|
(0, performance_util_1.startSpan)('Sub-task 2');
|
|
27
38
|
const start4 = performance.now();
|
|
28
|
-
while (performance.now() < start4 + 40) {
|
|
39
|
+
while (performance.now() < start4 + 40) {
|
|
40
|
+
}
|
|
29
41
|
(0, performance_util_1.endSpan)('Sub-task 2');
|
|
30
42
|
(0, performance_util_1.endSpan)('Main Processing');
|
|
31
43
|
(0, performance_util_1.startSpan)('Cleanup');
|
|
32
44
|
const start5 = performance.now();
|
|
33
|
-
while (performance.now() < start5 + 20) {
|
|
45
|
+
while (performance.now() < start5 + 20) {
|
|
46
|
+
}
|
|
34
47
|
(0, performance_util_1.endSpan)('Cleanup');
|
|
35
48
|
(0, performance_util_1.endSpan)('Complete Task');
|
|
36
49
|
(0, performance_util_1.displayTimingTree)();
|
|
@@ -38,15 +51,18 @@ function demonstrateStartEndSpan() {
|
|
|
38
51
|
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
39
52
|
(0, performance_util_1.startSpan)('Phase 1');
|
|
40
53
|
const start6 = performance.now();
|
|
41
|
-
while (performance.now() < start6 + 60) {
|
|
54
|
+
while (performance.now() < start6 + 60) {
|
|
55
|
+
}
|
|
42
56
|
(0, performance_util_1.endSpan)('Phase 1');
|
|
43
57
|
(0, performance_util_1.startSpan)('Phase 2');
|
|
44
58
|
const start7 = performance.now();
|
|
45
|
-
while (performance.now() < start7 + 80) {
|
|
59
|
+
while (performance.now() < start7 + 80) {
|
|
60
|
+
}
|
|
46
61
|
(0, performance_util_1.endSpan)('Phase 2');
|
|
47
62
|
(0, performance_util_1.startSpan)('Phase 3');
|
|
48
63
|
const start8 = performance.now();
|
|
49
|
-
while (performance.now() < start8 + 40) {
|
|
64
|
+
while (performance.now() < start8 + 40) {
|
|
65
|
+
}
|
|
50
66
|
(0, performance_util_1.endSpan)('Phase 3');
|
|
51
67
|
(0, performance_util_1.displayTimingTree)();
|
|
52
68
|
}
|
|
@@ -64,5 +80,219 @@ function demonstrateWarningBehavior() {
|
|
|
64
80
|
console.log('Attempted to end "Non-existent Span" (should see warning above)');
|
|
65
81
|
(0, performance_util_1.displayTimingTree)();
|
|
66
82
|
}
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
function demonstrateParentNodeId() {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
console.log('\n--- Demonstrating parentNodeId Functionality ---\n');
|
|
86
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
87
|
+
console.log('Example 5: Concurrent async operations with explicit parent');
|
|
88
|
+
yield (0, performance_util_1.withTimingAsync)('Main Operation', () => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
const mainOpId = (0, performance_util_1.getCurrentParentNodeId)();
|
|
90
|
+
console.log(`Main Operation ID: ${mainOpId}`);
|
|
91
|
+
console.log('Starting concurrent operations...');
|
|
92
|
+
const results = yield Promise.all([
|
|
93
|
+
(0, performance_util_1.withTimingAsync)('Fetch User Data', () => __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
yield new Promise((resolve) => setTimeout(resolve, 80));
|
|
95
|
+
console.log(' ✓ User data fetched');
|
|
96
|
+
return 'user-data';
|
|
97
|
+
}), { parentNodeId: mainOpId }),
|
|
98
|
+
(0, performance_util_1.withTimingAsync)('Fetch Permissions', () => __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
yield new Promise((resolve) => setTimeout(resolve, 60));
|
|
100
|
+
console.log(' ✓ Permissions fetched');
|
|
101
|
+
return 'permissions-data';
|
|
102
|
+
}), { parentNodeId: mainOpId }),
|
|
103
|
+
(0, performance_util_1.withTimingAsync)('Fetch Preferences', () => __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
yield new Promise((resolve) => setTimeout(resolve, 100));
|
|
105
|
+
console.log(' ✓ Preferences fetched');
|
|
106
|
+
return 'preferences-data';
|
|
107
|
+
}), { parentNodeId: mainOpId }),
|
|
108
|
+
]);
|
|
109
|
+
console.log('All concurrent operations completed:', results);
|
|
110
|
+
yield (0, performance_util_1.withTimingAsync)('Process Results', () => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
yield new Promise((resolve) => setTimeout(resolve, 30));
|
|
112
|
+
console.log(' ✓ Results processed');
|
|
113
|
+
}));
|
|
114
|
+
}));
|
|
115
|
+
(0, performance_util_1.displayTimingTree)();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function demonstrateMixedNesting() {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
console.log('\n--- Demonstrating Mixed Natural and Explicit Nesting ---\n');
|
|
121
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
122
|
+
console.log('Example 6: Mixed natural and explicit nesting');
|
|
123
|
+
yield (0, performance_util_1.withTimingAsync)('Application Startup', () => __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
yield (0, performance_util_1.withTimingAsync)('Load Configuration', () => __awaiter(this, void 0, void 0, function* () {
|
|
125
|
+
yield new Promise((resolve) => setTimeout(resolve, 50));
|
|
126
|
+
console.log(' ✓ Configuration loaded');
|
|
127
|
+
yield (0, performance_util_1.withTimingAsync)('Validate Config', () => __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
yield new Promise((resolve) => setTimeout(resolve, 20));
|
|
129
|
+
console.log(' ✓ Configuration validated');
|
|
130
|
+
}));
|
|
131
|
+
}));
|
|
132
|
+
console.log('Starting parallel initialization...');
|
|
133
|
+
(0, performance_util_1.startSpan)('Initialization');
|
|
134
|
+
const ininitializeId = (0, performance_util_1.getCurrentParentNodeId)();
|
|
135
|
+
(0, performance_util_1.withTimingSync)('Do something before initialization', () => {
|
|
136
|
+
const start = performance.now();
|
|
137
|
+
while (performance.now() < start + 20) {
|
|
138
|
+
}
|
|
139
|
+
console.log(' ✓ Pre-initialization task completed');
|
|
140
|
+
});
|
|
141
|
+
yield Promise.all([
|
|
142
|
+
(0, performance_util_1.withTimingAsync)('Initialize Database', () => __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
yield new Promise((resolve) => setTimeout(resolve, 120));
|
|
144
|
+
console.log(' ✓ Database initialized');
|
|
145
|
+
}), { parentNodeId: ininitializeId }),
|
|
146
|
+
(0, performance_util_1.withTimingAsync)('Initialize Cache', () => __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
yield new Promise((resolve) => setTimeout(resolve, 90));
|
|
148
|
+
console.log(' ✓ Cache initialized');
|
|
149
|
+
}), { parentNodeId: ininitializeId }),
|
|
150
|
+
(0, performance_util_1.withTimingAsync)('Initialize Logging', () => __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
yield new Promise((resolve) => setTimeout(resolve, 40));
|
|
152
|
+
console.log(' ✓ Logging initialized');
|
|
153
|
+
}), { parentNodeId: ininitializeId }),
|
|
154
|
+
]);
|
|
155
|
+
(0, performance_util_1.withTimingSync)('Do something after initialization', () => {
|
|
156
|
+
const start = performance.now();
|
|
157
|
+
while (performance.now() < start + 20) {
|
|
158
|
+
}
|
|
159
|
+
console.log(' ✓ Post-initialization task completed');
|
|
160
|
+
});
|
|
161
|
+
(0, performance_util_1.endSpan)('Initialization');
|
|
162
|
+
yield (0, performance_util_1.withTimingAsync)('Final Setup', () => __awaiter(this, void 0, void 0, function* () {
|
|
163
|
+
yield new Promise((resolve) => setTimeout(resolve, 30));
|
|
164
|
+
console.log(' ✓ Final setup completed');
|
|
165
|
+
}));
|
|
166
|
+
}));
|
|
167
|
+
(0, performance_util_1.displayTimingTree)();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function demonstrateSyncWithParentId() {
|
|
171
|
+
console.log('\n--- Demonstrating Sync Functions with parentNodeId ---\n');
|
|
172
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
173
|
+
console.log('Example 7: Sync functions with explicit parent');
|
|
174
|
+
(0, performance_util_1.withTimingSync)('Data Processing Pipeline', () => {
|
|
175
|
+
const pipelineId = (0, performance_util_1.getCurrentParentNodeId)();
|
|
176
|
+
console.log(`Pipeline ID: ${pipelineId}`);
|
|
177
|
+
(0, performance_util_1.withTimingSync)('Load Input Data', () => {
|
|
178
|
+
const start = performance.now();
|
|
179
|
+
while (performance.now() < start + 50) {
|
|
180
|
+
}
|
|
181
|
+
console.log(' ✓ Input data loaded');
|
|
182
|
+
});
|
|
183
|
+
(0, performance_util_1.withTimingSync)('Process Batch 1', () => {
|
|
184
|
+
const start = performance.now();
|
|
185
|
+
while (performance.now() < start + 80) {
|
|
186
|
+
}
|
|
187
|
+
console.log(' ✓ Batch 1 processed');
|
|
188
|
+
}, { parentNodeId: pipelineId });
|
|
189
|
+
(0, performance_util_1.withTimingSync)('Process Batch 2', () => {
|
|
190
|
+
const start = performance.now();
|
|
191
|
+
while (performance.now() < start + 70) {
|
|
192
|
+
}
|
|
193
|
+
console.log(' ✓ Batch 2 processed');
|
|
194
|
+
}, { parentNodeId: pipelineId });
|
|
195
|
+
(0, performance_util_1.withTimingSync)('Process Batch 3', () => {
|
|
196
|
+
const start = performance.now();
|
|
197
|
+
while (performance.now() < start + 90) {
|
|
198
|
+
}
|
|
199
|
+
console.log(' ✓ Batch 3 processed');
|
|
200
|
+
}, { parentNodeId: pipelineId });
|
|
201
|
+
(0, performance_util_1.withTimingSync)('Save Results', () => {
|
|
202
|
+
const start = performance.now();
|
|
203
|
+
while (performance.now() < start + 40) {
|
|
204
|
+
}
|
|
205
|
+
console.log(' ✓ Results saved');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
(0, performance_util_1.displayTimingTree)();
|
|
209
|
+
}
|
|
210
|
+
function demonstrateManualSpansWithParentId() {
|
|
211
|
+
console.log('\n--- Demonstrating Manual Spans with parentNodeId ---\n');
|
|
212
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
213
|
+
console.log('Example 8: Manual spans with explicit parent');
|
|
214
|
+
(0, performance_util_1.startSpan)('Service Request');
|
|
215
|
+
const serviceId = (0, performance_util_1.getCurrentParentNodeId)();
|
|
216
|
+
console.log(`Service Request ID: ${serviceId}`);
|
|
217
|
+
(0, performance_util_1.startSpan)('Authenticate User');
|
|
218
|
+
const start1 = performance.now();
|
|
219
|
+
while (performance.now() < start1 + 30) {
|
|
220
|
+
}
|
|
221
|
+
(0, performance_util_1.endSpan)('Authenticate User');
|
|
222
|
+
console.log(' ✓ User authenticated');
|
|
223
|
+
(0, performance_util_1.startSpan)('Validate Input', { parentNodeId: serviceId });
|
|
224
|
+
const start2 = performance.now();
|
|
225
|
+
while (performance.now() < start2 + 20) {
|
|
226
|
+
}
|
|
227
|
+
(0, performance_util_1.endSpan)('Validate Input');
|
|
228
|
+
console.log(' ✓ Input validated');
|
|
229
|
+
(0, performance_util_1.startSpan)('Check Rate Limits', { parentNodeId: serviceId });
|
|
230
|
+
const start3 = performance.now();
|
|
231
|
+
while (performance.now() < start3 + 15) {
|
|
232
|
+
}
|
|
233
|
+
(0, performance_util_1.endSpan)('Check Rate Limits');
|
|
234
|
+
console.log(' ✓ Rate limits checked');
|
|
235
|
+
(0, performance_util_1.startSpan)('Log Request', { parentNodeId: serviceId });
|
|
236
|
+
const start4 = performance.now();
|
|
237
|
+
while (performance.now() < start4 + 10) {
|
|
238
|
+
}
|
|
239
|
+
(0, performance_util_1.endSpan)('Log Request');
|
|
240
|
+
console.log(' ✓ Request logged');
|
|
241
|
+
(0, performance_util_1.startSpan)('Process Request');
|
|
242
|
+
const start5 = performance.now();
|
|
243
|
+
while (performance.now() < start5 + 60) {
|
|
244
|
+
}
|
|
245
|
+
(0, performance_util_1.endSpan)('Process Request');
|
|
246
|
+
console.log(' ✓ Request processed');
|
|
247
|
+
(0, performance_util_1.endSpan)('Service Request');
|
|
248
|
+
(0, performance_util_1.displayTimingTree)();
|
|
249
|
+
}
|
|
250
|
+
function demonstrateNestingComparison() {
|
|
251
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
+
console.log('\n--- Demonstrating Natural vs Explicit Nesting ---\n');
|
|
253
|
+
console.log('Natural Nesting (call stack based):');
|
|
254
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
255
|
+
yield (0, performance_util_1.withTimingAsync)('Sequential Operations', () => __awaiter(this, void 0, void 0, function* () {
|
|
256
|
+
yield (0, performance_util_1.withTimingAsync)('Operation 1', () => __awaiter(this, void 0, void 0, function* () {
|
|
257
|
+
yield new Promise((resolve) => setTimeout(resolve, 30));
|
|
258
|
+
}));
|
|
259
|
+
yield (0, performance_util_1.withTimingAsync)('Operation 2', () => __awaiter(this, void 0, void 0, function* () {
|
|
260
|
+
yield new Promise((resolve) => setTimeout(resolve, 40));
|
|
261
|
+
}));
|
|
262
|
+
yield (0, performance_util_1.withTimingAsync)('Operation 3', () => __awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
yield new Promise((resolve) => setTimeout(resolve, 35));
|
|
264
|
+
}));
|
|
265
|
+
}));
|
|
266
|
+
(0, performance_util_1.displayTimingTree)();
|
|
267
|
+
console.log('\nExplicit Parent Assignment (logical grouping):');
|
|
268
|
+
(0, performance_util_1.clearDefaultTimingProfile)();
|
|
269
|
+
yield (0, performance_util_1.withTimingAsync)('Parallel Operations', () => __awaiter(this, void 0, void 0, function* () {
|
|
270
|
+
const parentId = (0, performance_util_1.getCurrentParentNodeId)();
|
|
271
|
+
yield Promise.all([
|
|
272
|
+
(0, performance_util_1.withTimingAsync)('Operation 1', () => __awaiter(this, void 0, void 0, function* () {
|
|
273
|
+
yield new Promise((resolve) => setTimeout(resolve, 30));
|
|
274
|
+
}), { parentNodeId: parentId }),
|
|
275
|
+
(0, performance_util_1.withTimingAsync)('Operation 2', () => __awaiter(this, void 0, void 0, function* () {
|
|
276
|
+
yield new Promise((resolve) => setTimeout(resolve, 40));
|
|
277
|
+
}), { parentNodeId: parentId }),
|
|
278
|
+
(0, performance_util_1.withTimingAsync)('Operation 3', () => __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
yield new Promise((resolve) => setTimeout(resolve, 35));
|
|
280
|
+
}), { parentNodeId: parentId }),
|
|
281
|
+
]);
|
|
282
|
+
}));
|
|
283
|
+
(0, performance_util_1.displayTimingTree)();
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function runAllExamples() {
|
|
287
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
demonstrateStartEndSpan();
|
|
289
|
+
demonstrateWarningBehavior();
|
|
290
|
+
yield demonstrateParentNodeId();
|
|
291
|
+
yield demonstrateMixedNesting();
|
|
292
|
+
demonstrateSyncWithParentId();
|
|
293
|
+
demonstrateManualSpansWithParentId();
|
|
294
|
+
yield demonstrateNestingComparison();
|
|
295
|
+
console.log('\nAll examples completed. ');
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
runAllExamples().catch(console.error);
|
|
@@ -2,23 +2,34 @@ type TimingSpans = TimingNode[];
|
|
|
2
2
|
type TimingStack = TimingNode[];
|
|
3
3
|
type TimingNode = {
|
|
4
4
|
label: string;
|
|
5
|
+
id: string;
|
|
5
6
|
durationMs: number;
|
|
6
7
|
children: TimingNode[];
|
|
8
|
+
startTime: number;
|
|
7
9
|
};
|
|
8
10
|
type ActiveSpan = {
|
|
9
11
|
node: TimingNode;
|
|
10
12
|
startTime: number;
|
|
13
|
+
wasAddedToStack: boolean;
|
|
11
14
|
};
|
|
12
15
|
type TimingProfile = {
|
|
16
|
+
activeSpans: Map<string, ActiveSpan>;
|
|
17
|
+
spansById: Map<string, TimingNode>;
|
|
13
18
|
timingSpans: TimingSpans;
|
|
14
19
|
timingStack: TimingStack;
|
|
15
|
-
activeSpans: Map<string, ActiveSpan>;
|
|
16
20
|
};
|
|
17
21
|
export declare function getDefaultTimingProfile(): TimingProfile;
|
|
18
22
|
export declare function clearDefaultTimingProfile(): void;
|
|
19
|
-
export declare function
|
|
20
|
-
export declare function
|
|
23
|
+
export declare function getCurrentParentNodeId(): string | null;
|
|
24
|
+
export declare function withTimingAsync<T>(label: string, fn: () => Promise<T>, options?: {
|
|
25
|
+
parentNodeId?: string | null;
|
|
26
|
+
}): Promise<T>;
|
|
27
|
+
export declare function withTimingSync<T>(label: string, fn: () => T, options?: {
|
|
28
|
+
parentNodeId?: string | null;
|
|
29
|
+
}): T;
|
|
21
30
|
export declare function displayTimingTree(nodes?: TimingSpans, depth?: number): string;
|
|
22
|
-
export declare function startSpan(spanName: string
|
|
31
|
+
export declare function startSpan(spanName: string, options?: {
|
|
32
|
+
parentNodeId?: string | null;
|
|
33
|
+
}): void;
|
|
23
34
|
export declare function endSpan(spanName: string): void;
|
|
24
35
|
export {};
|
|
@@ -11,15 +11,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.getDefaultTimingProfile = getDefaultTimingProfile;
|
|
13
13
|
exports.clearDefaultTimingProfile = clearDefaultTimingProfile;
|
|
14
|
+
exports.getCurrentParentNodeId = getCurrentParentNodeId;
|
|
14
15
|
exports.withTimingAsync = withTimingAsync;
|
|
15
16
|
exports.withTimingSync = withTimingSync;
|
|
16
17
|
exports.displayTimingTree = displayTimingTree;
|
|
17
18
|
exports.startSpan = startSpan;
|
|
18
19
|
exports.endSpan = endSpan;
|
|
19
20
|
const DEFAULT_TIMING_PROFILE = {
|
|
21
|
+
activeSpans: new Map(),
|
|
22
|
+
spansById: new Map(),
|
|
20
23
|
timingSpans: [],
|
|
21
24
|
timingStack: [],
|
|
22
|
-
activeSpans: new Map(),
|
|
23
25
|
};
|
|
24
26
|
function getDefaultTimingProfile() {
|
|
25
27
|
return DEFAULT_TIMING_PROFILE;
|
|
@@ -30,63 +32,150 @@ function getTimingStack() {
|
|
|
30
32
|
function getTimingSpans() {
|
|
31
33
|
return DEFAULT_TIMING_PROFILE.timingSpans;
|
|
32
34
|
}
|
|
35
|
+
function getNodeById(id) {
|
|
36
|
+
return DEFAULT_TIMING_PROFILE.spansById.get(id);
|
|
37
|
+
}
|
|
38
|
+
function setSpanId(id, node) {
|
|
39
|
+
DEFAULT_TIMING_PROFILE.spansById.set(id, node);
|
|
40
|
+
}
|
|
33
41
|
function clearDefaultTimingProfile() {
|
|
34
42
|
DEFAULT_TIMING_PROFILE.timingSpans = [];
|
|
35
43
|
DEFAULT_TIMING_PROFILE.timingStack = [];
|
|
36
44
|
DEFAULT_TIMING_PROFILE.activeSpans.clear();
|
|
45
|
+
DEFAULT_TIMING_PROFILE.spansById.clear();
|
|
37
46
|
}
|
|
38
|
-
function
|
|
47
|
+
function getParentNode() {
|
|
48
|
+
const stack = getTimingStack();
|
|
49
|
+
return stack.length > 0 ? stack[stack.length - 1] : null;
|
|
50
|
+
}
|
|
51
|
+
function getCurrentParentNodeId() {
|
|
52
|
+
const parentNode = getParentNode();
|
|
53
|
+
return parentNode ? parentNode.id : null;
|
|
54
|
+
}
|
|
55
|
+
function withTimingAsync(label, fn, options) {
|
|
39
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40
57
|
const start = performance.now();
|
|
41
|
-
const
|
|
42
|
-
const
|
|
58
|
+
const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
|
|
59
|
+
const uniqueId = crypto.randomUUID();
|
|
60
|
+
const timingNode = {
|
|
61
|
+
label,
|
|
62
|
+
durationMs: 0,
|
|
63
|
+
children: [],
|
|
64
|
+
id: uniqueId,
|
|
65
|
+
startTime: start
|
|
66
|
+
};
|
|
67
|
+
setSpanId(uniqueId, timingNode);
|
|
68
|
+
const parent = chosenId ? getNodeById(chosenId) : getParentNode();
|
|
43
69
|
if (parent) {
|
|
44
70
|
parent.children.push(timingNode);
|
|
45
71
|
}
|
|
46
72
|
else {
|
|
47
73
|
getTimingSpans().push(timingNode);
|
|
48
74
|
}
|
|
49
|
-
|
|
75
|
+
const isRunningConcurrently = !!chosenId;
|
|
76
|
+
if (!isRunningConcurrently) {
|
|
77
|
+
getTimingStack().push(timingNode);
|
|
78
|
+
}
|
|
50
79
|
return fn().finally(() => {
|
|
51
80
|
const end = performance.now();
|
|
52
81
|
timingNode.durationMs = end - start;
|
|
53
|
-
|
|
82
|
+
if (!isRunningConcurrently) {
|
|
83
|
+
getTimingStack().pop();
|
|
84
|
+
}
|
|
54
85
|
});
|
|
55
86
|
});
|
|
56
87
|
}
|
|
57
|
-
function withTimingSync(label, fn) {
|
|
88
|
+
function withTimingSync(label, fn, options) {
|
|
58
89
|
const start = performance.now();
|
|
59
|
-
const
|
|
60
|
-
const
|
|
90
|
+
const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
|
|
91
|
+
const uniqueId = crypto.randomUUID();
|
|
92
|
+
const timingNode = {
|
|
93
|
+
label,
|
|
94
|
+
durationMs: 0,
|
|
95
|
+
children: [],
|
|
96
|
+
id: uniqueId,
|
|
97
|
+
startTime: start
|
|
98
|
+
};
|
|
99
|
+
setSpanId(uniqueId, timingNode);
|
|
100
|
+
const parent = chosenId ? getNodeById(chosenId) : getParentNode();
|
|
61
101
|
if (parent) {
|
|
62
102
|
parent.children.push(timingNode);
|
|
63
103
|
}
|
|
64
104
|
else {
|
|
65
105
|
getTimingSpans().push(timingNode);
|
|
66
106
|
}
|
|
67
|
-
|
|
107
|
+
const isRunningConcurrently = !!chosenId;
|
|
108
|
+
if (!isRunningConcurrently) {
|
|
109
|
+
getTimingStack().push(timingNode);
|
|
110
|
+
}
|
|
68
111
|
try {
|
|
69
112
|
return fn();
|
|
70
113
|
}
|
|
71
114
|
finally {
|
|
72
115
|
const end = performance.now();
|
|
73
116
|
timingNode.durationMs = end - start;
|
|
74
|
-
|
|
117
|
+
if (!isRunningConcurrently) {
|
|
118
|
+
getTimingStack().pop();
|
|
119
|
+
}
|
|
75
120
|
}
|
|
76
121
|
}
|
|
77
122
|
function displayTimingTree(nodes = DEFAULT_TIMING_PROFILE.timingSpans, depth = 0) {
|
|
78
123
|
const lines = [];
|
|
79
124
|
const indent = ' '.repeat(depth);
|
|
80
|
-
const totalWidth =
|
|
125
|
+
const totalWidth = 120;
|
|
81
126
|
const timeWidth = 10;
|
|
82
|
-
nodes.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
127
|
+
const sortedNodes = [...nodes].sort((a, b) => a.startTime - b.startTime);
|
|
128
|
+
const groups = [];
|
|
129
|
+
let currentGroup = [];
|
|
130
|
+
for (let i = 0; i < sortedNodes.length; i++) {
|
|
131
|
+
const node = sortedNodes[i];
|
|
132
|
+
if (currentGroup.length === 0) {
|
|
133
|
+
currentGroup = [node];
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const hasOverlap = currentGroup.some(groupNode => {
|
|
137
|
+
const nodeEnd = node.startTime + node.durationMs;
|
|
138
|
+
const groupNodeEnd = groupNode.startTime + groupNode.durationMs;
|
|
139
|
+
return (node.startTime < groupNodeEnd && nodeEnd > groupNode.startTime);
|
|
140
|
+
});
|
|
141
|
+
if (hasOverlap) {
|
|
142
|
+
currentGroup.push(node);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
groups.push(currentGroup);
|
|
146
|
+
currentGroup = [node];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (currentGroup.length > 0) {
|
|
151
|
+
groups.push(currentGroup);
|
|
152
|
+
}
|
|
153
|
+
groups.forEach((group) => {
|
|
154
|
+
if (group.length === 1) {
|
|
155
|
+
const node = group[0];
|
|
156
|
+
const timeStr = `${node.durationMs.toFixed(2)}ms`;
|
|
157
|
+
const labelWithIndent = `${indent}${node.label}`;
|
|
158
|
+
const availableWidth = totalWidth - timeWidth - labelWithIndent.length;
|
|
159
|
+
const dots = '.'.repeat(Math.max(2, availableWidth));
|
|
160
|
+
lines.push(`${labelWithIndent}${dots}${timeStr.padStart(timeWidth)}`);
|
|
161
|
+
if (node.children && node.children.length > 0) {
|
|
162
|
+
lines.push(displayTimingTree(node.children, depth + 1));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const parallelHeader = `${indent}∥ Parallel Operations (${group.length})`;
|
|
167
|
+
lines.push(parallelHeader);
|
|
168
|
+
group.forEach((node) => {
|
|
169
|
+
const timeStr = `${node.durationMs.toFixed(2)}ms`;
|
|
170
|
+
const parallelIndicator = '∥ ';
|
|
171
|
+
const labelWithIndent = `${indent}${parallelIndicator}${node.label}`;
|
|
172
|
+
const availableWidth = totalWidth - timeWidth - labelWithIndent.length;
|
|
173
|
+
const dots = '.'.repeat(Math.max(2, availableWidth));
|
|
174
|
+
lines.push(`${labelWithIndent}${dots}${timeStr.padStart(timeWidth)}`);
|
|
175
|
+
if (node.children && node.children.length > 0) {
|
|
176
|
+
lines.push(displayTimingTree(node.children, depth + 1));
|
|
177
|
+
}
|
|
178
|
+
});
|
|
90
179
|
}
|
|
91
180
|
});
|
|
92
181
|
const result = lines.join('\n');
|
|
@@ -97,24 +186,37 @@ function displayTimingTree(nodes = DEFAULT_TIMING_PROFILE.timingSpans, depth = 0
|
|
|
97
186
|
}
|
|
98
187
|
return result;
|
|
99
188
|
}
|
|
100
|
-
function startSpan(spanName) {
|
|
189
|
+
function startSpan(spanName, options) {
|
|
101
190
|
if (DEFAULT_TIMING_PROFILE.activeSpans.has(spanName)) {
|
|
102
191
|
console.warn(`Span "${spanName}" is already active. Please end it before starting a new one with the same name.`);
|
|
103
192
|
return;
|
|
104
193
|
}
|
|
105
194
|
const startTime = performance.now();
|
|
106
|
-
const
|
|
107
|
-
const
|
|
195
|
+
const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
|
|
196
|
+
const uniqueId = crypto.randomUUID();
|
|
197
|
+
const timingNode = {
|
|
198
|
+
label: spanName,
|
|
199
|
+
durationMs: 0,
|
|
200
|
+
children: [],
|
|
201
|
+
id: uniqueId,
|
|
202
|
+
startTime: startTime
|
|
203
|
+
};
|
|
204
|
+
setSpanId(uniqueId, timingNode);
|
|
205
|
+
const parent = chosenId ? getNodeById(chosenId) : getParentNode();
|
|
108
206
|
if (parent) {
|
|
109
207
|
parent.children.push(timingNode);
|
|
110
208
|
}
|
|
111
209
|
else {
|
|
112
210
|
getTimingSpans().push(timingNode);
|
|
113
211
|
}
|
|
114
|
-
|
|
212
|
+
const isRunningConcurrently = !!chosenId;
|
|
213
|
+
if (!isRunningConcurrently) {
|
|
214
|
+
getTimingStack().push(timingNode);
|
|
215
|
+
}
|
|
115
216
|
DEFAULT_TIMING_PROFILE.activeSpans.set(spanName, {
|
|
116
217
|
node: timingNode,
|
|
117
218
|
startTime: startTime,
|
|
219
|
+
wasAddedToStack: !isRunningConcurrently,
|
|
118
220
|
});
|
|
119
221
|
}
|
|
120
222
|
function endSpan(spanName) {
|
|
@@ -125,14 +227,16 @@ function endSpan(spanName) {
|
|
|
125
227
|
}
|
|
126
228
|
const endTime = performance.now();
|
|
127
229
|
activeSpan.node.durationMs = endTime - activeSpan.startTime;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
230
|
+
if (activeSpan.wasAddedToStack) {
|
|
231
|
+
const currentTop = getTimingStack()[getTimingStack().length - 1];
|
|
232
|
+
if (currentTop === activeSpan.node) {
|
|
233
|
+
getTimingStack().pop();
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const stackIndex = getTimingStack().findIndex((node) => node === activeSpan.node);
|
|
237
|
+
if (stackIndex !== -1) {
|
|
238
|
+
getTimingStack().splice(stackIndex, 1);
|
|
239
|
+
}
|
|
136
240
|
}
|
|
137
241
|
}
|
|
138
242
|
DEFAULT_TIMING_PROFILE.activeSpans.delete(spanName);
|