From b37575b67c28bb0f1936c6b2ad2b0ed84eca6d68 Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 26 Jul 2021 23:16:00 +0800 Subject: [PATCH] perf_hooks: fix performance timeline wpt failures PR-URL: https://github.com/nodejs/node/pull/39532 Reviewed-By: James M Snell Reviewed-By: Khaidi Chu --- lib/internal/perf/observe.js | 37 ++++++++++++++++++----- lib/perf_hooks.js | 6 +++- test/wpt/status/performance-timeline.json | 12 +++++++- test/wpt/test-performance-timeline.js | 4 ++- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/lib/internal/perf/observe.js b/lib/internal/perf/observe.js index af09d33c5405f3..67a37175a179b3 100644 --- a/lib/internal/perf/observe.js +++ b/lib/internal/perf/observe.js @@ -53,6 +53,7 @@ const { const { customInspectSymbol: kInspect, deprecate, + lazyDOMException, } = require('internal/util'); const { @@ -106,9 +107,10 @@ function queuePending() { isPending = true; setImmediate(() => { isPending = false; - for (const pending of kPending) - pending[kDispatch](); + const pendings = ArrayFrom(kPending.values()); kPending.clear(); + for (const pending of pendings) + pending[kDispatch](); }); } @@ -168,8 +170,13 @@ class PerformanceObserverEntryList { (entry) => entry.entryType === type); } - getEntriesByName(name) { + getEntriesByName(name, type) { name = `${name}`; + if (type != null /** not nullish */) { + return ArrayPrototypeFilter( + this[kBuffer], + (entry) => entry.name === name && entry.entryType === type); + } return ArrayPrototypeFilter( this[kBuffer], (entry) => entry.name === name); @@ -208,6 +215,11 @@ class PerformanceObserver { } = { ...options }; if (entryTypes === undefined && type === undefined) throw new ERR_MISSING_ARGS('options.entryTypes', 'options.type'); + if (entryTypes != null && type != null) + throw new ERR_INVALID_ARG_VALUE('options.entryTypes', + entryTypes, + 'options.entryTypes can not set with ' + + 'options.type together'); switch (this[kType]) { case undefined: @@ -216,11 +228,15 @@ class PerformanceObserver { break; case kTypeSingle: if (entryTypes !== undefined) - throw new ERR_INVALID_ARG_VALUE('options.entryTypes', entryTypes); + throw lazyDOMException( + 'PerformanceObserver can not change to multiple observations', + 'InvalidModificationError'); break; case kTypeMultiple: if (type !== undefined) - throw new ERR_INVALID_ARG_VALUE('options.type', type); + throw lazyDOMException( + 'PerformanceObserver can not change to single observation', + 'InvalidModificationError'); break; } @@ -271,7 +287,7 @@ class PerformanceObserver { takeRecords() { const list = this[kBuffer]; this[kBuffer] = []; - return new PerformanceObserverEntryList(list); + return list; } static get supportedEntryTypes() { @@ -287,7 +303,10 @@ class PerformanceObserver { queuePending(); } - [kDispatch]() { this[kCallback](this.takeRecords(), this); } + [kDispatch]() { + this[kCallback](new PerformanceObserverEntryList(this.takeRecords()), + this); + } [kInspect](depth, options) { if (depth < 0) return this; @@ -367,6 +386,7 @@ function clearEntriesFromBuffer(type, name) { let head = null; let tail = null; + let count = 0; for (let entry = buffer.head; entry !== null; entry = entry[kBufferNext]) { if (entry.name !== name) { head = head ?? entry; @@ -377,9 +397,11 @@ function clearEntriesFromBuffer(type, name) { continue; } tail[kBufferNext] = entry[kBufferNext]; + count++; } buffer.head = head; buffer.tail = tail; + buffer.count = count; } function filterBufferMapByNameAndType(name, type) { @@ -469,6 +491,7 @@ function resetBuffer(buffer) { module.exports = { PerformanceObserver, + PerformanceObserverEntryList, enqueue, hasObserver, clearEntriesFromBuffer, diff --git a/lib/perf_hooks.js b/lib/perf_hooks.js index 9916fd5ce40c35..74ba890f537bc2 100644 --- a/lib/perf_hooks.js +++ b/lib/perf_hooks.js @@ -9,7 +9,10 @@ const { } = internalBinding('performance'); const { PerformanceEntry } = require('internal/perf/performance_entry'); -const { PerformanceObserver } = require('internal/perf/observe'); +const { + PerformanceObserver, + PerformanceObserverEntryList, +} = require('internal/perf/observe'); const { PerformanceMark, PerformanceMeasure, @@ -27,6 +30,7 @@ module.exports = { PerformanceMark, PerformanceMeasure, PerformanceObserver, + PerformanceObserverEntryList, monitorEventLoopDelay, createHistogram, performance: new InternalPerformance(), diff --git a/test/wpt/status/performance-timeline.json b/test/wpt/status/performance-timeline.json index 0967ef424bce67..6c845c681ae44d 100644 --- a/test/wpt/status/performance-timeline.json +++ b/test/wpt/status/performance-timeline.json @@ -1 +1,11 @@ -{} +{ + "case-sensitivity.any.js": { + "fail": "resource entry type not supported" + }, + "idlharness.any.js": { + "skip": "idlharness cannot recognize Node.js environment" + }, + "webtiming-resolution.any.js": { + "skip": "flaky" + } +} diff --git a/test/wpt/test-performance-timeline.js b/test/wpt/test-performance-timeline.js index 36d13297ba57cc..12f1abd3a52a32 100644 --- a/test/wpt/test-performance-timeline.js +++ b/test/wpt/test-performance-timeline.js @@ -2,7 +2,7 @@ require('../common'); const { WPTRunner } = require('../common/wpt'); -const runner = new WPTRunner('user-timing'); +const runner = new WPTRunner('performance-timeline'); // Needed to access to DOMException. runner.setFlags(['--expose-internals']); @@ -12,11 +12,13 @@ runner.setInitScript(` PerformanceMark, PerformanceMeasure, PerformanceObserver, + PerformanceObserverEntryList, performance, } = require('perf_hooks'); global.PerformanceMark = performance; global.PerformanceMeasure = performance; global.PerformanceObserver = PerformanceObserver; + global.PerformanceObserverEntryList = PerformanceObserverEntryList; global.performance = performance; const { internalBinding } = require('internal/test/binding');