Skip to content

Commit 84fa8c9

Browse files
authored
fix(xs-worker): respect !managerOptions.metered (#3078)
* fix(xs-worker): respect metered from managerOptions * test(xsnap): meter details are still available with no limit * feat(swingset): allow caller to supply spawn power ... and use it to test that unmetered XS vats are spawned without the `-l` metering option.
1 parent 97f39fa commit 84fa8c9

File tree

4 files changed

+62
-9
lines changed

4 files changed

+62
-9
lines changed

packages/SwingSet/src/controller.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import path from 'path';
55
import process from 'process';
66
import re2 from 're2';
77
import { performance } from 'perf_hooks';
8-
import { spawn } from 'child_process';
8+
import { spawn as ambientSpawn } from 'child_process';
99
import { type as osType } from 'os';
1010
import { Worker } from 'worker_threads';
1111
import anylogger from 'anylogger';
@@ -46,9 +46,13 @@ function unhandledRejectionHandler(e) {
4646

4747
/**
4848
* @param {{ moduleFormat: string, source: string }[]} bundles
49-
* @param {{ snapstorePath?: string, env: Record<string, string | undefined> }} opts
49+
* @param {{
50+
* snapstorePath?: string,
51+
* spawn: typeof import('child_process').spawn
52+
* env: Record<string, string | undefined>,
53+
* }} opts
5054
*/
51-
export function makeStartXSnap(bundles, { snapstorePath, env }) {
55+
export function makeStartXSnap(bundles, { snapstorePath, env, spawn }) {
5256
/** @type { import('@agoric/xsnap/src/xsnap').XSnapOptions } */
5357
const xsnapOpts = {
5458
os: osType(),
@@ -79,16 +83,18 @@ export function makeStartXSnap(bundles, { snapstorePath, env }) {
7983
/**
8084
* @param {string} name
8185
* @param {(request: Uint8Array) => Promise<Uint8Array>} handleCommand
86+
* @param { boolean } [metered]
8287
*/
83-
async function startXSnap(name, handleCommand) {
88+
async function startXSnap(name, handleCommand, metered) {
8489
if (supervisorHash) {
8590
return snapStore.load(supervisorHash, async snapshot => {
8691
const xs = xsnap({ snapshot, name, handleCommand, ...xsnapOpts });
8792
await xs.evaluate('null'); // ensure that spawn is done
8893
return xs;
8994
});
9095
}
91-
const worker = xsnap({ handleCommand, name, ...xsnapOpts });
96+
const meterOpts = metered ? {} : { meteringLimit: 0 };
97+
const worker = xsnap({ handleCommand, name, ...meterOpts, ...xsnapOpts });
9298

9399
for (const bundle of bundles) {
94100
assert(
@@ -117,6 +123,7 @@ export function makeStartXSnap(bundles, { snapstorePath, env }) {
117123
* slogFile?: string,
118124
* testTrackDecref?: unknown,
119125
* snapstorePath?: string,
126+
* spawn?: typeof import('child_process').spawn,
120127
* env?: Record<string, string | undefined>
121128
* }} runtimeOptions
122129
*/
@@ -137,6 +144,7 @@ export async function makeSwingsetController(
137144
slogCallbacks,
138145
slogFile,
139146
snapstorePath,
147+
spawn = ambientSpawn,
140148
} = runtimeOptions;
141149
if (typeof Compartment === 'undefined') {
142150
throw Error('SES must be installed before calling makeSwingsetController');
@@ -271,7 +279,7 @@ export async function makeSwingsetController(
271279
// @ts-ignore assume supervisorBundle is set
272280
JSON.parse(hostStorage.get('supervisorBundle')),
273281
];
274-
const startXSnap = makeStartXSnap(bundles, { snapstorePath, env });
282+
const startXSnap = makeStartXSnap(bundles, { snapstorePath, env, spawn });
275283

276284
const kernelEndowments = {
277285
waitUntilQuiescent,

packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const decoder = new TextDecoder();
2020
* allVatPowers: VatPowers,
2121
* kernelKeeper: KernelKeeper,
2222
* kernelSlog: KernelSlog,
23-
* startXSnap: (name: string, handleCommand: SyncHandler) => Promise<XSnap>,
23+
* startXSnap: (name: string, handleCommand: SyncHandler, metered?: boolean) => Promise<XSnap>,
2424
* testLog: (...args: unknown[]) => void,
2525
* }} tools
2626
* @returns { VatManagerFactory }
@@ -53,6 +53,7 @@ export function makeXsSubprocessFactory({
5353
virtualObjectCacheSize,
5454
enableDisavow,
5555
name,
56+
metered,
5657
} = managerOptions;
5758
assert(
5859
!managerOptions.enableSetup,
@@ -101,7 +102,7 @@ export function makeXsSubprocessFactory({
101102
}
102103

103104
// start the worker and establish a connection
104-
const worker = await startXSnap(`${vatID}:${name}`, handleCommand);
105+
const worker = await startXSnap(`${vatID}:${name}`, handleCommand, metered);
105106

106107
/** @type { (item: Tagged) => Promise<CrankResults> } */
107108
async function issueTagged(item) {

packages/SwingSet/test/test-controller.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
import { test } from '../tools/prepare-test-env-ava';
44

55
import path from 'path';
6+
import { spawn } from 'child_process';
67
import { initSwingStore } from '@agoric/swing-store-simple';
7-
import { buildVatController, loadBasedir } from '../src/index';
8+
import {
9+
buildVatController,
10+
loadBasedir,
11+
makeSwingsetController,
12+
} from '../src/index';
13+
import { initializeSwingset } from '../src/initializeSwingset';
814
import { checkKT } from './util';
915

1016
function capdata(body, slots = []) {
@@ -117,6 +123,28 @@ test('XS bootstrap', async t => {
117123
);
118124
});
119125

126+
test('static vats are unmetered on XS', async t => {
127+
const hostStorage = initSwingStore().storage;
128+
const config = await loadBasedir(
129+
path.resolve(__dirname, 'basedir-controller-2'),
130+
);
131+
config.defaultManagerType = 'xs-worker';
132+
await initializeSwingset(config, [], hostStorage);
133+
const limited = [];
134+
const c = await makeSwingsetController(
135+
hostStorage,
136+
{},
137+
{
138+
spawn(command, args, options) {
139+
limited.push(args.includes('-l'));
140+
return spawn(command, args, options);
141+
},
142+
},
143+
);
144+
t.deepEqual(c.dump().log, ['bootstrap called']);
145+
t.deepEqual(limited, [false, false, false]);
146+
});
147+
120148
test('validate config.defaultManagerType', async t => {
121149
const config = await loadBasedir(
122150
path.resolve(__dirname, 'basedir-controller-2'),

packages/xsnap/test/test-xs-perf.js

+16
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ test('meter details', async t => {
7171
t.is(meterType, 'xs-meter-7');
7272
});
7373

74+
test('meter details are still available with no limit', async t => {
75+
const opts = options();
76+
const vat = xsnap({ ...opts, meteringLimit: 0 });
77+
t.teardown(() => vat.terminate());
78+
const result = await vat.evaluate(`
79+
for (ix = 0; ix < 200; ix++) {
80+
}
81+
`);
82+
const { meterUsage: meters } = result;
83+
t.log(meters);
84+
t.is(typeof meters.compute, 'number');
85+
t.is(typeof meters.allocate, 'number');
86+
t.true(meters.compute > 0);
87+
t.true(meters.allocate > 0);
88+
});
89+
7490
test('high resolution timer', async t => {
7591
const opts = options();
7692
const vat = xsnap(opts);

0 commit comments

Comments
 (0)