11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayFrom, 51cb0ef41Sopenharmony_ci ArrayIsArray, 61cb0ef41Sopenharmony_ci ArrayPrototypeFilter, 71cb0ef41Sopenharmony_ci ArrayPrototypeIncludes, 81cb0ef41Sopenharmony_ci ArrayPrototypePush, 91cb0ef41Sopenharmony_ci ArrayPrototypePushApply, 101cb0ef41Sopenharmony_ci ArrayPrototypeSlice, 111cb0ef41Sopenharmony_ci ArrayPrototypeSort, 121cb0ef41Sopenharmony_ci Error, 131cb0ef41Sopenharmony_ci MathMax, 141cb0ef41Sopenharmony_ci MathMin, 151cb0ef41Sopenharmony_ci ObjectDefineProperties, 161cb0ef41Sopenharmony_ci ObjectFreeze, 171cb0ef41Sopenharmony_ci ObjectKeys, 181cb0ef41Sopenharmony_ci SafeMap, 191cb0ef41Sopenharmony_ci SafeSet, 201cb0ef41Sopenharmony_ci Symbol, 211cb0ef41Sopenharmony_ci} = primordials; 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ciconst { 241cb0ef41Sopenharmony_ci constants: { 251cb0ef41Sopenharmony_ci NODE_PERFORMANCE_ENTRY_TYPE_GC, 261cb0ef41Sopenharmony_ci NODE_PERFORMANCE_ENTRY_TYPE_HTTP2, 271cb0ef41Sopenharmony_ci NODE_PERFORMANCE_ENTRY_TYPE_HTTP, 281cb0ef41Sopenharmony_ci NODE_PERFORMANCE_ENTRY_TYPE_NET, 291cb0ef41Sopenharmony_ci NODE_PERFORMANCE_ENTRY_TYPE_DNS, 301cb0ef41Sopenharmony_ci }, 311cb0ef41Sopenharmony_ci installGarbageCollectionTracking, 321cb0ef41Sopenharmony_ci observerCounts, 331cb0ef41Sopenharmony_ci removeGarbageCollectionTracking, 341cb0ef41Sopenharmony_ci setupObservers, 351cb0ef41Sopenharmony_ci} = internalBinding('performance'); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciconst { 381cb0ef41Sopenharmony_ci InternalPerformanceEntry, 391cb0ef41Sopenharmony_ci isPerformanceEntry, 401cb0ef41Sopenharmony_ci} = require('internal/perf/performance_entry'); 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciconst { 431cb0ef41Sopenharmony_ci codes: { 441cb0ef41Sopenharmony_ci ERR_INVALID_ARG_VALUE, 451cb0ef41Sopenharmony_ci ERR_INVALID_ARG_TYPE, 461cb0ef41Sopenharmony_ci ERR_MISSING_ARGS, 471cb0ef41Sopenharmony_ci }, 481cb0ef41Sopenharmony_ci} = require('internal/errors'); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ciconst { 511cb0ef41Sopenharmony_ci validateFunction, 521cb0ef41Sopenharmony_ci validateObject, 531cb0ef41Sopenharmony_ci} = require('internal/validators'); 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ciconst { 561cb0ef41Sopenharmony_ci customInspectSymbol: kInspect, 571cb0ef41Sopenharmony_ci deprecate, 581cb0ef41Sopenharmony_ci lazyDOMException, 591cb0ef41Sopenharmony_ci kEmptyObject, 601cb0ef41Sopenharmony_ci} = require('internal/util'); 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ciconst { 631cb0ef41Sopenharmony_ci setImmediate, 641cb0ef41Sopenharmony_ci} = require('timers'); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ciconst { inspect } = require('util'); 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ciconst { now } = require('internal/perf/utils'); 691cb0ef41Sopenharmony_ciconst { convertToInt } = require('internal/webidl'); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ciconst kDispatch = Symbol('kDispatch'); 721cb0ef41Sopenharmony_ciconst kMaybeBuffer = Symbol('kMaybeBuffer'); 731cb0ef41Sopenharmony_ciconst kDeprecatedFields = Symbol('kDeprecatedFields'); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ciconst kDeprecationMessage = 761cb0ef41Sopenharmony_ci 'Custom PerformanceEntry accessors are deprecated. ' + 771cb0ef41Sopenharmony_ci 'Please use the detail property.'; 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ciconst kTypeSingle = 0; 801cb0ef41Sopenharmony_ciconst kTypeMultiple = 1; 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_cilet gcTrackingInstalled = false; 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciconst kSupportedEntryTypes = ObjectFreeze([ 851cb0ef41Sopenharmony_ci 'dns', 861cb0ef41Sopenharmony_ci 'function', 871cb0ef41Sopenharmony_ci 'gc', 881cb0ef41Sopenharmony_ci 'http', 891cb0ef41Sopenharmony_ci 'http2', 901cb0ef41Sopenharmony_ci 'mark', 911cb0ef41Sopenharmony_ci 'measure', 921cb0ef41Sopenharmony_ci 'net', 931cb0ef41Sopenharmony_ci 'resource', 941cb0ef41Sopenharmony_ci]); 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci// Performance timeline entry Buffers 971cb0ef41Sopenharmony_cilet markEntryBuffer = []; 981cb0ef41Sopenharmony_cilet measureEntryBuffer = []; 991cb0ef41Sopenharmony_cilet resourceTimingBuffer = []; 1001cb0ef41Sopenharmony_cilet resourceTimingSecondaryBuffer = []; 1011cb0ef41Sopenharmony_ciconst kPerformanceEntryBufferWarnSize = 1e6; 1021cb0ef41Sopenharmony_ci// https://www.w3.org/TR/timing-entrytypes-registry/#registry 1031cb0ef41Sopenharmony_ci// Default buffer limit for resource timing entries. 1041cb0ef41Sopenharmony_cilet resourceTimingBufferSizeLimit = 250; 1051cb0ef41Sopenharmony_cilet dispatchBufferFull; 1061cb0ef41Sopenharmony_cilet resourceTimingBufferFullPending = false; 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ciconst kClearPerformanceEntryBuffers = ObjectFreeze({ 1091cb0ef41Sopenharmony_ci 'mark': 'performance.clearMarks', 1101cb0ef41Sopenharmony_ci 'measure': 'performance.clearMeasures', 1111cb0ef41Sopenharmony_ci}); 1121cb0ef41Sopenharmony_ciconst kWarnedEntryTypes = new SafeMap(); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ciconst kObservers = new SafeSet(); 1151cb0ef41Sopenharmony_ciconst kPending = new SafeSet(); 1161cb0ef41Sopenharmony_cilet isPending = false; 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_cifunction queuePending() { 1191cb0ef41Sopenharmony_ci if (isPending) return; 1201cb0ef41Sopenharmony_ci isPending = true; 1211cb0ef41Sopenharmony_ci setImmediate(() => { 1221cb0ef41Sopenharmony_ci isPending = false; 1231cb0ef41Sopenharmony_ci const pendings = ArrayFrom(kPending.values()); 1241cb0ef41Sopenharmony_ci kPending.clear(); 1251cb0ef41Sopenharmony_ci for (const pending of pendings) 1261cb0ef41Sopenharmony_ci pending[kDispatch](); 1271cb0ef41Sopenharmony_ci }); 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cifunction getObserverType(type) { 1311cb0ef41Sopenharmony_ci switch (type) { 1321cb0ef41Sopenharmony_ci case 'gc': return NODE_PERFORMANCE_ENTRY_TYPE_GC; 1331cb0ef41Sopenharmony_ci case 'http2': return NODE_PERFORMANCE_ENTRY_TYPE_HTTP2; 1341cb0ef41Sopenharmony_ci case 'http': return NODE_PERFORMANCE_ENTRY_TYPE_HTTP; 1351cb0ef41Sopenharmony_ci case 'net': return NODE_PERFORMANCE_ENTRY_TYPE_NET; 1361cb0ef41Sopenharmony_ci case 'dns': return NODE_PERFORMANCE_ENTRY_TYPE_DNS; 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci} 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_cifunction maybeDecrementObserverCounts(entryTypes) { 1411cb0ef41Sopenharmony_ci for (const type of entryTypes) { 1421cb0ef41Sopenharmony_ci const observerType = getObserverType(type); 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci if (observerType !== undefined) { 1451cb0ef41Sopenharmony_ci observerCounts[observerType]--; 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci if (observerType === NODE_PERFORMANCE_ENTRY_TYPE_GC && 1481cb0ef41Sopenharmony_ci observerCounts[observerType] === 0) { 1491cb0ef41Sopenharmony_ci removeGarbageCollectionTracking(); 1501cb0ef41Sopenharmony_ci gcTrackingInstalled = false; 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_cifunction maybeIncrementObserverCount(type) { 1571cb0ef41Sopenharmony_ci const observerType = getObserverType(type); 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci if (observerType !== undefined) { 1601cb0ef41Sopenharmony_ci observerCounts[observerType]++; 1611cb0ef41Sopenharmony_ci if (!gcTrackingInstalled && 1621cb0ef41Sopenharmony_ci observerType === NODE_PERFORMANCE_ENTRY_TYPE_GC) { 1631cb0ef41Sopenharmony_ci installGarbageCollectionTracking(); 1641cb0ef41Sopenharmony_ci gcTrackingInstalled = true; 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ciclass PerformanceObserverEntryList { 1701cb0ef41Sopenharmony_ci #buffer = []; 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci constructor(entries) { 1731cb0ef41Sopenharmony_ci this.#buffer = ArrayPrototypeSort(entries, (first, second) => { 1741cb0ef41Sopenharmony_ci return first.startTime - second.startTime; 1751cb0ef41Sopenharmony_ci }); 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci getEntries() { 1791cb0ef41Sopenharmony_ci return ArrayPrototypeSlice(this.#buffer); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci getEntriesByType(type) { 1831cb0ef41Sopenharmony_ci type = `${type}`; 1841cb0ef41Sopenharmony_ci return ArrayPrototypeFilter( 1851cb0ef41Sopenharmony_ci this.#buffer, 1861cb0ef41Sopenharmony_ci (entry) => entry.entryType === type); 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci getEntriesByName(name, type) { 1901cb0ef41Sopenharmony_ci name = `${name}`; 1911cb0ef41Sopenharmony_ci if (type != null /** not nullish */) { 1921cb0ef41Sopenharmony_ci return ArrayPrototypeFilter( 1931cb0ef41Sopenharmony_ci this.#buffer, 1941cb0ef41Sopenharmony_ci (entry) => entry.name === name && entry.entryType === type); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci return ArrayPrototypeFilter( 1971cb0ef41Sopenharmony_ci this.#buffer, 1981cb0ef41Sopenharmony_ci (entry) => entry.name === name); 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci [kInspect](depth, options) { 2021cb0ef41Sopenharmony_ci if (depth < 0) return this; 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci const opts = { 2051cb0ef41Sopenharmony_ci ...options, 2061cb0ef41Sopenharmony_ci depth: options.depth == null ? null : options.depth - 1, 2071cb0ef41Sopenharmony_ci }; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci return `PerformanceObserverEntryList ${inspect(this.#buffer, opts)}`; 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci} 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ciclass PerformanceObserver { 2141cb0ef41Sopenharmony_ci #buffer = []; 2151cb0ef41Sopenharmony_ci #entryTypes = new SafeSet(); 2161cb0ef41Sopenharmony_ci #type; 2171cb0ef41Sopenharmony_ci #callback; 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci constructor(callback) { 2201cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 2211cb0ef41Sopenharmony_ci this.#callback = callback; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci observe(options = kEmptyObject) { 2251cb0ef41Sopenharmony_ci validateObject(options, 'options'); 2261cb0ef41Sopenharmony_ci const { 2271cb0ef41Sopenharmony_ci entryTypes, 2281cb0ef41Sopenharmony_ci type, 2291cb0ef41Sopenharmony_ci buffered, 2301cb0ef41Sopenharmony_ci } = { ...options }; 2311cb0ef41Sopenharmony_ci if (entryTypes === undefined && type === undefined) 2321cb0ef41Sopenharmony_ci throw new ERR_MISSING_ARGS('options.entryTypes', 'options.type'); 2331cb0ef41Sopenharmony_ci if (entryTypes != null && type != null) 2341cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE('options.entryTypes', 2351cb0ef41Sopenharmony_ci entryTypes, 2361cb0ef41Sopenharmony_ci 'options.entryTypes can not set with ' + 2371cb0ef41Sopenharmony_ci 'options.type together'); 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci switch (this.#type) { 2401cb0ef41Sopenharmony_ci case undefined: 2411cb0ef41Sopenharmony_ci if (entryTypes !== undefined) this.#type = kTypeMultiple; 2421cb0ef41Sopenharmony_ci if (type !== undefined) this.#type = kTypeSingle; 2431cb0ef41Sopenharmony_ci break; 2441cb0ef41Sopenharmony_ci case kTypeSingle: 2451cb0ef41Sopenharmony_ci if (entryTypes !== undefined) 2461cb0ef41Sopenharmony_ci throw lazyDOMException( 2471cb0ef41Sopenharmony_ci 'PerformanceObserver can not change to multiple observations', 2481cb0ef41Sopenharmony_ci 'InvalidModificationError'); 2491cb0ef41Sopenharmony_ci break; 2501cb0ef41Sopenharmony_ci case kTypeMultiple: 2511cb0ef41Sopenharmony_ci if (type !== undefined) 2521cb0ef41Sopenharmony_ci throw lazyDOMException( 2531cb0ef41Sopenharmony_ci 'PerformanceObserver can not change to single observation', 2541cb0ef41Sopenharmony_ci 'InvalidModificationError'); 2551cb0ef41Sopenharmony_ci break; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci if (this.#type === kTypeMultiple) { 2591cb0ef41Sopenharmony_ci if (!ArrayIsArray(entryTypes)) { 2601cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 2611cb0ef41Sopenharmony_ci 'options.entryTypes', 2621cb0ef41Sopenharmony_ci 'string[]', 2631cb0ef41Sopenharmony_ci entryTypes); 2641cb0ef41Sopenharmony_ci } 2651cb0ef41Sopenharmony_ci maybeDecrementObserverCounts(this.#entryTypes); 2661cb0ef41Sopenharmony_ci this.#entryTypes.clear(); 2671cb0ef41Sopenharmony_ci for (let n = 0; n < entryTypes.length; n++) { 2681cb0ef41Sopenharmony_ci if (ArrayPrototypeIncludes(kSupportedEntryTypes, entryTypes[n])) { 2691cb0ef41Sopenharmony_ci this.#entryTypes.add(entryTypes[n]); 2701cb0ef41Sopenharmony_ci maybeIncrementObserverCount(entryTypes[n]); 2711cb0ef41Sopenharmony_ci } 2721cb0ef41Sopenharmony_ci } 2731cb0ef41Sopenharmony_ci } else { 2741cb0ef41Sopenharmony_ci if (!ArrayPrototypeIncludes(kSupportedEntryTypes, type)) 2751cb0ef41Sopenharmony_ci return; 2761cb0ef41Sopenharmony_ci this.#entryTypes.add(type); 2771cb0ef41Sopenharmony_ci maybeIncrementObserverCount(type); 2781cb0ef41Sopenharmony_ci if (buffered) { 2791cb0ef41Sopenharmony_ci const entries = filterBufferMapByNameAndType(undefined, type); 2801cb0ef41Sopenharmony_ci ArrayPrototypePushApply(this.#buffer, entries); 2811cb0ef41Sopenharmony_ci kPending.add(this); 2821cb0ef41Sopenharmony_ci if (kPending.size) 2831cb0ef41Sopenharmony_ci queuePending(); 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci if (this.#entryTypes.size) 2881cb0ef41Sopenharmony_ci kObservers.add(this); 2891cb0ef41Sopenharmony_ci else 2901cb0ef41Sopenharmony_ci this.disconnect(); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci disconnect() { 2941cb0ef41Sopenharmony_ci maybeDecrementObserverCounts(this.#entryTypes); 2951cb0ef41Sopenharmony_ci kObservers.delete(this); 2961cb0ef41Sopenharmony_ci kPending.delete(this); 2971cb0ef41Sopenharmony_ci this.#buffer = []; 2981cb0ef41Sopenharmony_ci this.#entryTypes.clear(); 2991cb0ef41Sopenharmony_ci this.#type = undefined; 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci takeRecords() { 3031cb0ef41Sopenharmony_ci const list = this.#buffer; 3041cb0ef41Sopenharmony_ci this.#buffer = []; 3051cb0ef41Sopenharmony_ci return list; 3061cb0ef41Sopenharmony_ci } 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci static get supportedEntryTypes() { 3091cb0ef41Sopenharmony_ci return kSupportedEntryTypes; 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci [kMaybeBuffer](entry) { 3131cb0ef41Sopenharmony_ci if (!this.#entryTypes.has(entry.entryType)) 3141cb0ef41Sopenharmony_ci return; 3151cb0ef41Sopenharmony_ci ArrayPrototypePush(this.#buffer, entry); 3161cb0ef41Sopenharmony_ci kPending.add(this); 3171cb0ef41Sopenharmony_ci if (kPending.size) 3181cb0ef41Sopenharmony_ci queuePending(); 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci [kDispatch]() { 3221cb0ef41Sopenharmony_ci this.#callback(new PerformanceObserverEntryList(this.takeRecords()), 3231cb0ef41Sopenharmony_ci this); 3241cb0ef41Sopenharmony_ci } 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci [kInspect](depth, options) { 3271cb0ef41Sopenharmony_ci if (depth < 0) return this; 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci const opts = { 3301cb0ef41Sopenharmony_ci ...options, 3311cb0ef41Sopenharmony_ci depth: options.depth == null ? null : options.depth - 1, 3321cb0ef41Sopenharmony_ci }; 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci return `PerformanceObserver ${inspect({ 3351cb0ef41Sopenharmony_ci connected: kObservers.has(this), 3361cb0ef41Sopenharmony_ci pending: kPending.has(this), 3371cb0ef41Sopenharmony_ci entryTypes: ArrayFrom(this.#entryTypes), 3381cb0ef41Sopenharmony_ci buffer: this.#buffer, 3391cb0ef41Sopenharmony_ci }, opts)}`; 3401cb0ef41Sopenharmony_ci } 3411cb0ef41Sopenharmony_ci} 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci/** 3441cb0ef41Sopenharmony_ci * https://www.w3.org/TR/performance-timeline/#dfn-queue-a-performanceentry 3451cb0ef41Sopenharmony_ci * 3461cb0ef41Sopenharmony_ci * Add the performance entry to the interested performance observer's queue. 3471cb0ef41Sopenharmony_ci */ 3481cb0ef41Sopenharmony_cifunction enqueue(entry) { 3491cb0ef41Sopenharmony_ci if (!isPerformanceEntry(entry)) 3501cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('entry', 'PerformanceEntry', entry); 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci for (const obs of kObservers) { 3531cb0ef41Sopenharmony_ci obs[kMaybeBuffer](entry); 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci} 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci/** 3581cb0ef41Sopenharmony_ci * Add the user timing entry to the global buffer. 3591cb0ef41Sopenharmony_ci */ 3601cb0ef41Sopenharmony_cifunction bufferUserTiming(entry) { 3611cb0ef41Sopenharmony_ci const entryType = entry.entryType; 3621cb0ef41Sopenharmony_ci let buffer; 3631cb0ef41Sopenharmony_ci if (entryType === 'mark') { 3641cb0ef41Sopenharmony_ci buffer = markEntryBuffer; 3651cb0ef41Sopenharmony_ci } else if (entryType === 'measure') { 3661cb0ef41Sopenharmony_ci buffer = measureEntryBuffer; 3671cb0ef41Sopenharmony_ci } else { 3681cb0ef41Sopenharmony_ci return; 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ci ArrayPrototypePush(buffer, entry); 3721cb0ef41Sopenharmony_ci const count = buffer.length; 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci if (count > kPerformanceEntryBufferWarnSize && 3751cb0ef41Sopenharmony_ci !kWarnedEntryTypes.has(entryType)) { 3761cb0ef41Sopenharmony_ci kWarnedEntryTypes.set(entryType, true); 3771cb0ef41Sopenharmony_ci // No error code for this since it is a Warning 3781cb0ef41Sopenharmony_ci // eslint-disable-next-line no-restricted-syntax 3791cb0ef41Sopenharmony_ci const w = new Error('Possible perf_hooks memory leak detected. ' + 3801cb0ef41Sopenharmony_ci `${count} ${entryType} entries added to the global ` + 3811cb0ef41Sopenharmony_ci 'performance entry buffer. Use ' + 3821cb0ef41Sopenharmony_ci `${kClearPerformanceEntryBuffers[entryType]} to ` + 3831cb0ef41Sopenharmony_ci 'clear the buffer.'); 3841cb0ef41Sopenharmony_ci w.name = 'MaxPerformanceEntryBufferExceededWarning'; 3851cb0ef41Sopenharmony_ci w.entryType = entryType; 3861cb0ef41Sopenharmony_ci w.count = count; 3871cb0ef41Sopenharmony_ci process.emitWarning(w); 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci} 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci/** 3921cb0ef41Sopenharmony_ci * Add the resource timing entry to the global buffer if the buffer size is not 3931cb0ef41Sopenharmony_ci * exceeding the buffer limit, or dispatch a buffer full event on the global 3941cb0ef41Sopenharmony_ci * performance object. 3951cb0ef41Sopenharmony_ci * 3961cb0ef41Sopenharmony_ci * See also https://www.w3.org/TR/resource-timing-2/#dfn-add-a-performanceresourcetiming-entry 3971cb0ef41Sopenharmony_ci */ 3981cb0ef41Sopenharmony_cifunction bufferResourceTiming(entry) { 3991cb0ef41Sopenharmony_ci if (resourceTimingBuffer.length < resourceTimingBufferSizeLimit && !resourceTimingBufferFullPending) { 4001cb0ef41Sopenharmony_ci ArrayPrototypePush(resourceTimingBuffer, entry); 4011cb0ef41Sopenharmony_ci return; 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci if (!resourceTimingBufferFullPending) { 4051cb0ef41Sopenharmony_ci resourceTimingBufferFullPending = true; 4061cb0ef41Sopenharmony_ci setImmediate(() => { 4071cb0ef41Sopenharmony_ci while (resourceTimingSecondaryBuffer.length > 0) { 4081cb0ef41Sopenharmony_ci const excessNumberBefore = resourceTimingSecondaryBuffer.length; 4091cb0ef41Sopenharmony_ci dispatchBufferFull('resourcetimingbufferfull'); 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci // Calculate the number of items to be pushed to the global buffer. 4121cb0ef41Sopenharmony_ci const numbersToPreserve = MathMax( 4131cb0ef41Sopenharmony_ci MathMin(resourceTimingBufferSizeLimit - resourceTimingBuffer.length, resourceTimingSecondaryBuffer.length), 4141cb0ef41Sopenharmony_ci 0, 4151cb0ef41Sopenharmony_ci ); 4161cb0ef41Sopenharmony_ci const excessNumberAfter = resourceTimingSecondaryBuffer.length - numbersToPreserve; 4171cb0ef41Sopenharmony_ci for (let idx = 0; idx < numbersToPreserve; idx++) { 4181cb0ef41Sopenharmony_ci ArrayPrototypePush(resourceTimingBuffer, resourceTimingSecondaryBuffer[idx]); 4191cb0ef41Sopenharmony_ci } 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci if (excessNumberBefore <= excessNumberAfter) { 4221cb0ef41Sopenharmony_ci resourceTimingSecondaryBuffer = []; 4231cb0ef41Sopenharmony_ci } 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci resourceTimingBufferFullPending = false; 4261cb0ef41Sopenharmony_ci }); 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci ArrayPrototypePush(resourceTimingSecondaryBuffer, entry); 4301cb0ef41Sopenharmony_ci} 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci// https://w3c.github.io/resource-timing/#dom-performance-setresourcetimingbuffersize 4331cb0ef41Sopenharmony_cifunction setResourceTimingBufferSize(maxSize) { 4341cb0ef41Sopenharmony_ci // unsigned long 4351cb0ef41Sopenharmony_ci maxSize = convertToInt('maxSize', maxSize, 32); 4361cb0ef41Sopenharmony_ci // If the maxSize parameter is less than resource timing buffer current 4371cb0ef41Sopenharmony_ci // size, no PerformanceResourceTiming objects are to be removed from the 4381cb0ef41Sopenharmony_ci // performance entry buffer. 4391cb0ef41Sopenharmony_ci resourceTimingBufferSizeLimit = maxSize; 4401cb0ef41Sopenharmony_ci} 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_cifunction setDispatchBufferFull(fn) { 4431cb0ef41Sopenharmony_ci dispatchBufferFull = fn; 4441cb0ef41Sopenharmony_ci} 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_cifunction clearEntriesFromBuffer(type, name) { 4471cb0ef41Sopenharmony_ci if (type !== 'mark' && type !== 'measure' && type !== 'resource') { 4481cb0ef41Sopenharmony_ci return; 4491cb0ef41Sopenharmony_ci } 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_ci if (type === 'mark') { 4521cb0ef41Sopenharmony_ci markEntryBuffer = name === undefined ? 4531cb0ef41Sopenharmony_ci [] : ArrayPrototypeFilter(markEntryBuffer, (entry) => entry.name !== name); 4541cb0ef41Sopenharmony_ci } else if (type === 'measure') { 4551cb0ef41Sopenharmony_ci measureEntryBuffer = name === undefined ? 4561cb0ef41Sopenharmony_ci [] : ArrayPrototypeFilter(measureEntryBuffer, (entry) => entry.name !== name); 4571cb0ef41Sopenharmony_ci } else { 4581cb0ef41Sopenharmony_ci resourceTimingBuffer = name === undefined ? 4591cb0ef41Sopenharmony_ci [] : ArrayPrototypeFilter(resourceTimingBuffer, (entry) => entry.name !== name); 4601cb0ef41Sopenharmony_ci } 4611cb0ef41Sopenharmony_ci} 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_cifunction filterBufferMapByNameAndType(name, type) { 4641cb0ef41Sopenharmony_ci let bufferList; 4651cb0ef41Sopenharmony_ci if (type === 'mark') { 4661cb0ef41Sopenharmony_ci bufferList = markEntryBuffer; 4671cb0ef41Sopenharmony_ci } else if (type === 'measure') { 4681cb0ef41Sopenharmony_ci bufferList = measureEntryBuffer; 4691cb0ef41Sopenharmony_ci } else if (type === 'resource') { 4701cb0ef41Sopenharmony_ci bufferList = resourceTimingBuffer; 4711cb0ef41Sopenharmony_ci } else if (type !== undefined) { 4721cb0ef41Sopenharmony_ci // Unrecognized type; 4731cb0ef41Sopenharmony_ci return []; 4741cb0ef41Sopenharmony_ci } else { 4751cb0ef41Sopenharmony_ci bufferList = []; 4761cb0ef41Sopenharmony_ci ArrayPrototypePushApply(bufferList, markEntryBuffer); 4771cb0ef41Sopenharmony_ci ArrayPrototypePushApply(bufferList, measureEntryBuffer); 4781cb0ef41Sopenharmony_ci ArrayPrototypePushApply(bufferList, resourceTimingBuffer); 4791cb0ef41Sopenharmony_ci } 4801cb0ef41Sopenharmony_ci if (name !== undefined) { 4811cb0ef41Sopenharmony_ci bufferList = ArrayPrototypeFilter(bufferList, (buffer) => buffer.name === name); 4821cb0ef41Sopenharmony_ci } else if (type !== undefined) { 4831cb0ef41Sopenharmony_ci bufferList = ArrayPrototypeSlice(bufferList); 4841cb0ef41Sopenharmony_ci } 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci return ArrayPrototypeSort(bufferList, (first, second) => { 4871cb0ef41Sopenharmony_ci return first.startTime - second.startTime; 4881cb0ef41Sopenharmony_ci }); 4891cb0ef41Sopenharmony_ci} 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_cifunction observerCallback(name, type, startTime, duration, details) { 4921cb0ef41Sopenharmony_ci const entry = 4931cb0ef41Sopenharmony_ci new InternalPerformanceEntry( 4941cb0ef41Sopenharmony_ci name, 4951cb0ef41Sopenharmony_ci type, 4961cb0ef41Sopenharmony_ci startTime, 4971cb0ef41Sopenharmony_ci duration, 4981cb0ef41Sopenharmony_ci details); 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci if (details !== undefined) { 5011cb0ef41Sopenharmony_ci // GC, HTTP2, and HTTP PerformanceEntry used additional 5021cb0ef41Sopenharmony_ci // properties directly off the entry. Those have been 5031cb0ef41Sopenharmony_ci // moved into the details property. The existing accessors 5041cb0ef41Sopenharmony_ci // are still included but are deprecated. 5051cb0ef41Sopenharmony_ci entry[kDeprecatedFields] = new SafeMap(); 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci const detailKeys = ObjectKeys(details); 5081cb0ef41Sopenharmony_ci const props = {}; 5091cb0ef41Sopenharmony_ci for (let n = 0; n < detailKeys.length; n++) { 5101cb0ef41Sopenharmony_ci const key = detailKeys[n]; 5111cb0ef41Sopenharmony_ci entry[kDeprecatedFields].set(key, details[key]); 5121cb0ef41Sopenharmony_ci props[key] = { 5131cb0ef41Sopenharmony_ci configurable: true, 5141cb0ef41Sopenharmony_ci enumerable: true, 5151cb0ef41Sopenharmony_ci get: deprecate(() => { 5161cb0ef41Sopenharmony_ci return entry[kDeprecatedFields].get(key); 5171cb0ef41Sopenharmony_ci }, kDeprecationMessage, 'DEP0152'), 5181cb0ef41Sopenharmony_ci set: deprecate((value) => { 5191cb0ef41Sopenharmony_ci entry[kDeprecatedFields].set(key, value); 5201cb0ef41Sopenharmony_ci }, kDeprecationMessage, 'DEP0152'), 5211cb0ef41Sopenharmony_ci }; 5221cb0ef41Sopenharmony_ci } 5231cb0ef41Sopenharmony_ci ObjectDefineProperties(entry, props); 5241cb0ef41Sopenharmony_ci } 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci enqueue(entry); 5271cb0ef41Sopenharmony_ci} 5281cb0ef41Sopenharmony_ci 5291cb0ef41Sopenharmony_cisetupObservers(observerCallback); 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_cifunction hasObserver(type) { 5321cb0ef41Sopenharmony_ci const observerType = getObserverType(type); 5331cb0ef41Sopenharmony_ci return observerCounts[observerType] > 0; 5341cb0ef41Sopenharmony_ci} 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_cifunction startPerf(target, key, context = {}) { 5381cb0ef41Sopenharmony_ci target[key] = { 5391cb0ef41Sopenharmony_ci ...context, 5401cb0ef41Sopenharmony_ci startTime: now(), 5411cb0ef41Sopenharmony_ci }; 5421cb0ef41Sopenharmony_ci} 5431cb0ef41Sopenharmony_ci 5441cb0ef41Sopenharmony_cifunction stopPerf(target, key, context = {}) { 5451cb0ef41Sopenharmony_ci const ctx = target[key]; 5461cb0ef41Sopenharmony_ci if (!ctx) { 5471cb0ef41Sopenharmony_ci return; 5481cb0ef41Sopenharmony_ci } 5491cb0ef41Sopenharmony_ci const startTime = ctx.startTime; 5501cb0ef41Sopenharmony_ci const entry = new InternalPerformanceEntry( 5511cb0ef41Sopenharmony_ci ctx.name, 5521cb0ef41Sopenharmony_ci ctx.type, 5531cb0ef41Sopenharmony_ci startTime, 5541cb0ef41Sopenharmony_ci now() - startTime, 5551cb0ef41Sopenharmony_ci { ...ctx.detail, ...context.detail }, 5561cb0ef41Sopenharmony_ci ); 5571cb0ef41Sopenharmony_ci enqueue(entry); 5581cb0ef41Sopenharmony_ci} 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_cimodule.exports = { 5611cb0ef41Sopenharmony_ci PerformanceObserver, 5621cb0ef41Sopenharmony_ci PerformanceObserverEntryList, 5631cb0ef41Sopenharmony_ci enqueue, 5641cb0ef41Sopenharmony_ci hasObserver, 5651cb0ef41Sopenharmony_ci clearEntriesFromBuffer, 5661cb0ef41Sopenharmony_ci filterBufferMapByNameAndType, 5671cb0ef41Sopenharmony_ci startPerf, 5681cb0ef41Sopenharmony_ci stopPerf, 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci bufferUserTiming, 5711cb0ef41Sopenharmony_ci bufferResourceTiming, 5721cb0ef41Sopenharmony_ci setResourceTimingBufferSize, 5731cb0ef41Sopenharmony_ci setDispatchBufferFull, 5741cb0ef41Sopenharmony_ci}; 575