Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRafaelGSS <rafael.nunu@hotmail.com>2022-04-10 05:37:03 +0300
committerBeth Griggs <bgriggs@redhat.com>2022-05-16 13:12:16 +0300
commitc92e291beb9dc832af5510bf7fb1e8e8a4923124 (patch)
tree4b036de25aeb0c9acd27ab17eeb4f19b4efdcd64 /lib
parent76096c2d4afac1cedd114d188ce09007b3da8282 (diff)
perf_hooks: add PerformanceResourceTiming
perf_hooks: create clearResourceTimings perf_hooks: add resourcetiming test parallel perf_hooks: add markResourceTiming perf_hooks: fix observable when using resource perf_hooks: fix observable when using resource perf_hooks: add class comments perf_hooks: add PerformanceResourceTiming perf_hooks: create clearResourceTimings perf_hooks: add resourcetiming test parallel perf_hooks: add markResourceTiming perf_hooks: fix observable when using resource perf_hooks: fix observable when using resource perf_hooks: add class comments perf_hooks: add Resource Timing documentation benchmark: measure resource timing module perf_hooks: add check avoiding new PerformanceResourceTiming perf_hooks: adjust doc PR-URL: https://github.com/nodejs/node/pull/42725 Fixes: https://github.com/nodejs/undici/issues/952 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/perf/observe.js16
-rw-r--r--lib/internal/perf/performance.js21
-rw-r--r--lib/internal/perf/resource_timing.js179
-rw-r--r--lib/perf_hooks.js2
4 files changed, 215 insertions, 3 deletions
diff --git a/lib/internal/perf/observe.js b/lib/internal/perf/observe.js
index 18fc10eb789..eedf84d1e7e 100644
--- a/lib/internal/perf/observe.js
+++ b/lib/internal/perf/observe.js
@@ -85,15 +85,18 @@ const kSupportedEntryTypes = ObjectFreeze([
'mark',
'measure',
'net',
+ 'resource',
]);
// Performance timeline entry Buffers
let markEntryBuffer = [];
let measureEntryBuffer = [];
+let resourceTimingBuffer = [];
const kMaxPerformanceEntryBuffers = 1e6;
const kClearPerformanceEntryBuffers = ObjectFreeze({
'mark': 'performance.clearMarks',
'measure': 'performance.clearMeasures',
+ 'resource': 'performance.clearResourceTimings',
});
const kWarnedEntryTypes = new SafeMap();
@@ -340,6 +343,8 @@ function enqueue(entry) {
buffer = markEntryBuffer;
} else if (entryType === 'measure') {
buffer = measureEntryBuffer;
+ } else if (entryType === 'resource') {
+ buffer = resourceTimingBuffer;
} else {
return;
}
@@ -365,16 +370,19 @@ function enqueue(entry) {
}
function clearEntriesFromBuffer(type, name) {
- if (type !== 'mark' && type !== 'measure') {
+ if (type !== 'mark' && type !== 'measure' && type !== 'resource') {
return;
}
if (type === 'mark') {
markEntryBuffer = name === undefined ?
[] : ArrayPrototypeFilter(markEntryBuffer, (entry) => entry.name !== name);
- } else {
+ } else if (type === 'measure') {
measureEntryBuffer = name === undefined ?
[] : ArrayPrototypeFilter(measureEntryBuffer, (entry) => entry.name !== name);
+ } else {
+ resourceTimingBuffer = name === undefined ?
+ [] : ArrayPrototypeFilter(resourceTimingBuffer, (entry) => entry.name !== name);
}
}
@@ -384,11 +392,13 @@ function filterBufferMapByNameAndType(name, type) {
bufferList = markEntryBuffer;
} else if (type === 'measure') {
bufferList = measureEntryBuffer;
+ } else if (type === 'resource') {
+ bufferList = resourceTimingBuffer;
} else if (type !== undefined) {
// Unrecognized type;
return [];
} else {
- bufferList = ArrayPrototypeConcat(markEntryBuffer, measureEntryBuffer);
+ bufferList = ArrayPrototypeConcat(markEntryBuffer, measureEntryBuffer, resourceTimingBuffer);
}
if (name !== undefined) {
bufferList = ArrayPrototypeFilter(bufferList, (buffer) => buffer.name === name);
diff --git a/lib/internal/perf/performance.js b/lib/internal/perf/performance.js
index 20603fa382e..5c7c008ee14 100644
--- a/lib/internal/perf/performance.js
+++ b/lib/internal/perf/performance.js
@@ -19,6 +19,8 @@ const {
const { now } = require('internal/perf/utils');
+const { markResourceTiming } = require('internal/perf/resource_timing');
+
const {
mark,
measure,
@@ -82,6 +84,13 @@ function clearMeasures(name) {
clearEntriesFromBuffer('measure', name);
}
+function clearResourceTimings(name) {
+ if (name !== undefined) {
+ name = `${name}`;
+ }
+ clearEntriesFromBuffer('resource', name);
+}
+
function getEntries() {
return filterBufferMapByNameAndType();
}
@@ -117,6 +126,11 @@ ObjectDefineProperties(Performance.prototype, {
enumerable: false,
value: clearMeasures,
},
+ clearResourceTimings: {
+ configurable: true,
+ enumerable: false,
+ value: clearResourceTimings,
+ },
eventLoopUtilization: {
configurable: true,
enumerable: false,
@@ -152,6 +166,13 @@ ObjectDefineProperties(Performance.prototype, {
enumerable: false,
value: nodeTiming,
},
+ // In the browser, this function is not public. However, it must be used inside fetch
+ // which is a Node.js dependency, not a internal module
+ markResourceTiming: {
+ configurable: true,
+ enumerable: false,
+ value: markResourceTiming,
+ },
now: {
configurable: true,
enumerable: false,
diff --git a/lib/internal/perf/resource_timing.js b/lib/internal/perf/resource_timing.js
new file mode 100644
index 00000000000..ff0728c9f0f
--- /dev/null
+++ b/lib/internal/perf/resource_timing.js
@@ -0,0 +1,179 @@
+'use strict';
+// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
+
+const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
+const { SymbolToStringTag } = primordials;
+const assert = require('internal/assert');
+const { enqueue } = require('internal/perf/observe');
+const { Symbol, ObjectSetPrototypeOf } = primordials;
+
+const kCacheMode = Symbol('kCacheMode');
+const kRequestedUrl = Symbol('kRequestedUrl');
+const kTimingInfo = Symbol('kTimingInfo');
+const kInitiatorType = Symbol('kInitiatorType');
+
+const {
+ codes: {
+ ERR_ILLEGAL_CONSTRUCTOR,
+ }
+} = require('internal/errors');
+
+class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
+ constructor(requestedUrl, initiatorType, timingInfo, cacheMode = '') {
+ super(requestedUrl, 'resource');
+ this[kInitiatorType] = initiatorType;
+ this[kRequestedUrl] = requestedUrl;
+ // https://fetch.spec.whatwg.org/#fetch-timing-info
+ // This class is using timingInfo assuming it's already validated.
+ // The spec doesn't say to validate it in the class construction.
+ this[kTimingInfo] = timingInfo;
+ this[kCacheMode] = cacheMode;
+ }
+
+ get [SymbolToStringTag]() {
+ return 'PerformanceResourceTiming';
+ }
+
+ get name() {
+ return this[kRequestedUrl];
+ }
+
+ get startTime() {
+ return this[kTimingInfo].startTime;
+ }
+
+ get duration() {
+ return this[kTimingInfo].endTime - this[kTimingInfo].startTime;
+ }
+
+ get workerStart() {
+ return this[kTimingInfo].finalServiceWorkerStartTime;
+ }
+
+ get redirectStart() {
+ return this[kTimingInfo].redirectStartTime;
+ }
+
+ get redirectEnd() {
+ return this[kTimingInfo].redirectEndTime;
+ }
+
+ get fetchStart() {
+ return this[kTimingInfo].postRedirectStartTime;
+ }
+
+ get domainLookupStart() {
+ return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupStartTime;
+ }
+
+ get domainLookupEnd() {
+ return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupEndTime;
+ }
+
+ get connectStart() {
+ return this[kTimingInfo].finalConnectionTimingInfo?.connectionStartTime;
+ }
+
+ get connectEnd() {
+ return this[kTimingInfo].finalConnectionTimingInfo?.connectionEndTime;
+ }
+
+ get secureConnectionStart() {
+ return this[kTimingInfo]
+ .finalConnectionTimingInfo?.secureConnectionStartTime;
+ }
+
+ get nextHopProtocol() {
+ return this[kTimingInfo]
+ .finalConnectionTimingInfo?.ALPNNegotiatedProtocol;
+ }
+
+ get requestStart() {
+ return this[kTimingInfo].finalNetworkRequestStartTime;
+ }
+
+ get responseStart() {
+ return this[kTimingInfo].finalNetworkResponseStartTime;
+ }
+
+ get responseEnd() {
+ return this[kTimingInfo].endTime;
+ }
+
+ get encodedBodySize() {
+ return this[kTimingInfo].encodedBodySize;
+ }
+
+ get decodedBodySize() {
+ return this[kTimingInfo].decodedBodySize;
+ }
+
+ get transferSize() {
+ if (this[kCacheMode] === 'local') return 0;
+ if (this[kCacheMode] === 'validated') return 300;
+
+ return this[kTimingInfo].encodedBodySize + 300;
+ }
+
+ toJSON() {
+ return {
+ name: this.name,
+ entryType: this.entryType,
+ startTime: this.startTime,
+ duration: this.duration,
+ initiatorType: this[kInitiatorType],
+ nextHopProtocol: this.nextHopProtocol,
+ workerStart: this.workerStart,
+ redirectStart: this.redirectStart,
+ redirectEnd: this.redirectEnd,
+ fetchStart: this.fetchStart,
+ domainLookupStart: this.domainLookupStart,
+ domainLookupEnd: this.domainLookupEnd,
+ connectStart: this.connectStart,
+ connectEnd: this.connectEnd,
+ secureConnectionStart: this.secureConnectionStart,
+ requestStart: this.requestStart,
+ responseStart: this.responseStart,
+ responseEnd: this.responseEnd,
+ transferSize: this.transferSize,
+ encodedBodySize: this.encodedBodySize,
+ decodedBodySize: this.decodedBodySize,
+ };
+ }
+}
+
+class PerformanceResourceTiming extends InternalPerformanceResourceTiming {
+ constructor() {
+ throw new ERR_ILLEGAL_CONSTRUCTOR();
+ }
+}
+
+// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
+function markResourceTiming(
+ timingInfo,
+ requestedUrl,
+ initiatorType,
+ global,
+ cacheMode,
+) {
+ // https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry
+ assert(
+ cacheMode === '' || cacheMode === 'local',
+ 'cache must be an empty string or \'local\'',
+ );
+ const resource = new InternalPerformanceResourceTiming(
+ requestedUrl,
+ initiatorType,
+ timingInfo,
+ cacheMode,
+ );
+
+ ObjectSetPrototypeOf(resource, PerformanceResourceTiming.prototype);
+ enqueue(resource);
+ return resource;
+}
+
+module.exports = {
+ PerformanceResourceTiming,
+ markResourceTiming,
+};
diff --git a/lib/perf_hooks.js b/lib/perf_hooks.js
index 74ba890f537..2456bcb7e7e 100644
--- a/lib/perf_hooks.js
+++ b/lib/perf_hooks.js
@@ -9,6 +9,7 @@ const {
} = internalBinding('performance');
const { PerformanceEntry } = require('internal/perf/performance_entry');
+const { PerformanceResourceTiming } = require('internal/perf/resource_timing');
const {
PerformanceObserver,
PerformanceObserverEntryList,
@@ -31,6 +32,7 @@ module.exports = {
PerformanceMeasure,
PerformanceObserver,
PerformanceObserverEntryList,
+ PerformanceResourceTiming,
monitorEventLoopDelay,
createHistogram,
performance: new InternalPerformance(),