Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6b44df2

Browse filesBrowse files
jasnellMylesBorins
authored andcommitted
perf,src: add HistogramBase and internal/histogram.js
Separating this out from the QUIC PR to allow it to be separately reviewed. The QUIC implementation makes use of the hdr_histogram for dynamic performance monitoring. This introduces a BaseObject class that allows the internal histograms to be accessed on the JavaScript side and adds a generic Histogram class that will be used by both QUIC and perf_hooks (for the event loop delay monitoring). Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: #31988 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 4d5318c commit 6b44df2
Copy full SHA for 6b44df2

File tree

Expand file treeCollapse file tree

8 files changed

+355
-74
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+355
-74
lines changed
Open diff view settings
Collapse file

‎lib/internal/histogram.js‎

Copy file name to clipboard
+94Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'use strict';
2+
3+
const {
4+
customInspectSymbol: kInspect,
5+
} = require('internal/util');
6+
7+
const { format } = require('util');
8+
const { Map, Symbol } = primordials;
9+
10+
const {
11+
ERR_INVALID_ARG_TYPE,
12+
ERR_INVALID_ARG_VALUE,
13+
} = require('internal/errors').codes;
14+
15+
const kDestroy = Symbol('kDestroy');
16+
const kHandle = Symbol('kHandle');
17+
18+
// Histograms are created internally by Node.js and used to
19+
// record various metrics. This Histogram class provides a
20+
// generally read-only view of the internal histogram.
21+
class Histogram {
22+
#handle = undefined;
23+
#map = new Map();
24+
25+
constructor(internal) {
26+
this.#handle = internal;
27+
}
28+
29+
[kInspect]() {
30+
const obj = {
31+
min: this.min,
32+
max: this.max,
33+
mean: this.mean,
34+
exceeds: this.exceeds,
35+
stddev: this.stddev,
36+
percentiles: this.percentiles,
37+
};
38+
return `Histogram ${format(obj)}`;
39+
}
40+
41+
get min() {
42+
return this.#handle ? this.#handle.min() : undefined;
43+
}
44+
45+
get max() {
46+
return this.#handle ? this.#handle.max() : undefined;
47+
}
48+
49+
get mean() {
50+
return this.#handle ? this.#handle.mean() : undefined;
51+
}
52+
53+
get exceeds() {
54+
return this.#handle ? this.#handle.exceeds() : undefined;
55+
}
56+
57+
get stddev() {
58+
return this.#handle ? this.#handle.stddev() : undefined;
59+
}
60+
61+
percentile(percentile) {
62+
if (typeof percentile !== 'number')
63+
throw new ERR_INVALID_ARG_TYPE('percentile', 'number', percentile);
64+
65+
if (percentile <= 0 || percentile > 100)
66+
throw new ERR_INVALID_ARG_VALUE.RangeError('percentile', percentile);
67+
68+
return this.#handle ? this.#handle.percentile(percentile) : undefined;
69+
}
70+
71+
get percentiles() {
72+
this.#map.clear();
73+
if (this.#handle)
74+
this.#handle.percentiles(this.#map);
75+
return this.#map;
76+
}
77+
78+
reset() {
79+
if (this.#handle)
80+
this.#handle.reset();
81+
}
82+
83+
[kDestroy]() {
84+
this.#handle = undefined;
85+
}
86+
87+
get [kHandle]() { return this.#handle; }
88+
}
89+
90+
module.exports = {
91+
Histogram,
92+
kDestroy,
93+
kHandle,
94+
};
Collapse file

‎lib/perf_hooks.js‎

Copy file name to clipboardExpand all lines: lib/perf_hooks.js
+6-43Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const {
44
ArrayIsArray,
55
Boolean,
6-
Map,
76
NumberIsSafeInteger,
87
ObjectDefineProperties,
98
ObjectDefineProperty,
@@ -52,16 +51,18 @@ const kInspect = require('internal/util').customInspectSymbol;
5251

5352
const {
5453
ERR_INVALID_CALLBACK,
55-
ERR_INVALID_ARG_VALUE,
5654
ERR_INVALID_ARG_TYPE,
5755
ERR_INVALID_OPT_VALUE,
5856
ERR_VALID_PERFORMANCE_ENTRY_TYPE,
5957
ERR_INVALID_PERFORMANCE_MARK
6058
} = require('internal/errors').codes;
6159

60+
const {
61+
Histogram,
62+
kHandle,
63+
} = require('internal/histogram');
64+
6265
const { setImmediate } = require('timers');
63-
const kHandle = Symbol('handle');
64-
const kMap = Symbol('map');
6566
const kCallback = Symbol('callback');
6667
const kTypes = Symbol('types');
6768
const kEntries = Symbol('entries');
@@ -557,47 +558,9 @@ function sortedInsert(list, entry) {
557558
list.splice(location, 0, entry);
558559
}
559560

560-
class ELDHistogram {
561-
constructor(handle) {
562-
this[kHandle] = handle;
563-
this[kMap] = new Map();
564-
}
565-
566-
reset() { this[kHandle].reset(); }
561+
class ELDHistogram extends Histogram {
567562
enable() { return this[kHandle].enable(); }
568563
disable() { return this[kHandle].disable(); }
569-
570-
get exceeds() { return this[kHandle].exceeds(); }
571-
get min() { return this[kHandle].min(); }
572-
get max() { return this[kHandle].max(); }
573-
get mean() { return this[kHandle].mean(); }
574-
get stddev() { return this[kHandle].stddev(); }
575-
percentile(percentile) {
576-
if (typeof percentile !== 'number') {
577-
throw new ERR_INVALID_ARG_TYPE('percentile', 'number', percentile);
578-
}
579-
if (percentile <= 0 || percentile > 100) {
580-
throw new ERR_INVALID_ARG_VALUE.RangeError('percentile',
581-
percentile);
582-
}
583-
return this[kHandle].percentile(percentile);
584-
}
585-
get percentiles() {
586-
this[kMap].clear();
587-
this[kHandle].percentiles(this[kMap]);
588-
return this[kMap];
589-
}
590-
591-
[kInspect]() {
592-
return {
593-
min: this.min,
594-
max: this.max,
595-
mean: this.mean,
596-
stddev: this.stddev,
597-
percentiles: this.percentiles,
598-
exceeds: this.exceeds
599-
};
600-
}
601564
}
602565

603566
function monitorEventLoopDelay(options = {}) {
Collapse file

‎node.gyp‎

Copy file name to clipboardExpand all lines: node.gyp
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
'lib/internal/fs/watchers.js',
141141
'lib/internal/http.js',
142142
'lib/internal/heap_utils.js',
143+
'lib/internal/histogram.js',
143144
'lib/internal/idna.js',
144145
'lib/internal/inspector_async_hook.js',
145146
'lib/internal/js_stream_socket.js',
@@ -533,6 +534,7 @@
533534
'src/fs_event_wrap.cc',
534535
'src/handle_wrap.cc',
535536
'src/heap_utils.cc',
537+
'src/histogram.cc',
536538
'src/js_native_api.h',
537539
'src/js_native_api_types.h',
538540
'src/js_native_api_v8.cc',
Collapse file

‎src/env.h‎

Copy file name to clipboardExpand all lines: src/env.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ constexpr size_t kFsStatsBufferLength =
406406
V(filehandlereadwrap_template, v8::ObjectTemplate) \
407407
V(fsreqpromise_constructor_template, v8::ObjectTemplate) \
408408
V(handle_wrap_ctor_template, v8::FunctionTemplate) \
409+
V(histogram_instance_template, v8::ObjectTemplate) \
409410
V(http2settings_constructor_template, v8::ObjectTemplate) \
410411
V(http2stream_constructor_template, v8::ObjectTemplate) \
411412
V(http2ping_constructor_template, v8::ObjectTemplate) \
Collapse file

‎src/histogram-inl.h‎

Copy file name to clipboardExpand all lines: src/histogram-inl.h
+45-25Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,78 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include "histogram.h"
7+
#include "base_object-inl.h"
78
#include "node_internals.h"
89

910
namespace node {
1011

11-
inline Histogram::Histogram(int64_t lowest, int64_t highest, int figures) {
12-
CHECK_EQ(0, hdr_init(lowest, highest, figures, &histogram_));
12+
void Histogram::Reset() {
13+
hdr_reset(histogram_.get());
1314
}
1415

15-
inline Histogram::~Histogram() {
16-
hdr_close(histogram_);
16+
bool Histogram::Record(int64_t value) {
17+
return hdr_record_value(histogram_.get(), value);
1718
}
1819

19-
inline void Histogram::Reset() {
20-
hdr_reset(histogram_);
20+
int64_t Histogram::Min() {
21+
return hdr_min(histogram_.get());
2122
}
2223

23-
inline bool Histogram::Record(int64_t value) {
24-
return hdr_record_value(histogram_, value);
24+
int64_t Histogram::Max() {
25+
return hdr_max(histogram_.get());
2526
}
2627

27-
inline int64_t Histogram::Min() {
28-
return hdr_min(histogram_);
28+
double Histogram::Mean() {
29+
return hdr_mean(histogram_.get());
2930
}
3031

31-
inline int64_t Histogram::Max() {
32-
return hdr_max(histogram_);
32+
double Histogram::Stddev() {
33+
return hdr_stddev(histogram_.get());
3334
}
3435

35-
inline double Histogram::Mean() {
36-
return hdr_mean(histogram_);
37-
}
38-
39-
inline double Histogram::Stddev() {
40-
return hdr_stddev(histogram_);
41-
}
42-
43-
inline double Histogram::Percentile(double percentile) {
36+
double Histogram::Percentile(double percentile) {
4437
CHECK_GT(percentile, 0);
4538
CHECK_LE(percentile, 100);
46-
return hdr_value_at_percentile(histogram_, percentile);
39+
return static_cast<double>(
40+
hdr_value_at_percentile(histogram_.get(), percentile));
4741
}
4842

49-
inline void Histogram::Percentiles(std::function<void(double, double)> fn) {
43+
template <typename Iterator>
44+
void Histogram::Percentiles(Iterator&& fn) {
5045
hdr_iter iter;
51-
hdr_iter_percentile_init(&iter, histogram_, 1);
46+
hdr_iter_percentile_init(&iter, histogram_.get(), 1);
5247
while (hdr_iter_next(&iter)) {
5348
double key = iter.specifics.percentiles.percentile;
54-
double value = iter.value;
49+
double value = static_cast<double>(iter.value);
5550
fn(key, value);
5651
}
5752
}
5853

54+
bool HistogramBase::RecordDelta() {
55+
uint64_t time = uv_hrtime();
56+
bool ret = true;
57+
if (prev_ > 0) {
58+
int64_t delta = time - prev_;
59+
if (delta > 0) {
60+
ret = Record(delta);
61+
TraceDelta(delta);
62+
if (!ret) {
63+
if (exceeds_ < 0xFFFFFFFF)
64+
exceeds_++;
65+
TraceExceeds(delta);
66+
}
67+
}
68+
}
69+
prev_ = time;
70+
return ret;
71+
}
72+
73+
void HistogramBase::ResetState() {
74+
Reset();
75+
exceeds_ = 0;
76+
prev_ = 0;
77+
}
78+
5979
} // namespace node
6080

6181
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.