summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/perf_hooks.md106
-rw-r--r--lib/perf_hooks.js101
-rw-r--r--src/node_perf.cc14
-rw-r--r--test/parallel/test-http2-perf_hooks.js10
-rw-r--r--test/parallel/test-performance-function.js10
-rw-r--r--test/parallel/test-performance-gc.js13
-rw-r--r--test/parallel/test-performance-warning.js29
-rw-r--r--test/parallel/test-performanceobserver.js16
-rw-r--r--test/sequential/test-performance.js59
9 files changed, 38 insertions, 320 deletions
diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md
index 0a81874adb..3e05ba285f 100644
--- a/doc/api/perf_hooks.md
+++ b/doc/api/perf_hooks.md
@@ -10,14 +10,18 @@ is to support collection of high resolution performance metrics.
This is the same Performance API as implemented in modern Web browsers.
```js
-const { performance } = require('perf_hooks');
+const { PerformanceObserver, performance } = require('perf_hooks');
+
+const obs = new PerformanceObserver((items) => {
+ console.log(items.getEntries()[0].duration);
+ performance.clearMarks();
+});
+obs.observe({ entryTypes: ['measure'] });
+
performance.mark('A');
doSomeLongRunningProcess(() => {
performance.mark('B');
performance.measure('A to B', 'A', 'B');
- const measure = performance.getEntriesByName('A to B')[0];
- console.log(measure.duration);
- // Prints the number of milliseconds between Mark 'A' and Mark 'B'
});
```
@@ -26,35 +30,6 @@ doSomeLongRunningProcess(() => {
added: v8.5.0
-->
-The `Performance` provides access to performance metric data. A single
-instance of this class is provided via the `performance` property.
-
-### performance.clearEntries(name)
-<!-- YAML
-added: v9.5.0
--->
-
-Remove all performance entry objects with `entryType` equal to `name` from the
-Performance Timeline.
-
-### performance.clearFunctions([name])
-<!-- YAML
-added: v8.5.0
--->
-
-* `name` {string}
-
-If `name` is not provided, removes all `PerformanceFunction` objects from the
-Performance Timeline. If `name` is provided, removes entries with `name`.
-
-### performance.clearGC()
-<!-- YAML
-added: v8.5.0
--->
-
-Remove all performance entry objects with `entryType` equal to `gc` from the
-Performance Timeline.
-
### performance.clearMarks([name])
<!-- YAML
added: v8.5.0
@@ -65,53 +40,6 @@ added: v8.5.0
If `name` is not provided, removes all `PerformanceMark` objects from the
Performance Timeline. If `name` is provided, removes only the named mark.
-### performance.clearMeasures([name])
-<!-- YAML
-added: v8.5.0
--->
-
-* `name` {string}
-
-If `name` is not provided, removes all `PerformanceMeasure` objects from the
-Performance Timeline. If `name` is provided, removes only objects whose
-`performanceEntry.name` matches `name`.
-
-### performance.getEntries()
-<!-- YAML
-added: v8.5.0
--->
-
-* Returns: {Array}
-
-Returns a list of all `PerformanceEntry` objects in chronological order
-with respect to `performanceEntry.startTime`.
-
-### performance.getEntriesByName(name[, type])
-<!-- YAML
-added: v8.5.0
--->
-
-* `name` {string}
-* `type` {string}
-* Returns: {Array}
-
-Returns a list of all `PerformanceEntry` objects in chronological order
-with respect to `performanceEntry.startTime` whose `performanceEntry.name` is
-equal to `name`, and optionally, whose `performanceEntry.entryType` is equal to
-`type`.
-
-### performance.getEntriesByType(type)
-<!-- YAML
-added: v8.5.0
--->
-
-* `type` {string}
-* Returns: {Array}
-
-Returns a list of all `PerformanceEntry` objects in chronological order
-with respect to `performanceEntry.startTime` whose `performanceEntry.entryType`
-is equal to `type`.
-
### performance.mark([name])
<!-- YAML
added: v8.5.0
@@ -125,20 +53,6 @@ Creates a new `PerformanceMark` entry in the Performance Timeline. A
`performanceEntry.duration` is always `0`. Performance marks are used
to mark specific significant moments in the Performance Timeline.
-### performance.maxEntries
-<!-- YAML
-added: v9.6.0
--->
-
-Value: {number}
-
-The maximum number of Performance Entry items that should be added to the
-Performance Timeline. This limit is not strictly enforced, but a process
-warning will be emitted if the number of entries in the timeline exceeds
-this limit.
-
-Defaults to 150.
-
### performance.measure(name, startMark, endMark)
<!-- YAML
added: v8.5.0
@@ -220,7 +134,6 @@ const wrapped = performance.timerify(someFunction);
const obs = new PerformanceObserver((list) => {
console.log(list.getEntries()[0].duration);
obs.disconnect();
- performance.clearFunctions();
});
obs.observe({ entryTypes: ['function'] });
@@ -608,7 +521,6 @@ hook.enable();
const obs = new PerformanceObserver((list, observer) => {
console.log(list.getEntries()[0]);
performance.clearMarks();
- performance.clearMeasures();
observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });
@@ -642,8 +554,6 @@ const obs = new PerformanceObserver((list) => {
console.log(`require('${entry[0]}')`, entry.duration);
});
obs.disconnect();
- // Free memory
- performance.clearFunctions();
});
obs.observe({ entryTypes: ['function'], buffered: true });
diff --git a/lib/perf_hooks.js b/lib/perf_hooks.js
index 7fa5501b28..9080cc7f26 100644
--- a/lib/perf_hooks.js
+++ b/lib/perf_hooks.js
@@ -3,6 +3,7 @@
const {
PerformanceEntry,
mark: _mark,
+ clearMark: _clearMark,
measure: _measure,
milestones,
observerCounts,
@@ -50,17 +51,11 @@ const kBuffering = Symbol('buffering');
const kQueued = Symbol('queued');
const kTimerified = Symbol('timerified');
const kInsertEntry = Symbol('insert-entry');
-const kIndexEntry = Symbol('index-entry');
-const kClearEntry = Symbol('clear-entry');
const kGetEntries = Symbol('get-entries');
const kIndex = Symbol('index');
const kMarks = Symbol('marks');
const kCount = Symbol('count');
-const kMaxCount = Symbol('max-count');
-const kDefaultMaxCount = 150;
-observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MARK] = 1;
-observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MEASURE] = 1;
const observers = {};
const observerableTypes = [
'node',
@@ -286,17 +281,12 @@ class PerformanceObserverEntryList {
const item = { entry };
L.append(this[kEntries], item);
this[kCount]++;
- this[kIndexEntry](item);
}
get length() {
return this[kCount];
}
- [kIndexEntry](entry) {
- // Default implementation does nothing
- }
-
[kGetEntries](name, type) {
const ret = [];
const list = this[kEntries];
@@ -407,72 +397,11 @@ class PerformanceObserver extends AsyncResource {
}
}
-class Performance extends PerformanceObserverEntryList {
+class Performance {
constructor() {
- super();
this[kIndex] = {
[kMarks]: new Set()
};
- this[kMaxCount] = kDefaultMaxCount;
- this[kInsertEntry](nodeTiming);
- }
-
- set maxEntries(val) {
- if (typeof val !== 'number' || val >>> 0 !== val) {
- const errors = lazyErrors();
- throw new errors.ERR_INVALID_ARG_TYPE('val', 'number', val);
- }
- this[kMaxCount] = Math.max(1, val >>> 0);
- }
-
- get maxEntries() {
- return this[kMaxCount];
- }
-
- [kIndexEntry](item) {
- const index = this[kIndex];
- const type = item.entry.entryType;
- let items = index[type];
- if (!items) {
- items = index[type] = {};
- L.init(items);
- }
- const entry = item.entry;
- L.append(items, { entry, item });
- const count = this[kCount];
- if (count > this[kMaxCount]) {
- const text = count === 1 ? 'is 1 entry' : `are ${count} entries`;
- process.emitWarning('Possible perf_hooks memory leak detected. ' +
- `There ${text} in the ` +
- 'Performance Timeline. Use the clear methods ' +
- 'to remove entries that are no longer needed or ' +
- 'set performance.maxEntries equal to a higher ' +
- 'value (currently the maxEntries is ' +
- `${this[kMaxCount]}).`);
- }
- }
-
- [kClearEntry](type, name) {
- const index = this[kIndex];
- const items = index[type];
- if (!items) return;
- let item = L.peek(items);
- while (item && item !== items) {
- const entry = item.entry;
- const next = item._idlePrev;
- if (name !== undefined) {
- if (entry.name === `${name}`) {
- L.remove(item); // remove from the index
- L.remove(item.item); // remove from the master
- this[kCount]--;
- }
- } else {
- L.remove(item); // remove from the index
- L.remove(item.item); // remove from the master
- this[kCount]--;
- }
- item = next;
- }
}
get nodeTiming() {
@@ -507,27 +436,13 @@ class Performance extends PerformanceObserverEntryList {
clearMarks(name) {
name = name !== undefined ? `${name}` : name;
- this[kClearEntry]('mark', name);
- if (name !== undefined)
+ if (name !== undefined) {
this[kIndex][kMarks].delete(name);
- else
+ _clearMark(name);
+ } else {
this[kIndex][kMarks].clear();
- }
-
- clearMeasures(name) {
- this[kClearEntry]('measure', name);
- }
-
- clearGC() {
- this[kClearEntry]('gc');
- }
-
- clearFunctions(name) {
- this[kClearEntry]('function', name);
- }
-
- clearEntries(name) {
- this[kClearEntry](name);
+ _clearMark();
+ }
}
timerify(fn) {
@@ -563,7 +478,6 @@ class Performance extends PerformanceObserverEntryList {
[kInspect]() {
return {
- maxEntries: this.maxEntries,
nodeTiming: this.nodeTiming,
timeOrigin: this.timeOrigin
};
@@ -595,7 +509,6 @@ function observersCallback(entry) {
if (type === NODE_PERFORMANCE_ENTRY_TYPE_HTTP2)
collectHttp2Stats(entry);
- performance[kInsertEntry](entry);
const list = getObserversList(type);
let current = L.peek(list);
diff --git a/src/node_perf.cc b/src/node_perf.cc
index ac17e5b873..521492e589 100644
--- a/src/node_perf.cc
+++ b/src/node_perf.cc
@@ -130,7 +130,7 @@ void PerformanceEntry::Notify(Environment* env,
object.As<Object>(),
env->performance_entry_callback(),
1, &object,
- node::async_context{0, 0}).ToLocalChecked();
+ node::async_context{0, 0});
}
}
@@ -153,6 +153,17 @@ void Mark(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(obj);
}
+void ClearMark(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ auto marks = env->performance_marks();
+
+ if (args.Length() == 0) {
+ marks->clear();
+ } else {
+ Utf8Value name(env->isolate(), args[0]);
+ marks->erase(*name);
+ }
+}
inline uint64_t GetPerformanceMark(Environment* env, std::string name) {
auto marks = env->performance_marks();
@@ -395,6 +406,7 @@ void Initialize(Local<Object> target,
target->Set(context, performanceEntryString, fn).FromJust();
env->set_performance_entry_template(fn);
+ env->SetMethod(target, "clearMark", ClearMark);
env->SetMethod(target, "mark", Mark);
env->SetMethod(target, "measure", Measure);
env->SetMethod(target, "markMilestone", MarkMilestone);
diff --git a/test/parallel/test-http2-perf_hooks.js b/test/parallel/test-http2-perf_hooks.js
index e30d0ac83e..07d9c55ed7 100644
--- a/test/parallel/test-http2-perf_hooks.js
+++ b/test/parallel/test-http2-perf_hooks.js
@@ -6,7 +6,7 @@ if (!common.hasCrypto)
const assert = require('assert');
const h2 = require('http2');
-const { PerformanceObserver, performance } = require('perf_hooks');
+const { PerformanceObserver } = require('perf_hooks');
const obs = new PerformanceObserver(common.mustCall((items) => {
const entry = items.getEntries()[0];
@@ -46,7 +46,6 @@ const obs = new PerformanceObserver(common.mustCall((items) => {
default:
assert.fail('invalid entry name');
}
- performance.clearEntries('http2');
}, 4));
obs.observe({ entryTypes: ['http2'] });
@@ -101,10 +100,3 @@ server.on('listening', common.mustCall(() => {
}));
}));
-
-process.on('exit', () => {
- const entries = performance.getEntries();
- // There shouldn't be any http2 entries left over.
- assert.strictEqual(entries.length, 1);
- assert.strictEqual(entries[0], performance.nodeTiming);
-});
diff --git a/test/parallel/test-performance-function.js b/test/parallel/test-performance-function.js
index 57dd2871ee..98b381e649 100644
--- a/test/parallel/test-performance-function.js
+++ b/test/parallel/test-performance-function.js
@@ -11,9 +11,6 @@ const {
{
// Intentional non-op. Do not wrap in common.mustCall();
const n = performance.timerify(() => {});
- n();
- const entries = performance.getEntriesByType('function');
- assert.strictEqual(entries.length, 0);
const obs = new PerformanceObserver(common.mustCall((list) => {
const entries = list.getEntries();
@@ -24,7 +21,6 @@ const {
assert.strictEqual(typeof entry.duration, 'number');
assert.strictEqual(typeof entry.startTime, 'number');
obs.disconnect();
- performance.clearFunctions();
}));
obs.observe({ entryTypes: ['function'] });
n();
@@ -39,17 +35,12 @@ const {
throw new Error('test');
});
assert.throws(() => n(), /^Error: test$/);
- const entries = performance.getEntriesByType('function');
- assert.strictEqual(entries.length, 0);
obs.disconnect();
}
{
class N {}
const n = performance.timerify(N);
- new n();
- const entries = performance.getEntriesByType('function');
- assert.strictEqual(entries.length, 0);
const obs = new PerformanceObserver(common.mustCall((list) => {
const entries = list.getEntries();
@@ -62,7 +53,6 @@ const {
assert.strictEqual(typeof entry.duration, 'number');
assert.strictEqual(typeof entry.startTime, 'number');
obs.disconnect();
- performance.clearFunctions();
}));
obs.observe({ entryTypes: ['function'] });
diff --git a/test/parallel/test-performance-gc.js b/test/parallel/test-performance-gc.js
index ec0714ea50..f4ff88a637 100644
--- a/test/parallel/test-performance-gc.js
+++ b/test/parallel/test-performance-gc.js
@@ -4,7 +4,6 @@
const common = require('../common');
const assert = require('assert');
const {
- performance,
PerformanceObserver
} = require('perf_hooks');
@@ -22,13 +21,6 @@ const kinds = [
NODE_PERFORMANCE_GC_WEAKCB
];
-// No observers for GC events, no entries should appear
-{
- global.gc();
- const entries = performance.getEntriesByType('gc');
- assert.strictEqual(entries.length, 0);
-}
-
// Adding an observer should force at least one gc to appear
{
const obs = new PerformanceObserver(common.mustCallAtLeast((list) => {
@@ -39,11 +31,6 @@ const kinds = [
assert(kinds.includes(entry.kind));
assert.strictEqual(typeof entry.startTime, 'number');
assert.strictEqual(typeof entry.duration, 'number');
-
- performance.clearGC();
-
- const entries = performance.getEntriesByType('gc');
- assert.strictEqual(entries.length, 0);
obs.disconnect();
}));
obs.observe({ entryTypes: ['gc'] });
diff --git a/test/parallel/test-performance-warning.js b/test/parallel/test-performance-warning.js
deleted file mode 100644
index 6a7d6f7b94..0000000000
--- a/test/parallel/test-performance-warning.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Flags: --no-warnings
-'use strict';
-
-const common = require('../common');
-const { performance } = require('perf_hooks');
-const assert = require('assert');
-
-assert.strictEqual(performance.length, 1);
-assert.strictEqual(performance.maxEntries, 150);
-
-performance.maxEntries = 1;
-
-[-1, 0xffffffff + 1, '', null, undefined, Infinity].forEach((i) => {
- common.expectsError(
- () => performance.maxEntries = i,
- {
- code: 'ERR_INVALID_ARG_TYPE',
- type: TypeError
- }
- );
-});
-
-common.expectWarning('Warning', 'Possible perf_hooks memory leak detected. ' +
- 'There are 2 entries in the ' +
- 'Performance Timeline. Use the clear methods to remove entries that are no ' +
- 'longer needed or set performance.maxEntries equal to a higher value ' +
- '(currently the maxEntries is 1).', common.noWarnCode);
-
-performance.mark('test');
diff --git a/test/parallel/test-performanceobserver.js b/test/parallel/test-performanceobserver.js
index 08e07a1518..5d6029fc0d 100644
--- a/test/parallel/test-performanceobserver.js
+++ b/test/parallel/test-performanceobserver.js
@@ -21,8 +21,8 @@ const {
} = constants;
assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_NODE], 0);
-assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
-assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MEASURE], 1);
+assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 0);
+assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MEASURE], 0);
assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_GC], 0);
assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION], 0);
@@ -67,7 +67,7 @@ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION], 0);
const countdown =
new Countdown(3, () => {
observer.disconnect();
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 0);
});
function callback(list, obs) {
@@ -76,9 +76,9 @@ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION], 0);
assert.strictEqual(entries.length, 1);
countdown.dec();
}
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 0);
observer.observe({ entryTypes: ['mark'] });
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 2);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
performance.mark('test1');
performance.mark('test2');
performance.mark('test3');
@@ -89,14 +89,14 @@ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION], 0);
{
const observer =
new PerformanceObserver(common.mustCall(callback, 1));
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 0);
function callback(list, obs) {
assert.strictEqual(obs, observer);
const entries = list.getEntries();
assert.strictEqual(entries.length, 3);
observer.disconnect();
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 0);
{
const entriesByName = list.getEntriesByName('test1');
@@ -129,7 +129,7 @@ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION], 0);
// Do this twice to make sure it doesn't throw
observer.observe({ entryTypes: ['mark', 'measure'], buffered: true });
// Even tho we called twice, count should be 1
- assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 2);
+ assert.strictEqual(counts[NODE_PERFORMANCE_ENTRY_TYPE_MARK], 1);
performance.mark('test1');
performance.mark('test2');
performance.measure('test3', 'test1', 'test2');
diff --git a/test/sequential/test-performance.js b/test/sequential/test-performance.js
index 037168dffb..ea7e17e18d 100644
--- a/test/sequential/test-performance.js
+++ b/test/sequential/test-performance.js
@@ -15,56 +15,12 @@ const inited = performance.now();
assert(inited < 20000);
{
- const entries = performance.getEntries();
- assert(Array.isArray(entries));
- assert.strictEqual(entries.length, 1);
- assert.strictEqual(entries[0], performance.nodeTiming);
-}
-
-{
- const entries = performance.getEntriesByName('node');
- assert(Array.isArray(entries));
- assert.strictEqual(entries.length, 1);
- assert.strictEqual(entries[0], performance.nodeTiming);
-}
-
-{
- let n;
- let entries = performance.getEntries();
- for (n = 0; n < entries.length; n++) {
- const entry = entries[n];
- assert.notStrictEqual(entry.name, 'A');
- assert.notStrictEqual(entry.entryType, 'mark');
- }
+ // Should work without throwing any errors
performance.mark('A');
- entries = performance.getEntries();
- const markA = entries[1];
- assert.strictEqual(markA.name, 'A');
- assert.strictEqual(markA.entryType, 'mark');
performance.clearMarks('A');
- entries = performance.getEntries();
- for (n = 0; n < entries.length; n++) {
- const entry = entries[n];
- assert.notStrictEqual(entry.name, 'A');
- assert.notStrictEqual(entry.entryType, 'mark');
- }
-}
-{
- let entries = performance.getEntries();
- for (let n = 0; n < entries.length; n++) {
- const entry = entries[n];
- assert.notStrictEqual(entry.name, 'B');
- assert.notStrictEqual(entry.entryType, 'mark');
- }
performance.mark('B');
- entries = performance.getEntries();
- const markB = entries[1];
- assert.strictEqual(markB.name, 'B');
- assert.strictEqual(markB.entryType, 'mark');
performance.clearMarks();
- entries = performance.getEntries();
- assert.strictEqual(entries.length, 1);
}
{
@@ -83,11 +39,7 @@ assert(inited < 20000);
});
});
- performance.clearMeasures();
performance.clearMarks();
-
- const entries = performance.getEntries();
- assert.strictEqual(entries.length, 1);
}
{
@@ -95,15 +47,6 @@ assert(inited < 20000);
setImmediate(() => {
performance.mark('B');
performance.measure('foo', 'A', 'B');
- const entry = performance.getEntriesByName('foo')[0];
- const markA = performance.getEntriesByName('A', 'mark')[0];
- performance.getEntriesByName('B', 'mark')[0];
- assert.strictEqual(entry.name, 'foo');
- assert.strictEqual(entry.entryType, 'measure');
- assert.strictEqual(entry.startTime, markA.startTime);
- // TODO(jasnell): This comparison is too imprecise on some systems
- // assert.strictEqual(entry.duration.toPrecision(3),
- // (markB.startTime - markA.startTime).toPrecision(3));
});
}