Skip to content

Commit

Permalink
perf: significantly improve the memory usage of histogram
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Shappir committed Feb 6, 2024
1 parent a88a5c3 commit 7c2cc63
Showing 1 changed file with 24 additions and 32 deletions.
56 changes: 24 additions & 32 deletions lib/histogram.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Histogram extends Metric {
this.type = 'histogram';
this.defaultLabels = {};
this.defaultExemplarLabelSet = {};
this.enableExemplars = false;
this.enableExemplars = config.enableExemplars;

for (const label of this.labelNames) {
if (label === 'le') {
Expand All @@ -38,27 +38,18 @@ class Histogram extends Metric {
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;
}
this.observe = this.enableExemplars
? this.observeWithExemplar
: this.observeWithoutExemplar;

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

if (this.labelNames.length === 0) {
this.hashMap = {
[hashObject({})]: createBaseValues(
{},
this.bucketValues,
this.bucketExemplars,
this.enableExemplars,
),
};
}
Expand All @@ -79,14 +70,15 @@ class Histogram extends Metric {
value,
exemplarLabels = this.defaultExemplarLabelSet,
} = {}) {
observe.call(this, labels === 0 ? 0 : labels || {})(value);
this.updateExemplar(labels, value, exemplarLabels);
const valueFromMap = observe.call(
this,
labels === 0 ? 0 : labels || {},
)(value);
this.updateExemplar(valueFromMap, value, exemplarLabels);
}

updateExemplar(labels, value, exemplarLabels) {
const hash = hashObject(labels, this.sortedLabelNames);
updateExemplar({ bucketExemplars }, value, exemplarLabels) {
const bound = findBound(this.upperBounds, value);
const { bucketExemplars } = this.hashMap[hash];
let exemplar = bucketExemplars[bound];
if (!isObject(exemplar)) {
exemplar = new Exemplar();
Expand Down Expand Up @@ -137,7 +129,7 @@ class Histogram extends Metric {
this.hashMap[hash] = createBaseValues(
labels,
this.bucketValues,
this.bucketExemplars,
this.enableExemplars,
);
}

Expand Down Expand Up @@ -244,32 +236,33 @@ function observe(labels) {
valueFromMap = createBaseValues(
labelValuePair.labels,
this.bucketValues,
this.bucketExemplars,
this.enableExemplars,
);
this.hashMap[hash] = valueFromMap;
}

const b = findBound(this.upperBounds, labelValuePair.value);

valueFromMap.sum += labelValuePair.value;
valueFromMap.count += 1;

if (Object.prototype.hasOwnProperty.call(valueFromMap.bucketValues, b)) {
if (typeof valueFromMap.bucketValues[b] === 'number') {
valueFromMap.bucketValues[b] += 1;
}

this.hashMap[hash] = valueFromMap;
return valueFromMap;
};
}

function createBaseValues(labels, bucketValues, bucketExemplars) {
function createBaseValues(labels, bucketValues, enableExemplars) {
const result = {
labels,
bucketValues: { ...bucketValues },
bucketValues: Object.create(bucketValues),
sum: 0,
count: 0,
};
if (bucketExemplars) {
result.bucketExemplars = { ...bucketExemplars };
if (enableExemplars) {
result.bucketExemplars = {};
}
return result;
}
Expand All @@ -290,16 +283,15 @@ function extractBucketValuesForExport(histogram) {
const name = `${histogram.name}_bucket`;
return bucketData => {
let acc = 0;
const { labels, bucketValues, bucketExemplars } = bucketData;
const buckets = histogram.upperBounds.map(upperBound => {
acc += bucketData.bucketValues[upperBound];
acc += bucketValues[upperBound];
return setValuePair(
{ le: upperBound },
acc,
name,
bucketData.bucketExemplars
? bucketData.bucketExemplars[upperBound]
: null,
bucketData.labels,
(bucketExemplars && bucketExemplars[upperBound]) || null,
labels,
);
});
return { buckets, data: bucketData };
Expand Down

0 comments on commit 7c2cc63

Please sign in to comment.