@agoric/cosmic-swingset 0.41.4-dev-0e80151.0 → 0.41.4-dev-b2b8029.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-telemetry.md +7 -4
- package/package.json +12 -12
- package/src/chain-main.js +1 -0
- package/src/kernel-stats.js +92 -180
- package/src/launch-chain.js +381 -349
- package/tools/prometheus.js +25 -0
package/README-telemetry.md
CHANGED
|
@@ -20,16 +20,19 @@ TCP connections from your Prometheus host's IP address.
|
|
|
20
20
|
|
|
21
21
|
SwingSet is responsible for the chain's Javascript execution. It is
|
|
22
22
|
instrumented with the [OpenTelemetry](https://opentelemetry.io/) (*OTEL*)
|
|
23
|
-
system.
|
|
23
|
+
system in a [slog sender module](../../docs/env.md#slogsender).
|
|
24
24
|
|
|
25
|
-
To enable the Prometheus exporter, set
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
To enable the Prometheus exporter, set environment variable
|
|
26
|
+
[`OTEL_EXPORTER_PROMETHEUS_PORT`](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#prometheus-exporter)
|
|
27
|
+
to the desired listening TCP port number when running the node.
|
|
28
|
+
To listen on http://0.0.0.0:9464/metrics (the OTEL default), use:
|
|
28
29
|
|
|
29
30
|
```sh
|
|
30
31
|
OTEL_EXPORTER_PROMETHEUS_PORT=9464 ag-chain-cosmos start ...
|
|
31
32
|
```
|
|
32
33
|
|
|
34
|
+
See also [env.md](../../docs/env.md#otel_exporter_prometheus_port).
|
|
35
|
+
|
|
33
36
|
## Cosmos SDK metrics
|
|
34
37
|
|
|
35
38
|
The [Cosmos SDK](https://docs.cosmos.network/) layer of the system is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/cosmic-swingset",
|
|
3
|
-
"version": "0.41.4-dev-
|
|
3
|
+
"version": "0.41.4-dev-b2b8029.0+b2b8029",
|
|
4
4
|
"description": "Agoric's Cosmos blockchain integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"author": "Agoric",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agoric/builders": "0.1.1-dev-
|
|
26
|
-
"@agoric/cosmos": "0.34.2-dev-
|
|
27
|
-
"@agoric/deploy-script-support": "0.10.4-dev-
|
|
28
|
-
"@agoric/internal": "0.3.3-dev-
|
|
29
|
-
"@agoric/store": "0.9.3-dev-
|
|
30
|
-
"@agoric/swing-store": "0.9.2-dev-
|
|
31
|
-
"@agoric/swingset-vat": "0.32.3-dev-
|
|
32
|
-
"@agoric/telemetry": "0.6.3-dev-
|
|
33
|
-
"@agoric/vm-config": "0.1.1-dev-
|
|
25
|
+
"@agoric/builders": "0.1.1-dev-b2b8029.0+b2b8029",
|
|
26
|
+
"@agoric/cosmos": "0.34.2-dev-b2b8029.0+b2b8029",
|
|
27
|
+
"@agoric/deploy-script-support": "0.10.4-dev-b2b8029.0+b2b8029",
|
|
28
|
+
"@agoric/internal": "0.3.3-dev-b2b8029.0+b2b8029",
|
|
29
|
+
"@agoric/store": "0.9.3-dev-b2b8029.0+b2b8029",
|
|
30
|
+
"@agoric/swing-store": "0.9.2-dev-b2b8029.0+b2b8029",
|
|
31
|
+
"@agoric/swingset-vat": "0.32.3-dev-b2b8029.0+b2b8029",
|
|
32
|
+
"@agoric/telemetry": "0.6.3-dev-b2b8029.0+b2b8029",
|
|
33
|
+
"@agoric/vm-config": "0.1.1-dev-b2b8029.0+b2b8029",
|
|
34
34
|
"@endo/bundle-source": "^3.5.1",
|
|
35
35
|
"@endo/env-options": "^1.1.8",
|
|
36
36
|
"@endo/errors": "^1.2.9",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"tmp": "^0.2.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@agoric/kmarshal": "0.1.1-dev-
|
|
55
|
+
"@agoric/kmarshal": "0.1.1-dev-b2b8029.0+b2b8029",
|
|
56
56
|
"ava": "^5.3.0",
|
|
57
57
|
"better-sqlite3": "^9.1.1",
|
|
58
58
|
"c8": "^10.1.2"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"typeCoverage": {
|
|
76
76
|
"atLeast": 84.59
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "b2b8029e5de97e794e4fe6b2e5e1ab36e2a7bc4f"
|
|
79
79
|
}
|
package/src/chain-main.js
CHANGED
package/src/kernel-stats.js
CHANGED
|
@@ -4,17 +4,19 @@ import { MeterProvider } from '@opentelemetry/sdk-metrics';
|
|
|
4
4
|
import { Fail } from '@endo/errors';
|
|
5
5
|
import { isNat } from '@endo/nat';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import { defineName } from '@agoric/internal/src/js-utils.js';
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
HISTOGRAM_METRICS,
|
|
10
|
+
KERNEL_STATS_METRICS,
|
|
11
|
+
makeQueueMetricsMeta,
|
|
12
|
+
QueueMetricAspect,
|
|
13
|
+
} from '@agoric/internal/src/metrics.js';
|
|
14
|
+
import { makeLegacyMap } from '@agoric/store';
|
|
13
15
|
|
|
14
16
|
import v8 from 'node:v8';
|
|
15
17
|
import process from 'node:process';
|
|
16
18
|
|
|
17
|
-
/** @import {Histogram, Meter as OTelMeter, MetricAttributes} from '@opentelemetry/api' */
|
|
19
|
+
/** @import {Histogram, Meter as OTelMeter, MetricAttributes, ObservableCounter, ObservableUpDownCounter} from '@opentelemetry/api' */
|
|
18
20
|
|
|
19
21
|
/** @import {TotalMap} from '@agoric/internal' */
|
|
20
22
|
|
|
@@ -29,86 +31,25 @@ import process from 'node:process';
|
|
|
29
31
|
*/
|
|
30
32
|
const VAT_ID_IS_TOO_HIGH_CARDINALITY = true;
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
HISTOGRAM_MS_LATENCY_BOUNDARIES.map(ms => ms / 1000);
|
|
48
|
-
|
|
49
|
-
// TODO: Validate these boundaries. We're not going to have 5ms blocks, but
|
|
50
|
-
// we probably care about the difference between 10 vs. 30 seconds.
|
|
51
|
-
const HISTOGRAM_METRICS = /** @type {const} */ ({
|
|
52
|
-
swingset_crank_processing_time: {
|
|
53
|
-
description: 'Processing time per crank (ms)',
|
|
54
|
-
boundaries: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91, Infinity],
|
|
55
|
-
},
|
|
56
|
-
swingset_block_processing_seconds: {
|
|
57
|
-
description: 'Processing time per block',
|
|
58
|
-
boundaries: HISTOGRAM_SECONDS_LATENCY_BOUNDARIES,
|
|
59
|
-
},
|
|
60
|
-
swingset_vat_startup: {
|
|
61
|
-
description: 'Vat startup time (ms)',
|
|
62
|
-
boundaries: HISTOGRAM_MS_LATENCY_BOUNDARIES,
|
|
63
|
-
},
|
|
64
|
-
swingset_vat_delivery: {
|
|
65
|
-
description: 'Vat delivery time (ms)',
|
|
66
|
-
boundaries: HISTOGRAM_MS_LATENCY_BOUNDARIES,
|
|
67
|
-
},
|
|
68
|
-
swingset_meter_usage: {
|
|
69
|
-
description: 'Vat meter usage',
|
|
70
|
-
boundaries: HISTOGRAM_MS_LATENCY_BOUNDARIES,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
/** @enum {(typeof QueueMetricAspect)[keyof typeof QueueMetricAspect]} */
|
|
75
|
-
const QueueMetricAspect = /** @type {const} */ ({
|
|
76
|
-
Length: 'length',
|
|
77
|
-
IncrementCount: 'increments',
|
|
78
|
-
DecrementCount: 'decrements',
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Queue metrics come in {length,add,remove} triples sharing a common prefix.
|
|
83
|
-
*
|
|
84
|
-
* @param {string} namePrefix
|
|
85
|
-
* @param {string} descPrefix
|
|
86
|
-
* @returns {Record<string, {aspect: QueueMetricAspect, description: string}>}
|
|
87
|
-
*/
|
|
88
|
-
const makeQueueMetrics = (namePrefix, descPrefix) => {
|
|
89
|
-
/** @type {Array<[QueueMetricAspect, string, string]>} */
|
|
90
|
-
const metricsMeta = [
|
|
91
|
-
[QueueMetricAspect.Length, 'length', 'length'],
|
|
92
|
-
[QueueMetricAspect.IncrementCount, 'add', 'increments'],
|
|
93
|
-
[QueueMetricAspect.DecrementCount, 'remove', 'decrements'],
|
|
94
|
-
];
|
|
95
|
-
const entries = metricsMeta.map(([aspect, nameSuffix, descSuffix]) => {
|
|
96
|
-
const name = `${namePrefix}_${nameSuffix}`;
|
|
97
|
-
const description = `${descPrefix} ${descSuffix}`;
|
|
98
|
-
return [name, { aspect, description }];
|
|
34
|
+
const inboundQueueMeta = harden(
|
|
35
|
+
makeQueueMetricsMeta('cosmic_swingset_inbound_queue', 'inbound queue'),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const maxAgeCache = (fn, maxAge, clock = Date.now) => {
|
|
39
|
+
// An initial invocation verifies that the function doesn't [always] throw.
|
|
40
|
+
let cached = fn();
|
|
41
|
+
let lastTime = -Infinity;
|
|
42
|
+
const get = defineName(`caching ${fn.name}`, () => {
|
|
43
|
+
const time = clock();
|
|
44
|
+
if (time - lastTime < maxAge) return cached;
|
|
45
|
+
|
|
46
|
+
lastTime = time;
|
|
47
|
+
cached = fn();
|
|
48
|
+
return cached;
|
|
99
49
|
});
|
|
100
|
-
return
|
|
50
|
+
return { get, firstResult: cached };
|
|
101
51
|
};
|
|
102
52
|
|
|
103
|
-
const QUEUE_METRICS = harden({
|
|
104
|
-
// "cosmic_swingset_inbound_queue_{length,add,remove}" measurements carry a
|
|
105
|
-
// "queue" attribute.
|
|
106
|
-
// Future OpenTelemetry SDKs should support expressing that in Instrument
|
|
107
|
-
// creation:
|
|
108
|
-
// https://opentelemetry.io/docs/specs/otel/metrics/api/#instrument-advisory-parameter-attributes
|
|
109
|
-
...makeQueueMetrics('cosmic_swingset_inbound_queue', 'inbound queue'),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
53
|
const wrapDeltaMS = (finisher, useDeltaMS) => {
|
|
113
54
|
const startMS = Date.now();
|
|
114
55
|
return (...finishArgs) => {
|
|
@@ -135,9 +76,9 @@ export function makeDefaultMeterProvider() {
|
|
|
135
76
|
* @param {string} name
|
|
136
77
|
*/
|
|
137
78
|
function createHistogram(metricMeter, name) {
|
|
138
|
-
const {
|
|
79
|
+
const { boundaries, ...options } = HISTOGRAM_METRICS[name] || {};
|
|
139
80
|
const advice = boundaries && { explicitBucketBoundaries: boundaries };
|
|
140
|
-
return metricMeter.createHistogram(name, {
|
|
81
|
+
return metricMeter.createHistogram(name, { ...options, advice });
|
|
141
82
|
}
|
|
142
83
|
|
|
143
84
|
/**
|
|
@@ -224,6 +165,8 @@ export function makeSlogCallbacks({ metricMeter, attributes = {} }) {
|
|
|
224
165
|
startup(_method, [vatID], finisher) {
|
|
225
166
|
return wrapDeltaMS(finisher, deltaMS => {
|
|
226
167
|
const group = getVatGroup(vatID);
|
|
168
|
+
// DEPRECATED: This should be equivalent to the "seconds" data of
|
|
169
|
+
// "vat-startup-finish" slog entries.
|
|
227
170
|
getGroupedRecorder('swingset_vat_startup', group).record(deltaMS);
|
|
228
171
|
});
|
|
229
172
|
},
|
|
@@ -232,10 +175,15 @@ export function makeSlogCallbacks({ metricMeter, attributes = {} }) {
|
|
|
232
175
|
finisher,
|
|
233
176
|
(deltaMS, [[_status, _problem, meterUsage]]) => {
|
|
234
177
|
const group = getVatGroup(vatID);
|
|
178
|
+
// DEPRECATED: This should be equivalent to the "seconds" data of
|
|
179
|
+
// "deliver-result" slog entries.
|
|
235
180
|
getGroupedRecorder('swingset_vat_delivery', group).record(deltaMS);
|
|
236
181
|
const { meterType, ...measurements } = meterUsage || {};
|
|
237
182
|
for (const [key, value] of Object.entries(measurements)) {
|
|
238
183
|
if (typeof value === 'object') continue;
|
|
184
|
+
// DEPRECATED: This should be equivalent to the data of
|
|
185
|
+
// "deliver-result" slog entries as the third element of the "dr"
|
|
186
|
+
// array.
|
|
239
187
|
// TODO: Each measurement key should have its own histogram; there's
|
|
240
188
|
// no reason to mix e.g. allocate/compute/currentHeapCount.
|
|
241
189
|
// cf. https://prometheus.io/docs/practices/naming/#metric-names
|
|
@@ -322,12 +270,11 @@ function makeInboundQueueMetrics(metricMeter, initialLengths, logger) {
|
|
|
322
270
|
// [monotonic] Counters.
|
|
323
271
|
// But note that the Prometheus representation of the former will be a Gauge:
|
|
324
272
|
// https://prometheus.io/docs/concepts/metric_types/
|
|
325
|
-
for (const [
|
|
273
|
+
for (const [aspect, { name, options }] of Object.entries(inboundQueueMeta)) {
|
|
326
274
|
const isMonotonic = aspect !== QueueMetricAspect.Length;
|
|
327
|
-
const instrumentOptions = { description };
|
|
328
275
|
const asyncInstrument = isMonotonic
|
|
329
|
-
? metricMeter.createObservableCounter(name,
|
|
330
|
-
: metricMeter.createObservableUpDownCounter(name,
|
|
276
|
+
? metricMeter.createObservableCounter(name, options)
|
|
277
|
+
: metricMeter.createObservableUpDownCounter(name, options);
|
|
331
278
|
asyncInstrument.addCallback(observer => {
|
|
332
279
|
for (const [queueName, value] of counterData[aspect].entries()) {
|
|
333
280
|
observer.observe(value, { queue: queueName });
|
|
@@ -366,7 +313,7 @@ function makeInboundQueueMetrics(metricMeter, initialLengths, logger) {
|
|
|
366
313
|
// (the latter is necessary for backwards compatibility until all old
|
|
367
314
|
// consumers of e.g. slog entries have been updated).
|
|
368
315
|
const entries = [];
|
|
369
|
-
for (const [
|
|
316
|
+
for (const [aspect, { name }] of Object.entries(inboundQueueMeta)) {
|
|
370
317
|
let sum = 0;
|
|
371
318
|
for (const [queueName, value] of counterData[aspect].entries()) {
|
|
372
319
|
sum += value;
|
|
@@ -395,37 +342,27 @@ export function exportKernelStats({
|
|
|
395
342
|
attributes = {},
|
|
396
343
|
initialQueueLengths = /** @type {any} */ ({}),
|
|
397
344
|
}) {
|
|
398
|
-
|
|
399
|
-
const kernelStatsCounters = new Map();
|
|
345
|
+
/** @type {Set<string>} */
|
|
400
346
|
const expectedKernelStats = new Set();
|
|
347
|
+
/** @type {Map<string, ObservableCounter | ObservableUpDownCounter>} */
|
|
348
|
+
const kernelStatsCounters = new Map();
|
|
401
349
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
log.warn(`Unexpected SwingSet kernel statistic`, key);
|
|
405
|
-
expectedKernelStats.add(key);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
let kernelStatsLast = 0;
|
|
410
|
-
let kernelStatsCache = {};
|
|
411
|
-
const getKernelStats = () => {
|
|
412
|
-
const now = Date.now();
|
|
413
|
-
if (now - kernelStatsLast < 800) {
|
|
414
|
-
return kernelStatsCache;
|
|
415
|
-
}
|
|
416
|
-
kernelStatsLast = now;
|
|
417
|
-
kernelStatsCache = controller.getStats();
|
|
418
|
-
for (const key of Object.keys(kernelStatsCache)) {
|
|
419
|
-
warnUnexpectedKernelStat(key);
|
|
420
|
-
}
|
|
421
|
-
return kernelStatsCache;
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
for (const { key, name, sub, ...options } of KERNEL_STATS_SUM_METRICS) {
|
|
350
|
+
for (const meta of KERNEL_STATS_METRICS) {
|
|
351
|
+
const { key, name, sub, metricType, ...options } = meta;
|
|
425
352
|
expectedKernelStats.add(key);
|
|
353
|
+
if (metricType === 'gauge') {
|
|
354
|
+
expectedKernelStats.add(`${key}Up`);
|
|
355
|
+
expectedKernelStats.add(`${key}Down`);
|
|
356
|
+
expectedKernelStats.add(`${key}Max`);
|
|
357
|
+
} else if (metricType !== 'counter') {
|
|
358
|
+
Fail`Unknown metric type ${metricType}`;
|
|
359
|
+
}
|
|
426
360
|
let counter = kernelStatsCounters.get(name);
|
|
427
361
|
if (!counter) {
|
|
428
|
-
counter =
|
|
362
|
+
counter =
|
|
363
|
+
metricType === 'counter'
|
|
364
|
+
? metricMeter.createObservableCounter(name, options)
|
|
365
|
+
: metricMeter.createObservableUpDownCounter(name, options);
|
|
429
366
|
kernelStatsCounters.set(name, counter);
|
|
430
367
|
}
|
|
431
368
|
const reportedAttributes = { ...attributes };
|
|
@@ -435,30 +372,27 @@ export function exportKernelStats({
|
|
|
435
372
|
counter.addCallback(observableResult => {
|
|
436
373
|
observableResult.observe(getKernelStats()[key], reportedAttributes);
|
|
437
374
|
});
|
|
438
|
-
kernelStatsMetrics.add(key);
|
|
439
375
|
}
|
|
440
376
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
expectedKernelStats.
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
377
|
+
const getKernelStats = maxAgeCache(() => {
|
|
378
|
+
const stats = controller.getStats();
|
|
379
|
+
|
|
380
|
+
const notYetFoundKernelStats = new Set(expectedKernelStats.keys());
|
|
381
|
+
for (const key of Object.keys(stats)) {
|
|
382
|
+
notYetFoundKernelStats.delete(key);
|
|
383
|
+
if (!expectedKernelStats.has(key)) {
|
|
384
|
+
log.warn('Unexpected SwingSet kernel statistic', key);
|
|
385
|
+
expectedKernelStats.add(key);
|
|
386
|
+
}
|
|
450
387
|
}
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
reportedAttributes[sub.dimension] = sub.value;
|
|
388
|
+
for (const key of notYetFoundKernelStats) {
|
|
389
|
+
log.warn('Expected SwingSet kernel statistic not found', key);
|
|
454
390
|
}
|
|
455
|
-
counter.addCallback(observableResult => {
|
|
456
|
-
observableResult.observe(getKernelStats()[key], reportedAttributes);
|
|
457
|
-
});
|
|
458
|
-
kernelStatsMetrics.add(key);
|
|
459
|
-
}
|
|
460
391
|
|
|
461
|
-
|
|
392
|
+
return stats;
|
|
393
|
+
}, 800).get;
|
|
394
|
+
|
|
395
|
+
// These are not kernel stats, they're outside the kernel.
|
|
462
396
|
const inboundQueueMetrics = makeInboundQueueMetrics(
|
|
463
397
|
metricMeter,
|
|
464
398
|
initialQueueLengths,
|
|
@@ -468,18 +402,11 @@ export function exportKernelStats({
|
|
|
468
402
|
// TODO: We probably shouldn't roll our own Node.js process metrics, but a
|
|
469
403
|
// cursory search for "opentelemetry node.js VM instrumentation" didn't reveal
|
|
470
404
|
// anything useful.
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
heapStatsLast = now;
|
|
477
|
-
heapStatsCache = v8.getHeapStatistics();
|
|
478
|
-
}
|
|
479
|
-
return heapStatsCache;
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
for (const key of Object.keys(heapStatsCache)) {
|
|
405
|
+
const cachingHeapStats = maxAgeCache(() => v8.getHeapStatistics(), 800);
|
|
406
|
+
const getHeapStats = cachingHeapStats.get;
|
|
407
|
+
// DEPRECATED: This should be equivalent to the "heapStats" data of
|
|
408
|
+
// "cosmic-swingset-end-block-finish" slog entries.
|
|
409
|
+
for (const key of Object.keys(cachingHeapStats.firstResult)) {
|
|
483
410
|
const name = `heapStats_${key}`;
|
|
484
411
|
const options = { description: 'v8 kernel heap statistic' };
|
|
485
412
|
const counter = metricMeter.createObservableUpDownCounter(name, options);
|
|
@@ -488,18 +415,11 @@ export function exportKernelStats({
|
|
|
488
415
|
});
|
|
489
416
|
}
|
|
490
417
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
memoryUsageLast = now;
|
|
497
|
-
memoryUsageCache = process.memoryUsage();
|
|
498
|
-
}
|
|
499
|
-
return memoryUsageCache;
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
for (const key of Object.keys(memoryUsageCache)) {
|
|
418
|
+
const cachingMemUsage = maxAgeCache(() => process.memoryUsage(), 800);
|
|
419
|
+
const getMemoryUsage = cachingMemUsage.get;
|
|
420
|
+
// DEPRECATED: This should be equivalent to the "memStats" data of
|
|
421
|
+
// "cosmic-swingset-end-block-finish" slog entries.
|
|
422
|
+
for (const key of Object.keys(cachingMemUsage.firstResult)) {
|
|
503
423
|
const name = `memoryUsage_${key}`;
|
|
504
424
|
const options = { description: 'kernel process memory statistic' };
|
|
505
425
|
const counter = metricMeter.createObservableUpDownCounter(name, options);
|
|
@@ -508,31 +428,23 @@ export function exportKernelStats({
|
|
|
508
428
|
});
|
|
509
429
|
}
|
|
510
430
|
|
|
511
|
-
function checkKernelStats(stats) {
|
|
512
|
-
const notYetFoundKernelStats = new Set(kernelStatsMetrics.keys());
|
|
513
|
-
for (const key of Object.keys(stats)) {
|
|
514
|
-
notYetFoundKernelStats.delete(key);
|
|
515
|
-
warnUnexpectedKernelStat(key);
|
|
516
|
-
}
|
|
517
|
-
for (const key of notYetFoundKernelStats) {
|
|
518
|
-
log.warn(`Expected SwingSet kernel statistic`, key, `not found`);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// We check everything on initialization. Other checks happen when scraping.
|
|
523
|
-
checkKernelStats(controller.getStats());
|
|
524
|
-
|
|
525
431
|
const [schedulerCrankTimeHistogram, schedulerBlockTimeHistogram] = [
|
|
526
432
|
'swingset_crank_processing_time',
|
|
527
433
|
'swingset_block_processing_seconds',
|
|
528
434
|
].map(name => createHistogram(metricMeter, name));
|
|
529
435
|
|
|
530
436
|
/**
|
|
437
|
+
* @deprecated Histogram measurements produced by this function should be
|
|
438
|
+
* equivalent to the "seconds" data of slog entries
|
|
439
|
+
* (schedulerCrankTimeHistogram via "crank-finish" entries;
|
|
440
|
+
* schedulerBlockTimeHistogram via "cosmic-swingset-run-finish" entries--and
|
|
441
|
+
* note that the latter name is inaccurate anyway because its measurements
|
|
442
|
+
* are produced once per `controller.run()` rather than once per block).
|
|
531
443
|
* @param {any} policy
|
|
532
|
-
* @param {() => number}
|
|
444
|
+
* @param {() => number} msClock
|
|
533
445
|
*/
|
|
534
|
-
async function crankScheduler(policy,
|
|
535
|
-
let now =
|
|
446
|
+
async function crankScheduler(policy, msClock = () => Date.now()) {
|
|
447
|
+
let now = msClock();
|
|
536
448
|
let crankStart = now;
|
|
537
449
|
const blockStart = now;
|
|
538
450
|
|
|
@@ -542,20 +454,20 @@ export function exportKernelStats({
|
|
|
542
454
|
const go = policy.crankComplete(details);
|
|
543
455
|
schedulerCrankTimeHistogram.record(now - crankStart, attributes);
|
|
544
456
|
crankStart = now;
|
|
545
|
-
now =
|
|
457
|
+
now = msClock();
|
|
546
458
|
return go;
|
|
547
459
|
},
|
|
548
460
|
});
|
|
549
461
|
await controller.run(instrumentedPolicy);
|
|
550
462
|
|
|
551
|
-
now =
|
|
463
|
+
now = msClock();
|
|
552
464
|
schedulerBlockTimeHistogram.record((now - blockStart) / 1000, attributes);
|
|
553
465
|
}
|
|
554
466
|
|
|
555
467
|
return {
|
|
556
468
|
crankScheduler,
|
|
469
|
+
getHeapStats,
|
|
470
|
+
getMemoryUsage,
|
|
557
471
|
inboundQueueMetrics,
|
|
558
|
-
schedulerCrankTimeHistogram,
|
|
559
|
-
schedulerBlockTimeHistogram,
|
|
560
472
|
};
|
|
561
473
|
}
|