@agoric/swingset-vat 0.33.0-u19.2 → 0.33.0-u21.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/package.json +38 -36
- package/src/controller/controller.js +424 -330
- package/src/controller/startNodeSubprocess.js +6 -0
- package/src/controller/upgradeSwingset.js +2 -4
- package/src/devices/bridge/device-bridge.js +2 -0
- package/src/devices/timer/device-timer.js +41 -22
- package/src/kernel/kernel.js +79 -17
- package/src/kernel/slogger.js +109 -35
- package/src/kernel/state/deviceKeeper.js +4 -3
- package/src/kernel/state/kernelKeeper.js +39 -31
- package/src/kernel/state/stats.js +12 -9
- package/src/kernel/state/storageHelper.js +7 -2
- package/src/kernel/state/vatKeeper.js +5 -3
- package/src/kernel/vat-warehouse.js +22 -11
- package/src/lib/capdata.js +4 -17
- package/src/lib/message.js +4 -0
- package/src/types-external.js +33 -9
- package/src/vats/plugin-manager.js +3 -9
- package/src/vats/timer/vat-timer.js +12 -5
- package/src/vats/vat-admin/vat-vat-admin.js +2 -2
- package/tools/manual-timer.js +3 -2
- package/tools/run-utils.js +2 -1
- package/src/kernel/metrics.js +0 -152
|
@@ -13,6 +13,12 @@ export function makeStartSubprocessWorkerNode(
|
|
|
13
13
|
).pathname;
|
|
14
14
|
const args = nodeOptions ? [...nodeOptions] : [];
|
|
15
15
|
if (profileVats.includes(vatID)) {
|
|
16
|
+
// Enable profiling with a 1 microsecond sampling interval,
|
|
17
|
+
// saving results to a file in the working directory
|
|
18
|
+
// with a portable name derived from the vat name
|
|
19
|
+
// and in particular replacing any colons with dashes.
|
|
20
|
+
// cf. ../kernel/vat-loader/manager-subprocess-node.js
|
|
21
|
+
// https://github.com/Agoric/agoric-sdk/blob/18d561f1b95755e58ca691b26938fc249618018d/packages/SwingSet/src/kernel/vat-loader/manager-subprocess-node.js#L32-L34
|
|
16
22
|
args.push('--cpu-prof');
|
|
17
23
|
args.push('--cpu-prof-interval');
|
|
18
24
|
args.push('1');
|
|
@@ -285,11 +285,9 @@ export const upgradeSwingset = kernelStorage => {
|
|
|
285
285
|
|
|
286
286
|
const buggyKPIDs = []; // [kpid, vatID]
|
|
287
287
|
for (const vatID of allVatIDs) {
|
|
288
|
-
const prefix = `${vatID}.c.`;
|
|
289
|
-
const len = prefix.length;
|
|
290
288
|
const ckpPrefix = `${vatID}.c.kp`;
|
|
291
|
-
for (const
|
|
292
|
-
const kpid =
|
|
289
|
+
for (const { suffix } of enumeratePrefixedKeys(kvStore, ckpPrefix)) {
|
|
290
|
+
const kpid = `kp${suffix}`;
|
|
293
291
|
if (isSettled(kpid)) {
|
|
294
292
|
const n = notifies.get(kpid);
|
|
295
293
|
if (!n || !n.includes(vatID)) {
|
|
@@ -86,6 +86,7 @@ function makeTimerMap(state = undefined) {
|
|
|
86
86
|
return copyState(schedule);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/** @param {bigint} time */
|
|
89
90
|
function eventsFor(time) {
|
|
90
91
|
assert.typeof(time, 'bigint');
|
|
91
92
|
for (let i = 0; i < schedule.length && schedule[i].time <= time; i += 1) {
|
|
@@ -101,17 +102,29 @@ function makeTimerMap(state = undefined) {
|
|
|
101
102
|
// There's some question as to whether it's important to invoke the handlers
|
|
102
103
|
// in the order of their deadlines. If so, we should probably ensure that the
|
|
103
104
|
// recorded deadlines don't have finer granularity than the turns.
|
|
104
|
-
|
|
105
|
+
/**
|
|
106
|
+
*
|
|
107
|
+
* @param {bigint} time
|
|
108
|
+
* @param {Waker} handler
|
|
109
|
+
* @param {number} [index]
|
|
110
|
+
* @returns {bigint}
|
|
111
|
+
*/
|
|
112
|
+
function add(time, handler, index = undefined) {
|
|
105
113
|
assert.typeof(time, 'bigint');
|
|
114
|
+
/** @type {IndexedHandler} */
|
|
106
115
|
const handlerRecord =
|
|
107
|
-
typeof
|
|
116
|
+
typeof index === 'number' ? { handler, index } : { handler };
|
|
108
117
|
const { handlers: records } = eventsFor(time);
|
|
109
118
|
records.push(handlerRecord);
|
|
110
119
|
schedule.sort((a, b) => Number(a.time - b.time));
|
|
111
120
|
return time;
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Remove and return all pairs indexed by numbers up to target
|
|
125
|
+
*
|
|
126
|
+
* @param {bigint} target
|
|
127
|
+
*/
|
|
115
128
|
function removeEventsThrough(target) {
|
|
116
129
|
assert.typeof(target, 'bigint');
|
|
117
130
|
const returnValues = [];
|
|
@@ -132,33 +145,29 @@ function makeTimerMap(state = undefined) {
|
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
// We don't expect this to be called often, so we don't optimize for it.
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
* @param {Waker} targetHandler
|
|
151
|
+
* @returns {bigint[]} times that have been removed (may contain duplicates)
|
|
152
|
+
*/
|
|
135
153
|
function remove(targetHandler) {
|
|
154
|
+
/** @type {bigint[]} */
|
|
136
155
|
const droppedTimes = [];
|
|
137
156
|
let i = 0;
|
|
138
157
|
while (i < schedule.length) {
|
|
139
158
|
const { time, handlers } = schedule[i];
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
159
|
+
// Nothing prevents a particular handler from appearing more than once
|
|
160
|
+
for (let j = handlers.length - 1; j >= 0; j -= 1) {
|
|
161
|
+
if (handlers[j].handler === targetHandler) {
|
|
162
|
+
handlers.splice(j, 1);
|
|
143
163
|
droppedTimes.push(time);
|
|
144
|
-
} else {
|
|
145
|
-
i += 1;
|
|
146
164
|
}
|
|
165
|
+
}
|
|
166
|
+
if (handlers.length === 0) {
|
|
167
|
+
// Splice out this element, preserving `i` so we visit any successor.
|
|
168
|
+
schedule.splice(i, 1);
|
|
147
169
|
} else {
|
|
148
|
-
|
|
149
|
-
for (const { handler } of handlers) {
|
|
150
|
-
// @ts-expect-error xxx Waker vs IndexedHandler
|
|
151
|
-
if (handler === targetHandler && handlers.indexOf(handler) !== -1) {
|
|
152
|
-
// @ts-expect-error xxx Waker vs IndexedHandler
|
|
153
|
-
handlers.splice(handlers.indexOf(handler), 1);
|
|
154
|
-
droppedTimes.push(time);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (handlers.length === 0) {
|
|
158
|
-
schedule.splice(i, 1);
|
|
159
|
-
} else {
|
|
160
|
-
i += 1;
|
|
161
|
-
}
|
|
170
|
+
i += 1;
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
return droppedTimes;
|
|
@@ -223,6 +232,7 @@ export function buildRootDeviceNode(tools) {
|
|
|
223
232
|
// The latest time poll() was called. This might be a block height or it
|
|
224
233
|
// might be a time from Date.now(). The current time is not reflected back
|
|
225
234
|
// to the user.
|
|
235
|
+
/** @type {bigint} */
|
|
226
236
|
let lastPolled = restart ? restart.lastPolled : 0n;
|
|
227
237
|
let nextRepeater = restart ? restart.nextRepeater : 0;
|
|
228
238
|
|
|
@@ -276,6 +286,10 @@ export function buildRootDeviceNode(tools) {
|
|
|
276
286
|
saveState();
|
|
277
287
|
return baseTime;
|
|
278
288
|
},
|
|
289
|
+
/**
|
|
290
|
+
* @param {Waker} handler
|
|
291
|
+
* @returns {bigint[]} times that have been removed (may contain duplicates)
|
|
292
|
+
*/
|
|
279
293
|
removeWakeup(handler) {
|
|
280
294
|
const times = deadlines.remove(handler);
|
|
281
295
|
saveState();
|
|
@@ -303,6 +317,10 @@ export function buildRootDeviceNode(tools) {
|
|
|
303
317
|
saveState();
|
|
304
318
|
return index;
|
|
305
319
|
},
|
|
320
|
+
/**
|
|
321
|
+
* @param {number} index
|
|
322
|
+
* @param {Waker} handler
|
|
323
|
+
*/
|
|
306
324
|
schedule(index, handler) {
|
|
307
325
|
const nextTime = nextScheduleTime(index, repeaters, lastPolled);
|
|
308
326
|
deadlines.add(nextTime, handler, index);
|
|
@@ -311,6 +329,7 @@ export function buildRootDeviceNode(tools) {
|
|
|
311
329
|
},
|
|
312
330
|
});
|
|
313
331
|
}
|
|
332
|
+
/** @typedef {import('../../types-external.js').Device<ReturnType<typeof buildRootDeviceNode>>} TimerDevice */
|
|
314
333
|
|
|
315
334
|
// exported for testing. Only buildRootDeviceNode is intended for production
|
|
316
335
|
// use.
|
package/src/kernel/kernel.js
CHANGED
|
@@ -99,6 +99,7 @@ export default function buildKernel(
|
|
|
99
99
|
startSubprocessWorkerNode,
|
|
100
100
|
startXSnap,
|
|
101
101
|
writeSlogObject,
|
|
102
|
+
slogDuration,
|
|
102
103
|
WeakRef,
|
|
103
104
|
FinalizationRegistry,
|
|
104
105
|
gcAndFinalize,
|
|
@@ -111,11 +112,12 @@ export default function buildKernel(
|
|
|
111
112
|
overrideVatManagerOptions = {},
|
|
112
113
|
} = kernelRuntimeOptions;
|
|
113
114
|
const logStartup = verbose ? console.debug : () => {};
|
|
115
|
+
if (verbose) kdebugEnable(true);
|
|
114
116
|
|
|
115
117
|
const vatAdminRootKref = kernelStorage.kvStore.get('vatAdminRootKref');
|
|
116
118
|
|
|
117
119
|
const kernelSlog = writeSlogObject
|
|
118
|
-
? makeSlogger(slogCallbacks, writeSlogObject)
|
|
120
|
+
? makeSlogger(slogCallbacks, writeSlogObject, slogDuration)
|
|
119
121
|
: makeDummySlogger(slogCallbacks, makeConsole('disabled slogger'));
|
|
120
122
|
|
|
121
123
|
const kernelKeeper = makeKernelKeeper(
|
|
@@ -559,6 +561,10 @@ export default function buildKernel(
|
|
|
559
561
|
*/
|
|
560
562
|
async function processSend(vatID, target, msg) {
|
|
561
563
|
insistMessage(msg);
|
|
564
|
+
// DEPRECATED: These counts are available as "crank-start"/"crank-finish"
|
|
565
|
+
// slog entries with crankType "delivery" (the latter count filtered on
|
|
566
|
+
// messageType "send") and "deliver"/"deliver-result" slog entries (the
|
|
567
|
+
// latter count filtered on dispatch "message").
|
|
562
568
|
kernelKeeper.incStat('dispatches');
|
|
563
569
|
kernelKeeper.incStat('dispatchDeliver');
|
|
564
570
|
|
|
@@ -589,6 +595,8 @@ export default function buildKernel(
|
|
|
589
595
|
const { vatID, kpid } = message;
|
|
590
596
|
insistVatID(vatID);
|
|
591
597
|
insistKernelType('promise', kpid);
|
|
598
|
+
// DEPRECATED: This count is available as "crank-start"/"crank-finish"
|
|
599
|
+
// slog entries with crankType "delivery".
|
|
592
600
|
kernelKeeper.incStat('dispatches');
|
|
593
601
|
const vatInfo = vatWarehouse.lookup(vatID);
|
|
594
602
|
if (!vatInfo) {
|
|
@@ -598,6 +606,8 @@ export default function buildKernel(
|
|
|
598
606
|
const { meterID } = vatInfo;
|
|
599
607
|
|
|
600
608
|
const p = kernelKeeper.getKernelPromise(kpid);
|
|
609
|
+
// DEPRECATED: This count is available as "deliver"/"deliver-result" slog
|
|
610
|
+
// entries with dispatch "notify".
|
|
601
611
|
kernelKeeper.incStat('dispatchNotify');
|
|
602
612
|
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
603
613
|
if (p.state === 'unresolved') {
|
|
@@ -1342,14 +1352,15 @@ export default function buildKernel(
|
|
|
1342
1352
|
* @returns {Promise<PolicyInput>}
|
|
1343
1353
|
*/
|
|
1344
1354
|
async function processDeliveryMessage(message) {
|
|
1355
|
+
const messageType = message.type;
|
|
1345
1356
|
kdebug('');
|
|
1346
1357
|
// prettier-ignore
|
|
1347
1358
|
kdebug(`processQ crank ${kernelKeeper.getCrankNumber()} ${JSON.stringify(message)}`);
|
|
1348
1359
|
kdebug(legibilizeMessage(message));
|
|
1349
|
-
kernelSlog.
|
|
1350
|
-
type: 'crank-start',
|
|
1360
|
+
const finish = kernelSlog.startDuration(['crank-start', 'crank-finish'], {
|
|
1351
1361
|
crankType: 'delivery',
|
|
1352
1362
|
crankNum: kernelKeeper.getCrankNumber(),
|
|
1363
|
+
messageType,
|
|
1353
1364
|
message,
|
|
1354
1365
|
});
|
|
1355
1366
|
/** @type { PolicyInput } */
|
|
@@ -1451,12 +1462,8 @@ export default function buildKernel(
|
|
|
1451
1462
|
const crankNum = kernelKeeper.getCrankNumber();
|
|
1452
1463
|
kernelKeeper.incrementCrankNumber();
|
|
1453
1464
|
const { crankhash, activityhash } = kernelKeeper.emitCrankHashes();
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
// stats: kernelKeeper.getStats(),
|
|
1457
|
-
// });
|
|
1458
|
-
kernelSlog.write({
|
|
1459
|
-
type: 'crank-finish',
|
|
1465
|
+
finish({
|
|
1466
|
+
message: undefined,
|
|
1460
1467
|
crankNum,
|
|
1461
1468
|
crankhash,
|
|
1462
1469
|
activityhash,
|
|
@@ -1494,14 +1501,15 @@ export default function buildKernel(
|
|
|
1494
1501
|
* @returns {Promise<PolicyInput>}
|
|
1495
1502
|
*/
|
|
1496
1503
|
async function processAcceptanceMessage(message) {
|
|
1504
|
+
const messageType = message.type;
|
|
1497
1505
|
kdebug('');
|
|
1498
1506
|
// prettier-ignore
|
|
1499
|
-
kdebug(`processAcceptanceQ crank ${kernelKeeper.getCrankNumber()} ${
|
|
1507
|
+
kdebug(`processAcceptanceQ crank ${kernelKeeper.getCrankNumber()} ${messageType}`);
|
|
1500
1508
|
// kdebug(legibilizeMessage(message));
|
|
1501
|
-
kernelSlog.
|
|
1502
|
-
type: 'crank-start',
|
|
1509
|
+
const finish = kernelSlog.startDuration(['crank-start', 'crank-finish'], {
|
|
1503
1510
|
crankType: 'routing',
|
|
1504
1511
|
crankNum: kernelKeeper.getCrankNumber(),
|
|
1512
|
+
messageType,
|
|
1505
1513
|
message,
|
|
1506
1514
|
});
|
|
1507
1515
|
/** @type { PolicyInput } */
|
|
@@ -1538,8 +1546,8 @@ export default function buildKernel(
|
|
|
1538
1546
|
const crankNum = kernelKeeper.getCrankNumber();
|
|
1539
1547
|
kernelKeeper.incrementCrankNumber();
|
|
1540
1548
|
const { crankhash, activityhash } = kernelKeeper.emitCrankHashes();
|
|
1541
|
-
|
|
1542
|
-
|
|
1549
|
+
finish({
|
|
1550
|
+
message: undefined,
|
|
1543
1551
|
crankNum,
|
|
1544
1552
|
crankhash,
|
|
1545
1553
|
activityhash,
|
|
@@ -1938,15 +1946,63 @@ export default function buildKernel(
|
|
|
1938
1946
|
}
|
|
1939
1947
|
}
|
|
1940
1948
|
|
|
1941
|
-
|
|
1949
|
+
/** @returns {Generator<VatID>} */
|
|
1950
|
+
function* getAllVatIds() {
|
|
1942
1951
|
for (const [_, vatID] of kernelKeeper.getStaticVats()) {
|
|
1943
|
-
|
|
1952
|
+
yield vatID;
|
|
1944
1953
|
}
|
|
1945
1954
|
for (const vatID of kernelKeeper.getDynamicVats()) {
|
|
1946
|
-
|
|
1955
|
+
yield vatID;
|
|
1947
1956
|
}
|
|
1948
1957
|
}
|
|
1949
1958
|
|
|
1959
|
+
function* getAllVatPosEntries() {
|
|
1960
|
+
for (const vatID of getAllVatIds()) {
|
|
1961
|
+
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
1962
|
+
yield /** @type {const} */ ([
|
|
1963
|
+
vatID,
|
|
1964
|
+
vatKeeper.getTranscriptEndPosition(),
|
|
1965
|
+
]);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
function reapAllVats(previousVatPos = {}) {
|
|
1970
|
+
/** @type {Record<string, number>} */
|
|
1971
|
+
const currentVatPos = {};
|
|
1972
|
+
|
|
1973
|
+
for (const [vatID, endPos] of getAllVatPosEntries()) {
|
|
1974
|
+
const vatUsesTranscript = endPos !== 0;
|
|
1975
|
+
if (!vatUsesTranscript) {
|
|
1976
|
+
// The comms vat is a little special. It doesn't use a transcript,
|
|
1977
|
+
// doesn't implement BOYD, and is created with a never reap threshold.
|
|
1978
|
+
//
|
|
1979
|
+
// Here we conflate a vat that doesn't use a transcript with a vat
|
|
1980
|
+
// that cannot reap. We do not bother checking the vat options because
|
|
1981
|
+
// in tests we would actually like to force reap normal vats that may
|
|
1982
|
+
// have been configured with a never threshold.
|
|
1983
|
+
continue;
|
|
1984
|
+
} else if ((previousVatPos[vatID] ?? 0) < endPos) {
|
|
1985
|
+
kernelKeeper.scheduleReap(vatID);
|
|
1986
|
+
// We just added one delivery
|
|
1987
|
+
currentVatPos[vatID] = endPos + 1;
|
|
1988
|
+
} else {
|
|
1989
|
+
currentVatPos[vatID] = endPos;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
return harden(currentVatPos);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
async function snapshotAllVats() {
|
|
1997
|
+
const snapshottedVats = [];
|
|
1998
|
+
await null;
|
|
1999
|
+
for (const vatID of getAllVatIds()) {
|
|
2000
|
+
const snapshotted = await vatWarehouse.maybeSaveSnapshot(vatID, 2);
|
|
2001
|
+
if (snapshotted) snapshottedVats.push(vatID);
|
|
2002
|
+
}
|
|
2003
|
+
return harden(snapshottedVats);
|
|
2004
|
+
}
|
|
2005
|
+
|
|
1950
2006
|
async function step() {
|
|
1951
2007
|
if (kernelPanic) {
|
|
1952
2008
|
throw kernelPanic;
|
|
@@ -2151,6 +2207,7 @@ export default function buildKernel(
|
|
|
2151
2207
|
run,
|
|
2152
2208
|
shutdown,
|
|
2153
2209
|
reapAllVats,
|
|
2210
|
+
snapshotAllVats,
|
|
2154
2211
|
changeKernelOptions,
|
|
2155
2212
|
|
|
2156
2213
|
// the rest are for testing and debugging
|
|
@@ -2161,6 +2218,11 @@ export default function buildKernel(
|
|
|
2161
2218
|
ephemeral.log.push(`${str}`);
|
|
2162
2219
|
},
|
|
2163
2220
|
|
|
2221
|
+
/**
|
|
2222
|
+
* Return a fresh stats snapshot.
|
|
2223
|
+
*
|
|
2224
|
+
* @returns {Record<string, number>}
|
|
2225
|
+
*/
|
|
2164
2226
|
getStats() {
|
|
2165
2227
|
return kernelKeeper.getStats();
|
|
2166
2228
|
},
|
package/src/kernel/slogger.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { q } from '@endo/errors';
|
|
1
|
+
import { q, Fail } from '@endo/errors';
|
|
2
|
+
import { makePromiseKit } from '@endo/promise-kit';
|
|
2
3
|
import { objectMap } from '@agoric/internal';
|
|
4
|
+
import { defineName } from '@agoric/internal/src/js-utils.js';
|
|
3
5
|
import { makeLimitedConsole } from '@agoric/internal/src/ses-utils.js';
|
|
4
6
|
|
|
5
7
|
/** @import {Callable} from '@agoric/internal'; */
|
|
6
8
|
/** @import {LimitedConsole} from '@agoric/internal/src/js-utils.js'; */
|
|
9
|
+
/** @import {SlogProps, SlogDurationProps, SwingsetController} from '../controller/controller.js'; */
|
|
7
10
|
|
|
8
11
|
const IDLE = 'idle';
|
|
9
12
|
const STARTUP = 'startup';
|
|
@@ -12,7 +15,7 @@ const DELIVERY = 'delivery';
|
|
|
12
15
|
const noopFinisher = harden(() => {});
|
|
13
16
|
|
|
14
17
|
/** @typedef {(...finishArgs: unknown[]) => unknown} AnyFinisher */
|
|
15
|
-
/** @typedef {Partial<Record<Exclude<keyof KernelSlog, 'write'>, (methodName: string, args: unknown[], finisher: AnyFinisher) => unknown>>} SlogWrappers */
|
|
18
|
+
/** @typedef {Partial<Record<Exclude<keyof KernelSlog, 'write' | 'startDuration'>, (methodName: string, args: unknown[], finisher: AnyFinisher) => unknown>>} SlogWrappers */
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Support asynchronous slog callbacks that are invoked at the start
|
|
@@ -96,24 +99,81 @@ export function makeDummySlogger(slogCallbacks, dummyConsole = badConsole) {
|
|
|
96
99
|
changeCList: () => noopFinisher,
|
|
97
100
|
terminateVat: () => noopFinisher,
|
|
98
101
|
});
|
|
99
|
-
return harden({
|
|
102
|
+
return harden({
|
|
103
|
+
...wrappedMethods,
|
|
104
|
+
write: noopFinisher,
|
|
105
|
+
startDuration: () => noopFinisher,
|
|
106
|
+
});
|
|
100
107
|
}
|
|
101
108
|
|
|
109
|
+
/**
|
|
110
|
+
* @callback StartDuration
|
|
111
|
+
* Capture an extended process, writing an entry with `type` $startLabel and
|
|
112
|
+
* then later (when the returned finish function is called) another entry with
|
|
113
|
+
* `type` $endLabel and `seconds` reporting the intervening duration.
|
|
114
|
+
*
|
|
115
|
+
* @param {readonly [startLabel: string, endLabel: string]} labels
|
|
116
|
+
* @param {SlogDurationProps} startProps
|
|
117
|
+
* @returns {import('../types-external').FinishSlogDuration}
|
|
118
|
+
*/
|
|
119
|
+
|
|
102
120
|
/**
|
|
103
121
|
* @param {SlogWrappers} slogCallbacks
|
|
104
|
-
* @param {
|
|
122
|
+
* @param {SwingsetController['writeSlogObject']} [writeSlogObject]
|
|
123
|
+
* @param {SwingsetController['slogDuration']} [slogDuration] required when writeSlogObject is provided
|
|
105
124
|
* @returns {KernelSlog}
|
|
106
125
|
*/
|
|
107
|
-
export function makeSlogger(slogCallbacks,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
export function makeSlogger(slogCallbacks, writeSlogObject, slogDuration) {
|
|
127
|
+
if (writeSlogObject && !slogDuration) {
|
|
128
|
+
throw Fail`slogDuration is required with writeSlogObject`;
|
|
129
|
+
}
|
|
130
|
+
const { safeWrite, startDuration } = (() => {
|
|
131
|
+
if (!writeSlogObject) {
|
|
132
|
+
const dummySafeWrite = () => {};
|
|
133
|
+
/** @type {StartDuration} */
|
|
134
|
+
const dummyStartDuration = () => defineName('dummyFinish', () => {});
|
|
135
|
+
return { safeWrite: dummySafeWrite, startDuration: dummyStartDuration };
|
|
136
|
+
}
|
|
137
|
+
/** @type {(obj: SlogProps) => void} */
|
|
138
|
+
// eslint-disable-next-line no-shadow
|
|
139
|
+
const safeWrite = obj => {
|
|
140
|
+
try {
|
|
141
|
+
writeSlogObject(obj);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.error('WARNING: slogger write error', err);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
/** @type {StartDuration} */
|
|
147
|
+
// eslint-disable-next-line no-shadow
|
|
148
|
+
const startDuration = (labels, startProps) => {
|
|
149
|
+
try {
|
|
150
|
+
/** @type {(extraProps?: SlogDurationProps) => void} */
|
|
151
|
+
let closeSpan;
|
|
152
|
+
// @ts-expect-error TS2722 slogDuration is not undefined here
|
|
153
|
+
void slogDuration(labels, startProps, async finish => {
|
|
154
|
+
const doneKit = makePromiseKit();
|
|
155
|
+
closeSpan = props => {
|
|
156
|
+
try {
|
|
157
|
+
finish(props);
|
|
158
|
+
} finally {
|
|
159
|
+
doneKit.resolve(undefined);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
// Hold the span open until `finish` is called.
|
|
163
|
+
await doneKit.promise;
|
|
164
|
+
});
|
|
165
|
+
// @ts-expect-error TS2454 closeSpan must have been assigned above
|
|
166
|
+
if (typeof closeSpan !== 'function') {
|
|
167
|
+
throw Fail`slogDuration did not synchronously provide a finisher`;
|
|
114
168
|
}
|
|
169
|
+
return closeSpan;
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error('WARNING: slogger write error', err);
|
|
172
|
+
return defineName('dummyFinish', () => {});
|
|
115
173
|
}
|
|
116
|
-
|
|
174
|
+
};
|
|
175
|
+
return { safeWrite, startDuration };
|
|
176
|
+
})();
|
|
117
177
|
|
|
118
178
|
const vatSlogs = new Map(); // vatID -> vatSlog
|
|
119
179
|
|
|
@@ -149,15 +209,17 @@ export function makeSlogger(slogCallbacks, writeObj) {
|
|
|
149
209
|
|
|
150
210
|
function startup() {
|
|
151
211
|
// provide a context for console calls during startup
|
|
152
|
-
checkOldState(IDLE, '
|
|
212
|
+
checkOldState(IDLE, 'vat-startup called twice?');
|
|
153
213
|
state = STARTUP;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
214
|
+
const finish = startDuration(
|
|
215
|
+
['vat-startup-start', 'vat-startup-finish'],
|
|
216
|
+
{ vatID },
|
|
217
|
+
);
|
|
218
|
+
return harden(() => {
|
|
219
|
+
checkOldState(STARTUP, 'vat-startup-finish called twice?');
|
|
157
220
|
state = IDLE;
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
return harden(finish);
|
|
221
|
+
finish();
|
|
222
|
+
});
|
|
161
223
|
}
|
|
162
224
|
|
|
163
225
|
// kd: kernelDelivery, vd: vatDelivery
|
|
@@ -167,32 +229,44 @@ export function makeSlogger(slogCallbacks, writeObj) {
|
|
|
167
229
|
crankNum = newCrankNum;
|
|
168
230
|
deliveryNum = newDeliveryNum;
|
|
169
231
|
replay = inReplay;
|
|
170
|
-
const when = { crankNum, vatID, deliveryNum, replay };
|
|
171
|
-
safeWrite({ type: 'deliver', ...when, kd, vd });
|
|
172
232
|
syscallNum = 0;
|
|
173
|
-
|
|
233
|
+
const dispatch = vd?.[0]; // using vd because kd is undefined in replay
|
|
234
|
+
const finish = startDuration(['deliver', 'deliver-result'], {
|
|
235
|
+
crankNum,
|
|
236
|
+
vatID,
|
|
237
|
+
deliveryNum,
|
|
238
|
+
replay,
|
|
239
|
+
dispatch,
|
|
240
|
+
kd,
|
|
241
|
+
vd,
|
|
242
|
+
});
|
|
174
243
|
// dr: deliveryResult
|
|
175
|
-
|
|
176
|
-
checkOldState(DELIVERY, '
|
|
177
|
-
safeWrite({ type: 'deliver-result', ...when, dr });
|
|
244
|
+
return harden(dr => {
|
|
245
|
+
checkOldState(DELIVERY, 'deliver-result called twice?');
|
|
178
246
|
state = IDLE;
|
|
179
|
-
|
|
180
|
-
|
|
247
|
+
finish({ kd: undefined, vd: undefined, dr });
|
|
248
|
+
});
|
|
181
249
|
}
|
|
182
250
|
|
|
183
251
|
// ksc: kernelSyscallObject, vsc: vatSyscallObject
|
|
184
252
|
function syscall(ksc, vsc) {
|
|
185
253
|
checkOldState(DELIVERY, 'syscall invoked outside of delivery');
|
|
186
|
-
const
|
|
187
|
-
|
|
254
|
+
const finish = startDuration(['syscall', 'syscall-result'], {
|
|
255
|
+
crankNum,
|
|
256
|
+
vatID,
|
|
257
|
+
deliveryNum,
|
|
258
|
+
syscallNum,
|
|
259
|
+
replay,
|
|
260
|
+
syscall: vsc?.[0],
|
|
261
|
+
ksc,
|
|
262
|
+
vsc,
|
|
263
|
+
});
|
|
188
264
|
syscallNum += 1;
|
|
189
|
-
|
|
190
265
|
// ksr: kernelSyscallResult, vsr: vatSyscallResult
|
|
191
|
-
|
|
266
|
+
return harden((ksr, vsr) => {
|
|
192
267
|
checkOldState(DELIVERY, 'syscall finished after delivery?');
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
return harden(finish);
|
|
268
|
+
finish({ ksc: undefined, vsc: undefined, ksr, vsr });
|
|
269
|
+
});
|
|
196
270
|
}
|
|
197
271
|
|
|
198
272
|
// mode: 'import' | 'export' | 'drop'
|
|
@@ -258,5 +332,5 @@ export function makeSlogger(slogCallbacks, writeObj) {
|
|
|
258
332
|
terminateVat: (vatID, ...args) =>
|
|
259
333
|
provideVatSlogger(vatID).vatSlog.terminateVat(...args),
|
|
260
334
|
});
|
|
261
|
-
return harden({ ...wrappedMethods, write: safeWrite });
|
|
335
|
+
return harden({ ...wrappedMethods, write: safeWrite, startDuration });
|
|
262
336
|
}
|
|
@@ -189,11 +189,12 @@ export function makeDeviceKeeper(kvStore, deviceID, tools) {
|
|
|
189
189
|
/** @type {Array<[string, string, string]>} */
|
|
190
190
|
const res = [];
|
|
191
191
|
const prefix = `${deviceID}.c.`;
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
const prefixedKeys = enumeratePrefixedKeys(kvStore, prefix);
|
|
193
|
+
|
|
194
|
+
for (const { key, suffix: slot } of prefixedKeys) {
|
|
194
195
|
if (!slot.startsWith('k')) {
|
|
195
196
|
const devSlot = slot;
|
|
196
|
-
const kernelSlot = kvStore.get(
|
|
197
|
+
const kernelSlot = kvStore.get(key);
|
|
197
198
|
res.push([kernelSlot, deviceID, devSlot]);
|
|
198
199
|
}
|
|
199
200
|
}
|