@gnsx/three 0.184.18 → 0.184.20
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/build/three.cjs +271 -41
- package/build/three.core.js +271 -41
- package/build/three.core.min.js +1 -1
- package/package.json +2 -2
- package/src/profiler/ProfilerService.js +271 -41
package/build/three.cjs
CHANGED
|
@@ -59718,14 +59718,22 @@ class TextureUtils {
|
|
|
59718
59718
|
* __gnsx_profiler.downloadTrace() // download gnsx-trace.json for Speedscope / Perfetto
|
|
59719
59719
|
* __gnsx_profiler.reset() // clear samples and trace
|
|
59720
59720
|
* __gnsx_profiler.disable()
|
|
59721
|
+
*
|
|
59722
|
+
* Chrome trace: `tid=1` is synchronous work; `@profile` on async methods records the
|
|
59723
|
+
* promise lifetime on `tid=2` so long async does not flatten the main row. For manual
|
|
59724
|
+
* spans, use `beginSpan` / `endSpan` with `{ asyncTimeline: true }` in a `.finally()`.
|
|
59721
59725
|
*/
|
|
59722
59726
|
|
|
59723
59727
|
const RING_SIZE = 120;
|
|
59724
59728
|
const FRAME_BUDGET_MS = 1000 / 60;
|
|
59725
|
-
|
|
59726
|
-
const
|
|
59729
|
+
const TRACE_TID_MAIN = 1;
|
|
59730
|
+
const TRACE_TID_ASYNC = 2;
|
|
59727
59731
|
const NOOP = () => {};
|
|
59728
59732
|
|
|
59733
|
+
const DUMMY_SPAN = Object.freeze( { label: '', t0: 0, _seq: 0 } );
|
|
59734
|
+
const NOOP_BEGIN_SPAN = () => DUMMY_SPAN;
|
|
59735
|
+
const NOOP_END_SPAN = () => {};
|
|
59736
|
+
|
|
59729
59737
|
class ProfilerServiceClass {
|
|
59730
59738
|
|
|
59731
59739
|
constructor() {
|
|
@@ -59733,24 +59741,40 @@ class ProfilerServiceClass {
|
|
|
59733
59741
|
this._profile = 'full';
|
|
59734
59742
|
this._enabled = false;
|
|
59735
59743
|
|
|
59736
|
-
/** @type {Map<string, Float64Array>} */
|
|
59744
|
+
/** @type {Map<string, Float64Array>} Inclusive time ring buffers (one per label). */
|
|
59737
59745
|
this.buffers = new Map();
|
|
59738
59746
|
/** @type {Map<string, number>} */
|
|
59739
59747
|
this.cursors = new Map();
|
|
59740
59748
|
/** @type {Map<string, number>} */
|
|
59741
59749
|
this.counts = new Map();
|
|
59742
|
-
/** @type {Map<string, Array<{ startTime: number, startMark: string
|
|
59750
|
+
/** @type {Map<string, Array<{ startTime: number, startMark: string }>>} */
|
|
59743
59751
|
this.marks = new Map();
|
|
59744
59752
|
/** @type {ChromeTraceEvent[]} */
|
|
59745
59753
|
this.traceEvents = [];
|
|
59746
59754
|
this.traceStartTime = 0;
|
|
59747
59755
|
this._markId = 0;
|
|
59748
59756
|
|
|
59757
|
+
/** @type {Map<string, Float64Array>} Exclusive (self) time ring buffers (one per label). */
|
|
59758
|
+
this.selfBuffers = new Map();
|
|
59759
|
+
/** @type {Map<string, number>} */
|
|
59760
|
+
this.selfCursors = new Map();
|
|
59761
|
+
/** @type {Map<string, number>} */
|
|
59762
|
+
this.selfCounts = new Map();
|
|
59763
|
+
/**
|
|
59764
|
+
* Global call stack tracking nesting across all labels for exclusive-time computation.
|
|
59765
|
+
* @type {Array<{ label: string, childTime: number }>}
|
|
59766
|
+
*/
|
|
59767
|
+
this.callStack = [];
|
|
59768
|
+
/** @type {Map<string, number>} Total (uncapped) invocation count since last reset, for calls-per-frame. */
|
|
59769
|
+
this.invocations = new Map();
|
|
59770
|
+
|
|
59749
59771
|
if ( this._enabled ) {
|
|
59750
59772
|
|
|
59751
59773
|
this.traceStartTime = performance.now();
|
|
59752
59774
|
this.begin = this._beginImpl.bind( this );
|
|
59753
59775
|
this.end = this._endImpl.bind( this );
|
|
59776
|
+
this.beginSpan = this._beginSpanImpl.bind( this );
|
|
59777
|
+
this.endSpan = this._endSpanImpl.bind( this );
|
|
59754
59778
|
this._exposeGlobal();
|
|
59755
59779
|
console.log( `[ProfilerService] auto-started from env (profile: ${this._profile})` );
|
|
59756
59780
|
|
|
@@ -59758,6 +59782,8 @@ class ProfilerServiceClass {
|
|
|
59758
59782
|
|
|
59759
59783
|
this.begin = NOOP;
|
|
59760
59784
|
this.end = NOOP;
|
|
59785
|
+
this.beginSpan = NOOP_BEGIN_SPAN;
|
|
59786
|
+
this.endSpan = NOOP_END_SPAN;
|
|
59761
59787
|
|
|
59762
59788
|
}
|
|
59763
59789
|
|
|
@@ -59789,6 +59815,8 @@ class ProfilerServiceClass {
|
|
|
59789
59815
|
this._enabled = true;
|
|
59790
59816
|
this.begin = this._beginImpl.bind( this );
|
|
59791
59817
|
this.end = this._endImpl.bind( this );
|
|
59818
|
+
this.beginSpan = this._beginSpanImpl.bind( this );
|
|
59819
|
+
this.endSpan = this._endSpanImpl.bind( this );
|
|
59792
59820
|
this._exposeGlobal();
|
|
59793
59821
|
console.log( `[ProfilerService] enabled (profile: ${this._profile}) — call __gnsx_profiler.report() or downloadTrace() from the console` );
|
|
59794
59822
|
|
|
@@ -59800,6 +59828,8 @@ class ProfilerServiceClass {
|
|
|
59800
59828
|
this._enabled = false;
|
|
59801
59829
|
this.begin = NOOP;
|
|
59802
59830
|
this.end = NOOP;
|
|
59831
|
+
this.beginSpan = NOOP_BEGIN_SPAN;
|
|
59832
|
+
this.endSpan = NOOP_END_SPAN;
|
|
59803
59833
|
console.log( '[ProfilerService] disabled' );
|
|
59804
59834
|
|
|
59805
59835
|
}
|
|
@@ -59835,22 +59865,11 @@ class ProfilerServiceClass {
|
|
|
59835
59865
|
|
|
59836
59866
|
}
|
|
59837
59867
|
|
|
59838
|
-
const traced = this._profile === 'full' && this.traceEvents.length < MAX_TRACE_EVENTS;
|
|
59839
|
-
if ( traced ) {
|
|
59840
|
-
|
|
59841
|
-
this.traceEvents.push( {
|
|
59842
|
-
name: label,
|
|
59843
|
-
ph: 'B',
|
|
59844
|
-
ts: this._getTraceTimestamp( startTime ),
|
|
59845
|
-
pid: 1,
|
|
59846
|
-
tid: 1,
|
|
59847
|
-
cat: 'gnsx',
|
|
59848
|
-
} );
|
|
59849
|
-
|
|
59850
|
-
}
|
|
59851
|
-
|
|
59852
59868
|
performance.mark( startMark );
|
|
59853
|
-
stack.push( { startTime, startMark
|
|
59869
|
+
stack.push( { startTime, startMark } );
|
|
59870
|
+
|
|
59871
|
+
// Push onto the global call stack for exclusive-time tracking.
|
|
59872
|
+
this.callStack.push( { label, childTime: 0 } );
|
|
59854
59873
|
|
|
59855
59874
|
}
|
|
59856
59875
|
|
|
@@ -59865,13 +59884,61 @@ class ProfilerServiceClass {
|
|
|
59865
59884
|
if ( stack.length === 0 ) this.marks.delete( label );
|
|
59866
59885
|
|
|
59867
59886
|
const now = performance.now();
|
|
59868
|
-
const { startTime, startMark
|
|
59887
|
+
const { startTime, startMark } = mark;
|
|
59869
59888
|
const duration = now - startTime;
|
|
59870
59889
|
const endMark = `gnsx:${label}:end:${++ this._markId}`;
|
|
59871
59890
|
|
|
59872
59891
|
performance.mark( endMark );
|
|
59873
59892
|
performance.measure( `gnsx:${label}`, startMark, endMark );
|
|
59874
59893
|
|
|
59894
|
+
this._commitDurationSample( label, startTime, duration, TRACE_TID_MAIN );
|
|
59895
|
+
|
|
59896
|
+
}
|
|
59897
|
+
|
|
59898
|
+
/**
|
|
59899
|
+
* Per-invocation span start (pair with {@link ProfilerServiceClass#endSpan}).
|
|
59900
|
+
* Safe for concurrent async with the same label.
|
|
59901
|
+
*
|
|
59902
|
+
* @param {string} label
|
|
59903
|
+
* @return {import('./ProfilerService.js').SpanHandle}
|
|
59904
|
+
*/
|
|
59905
|
+
_beginSpanImpl( label ) {
|
|
59906
|
+
|
|
59907
|
+
const seq = ++ this._markId;
|
|
59908
|
+
const t0 = performance.now();
|
|
59909
|
+
const startMark = `gnsx:${label}:s${seq}:start`;
|
|
59910
|
+
performance.mark( startMark );
|
|
59911
|
+
return { label, t0, _seq: seq, _startMark: startMark };
|
|
59912
|
+
|
|
59913
|
+
}
|
|
59914
|
+
|
|
59915
|
+
/**
|
|
59916
|
+
* @param {import('./ProfilerService.js').SpanHandle} handle
|
|
59917
|
+
* @param {import('./ProfilerService.js').EndSpanOptions} [opts]
|
|
59918
|
+
*/
|
|
59919
|
+
_endSpanImpl( handle, opts ) {
|
|
59920
|
+
|
|
59921
|
+
if ( handle._seq === 0 ) return;
|
|
59922
|
+
|
|
59923
|
+
const now = performance.now();
|
|
59924
|
+
const duration = now - handle.t0;
|
|
59925
|
+
const endMark = `gnsx:${handle.label}:s${handle._seq}:end`;
|
|
59926
|
+
performance.mark( endMark );
|
|
59927
|
+
performance.measure( `gnsx:${handle.label}#${handle._seq}`, handle._startMark, endMark );
|
|
59928
|
+
|
|
59929
|
+
const traceTid = opts?.asyncTimeline === true ? TRACE_TID_ASYNC : TRACE_TID_MAIN;
|
|
59930
|
+
this._commitDurationSample( handle.label, handle.t0, duration, traceTid );
|
|
59931
|
+
|
|
59932
|
+
}
|
|
59933
|
+
|
|
59934
|
+
/**
|
|
59935
|
+
* @param {string} label
|
|
59936
|
+
* @param {number} startTime
|
|
59937
|
+
* @param {number} durationMs
|
|
59938
|
+
* @param {typeof TRACE_TID_MAIN|typeof TRACE_TID_ASYNC} traceTid
|
|
59939
|
+
*/
|
|
59940
|
+
_commitDurationSample( label, startTime, durationMs, traceTid ) {
|
|
59941
|
+
|
|
59875
59942
|
let buffer = this.buffers.get( label );
|
|
59876
59943
|
if ( ! buffer ) {
|
|
59877
59944
|
|
|
@@ -59883,18 +59950,56 @@ class ProfilerServiceClass {
|
|
|
59883
59950
|
}
|
|
59884
59951
|
|
|
59885
59952
|
const cursor = this.cursors.get( label );
|
|
59886
|
-
buffer[ cursor ] =
|
|
59953
|
+
buffer[ cursor ] = durationMs;
|
|
59887
59954
|
this.cursors.set( label, ( cursor + 1 ) % RING_SIZE );
|
|
59888
59955
|
this.counts.set( label, Math.min( ( this.counts.get( label ) + 1 ), RING_SIZE ) );
|
|
59889
59956
|
|
|
59890
|
-
|
|
59957
|
+
// Track total invocations (uncapped) for calls-per-frame computation.
|
|
59958
|
+
this.invocations.set( label, ( this.invocations.get( label ) ?? 0 ) + 1 );
|
|
59959
|
+
|
|
59960
|
+
// Exclusive (self) time via the global call stack.
|
|
59961
|
+
const top = this.callStack.length > 0 ? this.callStack[ this.callStack.length - 1 ] : undefined;
|
|
59962
|
+
if ( top !== undefined && top.label === label ) {
|
|
59963
|
+
|
|
59964
|
+
this.callStack.pop();
|
|
59965
|
+
const selfTime = Math.max( 0, durationMs - top.childTime );
|
|
59966
|
+
|
|
59967
|
+
let selfBuffer = this.selfBuffers.get( label );
|
|
59968
|
+
if ( ! selfBuffer ) {
|
|
59969
|
+
|
|
59970
|
+
selfBuffer = new Float64Array( RING_SIZE );
|
|
59971
|
+
this.selfBuffers.set( label, selfBuffer );
|
|
59972
|
+
this.selfCursors.set( label, 0 );
|
|
59973
|
+
this.selfCounts.set( label, 0 );
|
|
59974
|
+
|
|
59975
|
+
}
|
|
59976
|
+
|
|
59977
|
+
const selfCursor = this.selfCursors.get( label );
|
|
59978
|
+
selfBuffer[ selfCursor ] = selfTime;
|
|
59979
|
+
this.selfCursors.set( label, ( selfCursor + 1 ) % RING_SIZE );
|
|
59980
|
+
this.selfCounts.set( label, Math.min( ( this.selfCounts.get( label ) + 1 ), RING_SIZE ) );
|
|
59981
|
+
|
|
59982
|
+
// Propagate inclusive duration to the parent scope's child accumulator.
|
|
59983
|
+
const parent = this.callStack.length > 0 ? this.callStack[ this.callStack.length - 1 ] : undefined;
|
|
59984
|
+
if ( parent !== undefined ) parent.childTime += durationMs;
|
|
59985
|
+
|
|
59986
|
+
} else {
|
|
59987
|
+
|
|
59988
|
+
// Label mismatch — likely async interleaving. Reset to avoid corruption.
|
|
59989
|
+
this.callStack.length = 0;
|
|
59990
|
+
|
|
59991
|
+
}
|
|
59891
59992
|
|
|
59993
|
+
if ( traceTid ) {
|
|
59994
|
+
|
|
59995
|
+
const traceName = traceTid === TRACE_TID_ASYNC ? `${label} (promise)` : label;
|
|
59892
59996
|
this.traceEvents.push( {
|
|
59893
|
-
name:
|
|
59894
|
-
ph: '
|
|
59895
|
-
ts: this._getTraceTimestamp(
|
|
59997
|
+
name: traceName,
|
|
59998
|
+
ph: 'X',
|
|
59999
|
+
ts: Math.round( this._getTraceTimestamp( startTime ) ),
|
|
60000
|
+
dur: Math.max( 1, Math.round( durationMs * 1000 ) ),
|
|
59896
60001
|
pid: 1,
|
|
59897
|
-
tid:
|
|
60002
|
+
tid: traceTid,
|
|
59898
60003
|
cat: 'gnsx',
|
|
59899
60004
|
} );
|
|
59900
60005
|
|
|
@@ -59929,6 +60034,23 @@ class ProfilerServiceClass {
|
|
|
59929
60034
|
const sorted = [ ...samples ].sort( ( a, b ) => a - b );
|
|
59930
60035
|
const avg = sorted.reduce( ( a, b ) => a + b, 0 ) / sorted.length;
|
|
59931
60036
|
|
|
60037
|
+
// Exclusive (self) time stats.
|
|
60038
|
+
const selfCount = this.selfCounts.get( label ) ?? 0;
|
|
60039
|
+
let selfAvg, selfMin, selfMax, selfP95, selfFrameBudget;
|
|
60040
|
+
if ( selfCount > 0 ) {
|
|
60041
|
+
|
|
60042
|
+
const selfBuffer = this.selfBuffers.get( label );
|
|
60043
|
+
const selfSamples = [ ...( selfCount < RING_SIZE
|
|
60044
|
+
? selfBuffer.subarray( 0, selfCount )
|
|
60045
|
+
: selfBuffer ) ].sort( ( a, b ) => a - b );
|
|
60046
|
+
selfAvg = selfSamples.reduce( ( a, b ) => a + b, 0 ) / selfSamples.length;
|
|
60047
|
+
selfMin = selfSamples[ 0 ];
|
|
60048
|
+
selfMax = selfSamples[ selfSamples.length - 1 ];
|
|
60049
|
+
selfP95 = selfSamples[ Math.floor( selfSamples.length * 0.95 ) ];
|
|
60050
|
+
selfFrameBudget = ( selfAvg / FRAME_BUDGET_MS ) * 100;
|
|
60051
|
+
|
|
60052
|
+
}
|
|
60053
|
+
|
|
59932
60054
|
return {
|
|
59933
60055
|
label,
|
|
59934
60056
|
samples: samples.length,
|
|
@@ -59937,6 +60059,12 @@ class ProfilerServiceClass {
|
|
|
59937
60059
|
max: sorted[ sorted.length - 1 ],
|
|
59938
60060
|
p95: sorted[ Math.floor( sorted.length * 0.95 ) ],
|
|
59939
60061
|
frameBudget: ( avg / FRAME_BUDGET_MS ) * 100,
|
|
60062
|
+
totalInvocations: this.invocations.get( label ) ?? 0,
|
|
60063
|
+
selfAvg,
|
|
60064
|
+
selfMin,
|
|
60065
|
+
selfMax,
|
|
60066
|
+
selfP95,
|
|
60067
|
+
selfFrameBudget,
|
|
59940
60068
|
};
|
|
59941
60069
|
|
|
59942
60070
|
}
|
|
@@ -59982,13 +60110,53 @@ class ProfilerServiceClass {
|
|
|
59982
60110
|
*/
|
|
59983
60111
|
exportChromeTrace() {
|
|
59984
60112
|
|
|
60113
|
+
const slices = [ ...this.traceEvents ];
|
|
60114
|
+
slices.sort( ( a, b ) => {
|
|
60115
|
+
|
|
60116
|
+
if ( a.ts !== b.ts ) return a.ts - b.ts;
|
|
60117
|
+
if ( a.tid !== b.tid ) return a.tid - b.tid;
|
|
60118
|
+
return a.name.localeCompare( b.name );
|
|
60119
|
+
|
|
60120
|
+
} );
|
|
60121
|
+
const hasAsync = slices.some( e => e.tid === TRACE_TID_ASYNC );
|
|
60122
|
+
/** @type {import('./ProfilerService.js').ChromeTraceMetadataEvent[]} */
|
|
60123
|
+
const prefix = [
|
|
60124
|
+
{
|
|
60125
|
+
cat: '__metadata',
|
|
60126
|
+
name: 'process_name',
|
|
60127
|
+
ph: 'M',
|
|
60128
|
+
pid: 1,
|
|
60129
|
+
tid: 0,
|
|
60130
|
+
ts: 0,
|
|
60131
|
+
args: { name: 'Genesys Profiler' },
|
|
60132
|
+
},
|
|
60133
|
+
{
|
|
60134
|
+
cat: '__metadata',
|
|
60135
|
+
name: 'thread_name',
|
|
60136
|
+
ph: 'M',
|
|
60137
|
+
pid: 1,
|
|
60138
|
+
tid: TRACE_TID_MAIN,
|
|
60139
|
+
ts: 0,
|
|
60140
|
+
args: { name: 'Main thread' },
|
|
60141
|
+
},
|
|
60142
|
+
];
|
|
60143
|
+
if ( hasAsync ) {
|
|
60144
|
+
|
|
60145
|
+
prefix.push( {
|
|
60146
|
+
cat: '__metadata',
|
|
60147
|
+
name: 'thread_name',
|
|
60148
|
+
ph: 'M',
|
|
60149
|
+
pid: 1,
|
|
60150
|
+
tid: TRACE_TID_ASYNC,
|
|
60151
|
+
ts: 0,
|
|
60152
|
+
args: { name: 'Async (promise lifetime)' },
|
|
60153
|
+
} );
|
|
60154
|
+
|
|
60155
|
+
}
|
|
60156
|
+
|
|
59985
60157
|
return {
|
|
59986
60158
|
displayTimeUnit: 'ms',
|
|
59987
|
-
traceEvents: [
|
|
59988
|
-
{ name: 'process_name', ph: 'M', pid: 1, args: { name: 'Genesys Profiler' } },
|
|
59989
|
-
{ name: 'thread_name', ph: 'M', pid: 1, tid: 1, args: { name: 'Main Thread' } },
|
|
59990
|
-
...this.traceEvents,
|
|
59991
|
-
],
|
|
60159
|
+
traceEvents: [ ...prefix, ...slices ],
|
|
59992
60160
|
};
|
|
59993
60161
|
|
|
59994
60162
|
}
|
|
@@ -60059,6 +60227,11 @@ class ProfilerServiceClass {
|
|
|
60059
60227
|
this.traceEvents = [];
|
|
60060
60228
|
this.traceStartTime = performance.now();
|
|
60061
60229
|
this._markId = 0;
|
|
60230
|
+
this.selfBuffers.clear();
|
|
60231
|
+
this.selfCursors.clear();
|
|
60232
|
+
this.selfCounts.clear();
|
|
60233
|
+
this.callStack.length = 0;
|
|
60234
|
+
this.invocations.clear();
|
|
60062
60235
|
|
|
60063
60236
|
}
|
|
60064
60237
|
|
|
@@ -60080,24 +60253,46 @@ class ProfilerServiceClass {
|
|
|
60080
60253
|
* @property {number} max
|
|
60081
60254
|
* @property {number} p95
|
|
60082
60255
|
* @property {number} frameBudget Percentage of a 60 fps frame budget (16.67 ms)
|
|
60256
|
+
* @property {number} totalInvocations Total (uncapped) call count since last reset, for calls-per-frame computation.
|
|
60257
|
+
* @property {number|undefined} selfAvg Exclusive (self) avg ms — inclusive time minus child scope time.
|
|
60258
|
+
* @property {number|undefined} selfMin
|
|
60259
|
+
* @property {number|undefined} selfMax
|
|
60260
|
+
* @property {number|undefined} selfP95
|
|
60261
|
+
* @property {number|undefined} selfFrameBudget Exclusive time as percentage of a 60 fps frame budget.
|
|
60262
|
+
*/
|
|
60263
|
+
|
|
60264
|
+
/**
|
|
60265
|
+
* @typedef {Object} SpanHandle
|
|
60266
|
+
* @property {string} label
|
|
60267
|
+
* @property {number} t0
|
|
60268
|
+
* @property {number} _seq
|
|
60269
|
+
* @property {string} _startMark
|
|
60270
|
+
*/
|
|
60271
|
+
|
|
60272
|
+
/**
|
|
60273
|
+
* @typedef {Object} EndSpanOptions
|
|
60274
|
+
* @property {boolean} [asyncTimeline] When true, trace slice uses `tid=2` (virtual async row).
|
|
60083
60275
|
*/
|
|
60084
60276
|
|
|
60085
60277
|
/**
|
|
60086
60278
|
* @typedef {Object} ChromeTraceEvent
|
|
60087
60279
|
* @property {string} name
|
|
60088
|
-
* @property {'
|
|
60280
|
+
* @property {'X'} ph
|
|
60089
60281
|
* @property {number} ts
|
|
60282
|
+
* @property {number} dur
|
|
60090
60283
|
* @property {1} pid
|
|
60091
|
-
* @property {
|
|
60284
|
+
* @property {number} tid
|
|
60092
60285
|
* @property {'gnsx'} cat
|
|
60093
60286
|
*/
|
|
60094
60287
|
|
|
60095
60288
|
/**
|
|
60096
60289
|
* @typedef {Object} ChromeTraceMetadataEvent
|
|
60290
|
+
* @property {'__metadata'} cat
|
|
60097
60291
|
* @property {'process_name'|'thread_name'} name
|
|
60098
60292
|
* @property {'M'} ph
|
|
60099
60293
|
* @property {1} pid
|
|
60100
|
-
* @property {
|
|
60294
|
+
* @property {number} [tid]
|
|
60295
|
+
* @property {0} ts
|
|
60101
60296
|
* @property {{ name: string }} args
|
|
60102
60297
|
*/
|
|
60103
60298
|
|
|
@@ -60113,28 +60308,38 @@ class ProfilerServiceClass {
|
|
|
60113
60308
|
|
|
60114
60309
|
const ProfilerService = new ProfilerServiceClass();
|
|
60115
60310
|
|
|
60311
|
+
function isThenable( x ) {
|
|
60312
|
+
|
|
60313
|
+
return (
|
|
60314
|
+
( typeof x === 'object' || typeof x === 'function' ) &&
|
|
60315
|
+
x !== null &&
|
|
60316
|
+
typeof x.then === 'function'
|
|
60317
|
+
);
|
|
60318
|
+
|
|
60319
|
+
}
|
|
60320
|
+
|
|
60116
60321
|
function applyProfileToMethod( label, descriptor ) {
|
|
60117
60322
|
|
|
60118
60323
|
const original = descriptor.value;
|
|
60119
60324
|
|
|
60120
60325
|
function profiled( ...args ) {
|
|
60121
60326
|
|
|
60122
|
-
ProfilerService.
|
|
60327
|
+
const span = ProfilerService.beginSpan( label );
|
|
60123
60328
|
try {
|
|
60124
60329
|
|
|
60125
60330
|
const result = original.apply( this, args );
|
|
60126
|
-
if ( result
|
|
60331
|
+
if ( isThenable( result ) ) {
|
|
60127
60332
|
|
|
60128
|
-
return result.finally( () => ProfilerService.
|
|
60333
|
+
return Promise.resolve( result ).finally( () => ProfilerService.endSpan( span, { asyncTimeline: true } ) );
|
|
60129
60334
|
|
|
60130
60335
|
}
|
|
60131
60336
|
|
|
60132
|
-
ProfilerService.
|
|
60337
|
+
ProfilerService.endSpan( span );
|
|
60133
60338
|
return result;
|
|
60134
60339
|
|
|
60135
60340
|
} catch ( error ) {
|
|
60136
60341
|
|
|
60137
|
-
ProfilerService.
|
|
60342
|
+
ProfilerService.endSpan( span );
|
|
60138
60343
|
throw error;
|
|
60139
60344
|
|
|
60140
60345
|
}
|
|
@@ -60148,14 +60353,39 @@ function applyProfileToMethod( label, descriptor ) {
|
|
|
60148
60353
|
|
|
60149
60354
|
/**
|
|
60150
60355
|
* Method decorator that profiles the decorated method.
|
|
60151
|
-
*
|
|
60356
|
+
* Default label: `ClassName.methodName`. Pass a custom tag via `@profile('My tag')`.
|
|
60152
60357
|
*
|
|
60358
|
+
* @param {Object|string} [targetOrTag]
|
|
60359
|
+
* @param {string|symbol} [propertyKey]
|
|
60360
|
+
* @param {PropertyDescriptor} [descriptor]
|
|
60361
|
+
* @return {PropertyDescriptor|function(Object, string|symbol, PropertyDescriptor): PropertyDescriptor}
|
|
60362
|
+
*/
|
|
60363
|
+
function profile( targetOrTag, propertyKey, descriptor ) {
|
|
60364
|
+
|
|
60365
|
+
if ( arguments.length === 0 ) {
|
|
60366
|
+
|
|
60367
|
+
return defaultProfileDecorator;
|
|
60368
|
+
|
|
60369
|
+
}
|
|
60370
|
+
|
|
60371
|
+
if ( arguments.length === 1 && typeof targetOrTag === 'string' ) {
|
|
60372
|
+
|
|
60373
|
+
const customTag = targetOrTag;
|
|
60374
|
+
return ( target, key, desc ) => applyProfileToMethod( customTag, desc );
|
|
60375
|
+
|
|
60376
|
+
}
|
|
60377
|
+
|
|
60378
|
+
return defaultProfileDecorator( targetOrTag, propertyKey, descriptor );
|
|
60379
|
+
|
|
60380
|
+
}
|
|
60381
|
+
|
|
60382
|
+
/**
|
|
60153
60383
|
* @param {Object} target
|
|
60154
60384
|
* @param {string|symbol} propertyKey
|
|
60155
60385
|
* @param {PropertyDescriptor} descriptor
|
|
60156
60386
|
* @return {PropertyDescriptor}
|
|
60157
60387
|
*/
|
|
60158
|
-
function
|
|
60388
|
+
function defaultProfileDecorator( target, propertyKey, descriptor ) {
|
|
60159
60389
|
|
|
60160
60390
|
const className = target.constructor?.name ?? 'Unknown';
|
|
60161
60391
|
return applyProfileToMethod( `${className}.${String( propertyKey )}`, descriptor );
|