@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.core.js
CHANGED
|
@@ -59738,14 +59738,22 @@ class TextureUtils {
|
|
|
59738
59738
|
* __gnsx_profiler.downloadTrace() // download gnsx-trace.json for Speedscope / Perfetto
|
|
59739
59739
|
* __gnsx_profiler.reset() // clear samples and trace
|
|
59740
59740
|
* __gnsx_profiler.disable()
|
|
59741
|
+
*
|
|
59742
|
+
* Chrome trace: `tid=1` is synchronous work; `@profile` on async methods records the
|
|
59743
|
+
* promise lifetime on `tid=2` so long async does not flatten the main row. For manual
|
|
59744
|
+
* spans, use `beginSpan` / `endSpan` with `{ asyncTimeline: true }` in a `.finally()`.
|
|
59741
59745
|
*/
|
|
59742
59746
|
|
|
59743
59747
|
const RING_SIZE = 120;
|
|
59744
59748
|
const FRAME_BUDGET_MS = 1000 / 60;
|
|
59745
|
-
|
|
59746
|
-
const
|
|
59749
|
+
const TRACE_TID_MAIN = 1;
|
|
59750
|
+
const TRACE_TID_ASYNC = 2;
|
|
59747
59751
|
const NOOP = () => {};
|
|
59748
59752
|
|
|
59753
|
+
const DUMMY_SPAN = Object.freeze( { label: '', t0: 0, _seq: 0 } );
|
|
59754
|
+
const NOOP_BEGIN_SPAN = () => DUMMY_SPAN;
|
|
59755
|
+
const NOOP_END_SPAN = () => {};
|
|
59756
|
+
|
|
59749
59757
|
class ProfilerServiceClass {
|
|
59750
59758
|
|
|
59751
59759
|
constructor() {
|
|
@@ -59753,24 +59761,40 @@ class ProfilerServiceClass {
|
|
|
59753
59761
|
this._profile = 'full';
|
|
59754
59762
|
this._enabled = false;
|
|
59755
59763
|
|
|
59756
|
-
/** @type {Map<string, Float64Array>} */
|
|
59764
|
+
/** @type {Map<string, Float64Array>} Inclusive time ring buffers (one per label). */
|
|
59757
59765
|
this.buffers = new Map();
|
|
59758
59766
|
/** @type {Map<string, number>} */
|
|
59759
59767
|
this.cursors = new Map();
|
|
59760
59768
|
/** @type {Map<string, number>} */
|
|
59761
59769
|
this.counts = new Map();
|
|
59762
|
-
/** @type {Map<string, Array<{ startTime: number, startMark: string
|
|
59770
|
+
/** @type {Map<string, Array<{ startTime: number, startMark: string }>>} */
|
|
59763
59771
|
this.marks = new Map();
|
|
59764
59772
|
/** @type {ChromeTraceEvent[]} */
|
|
59765
59773
|
this.traceEvents = [];
|
|
59766
59774
|
this.traceStartTime = 0;
|
|
59767
59775
|
this._markId = 0;
|
|
59768
59776
|
|
|
59777
|
+
/** @type {Map<string, Float64Array>} Exclusive (self) time ring buffers (one per label). */
|
|
59778
|
+
this.selfBuffers = new Map();
|
|
59779
|
+
/** @type {Map<string, number>} */
|
|
59780
|
+
this.selfCursors = new Map();
|
|
59781
|
+
/** @type {Map<string, number>} */
|
|
59782
|
+
this.selfCounts = new Map();
|
|
59783
|
+
/**
|
|
59784
|
+
* Global call stack tracking nesting across all labels for exclusive-time computation.
|
|
59785
|
+
* @type {Array<{ label: string, childTime: number }>}
|
|
59786
|
+
*/
|
|
59787
|
+
this.callStack = [];
|
|
59788
|
+
/** @type {Map<string, number>} Total (uncapped) invocation count since last reset, for calls-per-frame. */
|
|
59789
|
+
this.invocations = new Map();
|
|
59790
|
+
|
|
59769
59791
|
if ( this._enabled ) {
|
|
59770
59792
|
|
|
59771
59793
|
this.traceStartTime = performance.now();
|
|
59772
59794
|
this.begin = this._beginImpl.bind( this );
|
|
59773
59795
|
this.end = this._endImpl.bind( this );
|
|
59796
|
+
this.beginSpan = this._beginSpanImpl.bind( this );
|
|
59797
|
+
this.endSpan = this._endSpanImpl.bind( this );
|
|
59774
59798
|
this._exposeGlobal();
|
|
59775
59799
|
console.log( `[ProfilerService] auto-started from env (profile: ${this._profile})` );
|
|
59776
59800
|
|
|
@@ -59778,6 +59802,8 @@ class ProfilerServiceClass {
|
|
|
59778
59802
|
|
|
59779
59803
|
this.begin = NOOP;
|
|
59780
59804
|
this.end = NOOP;
|
|
59805
|
+
this.beginSpan = NOOP_BEGIN_SPAN;
|
|
59806
|
+
this.endSpan = NOOP_END_SPAN;
|
|
59781
59807
|
|
|
59782
59808
|
}
|
|
59783
59809
|
|
|
@@ -59809,6 +59835,8 @@ class ProfilerServiceClass {
|
|
|
59809
59835
|
this._enabled = true;
|
|
59810
59836
|
this.begin = this._beginImpl.bind( this );
|
|
59811
59837
|
this.end = this._endImpl.bind( this );
|
|
59838
|
+
this.beginSpan = this._beginSpanImpl.bind( this );
|
|
59839
|
+
this.endSpan = this._endSpanImpl.bind( this );
|
|
59812
59840
|
this._exposeGlobal();
|
|
59813
59841
|
console.log( `[ProfilerService] enabled (profile: ${this._profile}) — call __gnsx_profiler.report() or downloadTrace() from the console` );
|
|
59814
59842
|
|
|
@@ -59820,6 +59848,8 @@ class ProfilerServiceClass {
|
|
|
59820
59848
|
this._enabled = false;
|
|
59821
59849
|
this.begin = NOOP;
|
|
59822
59850
|
this.end = NOOP;
|
|
59851
|
+
this.beginSpan = NOOP_BEGIN_SPAN;
|
|
59852
|
+
this.endSpan = NOOP_END_SPAN;
|
|
59823
59853
|
console.log( '[ProfilerService] disabled' );
|
|
59824
59854
|
|
|
59825
59855
|
}
|
|
@@ -59855,22 +59885,11 @@ class ProfilerServiceClass {
|
|
|
59855
59885
|
|
|
59856
59886
|
}
|
|
59857
59887
|
|
|
59858
|
-
const traced = this._profile === 'full' && this.traceEvents.length < MAX_TRACE_EVENTS;
|
|
59859
|
-
if ( traced ) {
|
|
59860
|
-
|
|
59861
|
-
this.traceEvents.push( {
|
|
59862
|
-
name: label,
|
|
59863
|
-
ph: 'B',
|
|
59864
|
-
ts: this._getTraceTimestamp( startTime ),
|
|
59865
|
-
pid: 1,
|
|
59866
|
-
tid: 1,
|
|
59867
|
-
cat: 'gnsx',
|
|
59868
|
-
} );
|
|
59869
|
-
|
|
59870
|
-
}
|
|
59871
|
-
|
|
59872
59888
|
performance.mark( startMark );
|
|
59873
|
-
stack.push( { startTime, startMark
|
|
59889
|
+
stack.push( { startTime, startMark } );
|
|
59890
|
+
|
|
59891
|
+
// Push onto the global call stack for exclusive-time tracking.
|
|
59892
|
+
this.callStack.push( { label, childTime: 0 } );
|
|
59874
59893
|
|
|
59875
59894
|
}
|
|
59876
59895
|
|
|
@@ -59885,13 +59904,61 @@ class ProfilerServiceClass {
|
|
|
59885
59904
|
if ( stack.length === 0 ) this.marks.delete( label );
|
|
59886
59905
|
|
|
59887
59906
|
const now = performance.now();
|
|
59888
|
-
const { startTime, startMark
|
|
59907
|
+
const { startTime, startMark } = mark;
|
|
59889
59908
|
const duration = now - startTime;
|
|
59890
59909
|
const endMark = `gnsx:${label}:end:${++ this._markId}`;
|
|
59891
59910
|
|
|
59892
59911
|
performance.mark( endMark );
|
|
59893
59912
|
performance.measure( `gnsx:${label}`, startMark, endMark );
|
|
59894
59913
|
|
|
59914
|
+
this._commitDurationSample( label, startTime, duration, TRACE_TID_MAIN );
|
|
59915
|
+
|
|
59916
|
+
}
|
|
59917
|
+
|
|
59918
|
+
/**
|
|
59919
|
+
* Per-invocation span start (pair with {@link ProfilerServiceClass#endSpan}).
|
|
59920
|
+
* Safe for concurrent async with the same label.
|
|
59921
|
+
*
|
|
59922
|
+
* @param {string} label
|
|
59923
|
+
* @return {import('./ProfilerService.js').SpanHandle}
|
|
59924
|
+
*/
|
|
59925
|
+
_beginSpanImpl( label ) {
|
|
59926
|
+
|
|
59927
|
+
const seq = ++ this._markId;
|
|
59928
|
+
const t0 = performance.now();
|
|
59929
|
+
const startMark = `gnsx:${label}:s${seq}:start`;
|
|
59930
|
+
performance.mark( startMark );
|
|
59931
|
+
return { label, t0, _seq: seq, _startMark: startMark };
|
|
59932
|
+
|
|
59933
|
+
}
|
|
59934
|
+
|
|
59935
|
+
/**
|
|
59936
|
+
* @param {import('./ProfilerService.js').SpanHandle} handle
|
|
59937
|
+
* @param {import('./ProfilerService.js').EndSpanOptions} [opts]
|
|
59938
|
+
*/
|
|
59939
|
+
_endSpanImpl( handle, opts ) {
|
|
59940
|
+
|
|
59941
|
+
if ( handle._seq === 0 ) return;
|
|
59942
|
+
|
|
59943
|
+
const now = performance.now();
|
|
59944
|
+
const duration = now - handle.t0;
|
|
59945
|
+
const endMark = `gnsx:${handle.label}:s${handle._seq}:end`;
|
|
59946
|
+
performance.mark( endMark );
|
|
59947
|
+
performance.measure( `gnsx:${handle.label}#${handle._seq}`, handle._startMark, endMark );
|
|
59948
|
+
|
|
59949
|
+
const traceTid = opts?.asyncTimeline === true ? TRACE_TID_ASYNC : TRACE_TID_MAIN;
|
|
59950
|
+
this._commitDurationSample( handle.label, handle.t0, duration, traceTid );
|
|
59951
|
+
|
|
59952
|
+
}
|
|
59953
|
+
|
|
59954
|
+
/**
|
|
59955
|
+
* @param {string} label
|
|
59956
|
+
* @param {number} startTime
|
|
59957
|
+
* @param {number} durationMs
|
|
59958
|
+
* @param {typeof TRACE_TID_MAIN|typeof TRACE_TID_ASYNC} traceTid
|
|
59959
|
+
*/
|
|
59960
|
+
_commitDurationSample( label, startTime, durationMs, traceTid ) {
|
|
59961
|
+
|
|
59895
59962
|
let buffer = this.buffers.get( label );
|
|
59896
59963
|
if ( ! buffer ) {
|
|
59897
59964
|
|
|
@@ -59903,18 +59970,56 @@ class ProfilerServiceClass {
|
|
|
59903
59970
|
}
|
|
59904
59971
|
|
|
59905
59972
|
const cursor = this.cursors.get( label );
|
|
59906
|
-
buffer[ cursor ] =
|
|
59973
|
+
buffer[ cursor ] = durationMs;
|
|
59907
59974
|
this.cursors.set( label, ( cursor + 1 ) % RING_SIZE );
|
|
59908
59975
|
this.counts.set( label, Math.min( ( this.counts.get( label ) + 1 ), RING_SIZE ) );
|
|
59909
59976
|
|
|
59910
|
-
|
|
59977
|
+
// Track total invocations (uncapped) for calls-per-frame computation.
|
|
59978
|
+
this.invocations.set( label, ( this.invocations.get( label ) ?? 0 ) + 1 );
|
|
59979
|
+
|
|
59980
|
+
// Exclusive (self) time via the global call stack.
|
|
59981
|
+
const top = this.callStack.length > 0 ? this.callStack[ this.callStack.length - 1 ] : undefined;
|
|
59982
|
+
if ( top !== undefined && top.label === label ) {
|
|
59983
|
+
|
|
59984
|
+
this.callStack.pop();
|
|
59985
|
+
const selfTime = Math.max( 0, durationMs - top.childTime );
|
|
59986
|
+
|
|
59987
|
+
let selfBuffer = this.selfBuffers.get( label );
|
|
59988
|
+
if ( ! selfBuffer ) {
|
|
59989
|
+
|
|
59990
|
+
selfBuffer = new Float64Array( RING_SIZE );
|
|
59991
|
+
this.selfBuffers.set( label, selfBuffer );
|
|
59992
|
+
this.selfCursors.set( label, 0 );
|
|
59993
|
+
this.selfCounts.set( label, 0 );
|
|
59994
|
+
|
|
59995
|
+
}
|
|
59996
|
+
|
|
59997
|
+
const selfCursor = this.selfCursors.get( label );
|
|
59998
|
+
selfBuffer[ selfCursor ] = selfTime;
|
|
59999
|
+
this.selfCursors.set( label, ( selfCursor + 1 ) % RING_SIZE );
|
|
60000
|
+
this.selfCounts.set( label, Math.min( ( this.selfCounts.get( label ) + 1 ), RING_SIZE ) );
|
|
60001
|
+
|
|
60002
|
+
// Propagate inclusive duration to the parent scope's child accumulator.
|
|
60003
|
+
const parent = this.callStack.length > 0 ? this.callStack[ this.callStack.length - 1 ] : undefined;
|
|
60004
|
+
if ( parent !== undefined ) parent.childTime += durationMs;
|
|
59911
60005
|
|
|
60006
|
+
} else {
|
|
60007
|
+
|
|
60008
|
+
// Label mismatch — likely async interleaving. Reset to avoid corruption.
|
|
60009
|
+
this.callStack.length = 0;
|
|
60010
|
+
|
|
60011
|
+
}
|
|
60012
|
+
|
|
60013
|
+
if ( traceTid ) {
|
|
60014
|
+
|
|
60015
|
+
const traceName = traceTid === TRACE_TID_ASYNC ? `${label} (promise)` : label;
|
|
59912
60016
|
this.traceEvents.push( {
|
|
59913
|
-
name:
|
|
59914
|
-
ph: '
|
|
59915
|
-
ts: this._getTraceTimestamp(
|
|
60017
|
+
name: traceName,
|
|
60018
|
+
ph: 'X',
|
|
60019
|
+
ts: Math.round( this._getTraceTimestamp( startTime ) ),
|
|
60020
|
+
dur: Math.max( 1, Math.round( durationMs * 1000 ) ),
|
|
59916
60021
|
pid: 1,
|
|
59917
|
-
tid:
|
|
60022
|
+
tid: traceTid,
|
|
59918
60023
|
cat: 'gnsx',
|
|
59919
60024
|
} );
|
|
59920
60025
|
|
|
@@ -59949,6 +60054,23 @@ class ProfilerServiceClass {
|
|
|
59949
60054
|
const sorted = [ ...samples ].sort( ( a, b ) => a - b );
|
|
59950
60055
|
const avg = sorted.reduce( ( a, b ) => a + b, 0 ) / sorted.length;
|
|
59951
60056
|
|
|
60057
|
+
// Exclusive (self) time stats.
|
|
60058
|
+
const selfCount = this.selfCounts.get( label ) ?? 0;
|
|
60059
|
+
let selfAvg, selfMin, selfMax, selfP95, selfFrameBudget;
|
|
60060
|
+
if ( selfCount > 0 ) {
|
|
60061
|
+
|
|
60062
|
+
const selfBuffer = this.selfBuffers.get( label );
|
|
60063
|
+
const selfSamples = [ ...( selfCount < RING_SIZE
|
|
60064
|
+
? selfBuffer.subarray( 0, selfCount )
|
|
60065
|
+
: selfBuffer ) ].sort( ( a, b ) => a - b );
|
|
60066
|
+
selfAvg = selfSamples.reduce( ( a, b ) => a + b, 0 ) / selfSamples.length;
|
|
60067
|
+
selfMin = selfSamples[ 0 ];
|
|
60068
|
+
selfMax = selfSamples[ selfSamples.length - 1 ];
|
|
60069
|
+
selfP95 = selfSamples[ Math.floor( selfSamples.length * 0.95 ) ];
|
|
60070
|
+
selfFrameBudget = ( selfAvg / FRAME_BUDGET_MS ) * 100;
|
|
60071
|
+
|
|
60072
|
+
}
|
|
60073
|
+
|
|
59952
60074
|
return {
|
|
59953
60075
|
label,
|
|
59954
60076
|
samples: samples.length,
|
|
@@ -59957,6 +60079,12 @@ class ProfilerServiceClass {
|
|
|
59957
60079
|
max: sorted[ sorted.length - 1 ],
|
|
59958
60080
|
p95: sorted[ Math.floor( sorted.length * 0.95 ) ],
|
|
59959
60081
|
frameBudget: ( avg / FRAME_BUDGET_MS ) * 100,
|
|
60082
|
+
totalInvocations: this.invocations.get( label ) ?? 0,
|
|
60083
|
+
selfAvg,
|
|
60084
|
+
selfMin,
|
|
60085
|
+
selfMax,
|
|
60086
|
+
selfP95,
|
|
60087
|
+
selfFrameBudget,
|
|
59960
60088
|
};
|
|
59961
60089
|
|
|
59962
60090
|
}
|
|
@@ -60002,13 +60130,53 @@ class ProfilerServiceClass {
|
|
|
60002
60130
|
*/
|
|
60003
60131
|
exportChromeTrace() {
|
|
60004
60132
|
|
|
60133
|
+
const slices = [ ...this.traceEvents ];
|
|
60134
|
+
slices.sort( ( a, b ) => {
|
|
60135
|
+
|
|
60136
|
+
if ( a.ts !== b.ts ) return a.ts - b.ts;
|
|
60137
|
+
if ( a.tid !== b.tid ) return a.tid - b.tid;
|
|
60138
|
+
return a.name.localeCompare( b.name );
|
|
60139
|
+
|
|
60140
|
+
} );
|
|
60141
|
+
const hasAsync = slices.some( e => e.tid === TRACE_TID_ASYNC );
|
|
60142
|
+
/** @type {import('./ProfilerService.js').ChromeTraceMetadataEvent[]} */
|
|
60143
|
+
const prefix = [
|
|
60144
|
+
{
|
|
60145
|
+
cat: '__metadata',
|
|
60146
|
+
name: 'process_name',
|
|
60147
|
+
ph: 'M',
|
|
60148
|
+
pid: 1,
|
|
60149
|
+
tid: 0,
|
|
60150
|
+
ts: 0,
|
|
60151
|
+
args: { name: 'Genesys Profiler' },
|
|
60152
|
+
},
|
|
60153
|
+
{
|
|
60154
|
+
cat: '__metadata',
|
|
60155
|
+
name: 'thread_name',
|
|
60156
|
+
ph: 'M',
|
|
60157
|
+
pid: 1,
|
|
60158
|
+
tid: TRACE_TID_MAIN,
|
|
60159
|
+
ts: 0,
|
|
60160
|
+
args: { name: 'Main thread' },
|
|
60161
|
+
},
|
|
60162
|
+
];
|
|
60163
|
+
if ( hasAsync ) {
|
|
60164
|
+
|
|
60165
|
+
prefix.push( {
|
|
60166
|
+
cat: '__metadata',
|
|
60167
|
+
name: 'thread_name',
|
|
60168
|
+
ph: 'M',
|
|
60169
|
+
pid: 1,
|
|
60170
|
+
tid: TRACE_TID_ASYNC,
|
|
60171
|
+
ts: 0,
|
|
60172
|
+
args: { name: 'Async (promise lifetime)' },
|
|
60173
|
+
} );
|
|
60174
|
+
|
|
60175
|
+
}
|
|
60176
|
+
|
|
60005
60177
|
return {
|
|
60006
60178
|
displayTimeUnit: 'ms',
|
|
60007
|
-
traceEvents: [
|
|
60008
|
-
{ name: 'process_name', ph: 'M', pid: 1, args: { name: 'Genesys Profiler' } },
|
|
60009
|
-
{ name: 'thread_name', ph: 'M', pid: 1, tid: 1, args: { name: 'Main Thread' } },
|
|
60010
|
-
...this.traceEvents,
|
|
60011
|
-
],
|
|
60179
|
+
traceEvents: [ ...prefix, ...slices ],
|
|
60012
60180
|
};
|
|
60013
60181
|
|
|
60014
60182
|
}
|
|
@@ -60079,6 +60247,11 @@ class ProfilerServiceClass {
|
|
|
60079
60247
|
this.traceEvents = [];
|
|
60080
60248
|
this.traceStartTime = performance.now();
|
|
60081
60249
|
this._markId = 0;
|
|
60250
|
+
this.selfBuffers.clear();
|
|
60251
|
+
this.selfCursors.clear();
|
|
60252
|
+
this.selfCounts.clear();
|
|
60253
|
+
this.callStack.length = 0;
|
|
60254
|
+
this.invocations.clear();
|
|
60082
60255
|
|
|
60083
60256
|
}
|
|
60084
60257
|
|
|
@@ -60100,24 +60273,46 @@ class ProfilerServiceClass {
|
|
|
60100
60273
|
* @property {number} max
|
|
60101
60274
|
* @property {number} p95
|
|
60102
60275
|
* @property {number} frameBudget Percentage of a 60 fps frame budget (16.67 ms)
|
|
60276
|
+
* @property {number} totalInvocations Total (uncapped) call count since last reset, for calls-per-frame computation.
|
|
60277
|
+
* @property {number|undefined} selfAvg Exclusive (self) avg ms — inclusive time minus child scope time.
|
|
60278
|
+
* @property {number|undefined} selfMin
|
|
60279
|
+
* @property {number|undefined} selfMax
|
|
60280
|
+
* @property {number|undefined} selfP95
|
|
60281
|
+
* @property {number|undefined} selfFrameBudget Exclusive time as percentage of a 60 fps frame budget.
|
|
60282
|
+
*/
|
|
60283
|
+
|
|
60284
|
+
/**
|
|
60285
|
+
* @typedef {Object} SpanHandle
|
|
60286
|
+
* @property {string} label
|
|
60287
|
+
* @property {number} t0
|
|
60288
|
+
* @property {number} _seq
|
|
60289
|
+
* @property {string} _startMark
|
|
60290
|
+
*/
|
|
60291
|
+
|
|
60292
|
+
/**
|
|
60293
|
+
* @typedef {Object} EndSpanOptions
|
|
60294
|
+
* @property {boolean} [asyncTimeline] When true, trace slice uses `tid=2` (virtual async row).
|
|
60103
60295
|
*/
|
|
60104
60296
|
|
|
60105
60297
|
/**
|
|
60106
60298
|
* @typedef {Object} ChromeTraceEvent
|
|
60107
60299
|
* @property {string} name
|
|
60108
|
-
* @property {'
|
|
60300
|
+
* @property {'X'} ph
|
|
60109
60301
|
* @property {number} ts
|
|
60302
|
+
* @property {number} dur
|
|
60110
60303
|
* @property {1} pid
|
|
60111
|
-
* @property {
|
|
60304
|
+
* @property {number} tid
|
|
60112
60305
|
* @property {'gnsx'} cat
|
|
60113
60306
|
*/
|
|
60114
60307
|
|
|
60115
60308
|
/**
|
|
60116
60309
|
* @typedef {Object} ChromeTraceMetadataEvent
|
|
60310
|
+
* @property {'__metadata'} cat
|
|
60117
60311
|
* @property {'process_name'|'thread_name'} name
|
|
60118
60312
|
* @property {'M'} ph
|
|
60119
60313
|
* @property {1} pid
|
|
60120
|
-
* @property {
|
|
60314
|
+
* @property {number} [tid]
|
|
60315
|
+
* @property {0} ts
|
|
60121
60316
|
* @property {{ name: string }} args
|
|
60122
60317
|
*/
|
|
60123
60318
|
|
|
@@ -60133,28 +60328,38 @@ class ProfilerServiceClass {
|
|
|
60133
60328
|
|
|
60134
60329
|
const ProfilerService = new ProfilerServiceClass();
|
|
60135
60330
|
|
|
60331
|
+
function isThenable( x ) {
|
|
60332
|
+
|
|
60333
|
+
return (
|
|
60334
|
+
( typeof x === 'object' || typeof x === 'function' ) &&
|
|
60335
|
+
x !== null &&
|
|
60336
|
+
typeof x.then === 'function'
|
|
60337
|
+
);
|
|
60338
|
+
|
|
60339
|
+
}
|
|
60340
|
+
|
|
60136
60341
|
function applyProfileToMethod( label, descriptor ) {
|
|
60137
60342
|
|
|
60138
60343
|
const original = descriptor.value;
|
|
60139
60344
|
|
|
60140
60345
|
function profiled( ...args ) {
|
|
60141
60346
|
|
|
60142
|
-
ProfilerService.
|
|
60347
|
+
const span = ProfilerService.beginSpan( label );
|
|
60143
60348
|
try {
|
|
60144
60349
|
|
|
60145
60350
|
const result = original.apply( this, args );
|
|
60146
|
-
if ( result
|
|
60351
|
+
if ( isThenable( result ) ) {
|
|
60147
60352
|
|
|
60148
|
-
return result.finally( () => ProfilerService.
|
|
60353
|
+
return Promise.resolve( result ).finally( () => ProfilerService.endSpan( span, { asyncTimeline: true } ) );
|
|
60149
60354
|
|
|
60150
60355
|
}
|
|
60151
60356
|
|
|
60152
|
-
ProfilerService.
|
|
60357
|
+
ProfilerService.endSpan( span );
|
|
60153
60358
|
return result;
|
|
60154
60359
|
|
|
60155
60360
|
} catch ( error ) {
|
|
60156
60361
|
|
|
60157
|
-
ProfilerService.
|
|
60362
|
+
ProfilerService.endSpan( span );
|
|
60158
60363
|
throw error;
|
|
60159
60364
|
|
|
60160
60365
|
}
|
|
@@ -60168,14 +60373,39 @@ function applyProfileToMethod( label, descriptor ) {
|
|
|
60168
60373
|
|
|
60169
60374
|
/**
|
|
60170
60375
|
* Method decorator that profiles the decorated method.
|
|
60171
|
-
*
|
|
60376
|
+
* Default label: `ClassName.methodName`. Pass a custom tag via `@profile('My tag')`.
|
|
60172
60377
|
*
|
|
60378
|
+
* @param {Object|string} [targetOrTag]
|
|
60379
|
+
* @param {string|symbol} [propertyKey]
|
|
60380
|
+
* @param {PropertyDescriptor} [descriptor]
|
|
60381
|
+
* @return {PropertyDescriptor|function(Object, string|symbol, PropertyDescriptor): PropertyDescriptor}
|
|
60382
|
+
*/
|
|
60383
|
+
function profile( targetOrTag, propertyKey, descriptor ) {
|
|
60384
|
+
|
|
60385
|
+
if ( arguments.length === 0 ) {
|
|
60386
|
+
|
|
60387
|
+
return defaultProfileDecorator;
|
|
60388
|
+
|
|
60389
|
+
}
|
|
60390
|
+
|
|
60391
|
+
if ( arguments.length === 1 && typeof targetOrTag === 'string' ) {
|
|
60392
|
+
|
|
60393
|
+
const customTag = targetOrTag;
|
|
60394
|
+
return ( target, key, desc ) => applyProfileToMethod( customTag, desc );
|
|
60395
|
+
|
|
60396
|
+
}
|
|
60397
|
+
|
|
60398
|
+
return defaultProfileDecorator( targetOrTag, propertyKey, descriptor );
|
|
60399
|
+
|
|
60400
|
+
}
|
|
60401
|
+
|
|
60402
|
+
/**
|
|
60173
60403
|
* @param {Object} target
|
|
60174
60404
|
* @param {string|symbol} propertyKey
|
|
60175
60405
|
* @param {PropertyDescriptor} descriptor
|
|
60176
60406
|
* @return {PropertyDescriptor}
|
|
60177
60407
|
*/
|
|
60178
|
-
function
|
|
60408
|
+
function defaultProfileDecorator( target, propertyKey, descriptor ) {
|
|
60179
60409
|
|
|
60180
60410
|
const className = target.constructor?.name ?? 'Unknown';
|
|
60181
60411
|
return applyProfileToMethod( `${className}.${String( propertyKey )}`, descriptor );
|