Skip to content

Commit

Permalink
perf: improve the memory usage of histogram (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
xsbchen committed Jan 16, 2024
1 parent 4d186fd commit a88a5c3
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
*.log
coverage/
package-lock.json
*.heapsnapshot
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Improve the memory usage of histograms when the `enableExemplars` option is disabled

### Added

## [15.1.0] - 2023-12-15
Expand Down
33 changes: 33 additions & 0 deletions example/histogram-large-memory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

const v8 = require('v8');
const { register, Histogram } = require('..');

// Create more metrics

async function run() {
const labelNames = Array(10).map((_, idx) => `label_${idx}`);

const getRandomLabels = () =>
labelNames.reduce((acc, label) => {
return { ...acc, [label]: `value_${Math.random()}` };
}, {});

for (let i = 0; i < 100000; i++) {
const h = new Histogram({
name: `test_histogram_${i}`,
help: `Example of a histogram ${i}`,
buckets: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
labelNames,
});
h.observe(getRandomLabels(), Math.random());
}

await register.metrics();

global.gc();

v8.writeHeapSnapshot();
}

run();
36 changes: 20 additions & 16 deletions lib/histogram.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ class Histogram extends Metric {
this.defaultExemplarLabelSet = {};
this.enableExemplars = false;

if (config.enableExemplars) {
this.enableExemplars = true;
this.observe = this.observeWithExemplar;
} else {
this.observe = this.observeWithoutExemplar;
}

for (const label of this.labelNames) {
if (label === 'le') {
throw new Error('le is a reserved label keyword');
Expand All @@ -45,13 +38,19 @@ class Histogram extends Metric {
return acc;
}, {});

this.bucketExemplars = this.upperBounds.reduce((acc, upperBound) => {
acc[upperBound] = null;
return acc;
}, {});
if (config.enableExemplars) {
this.enableExemplars = true;
this.bucketExemplars = this.upperBounds.reduce((acc, upperBound) => {
acc[upperBound] = null;
return acc;
}, {});
Object.freeze(this.bucketExemplars);
this.observe = this.observeWithExemplar;
} else {
this.observe = this.observeWithoutExemplar;
}

Object.freeze(this.bucketValues);
Object.freeze(this.bucketExemplars);
Object.freeze(this.upperBounds);

if (this.labelNames.length === 0) {
Expand Down Expand Up @@ -263,13 +262,16 @@ function observe(labels) {
}

function createBaseValues(labels, bucketValues, bucketExemplars) {
return {
const result = {
labels,
bucketValues: { ...bucketValues },
bucketExemplars: { ...bucketExemplars },
sum: 0,
count: 0,
};
if (bucketExemplars) {
result.bucketExemplars = { ...bucketExemplars };
}
return result;
}

function convertLabelsAndValues(labels, value) {
Expand All @@ -294,7 +296,9 @@ function extractBucketValuesForExport(histogram) {
{ le: upperBound },
acc,
name,
bucketData.bucketExemplars[upperBound],
bucketData.bucketExemplars
? bucketData.bucketExemplars[upperBound]
: null,
bucketData.labels,
);
});
Expand All @@ -312,7 +316,7 @@ function addSumAndCountForExport(histogram) {
infLabel,
d.data.count,
`${histogram.name}_bucket`,
d.data.bucketExemplars['-1'],
d.data.bucketExemplars ? d.data.bucketExemplars['-1'] : null,
d.data.labels,
),
setValuePair(
Expand Down

0 comments on commit a88a5c3

Please sign in to comment.