whet 0.1.0 → 0.2.0
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.
- package/bin/haxe/ds/IntMap.d.ts +6 -0
- package/bin/haxe/ds/IntMap.js +25 -0
- package/bin/haxe/ds/Vector.d.ts +2 -0
- package/bin/minimatch/MinimatchOptions.d.ts +28 -0
- package/bin/whet/Project.d.ts +10 -0
- package/bin/whet/Project.js +52 -1
- package/bin/whet/Stone.d.ts +21 -0
- package/bin/whet/Stone.js +70 -6
- package/bin/whet/Whet.js +20 -1
- package/bin/whet/cache/BaseCache.d.ts +2 -0
- package/bin/whet/cache/BaseCache.js +96 -7
- package/bin/whet/cache/CacheManager.js +89 -7
- package/bin/whet/profiler/Profiler.d.ts +65 -0
- package/bin/whet/profiler/Profiler.js +351 -0
- package/bin/whet/profiler/Span.d.ts +90 -0
- package/bin/whet/profiler/Span.js +56 -0
- package/bin/whet/profiler/SpanRecorder.d.ts +20 -0
- package/bin/whet/profiler/SpanRecorder.js +63 -0
- package/bin/whet/profiler/SpanStats.d.ts +15 -0
- package/bin/whet/profiler/SpanStats.js +49 -0
- package/bin/whet/route/Router.d.ts +5 -0
- package/bin/whet/route/Router.js +30 -0
- package/package.json +2 -2
- package/bin/haxe/Log.d.ts +0 -33
- package/bin/haxe/Log.js +0 -61
- package/bin/pino_pretty/PrettyOptions.d.ts +0 -98
- package/bin/pino_pretty/default_/MessageFormatFunc.d.ts +0 -2
- package/bin/pino_pretty/default_/Prettifier.d.ts +0 -2
- package/bin/whet/extern/Minimatch.d.ts +0 -77
- package/bin/whet/stones/Server.d.ts +0 -59
- package/bin/whet/stones/Server.js +0 -261
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {MemoryCache} from "./MemoryCache.js"
|
|
2
2
|
import {FileCache} from "./FileCache.js"
|
|
3
3
|
import {CacheStrategy, CacheDurability, DurabilityCheck} from "./Cache.js"
|
|
4
|
+
import {BaseCache} from "./BaseCache.js"
|
|
4
5
|
import {RootDir} from "../SourceId.js"
|
|
6
|
+
import {SourceHash} from "../SourceHash.js"
|
|
5
7
|
import {Log} from "../Log.js"
|
|
6
8
|
import * as Path from "path"
|
|
7
9
|
import {Register} from "../../genes/Register.js"
|
|
@@ -26,8 +28,36 @@ class CacheManager extends Register.inherits() {
|
|
|
26
28
|
switch (_g._hx_index) {
|
|
27
29
|
case 0:
|
|
28
30
|
return stone.acquire(function () {
|
|
29
|
-
return stone.
|
|
30
|
-
return stone.
|
|
31
|
+
return ((stone.project.profiler != null) ? stone.project.profiler.withSpan(stone, "Hash", function () {
|
|
32
|
+
return stone.finalMaybeHash().then(function (hash) {
|
|
33
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
34
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
35
|
+
if (span != null) {
|
|
36
|
+
span.metadata = {"hashHex": meta};
|
|
37
|
+
};
|
|
38
|
+
return hash;
|
|
39
|
+
});
|
|
40
|
+
}, null) : stone.finalMaybeHash().then(function (hash) {
|
|
41
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
42
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
43
|
+
if (span != null) {
|
|
44
|
+
span.metadata = {"hashHex": meta};
|
|
45
|
+
};
|
|
46
|
+
return hash;
|
|
47
|
+
})).then(function (hash) {
|
|
48
|
+
if (stone.project.profiler != null) {
|
|
49
|
+
return stone.project.profiler.withSpan(stone, "Generate", function () {
|
|
50
|
+
return stone.generateSource(hash).then(function (src) {
|
|
51
|
+
BaseCache.setGenerateMeta((stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null, src);
|
|
52
|
+
return src;
|
|
53
|
+
});
|
|
54
|
+
}, null);
|
|
55
|
+
} else {
|
|
56
|
+
return stone.generateSource(hash).then(function (src) {
|
|
57
|
+
BaseCache.setGenerateMeta((stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null, src);
|
|
58
|
+
return src;
|
|
59
|
+
});
|
|
60
|
+
};
|
|
31
61
|
});
|
|
32
62
|
});
|
|
33
63
|
break
|
|
@@ -51,10 +81,34 @@ class CacheManager extends Register.inherits() {
|
|
|
51
81
|
switch (_g._hx_index) {
|
|
52
82
|
case 0:
|
|
53
83
|
return stone.acquire(function () {
|
|
54
|
-
return stone.
|
|
55
|
-
return stone.
|
|
56
|
-
|
|
84
|
+
return ((stone.project.profiler != null) ? stone.project.profiler.withSpan(stone, "Hash", function () {
|
|
85
|
+
return stone.finalMaybeHash().then(function (hash) {
|
|
86
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
87
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
88
|
+
if (span != null) {
|
|
89
|
+
span.metadata = {"hashHex": meta};
|
|
90
|
+
};
|
|
91
|
+
return hash;
|
|
57
92
|
});
|
|
93
|
+
}, null) : stone.finalMaybeHash().then(function (hash) {
|
|
94
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
95
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
96
|
+
if (span != null) {
|
|
97
|
+
span.metadata = {"hashHex": meta};
|
|
98
|
+
};
|
|
99
|
+
return hash;
|
|
100
|
+
})).then(function (hash) {
|
|
101
|
+
if (stone.project.profiler != null) {
|
|
102
|
+
return stone.project.profiler.withSpan(stone, "GeneratePartial", function () {
|
|
103
|
+
return stone.generatePartialSource(sourceId, hash).then(function (r) {
|
|
104
|
+
return r.source.filterTo(sourceId);
|
|
105
|
+
});
|
|
106
|
+
}, {"sourceId": sourceId});
|
|
107
|
+
} else {
|
|
108
|
+
return stone.generatePartialSource(sourceId, hash).then(function (r) {
|
|
109
|
+
return r.source.filterTo(sourceId);
|
|
110
|
+
});
|
|
111
|
+
};
|
|
58
112
|
});
|
|
59
113
|
});
|
|
60
114
|
break
|
|
@@ -82,8 +136,36 @@ class CacheManager extends Register.inherits() {
|
|
|
82
136
|
switch (stone.cacheStrategy._hx_index) {
|
|
83
137
|
case 0:
|
|
84
138
|
return stone.acquire(function () {
|
|
85
|
-
return stone.
|
|
86
|
-
return stone.
|
|
139
|
+
return ((stone.project.profiler != null) ? stone.project.profiler.withSpan(stone, "Hash", function () {
|
|
140
|
+
return stone.finalMaybeHash().then(function (hash) {
|
|
141
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
142
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
143
|
+
if (span != null) {
|
|
144
|
+
span.metadata = {"hashHex": meta};
|
|
145
|
+
};
|
|
146
|
+
return hash;
|
|
147
|
+
});
|
|
148
|
+
}, null) : stone.finalMaybeHash().then(function (hash) {
|
|
149
|
+
let span = (stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null;
|
|
150
|
+
let meta = (hash != null) ? SourceHash.toHex(hash) : null;
|
|
151
|
+
if (span != null) {
|
|
152
|
+
span.metadata = {"hashHex": meta};
|
|
153
|
+
};
|
|
154
|
+
return hash;
|
|
155
|
+
})).then(function (hash) {
|
|
156
|
+
if (stone.project.profiler != null) {
|
|
157
|
+
return stone.project.profiler.withSpan(stone, "Generate", function () {
|
|
158
|
+
return stone.generateSource(hash).then(function (src) {
|
|
159
|
+
BaseCache.setGenerateMeta((stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null, src);
|
|
160
|
+
return src;
|
|
161
|
+
});
|
|
162
|
+
}, null);
|
|
163
|
+
} else {
|
|
164
|
+
return stone.generateSource(hash).then(function (src) {
|
|
165
|
+
BaseCache.setGenerateMeta((stone.project.profiler != null) ? stone.project.profiler.getCurrentSpan() : null, src);
|
|
166
|
+
return src;
|
|
167
|
+
});
|
|
168
|
+
};
|
|
87
169
|
});
|
|
88
170
|
});
|
|
89
171
|
break
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {SpanStats} from "./SpanStats"
|
|
2
|
+
import {SpanRecorder} from "./SpanRecorder"
|
|
3
|
+
import {SpanEvent, AnySpan, SpanEventType} from "./Span"
|
|
4
|
+
import {AnyStone} from "../Stone"
|
|
5
|
+
import {AsyncLocalStorage} from "node:async_hooks"
|
|
6
|
+
|
|
7
|
+
export declare class Profiler {
|
|
8
|
+
constructor(config?: null | ProfilerConfig)
|
|
9
|
+
recorder: SpanRecorder
|
|
10
|
+
stats: SpanStats
|
|
11
|
+
protected listeners: ((arg0: SpanEvent) => void)[]
|
|
12
|
+
protected context: AsyncLocalStorage<AnySpan>
|
|
13
|
+
protected baseEpochUs: number
|
|
14
|
+
protected basePerfUs: number
|
|
15
|
+
protected nextSpanId: number
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
Primary API: wraps an async operation with timing and ALS context.
|
|
19
|
+
*/
|
|
20
|
+
withSpan<T, R>(stone: AnyStone, op: string, fn: (() => Promise<R>), meta?: null | T): Promise<R>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
Secondary API: manual start for spans where no function can be wrapped (e.g. LockWait).
|
|
24
|
+
*/
|
|
25
|
+
startSpan<T>(stone: AnyStone, op: string, meta?: null | T): AnySpan
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Complete a manually started span.
|
|
29
|
+
*/
|
|
30
|
+
endSpan(span: AnySpan): void
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
Returns the current span from AsyncLocalStorage context, or null if none.
|
|
34
|
+
*/
|
|
35
|
+
getCurrentSpan(): null | AnySpan
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
Subscribe to span events. Returns unsubscribe function.
|
|
39
|
+
*/
|
|
40
|
+
subscribe(listener: ((arg0: SpanEvent) => void)): (() => void)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
Export spans in the given format ("json" or "trace"). Defaults to "json".
|
|
44
|
+
*/
|
|
45
|
+
export(format: string): any
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
Return spans recorded since the given span ID (exclusive).
|
|
49
|
+
*/
|
|
50
|
+
getSpansSince(sinceId: number): AnySpan[]
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
Return aggregated profiling summary.
|
|
54
|
+
*/
|
|
55
|
+
getSummary(): any
|
|
56
|
+
protected exportJson(): any
|
|
57
|
+
protected exportChromeTrace(): any
|
|
58
|
+
protected serializeSpan(span: AnySpan): any
|
|
59
|
+
protected emit(type: SpanEventType, span: AnySpan): void
|
|
60
|
+
protected static ensureStoneEntry(byStone: {[key: string]: any}, stone: string): void
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type ProfilerConfig = {
|
|
64
|
+
maxSpans?: null | number
|
|
65
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import {SpanStats} from "./SpanStats.js"
|
|
2
|
+
import {SpanRecorder} from "./SpanRecorder.js"
|
|
3
|
+
import {Span, SpanEventType, SpanStatus} from "./Span.js"
|
|
4
|
+
import {AsyncLocalStorage} from "node:async_hooks"
|
|
5
|
+
import {IntMap} from "../../haxe/ds/IntMap.js"
|
|
6
|
+
import {EsMap} from "../../genes/util/EsMap.js"
|
|
7
|
+
import {Register} from "../../genes/Register.js"
|
|
8
|
+
import {Std} from "../../Std.js"
|
|
9
|
+
import {Reflect as Reflect__1} from "../../Reflect.js"
|
|
10
|
+
import {HxOverrides} from "../../HxOverrides.js"
|
|
11
|
+
|
|
12
|
+
const $global = Register.$global
|
|
13
|
+
|
|
14
|
+
export const Profiler = Register.global("$hxClasses")["whet.profiler.Profiler"] =
|
|
15
|
+
class Profiler extends Register.inherits() {
|
|
16
|
+
[Register.new](config) {
|
|
17
|
+
this.nextSpanId = 0;
|
|
18
|
+
this.listeners = [];
|
|
19
|
+
this.recorder = new SpanRecorder((config != null && config.maxSpans != null) ? config.maxSpans : 10000);
|
|
20
|
+
this.stats = new SpanStats();
|
|
21
|
+
this.context = new AsyncLocalStorage();
|
|
22
|
+
this.baseEpochUs = Date.now() * 1000;
|
|
23
|
+
this.basePerfUs = performance.now() * 1000;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
Primary API: wraps an async operation with timing and ALS context.
|
|
28
|
+
*/
|
|
29
|
+
withSpan(stone, op, fn, meta) {
|
|
30
|
+
let parent = this.context.getStore();
|
|
31
|
+
let span = new Span(this.nextSpanId++, (parent != null) ? parent.id : null, stone.id, op, performance.now(), meta);
|
|
32
|
+
span.estimatedDuration = this.stats.getEstimate(stone.id, op);
|
|
33
|
+
this.emit(SpanEventType.Start, span);
|
|
34
|
+
let _gthis = this;
|
|
35
|
+
return this.context.run(span, function () {
|
|
36
|
+
return fn().then(function (result) {
|
|
37
|
+
span.endTime = performance.now();
|
|
38
|
+
span.duration = span.endTime - span.startTime;
|
|
39
|
+
span.status = SpanStatus.Ok;
|
|
40
|
+
_gthis.recorder.record(span);
|
|
41
|
+
_gthis.stats.update(stone.id, op, span.duration);
|
|
42
|
+
_gthis.emit(SpanEventType.End, span);
|
|
43
|
+
return result;
|
|
44
|
+
})["catch"](function (err) {
|
|
45
|
+
span.endTime = performance.now();
|
|
46
|
+
span.duration = span.endTime - span.startTime;
|
|
47
|
+
span.status = SpanStatus.Error(Std.string(err));
|
|
48
|
+
_gthis.recorder.record(span);
|
|
49
|
+
_gthis.emit(SpanEventType.End, span);
|
|
50
|
+
return Promise.reject(err);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
Secondary API: manual start for spans where no function can be wrapped (e.g. LockWait).
|
|
57
|
+
*/
|
|
58
|
+
startSpan(stone, op, meta) {
|
|
59
|
+
let parent = this.context.getStore();
|
|
60
|
+
let span = new Span(this.nextSpanId++, (parent != null) ? parent.id : null, stone.id, op, performance.now(), meta);
|
|
61
|
+
span.estimatedDuration = this.stats.getEstimate(stone.id, op);
|
|
62
|
+
this.emit(SpanEventType.Start, span);
|
|
63
|
+
return span;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
Complete a manually started span.
|
|
68
|
+
*/
|
|
69
|
+
endSpan(span) {
|
|
70
|
+
span.endTime = performance.now();
|
|
71
|
+
span.duration = span.endTime - span.startTime;
|
|
72
|
+
span.status = SpanStatus.Ok;
|
|
73
|
+
this.recorder.record(span);
|
|
74
|
+
this.stats.update(span.stone, span.operation, span.duration);
|
|
75
|
+
this.emit(SpanEventType.End, span);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
Returns the current span from AsyncLocalStorage context, or null if none.
|
|
80
|
+
*/
|
|
81
|
+
getCurrentSpan() {
|
|
82
|
+
return this.context.getStore();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
Subscribe to span events. Returns unsubscribe function.
|
|
87
|
+
*/
|
|
88
|
+
subscribe(listener) {
|
|
89
|
+
this.listeners.push(listener);
|
|
90
|
+
let _gthis = this;
|
|
91
|
+
return function () {
|
|
92
|
+
HxOverrides.remove(_gthis.listeners, listener);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
Export spans in the given format ("json" or "trace"). Defaults to "json".
|
|
98
|
+
*/
|
|
99
|
+
export(format) {
|
|
100
|
+
if (format == "trace") {
|
|
101
|
+
return this.exportChromeTrace();
|
|
102
|
+
} else {
|
|
103
|
+
return this.exportJson();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
Return spans recorded since the given span ID (exclusive).
|
|
109
|
+
*/
|
|
110
|
+
getSpansSince(sinceId) {
|
|
111
|
+
return this.recorder.getSpansSince(sinceId);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
Return aggregated profiling summary.
|
|
116
|
+
*/
|
|
117
|
+
getSummary() {
|
|
118
|
+
let spans = this.recorder.getSpans();
|
|
119
|
+
let byStone = {};
|
|
120
|
+
let byOperation = {};
|
|
121
|
+
let cacheHits = 0;
|
|
122
|
+
let cacheLookups = 0;
|
|
123
|
+
let _g = 0;
|
|
124
|
+
while (_g < spans.length) {
|
|
125
|
+
let span = spans[_g];
|
|
126
|
+
++_g;
|
|
127
|
+
let opKey = span.operation;
|
|
128
|
+
let opEntry = byOperation[opKey];
|
|
129
|
+
if (opEntry == null) {
|
|
130
|
+
opEntry = {"count": 0, "totalMs": 0.0};
|
|
131
|
+
byOperation[opKey] = opEntry;
|
|
132
|
+
};
|
|
133
|
+
opEntry.count++;
|
|
134
|
+
opEntry.totalMs += span.duration;
|
|
135
|
+
if (opKey == "Generate") {
|
|
136
|
+
Profiler.ensureStoneEntry(byStone, span.stone);
|
|
137
|
+
let entry = byStone[span.stone];
|
|
138
|
+
entry.generates++;
|
|
139
|
+
entry.totalDuration += span.duration;
|
|
140
|
+
entry.avgDuration = entry.totalDuration / entry.generates;
|
|
141
|
+
entry.lastDuration = span.duration;
|
|
142
|
+
};
|
|
143
|
+
if (span.metadata != null) {
|
|
144
|
+
let meta = span.metadata;
|
|
145
|
+
if (meta.cacheResult != null) {
|
|
146
|
+
++cacheLookups;
|
|
147
|
+
if (meta.cacheResult == "hit") {
|
|
148
|
+
++cacheHits;
|
|
149
|
+
Profiler.ensureStoneEntry(byStone, span.stone);
|
|
150
|
+
byStone[span.stone].cacheHits++;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
return {"byStone": byStone, "byOperation": byOperation, "cacheHitRate": (cacheLookups > 0) ? cacheHits / cacheLookups : 0.0};
|
|
156
|
+
}
|
|
157
|
+
exportJson() {
|
|
158
|
+
let spans = this.recorder.getSpans();
|
|
159
|
+
let _g = [];
|
|
160
|
+
let _g1 = 0;
|
|
161
|
+
while (_g1 < spans.length) _g.push(this.serializeSpan(spans[_g1++]));
|
|
162
|
+
let stoneSet_inst = new Map();
|
|
163
|
+
let generateCount = 0;
|
|
164
|
+
let cacheHits = 0;
|
|
165
|
+
let cacheLookups = 0;
|
|
166
|
+
let _g2 = 0;
|
|
167
|
+
while (_g2 < spans.length) {
|
|
168
|
+
let span = spans[_g2];
|
|
169
|
+
++_g2;
|
|
170
|
+
stoneSet_inst.set(span.stone, true);
|
|
171
|
+
if (span.operation == "Generate") {
|
|
172
|
+
++generateCount;
|
|
173
|
+
};
|
|
174
|
+
if (span.metadata != null) {
|
|
175
|
+
let meta = span.metadata;
|
|
176
|
+
if (meta.cacheResult != null) {
|
|
177
|
+
++cacheLookups;
|
|
178
|
+
if (meta.cacheResult == "hit") {
|
|
179
|
+
++cacheHits;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
let stoneCount = 0;
|
|
185
|
+
let _ = EsMap.adaptIterator(stoneSet_inst.values());
|
|
186
|
+
while (_.hasNext()) {
|
|
187
|
+
_.next();
|
|
188
|
+
++stoneCount;
|
|
189
|
+
};
|
|
190
|
+
return {"spans": _g, "meta": {"spanCount": spans.length, "stoneCount": stoneCount, "totalGenerations": generateCount, "cacheHitRate": (cacheLookups > 0) ? cacheHits / cacheLookups : 0.0}};
|
|
191
|
+
}
|
|
192
|
+
exportChromeTrace() {
|
|
193
|
+
let spans = this.recorder.getSpans();
|
|
194
|
+
let spanById_inst = new Map();
|
|
195
|
+
let _g = 0;
|
|
196
|
+
while (_g < spans.length) {
|
|
197
|
+
let span = spans[_g];
|
|
198
|
+
++_g;
|
|
199
|
+
spanById_inst.set(span.id, span);
|
|
200
|
+
};
|
|
201
|
+
let childrenOf_inst = new Map();
|
|
202
|
+
let roots = [];
|
|
203
|
+
let _g1 = 0;
|
|
204
|
+
while (_g1 < spans.length) {
|
|
205
|
+
let span = spans[_g1];
|
|
206
|
+
++_g1;
|
|
207
|
+
let pid = span.parentId;
|
|
208
|
+
if (pid == null || !spanById_inst.has(pid)) {
|
|
209
|
+
roots.push(span);
|
|
210
|
+
} else {
|
|
211
|
+
if (!childrenOf_inst.has(pid)) {
|
|
212
|
+
childrenOf_inst.set(pid, []);
|
|
213
|
+
};
|
|
214
|
+
childrenOf_inst.get(pid).push(span);
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
let spanTid_inst = new Map();
|
|
218
|
+
let nextTid = 1;
|
|
219
|
+
let assignTids = null;
|
|
220
|
+
assignTids = function (span, tid) {
|
|
221
|
+
spanTid_inst.set(span.id, tid);
|
|
222
|
+
let children = childrenOf_inst.get(span.id);
|
|
223
|
+
if (children == null || children.length == 0) {
|
|
224
|
+
return;
|
|
225
|
+
};
|
|
226
|
+
children.sort(function (a, b) {
|
|
227
|
+
return Reflect__1.compare(a.startTime, b.startTime);
|
|
228
|
+
});
|
|
229
|
+
let laneEndTimes = [];
|
|
230
|
+
let laneTids = [];
|
|
231
|
+
let _g = 0;
|
|
232
|
+
while (_g < children.length) {
|
|
233
|
+
let child = children[_g];
|
|
234
|
+
++_g;
|
|
235
|
+
let lane = -1;
|
|
236
|
+
let _g1 = 0;
|
|
237
|
+
let _g2 = laneEndTimes.length;
|
|
238
|
+
while (_g1 < _g2) {
|
|
239
|
+
let i = _g1++;
|
|
240
|
+
if (laneEndTimes[i] <= child.startTime) {
|
|
241
|
+
lane = i;
|
|
242
|
+
break;
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
if (lane == -1) {
|
|
246
|
+
lane = laneEndTimes.length;
|
|
247
|
+
let assignTids;
|
|
248
|
+
if (lane == 0) {
|
|
249
|
+
assignTids = tid;
|
|
250
|
+
} else {
|
|
251
|
+
nextTid += 1;
|
|
252
|
+
assignTids = nextTid - 1;
|
|
253
|
+
};
|
|
254
|
+
laneTids.push(assignTids);
|
|
255
|
+
laneEndTimes.push(child.endTime);
|
|
256
|
+
} else {
|
|
257
|
+
laneEndTimes[lane] = child.endTime;
|
|
258
|
+
};
|
|
259
|
+
assignTids(child, laneTids[lane]);
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
roots.sort(function (a, b) {
|
|
263
|
+
return Reflect__1.compare(a.startTime, b.startTime);
|
|
264
|
+
});
|
|
265
|
+
let _g2 = 0;
|
|
266
|
+
while (_g2 < roots.length) {
|
|
267
|
+
nextTid += 1;
|
|
268
|
+
assignTids(roots[_g2++], nextTid - 1);
|
|
269
|
+
};
|
|
270
|
+
let events = [];
|
|
271
|
+
let tidNames = new IntMap();
|
|
272
|
+
let _g3 = 0;
|
|
273
|
+
while (_g3 < spans.length) {
|
|
274
|
+
let span = spans[_g3];
|
|
275
|
+
++_g3;
|
|
276
|
+
let tid = spanTid_inst.get(span.id);
|
|
277
|
+
if (tid != null && !tidNames.inst.has(tid)) {
|
|
278
|
+
tidNames.inst.set(tid, span.stone);
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
let map = tidNames;
|
|
282
|
+
let _g_keys = map.keys();
|
|
283
|
+
while (_g_keys.hasNext()) {
|
|
284
|
+
let key = _g_keys.next();
|
|
285
|
+
events.push({"ph": "M", "pid": 1, "tid": key, "name": "thread_name", "args": {"name": map.get(key)}});
|
|
286
|
+
};
|
|
287
|
+
let flowId = 0;
|
|
288
|
+
let _g4 = 0;
|
|
289
|
+
while (_g4 < spans.length) {
|
|
290
|
+
let span = spans[_g4];
|
|
291
|
+
++_g4;
|
|
292
|
+
let tid = spanTid_inst.get(span.id);
|
|
293
|
+
if (tid == null) {
|
|
294
|
+
continue;
|
|
295
|
+
};
|
|
296
|
+
let ts = this.baseEpochUs + (span.startTime * 1000 - this.basePerfUs);
|
|
297
|
+
events.push({"ph": "X", "name": span.operation + " " + span.stone, "cat": "whet", "ts": ts, "dur": span.duration * 1000, "pid": 1, "tid": tid, "args": (span.metadata != null) ? span.metadata : {}});
|
|
298
|
+
if (span.parentId != null) {
|
|
299
|
+
let parent = spanById_inst.get(span.parentId);
|
|
300
|
+
if (parent != null) {
|
|
301
|
+
let parentTid = spanTid_inst.get(parent.id);
|
|
302
|
+
if (parentTid != null && parentTid != tid) {
|
|
303
|
+
events.push({"ph": "s", "id": flowId, "pid": 1, "tid": parentTid, "ts": this.baseEpochUs + (parent.startTime * 1000 - this.basePerfUs), "name": "trigger", "cat": "flow"});
|
|
304
|
+
events.push({"ph": "f", "bp": "e", "id": flowId, "pid": 1, "tid": tid, "ts": ts, "name": "trigger", "cat": "flow"});
|
|
305
|
+
++flowId;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
return {"traceEvents": events};
|
|
311
|
+
}
|
|
312
|
+
serializeSpan(span) {
|
|
313
|
+
let _g = span.status;
|
|
314
|
+
let tmp;
|
|
315
|
+
switch (_g._hx_index) {
|
|
316
|
+
case 0:
|
|
317
|
+
tmp = "ok";
|
|
318
|
+
break
|
|
319
|
+
case 1:
|
|
320
|
+
tmp = "error: " + _g.msg;
|
|
321
|
+
break
|
|
322
|
+
|
|
323
|
+
};
|
|
324
|
+
return {"id": span.id, "parentId": span.parentId, "stone": span.stone, "operation": span.operation, "startTime": span.startTime, "endTime": span.endTime, "duration": span.duration, "estimatedDuration": span.estimatedDuration, "metadata": span.metadata, "status": tmp};
|
|
325
|
+
}
|
|
326
|
+
emit(type, span) {
|
|
327
|
+
let event = {"type": type, "span": span};
|
|
328
|
+
let _g = 0;
|
|
329
|
+
let _g1 = this.listeners;
|
|
330
|
+
while (_g < _g1.length) _g1[_g++](event);
|
|
331
|
+
}
|
|
332
|
+
static ensureStoneEntry(byStone, stone) {
|
|
333
|
+
if (!Object.prototype.hasOwnProperty.call(byStone, stone)) {
|
|
334
|
+
byStone[stone] = {"generates": 0, "totalDuration": 0.0, "avgDuration": 0.0, "lastDuration": 0.0, "cacheHits": 0};
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
static get __name__() {
|
|
338
|
+
return "whet.profiler.Profiler"
|
|
339
|
+
}
|
|
340
|
+
get __class__() {
|
|
341
|
+
return Profiler
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
Profiler.prototype.recorder = null;
|
|
345
|
+
Profiler.prototype.stats = null;
|
|
346
|
+
Profiler.prototype.listeners = null;
|
|
347
|
+
Profiler.prototype.context = null;
|
|
348
|
+
Profiler.prototype.baseEpochUs = null;
|
|
349
|
+
Profiler.prototype.basePerfUs = null;
|
|
350
|
+
Profiler.prototype.nextSpanId = null;
|
|
351
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
export declare class Span<T> {
|
|
3
|
+
constructor(id: number, parentId: null | number, stone: string, op: string, startTime: number, metadata?: null | T)
|
|
4
|
+
id: number
|
|
5
|
+
parentId: null | number
|
|
6
|
+
stone: string
|
|
7
|
+
operation: string
|
|
8
|
+
startTime: number
|
|
9
|
+
endTime: number
|
|
10
|
+
duration: number
|
|
11
|
+
estimatedDuration: number
|
|
12
|
+
metadata: T
|
|
13
|
+
status: SpanStatus
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type AnySpan = Span<any>
|
|
17
|
+
|
|
18
|
+
export declare namespace SpanStatus {
|
|
19
|
+
export type Ok = {_hx_index: 0, __enum__: "whet.profiler.SpanStatus"}
|
|
20
|
+
export const Ok: Ok
|
|
21
|
+
export type Error = {_hx_index: 1, msg: string, __enum__: "whet.profiler.SpanStatus"}
|
|
22
|
+
export const Error: (msg: string) => SpanStatus
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export declare type SpanStatus =
|
|
26
|
+
| SpanStatus.Ok
|
|
27
|
+
| SpanStatus.Error
|
|
28
|
+
|
|
29
|
+
export declare namespace SpanEventType {
|
|
30
|
+
export type Start = {_hx_index: 0, __enum__: "whet.profiler.SpanEventType"}
|
|
31
|
+
export const Start: Start
|
|
32
|
+
export type End = {_hx_index: 1, __enum__: "whet.profiler.SpanEventType"}
|
|
33
|
+
export const End: End
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export declare type SpanEventType =
|
|
37
|
+
| SpanEventType.Start
|
|
38
|
+
| SpanEventType.End
|
|
39
|
+
|
|
40
|
+
export type SpanEvent = {
|
|
41
|
+
span: AnySpan,
|
|
42
|
+
type: SpanEventType
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
Metadata types per span operation.
|
|
47
|
+
*/
|
|
48
|
+
export type LockWaitMeta = {
|
|
49
|
+
queueLength?: null | number,
|
|
50
|
+
queuePosition?: null | number
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type LockHeldMeta = {
|
|
54
|
+
cacheResult?: null | string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type HashMeta = {
|
|
58
|
+
dependencyCount?: null | number,
|
|
59
|
+
hashHex?: null | string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type GenerateMeta = {
|
|
63
|
+
outputCount?: null | number,
|
|
64
|
+
totalBytes?: null | number
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type GeneratePartialMeta = {
|
|
68
|
+
outputBytes?: null | number,
|
|
69
|
+
sourceId?: null | string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type DepResolveMeta = {
|
|
73
|
+
dependencyIds?: null | string[]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type CacheWriteMeta = {
|
|
77
|
+
entryCount?: null | number,
|
|
78
|
+
strategy?: null | string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ListMeta = {
|
|
82
|
+
resultCount?: null | number
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type ServeMeta = {
|
|
86
|
+
method?: null | string,
|
|
87
|
+
path?: null | string,
|
|
88
|
+
responseBytes?: null | number,
|
|
89
|
+
statusCode?: null | number
|
|
90
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {Register} from "../../genes/Register.js"
|
|
2
|
+
|
|
3
|
+
const $global = Register.$global
|
|
4
|
+
|
|
5
|
+
export const Span = Register.global("$hxClasses")["whet.profiler.Span"] =
|
|
6
|
+
class Span extends Register.inherits() {
|
|
7
|
+
[Register.new](id, parentId, stone, op, startTime, metadata) {
|
|
8
|
+
this.id = id;
|
|
9
|
+
this.parentId = parentId;
|
|
10
|
+
this.stone = stone;
|
|
11
|
+
this.operation = op;
|
|
12
|
+
this.startTime = startTime;
|
|
13
|
+
this.metadata = metadata;
|
|
14
|
+
this.estimatedDuration = 0;
|
|
15
|
+
this.status = SpanStatus.Ok;
|
|
16
|
+
}
|
|
17
|
+
static get __name__() {
|
|
18
|
+
return "whet.profiler.Span"
|
|
19
|
+
}
|
|
20
|
+
get __class__() {
|
|
21
|
+
return Span
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
Span.prototype.id = null;
|
|
25
|
+
Span.prototype.parentId = null;
|
|
26
|
+
Span.prototype.stone = null;
|
|
27
|
+
Span.prototype.operation = null;
|
|
28
|
+
Span.prototype.startTime = null;
|
|
29
|
+
Span.prototype.endTime = null;
|
|
30
|
+
Span.prototype.duration = null;
|
|
31
|
+
Span.prototype.estimatedDuration = null;
|
|
32
|
+
Span.prototype.metadata = null;
|
|
33
|
+
Span.prototype.status = null;
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
export const SpanStatus =
|
|
37
|
+
Register.global("$hxEnums")["whet.profiler.SpanStatus"] =
|
|
38
|
+
{
|
|
39
|
+
__ename__: "whet.profiler.SpanStatus",
|
|
40
|
+
|
|
41
|
+
Ok: {_hx_name: "Ok", _hx_index: 0, __enum__: "whet.profiler.SpanStatus"},
|
|
42
|
+
Error: Object.assign((msg) => ({_hx_index: 1, __enum__: "whet.profiler.SpanStatus", "msg": msg}), {_hx_name: "Error", __params__: ["msg"]})
|
|
43
|
+
}
|
|
44
|
+
SpanStatus.__constructs__ = [SpanStatus.Ok, SpanStatus.Error]
|
|
45
|
+
SpanStatus.__empty_constructs__ = [SpanStatus.Ok]
|
|
46
|
+
|
|
47
|
+
export const SpanEventType =
|
|
48
|
+
Register.global("$hxEnums")["whet.profiler.SpanEventType"] =
|
|
49
|
+
{
|
|
50
|
+
__ename__: "whet.profiler.SpanEventType",
|
|
51
|
+
|
|
52
|
+
Start: {_hx_name: "Start", _hx_index: 0, __enum__: "whet.profiler.SpanEventType"},
|
|
53
|
+
End: {_hx_name: "End", _hx_index: 1, __enum__: "whet.profiler.SpanEventType"}
|
|
54
|
+
}
|
|
55
|
+
SpanEventType.__constructs__ = [SpanEventType.Start, SpanEventType.End]
|
|
56
|
+
SpanEventType.__empty_constructs__ = [SpanEventType.Start, SpanEventType.End]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {AnySpan} from "./Span"
|
|
2
|
+
|
|
3
|
+
export declare class SpanRecorder {
|
|
4
|
+
constructor(maxSize: number)
|
|
5
|
+
maxSize: number
|
|
6
|
+
totalCount: number
|
|
7
|
+
protected buffer: AnySpan[]
|
|
8
|
+
protected writeIndex: number
|
|
9
|
+
record(span: AnySpan): void
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
Returns all recorded spans in chronological order.
|
|
13
|
+
*/
|
|
14
|
+
getSpans(): AnySpan[]
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
Returns spans recorded since the given span ID (exclusive).
|
|
18
|
+
*/
|
|
19
|
+
getSpansSince(sinceId: number): AnySpan[]
|
|
20
|
+
}
|