Skip to content

Commit 5fd8c22

Browse files
committed
lib: rewrite metrics interface
1 parent 0cf65ce commit 5fd8c22

File tree

57 files changed

+7314
-1003
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+7314
-1003
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e7, 1e8],
10+
boundaryCount: [5, 10, 20, 50],
11+
});
12+
13+
function main({ n, boundaryCount }) {
14+
const metric = metrics.create('bench.aggregator.histogram', { unit: 'ms' });
15+
16+
// Generate exponential boundaries like OTel defaults
17+
const boundaries = [];
18+
for (let i = 0; i < boundaryCount; i++) {
19+
boundaries.push(Math.pow(2, i));
20+
}
21+
22+
const consumer = metrics.createConsumer({
23+
'bench.aggregator.histogram': {
24+
aggregation: 'histogram',
25+
boundaries,
26+
},
27+
});
28+
29+
// Generate values that spread across buckets
30+
const maxBoundary = boundaries[boundaries.length - 1];
31+
32+
bench.start();
33+
for (let i = 0; i < n; i++) {
34+
// Distribute values across the range
35+
const value = (i % (maxBoundary + 1));
36+
metric.record(value);
37+
}
38+
bench.end(n);
39+
40+
// Cleanup and avoid deadcode elimination
41+
assert.ok(consumer.collect());
42+
consumer.close();
43+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e7, 1e8],
10+
monotonic: ['yes', 'no'],
11+
valueType: ['number', 'bigint'],
12+
});
13+
14+
function main({ n, monotonic, valueType }) {
15+
const metric = metrics.create('bench.aggregator.sum', { unit: 'count' });
16+
17+
const consumer = metrics.createConsumer({
18+
'bench.aggregator.sum': {
19+
aggregation: 'sum',
20+
monotonic: monotonic === 'yes',
21+
},
22+
});
23+
24+
const useBigInt = valueType === 'bigint';
25+
const increment = useBigInt ? 1n : 1;
26+
const decrement = useBigInt ? -1n : -1;
27+
28+
bench.start();
29+
if (monotonic === 'yes') {
30+
// Monotonic - always positive values
31+
for (let i = 0; i < n; i++) {
32+
metric.record(increment);
33+
}
34+
} else {
35+
// Non-monotonic - mix of positive and negative
36+
for (let i = 0; i < n; i++) {
37+
metric.record(i % 2 === 0 ? increment : decrement);
38+
}
39+
}
40+
bench.end(n);
41+
42+
// Cleanup and avoid deadcode elimination
43+
assert.ok(consumer.collect());
44+
consumer.close();
45+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e6, 1e7],
10+
quantileCount: [3, 5, 10],
11+
});
12+
13+
function main({ n, quantileCount }) {
14+
const metric = metrics.create('bench.aggregator.summary', { unit: 'ms' });
15+
16+
// Generate quantiles
17+
const quantiles = [];
18+
for (let i = 1; i <= quantileCount; i++) {
19+
quantiles.push(i / (quantileCount + 1));
20+
}
21+
22+
const consumer = metrics.createConsumer({
23+
'bench.aggregator.summary': {
24+
aggregation: 'summary',
25+
quantiles,
26+
},
27+
});
28+
29+
bench.start();
30+
for (let i = 0; i < n; i++) {
31+
// Record values that simulate realistic latency distribution (min 1)
32+
metric.record(Math.random() * 999 + 1);
33+
}
34+
bench.end(n);
35+
36+
// Cleanup and avoid deadcode elimination
37+
assert.ok(consumer.collect());
38+
consumer.close();
39+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e5, 1e6],
10+
metricsCount: [10, 100],
11+
attrCardinality: [1, 10, 100],
12+
aggregation: ['sum', 'histogram'],
13+
});
14+
15+
function main({ n, metricsCount, attrCardinality, aggregation }) {
16+
// Create multiple metrics
17+
const metricsList = [];
18+
const subscriptions = {};
19+
20+
for (let i = 0; i < metricsCount; i++) {
21+
const name = `bench.collect.${i}`;
22+
metricsList.push(metrics.create(name, { unit: 'count' }));
23+
subscriptions[name] = { aggregation };
24+
}
25+
26+
const consumer = metrics.createConsumer(subscriptions);
27+
28+
// Pre-populate data with attribute cardinality
29+
for (const metric of metricsList) {
30+
for (let c = 0; c < attrCardinality; c++) {
31+
metric.record(1, { variant: `v${c}` });
32+
}
33+
}
34+
35+
bench.start();
36+
for (let i = 0; i < n; i++) {
37+
consumer.collect();
38+
}
39+
bench.end(n);
40+
41+
// Cleanup and avoid deadcode elimination
42+
assert.ok(consumer);
43+
consumer.close();
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
const dc = require('diagnostics_channel');
6+
7+
const { metrics } = require('perf_hooks');
8+
9+
const bench = common.createBenchmark(main, {
10+
n: [1e7, 1e8],
11+
hasSubscribers: ['yes', 'no'],
12+
});
13+
14+
function main({ n, hasSubscribers }) {
15+
const metric = metrics.create('bench.dc', { unit: 'count' });
16+
17+
// Create DC consumer
18+
const dcConsumer = metrics.createDiagnosticsChannelConsumer();
19+
20+
// Optionally subscribe to the channel
21+
let received = 0;
22+
if (hasSubscribers === 'yes') {
23+
dc.subscribe('metrics:bench.dc', () => {
24+
received++;
25+
});
26+
}
27+
28+
bench.start();
29+
for (let i = 0; i < n; i++) {
30+
metric.record(i);
31+
}
32+
bench.end(n);
33+
34+
// Cleanup and avoid deadcode elimination
35+
assert.ok(dcConsumer);
36+
if (hasSubscribers === 'yes') {
37+
assert.strictEqual(received, n);
38+
}
39+
dcConsumer.close();
40+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e5, 1e6],
10+
observableCount: [1, 10, 100],
11+
});
12+
13+
function main({ n, observableCount }) {
14+
// Create observable metrics
15+
const subscriptions = {};
16+
let counter = 0;
17+
18+
for (let i = 0; i < observableCount; i++) {
19+
const name = `bench.observable.${i}`;
20+
metrics.create(name, {
21+
unit: 'count',
22+
observable: (m) => { m.record(counter++); },
23+
});
24+
subscriptions[name] = { aggregation: 'lastValue' };
25+
}
26+
27+
const consumer = metrics.createConsumer(subscriptions);
28+
29+
bench.start();
30+
for (let i = 0; i < n; i++) {
31+
consumer.collect();
32+
}
33+
bench.end(n);
34+
35+
// Cleanup and avoid deadcode elimination
36+
assert.ok(counter > 0);
37+
consumer.close();
38+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e7, 1e8],
10+
attrCount: [0, 1, 5, 10],
11+
attrCardinality: [1, 10, 100],
12+
});
13+
14+
function main({ n, attrCount, attrCardinality }) {
15+
const metric = metrics.create('bench.record.attrs', { unit: 'count' });
16+
17+
const consumer = metrics.createConsumer({
18+
'bench.record.attrs': { aggregation: 'sum' },
19+
});
20+
21+
// Pre-generate attribute objects with specified cardinality
22+
const attributeSets = [];
23+
for (let c = 0; c < attrCardinality; c++) {
24+
const attrs = {};
25+
for (let a = 0; a < attrCount; a++) {
26+
attrs[`attr${a}`] = `value${c}`;
27+
}
28+
attributeSets.push(attrs);
29+
}
30+
31+
bench.start();
32+
for (let i = 0; i < n; i++) {
33+
const attrs = attrCount > 0 ? attributeSets[i % attrCardinality] : undefined;
34+
metric.record(i, attrs);
35+
}
36+
bench.end(n);
37+
38+
// Cleanup and avoid deadcode elimination
39+
assert.ok(consumer.collect());
40+
consumer.close();
41+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e7, 1e8],
10+
consumerCount: [1, 5, 10],
11+
aggregation: ['sum', 'lastValue', 'histogram'],
12+
});
13+
14+
function main({ n, consumerCount, aggregation }) {
15+
const metric = metrics.create('bench.record', { unit: 'count' });
16+
17+
// Create consumers with the specified aggregation
18+
const consumers = [];
19+
for (let i = 0; i < consumerCount; i++) {
20+
consumers.push(metrics.createConsumer({
21+
'bench.record': { aggregation },
22+
}));
23+
}
24+
25+
bench.start();
26+
for (let i = 0; i < n; i++) {
27+
metric.record(i);
28+
}
29+
bench.end(n);
30+
31+
// Cleanup and avoid deadcode elimination
32+
for (const consumer of consumers) {
33+
assert.ok(consumer.collect());
34+
consumer.close();
35+
}
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { metrics } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e6, 1e7],
10+
method: ['startStop', 'using'],
11+
consumerCount: [1, 5],
12+
});
13+
14+
function main({ n, method, consumerCount }) {
15+
const metric = metrics.create('bench.timer', { unit: 'ms' });
16+
17+
// Create consumers
18+
const consumers = [];
19+
for (let i = 0; i < consumerCount; i++) {
20+
consumers.push(metrics.createConsumer({
21+
'bench.timer': { aggregation: 'sum' },
22+
}));
23+
}
24+
25+
bench.start();
26+
if (method === 'startStop') {
27+
// Manual start/stop
28+
for (let i = 0; i < n; i++) {
29+
const timer = metric.startTimer();
30+
timer.stop();
31+
}
32+
} else {
33+
// Using Symbol.dispose
34+
for (let i = 0; i < n; i++) {
35+
// eslint-disable-next-line no-unused-vars
36+
using timer = metric.startTimer();
37+
}
38+
}
39+
bench.end(n);
40+
41+
// Cleanup and avoid deadcode elimination
42+
for (const consumer of consumers) {
43+
assert.ok(consumer.collect());
44+
consumer.close();
45+
}
46+
}

0 commit comments

Comments
 (0)