Skip to content

Commit

Permalink
Merge pull request #7235 from Agoric/refactor-start-xsnap
Browse files Browse the repository at this point in the history
refactor startXSnap
  • Loading branch information
mergify[bot] authored Mar 24, 2023
2 parents 33ffd7b + 9b5dff0 commit 7a6e197
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 134 deletions.
8 changes: 2 additions & 6 deletions packages/SwingSet/misc-tools/replay-transcript.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { makeSnapStore } from '@agoric/swing-store';
import { entryPaths as lockdownEntryPaths } from '@agoric/xsnap-lockdown/src/paths.js';
import { entryPaths as supervisorEntryPaths } from '@agoric/swingset-xsnap-supervisor/src/paths.js';
import { waitUntilQuiescent } from '../src/lib-nodejs/waitUntilQuiescent.js';
import { makeStartXSnap } from '../src/controller/controller.js';
import { makeStartXSnap } from '../src/controller/startXSnap.js';
import { makeXsSubprocessFactory } from '../src/kernel/vat-loader/manager-subprocess-xsnap.js';
import { makeLocalVatManagerFactory } from '../src/kernel/vat-loader/manager-local.js';
import { requireIdentical } from '../src/kernel/vat-loader/transcript.js';
Expand Down Expand Up @@ -152,10 +152,6 @@ async function replay(transcriptFile) {
JSON.parse(fs.readFileSync('lockdown-bundle')),
JSON.parse(fs.readFileSync('supervisor-bundle')),
];
const env = {};
if (RECORD_XSNAP_TRACE) {
env.XSNAP_TEST_RECORD = process.cwd();
}

const capturePIDSpawn = (...args) => {
const child = spawn(...args);
Expand All @@ -164,8 +160,8 @@ async function replay(transcriptFile) {
};
const startXSnap = makeStartXSnap(bundles, {
snapStore,
env,
spawn: capturePIDSpawn,
workerTraceRootPath: RECORD_XSNAP_TRACE ? process.cwd() : undefined,
});
factory = makeXsSubprocessFactory({
kernelKeeper: fakeKernelKeeper,
Expand Down
1 change: 1 addition & 0 deletions packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"lint:eslint": "eslint ."
},
"devDependencies": {
"@endo/far": "^0.2.14",
"@types/better-sqlite3": "^7.5.0",
"@types/microtime": "^2.1.0",
"@types/tmp": "^0.2.0",
Expand Down
89 changes: 3 additions & 86 deletions packages/SwingSet/src/controller/controller.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
/* global globalThis, WeakRef, FinalizationRegistry */
/* eslint-disable @typescript-eslint/prefer-ts-expect-error -- https://github.com/Agoric/agoric-sdk/issues/4620 */

import fs from 'fs';
import path from 'path';
import process from 'process';
import crypto from 'crypto';
import { performance } from 'perf_hooks';
import { spawn as ambientSpawn } from 'child_process';
import { type as osType } from 'os';
import anylogger from 'anylogger';
import microtime from 'microtime';

import { assert, Fail } from '@agoric/assert';
import { importBundle } from '@endo/import-bundle';
import { xsnap, recordXSnap } from '@agoric/xsnap';
import { initSwingStore } from '@agoric/swing-store';

import { checkBundle } from '@endo/check-bundle/lite.js';
Expand All @@ -27,8 +23,7 @@ import {
swingsetIsInitialized,
initializeSwingset,
} from './initializeSwingset.js';

const NETSTRING_MAX_CHUNK_SIZE = 12_000_000;
import { makeStartXSnap } from './startXSnap.js';

/** @param {Uint8Array} bytes */
export function computeSha512(bytes) {
Expand Down Expand Up @@ -77,85 +72,6 @@ function unhandledRejectionHandler(e, pr) {
console.error('UnhandledPromiseRejectionWarning:', e);
}

/**
* @param {{ moduleFormat: string, source: string }[]} bundles
* @param {{
* snapStore?: SnapStore,
* spawn: typeof import('child_process').spawn
* env: Record<string, string | undefined>,
* }} opts
*/
export function makeStartXSnap(bundles, { snapStore, env, spawn }) {
/** @type { import('@agoric/xsnap/src/xsnap').XSnapOptions } */
const xsnapOpts = {
os: osType(),
spawn,
stdout: 'inherit',
stderr: 'inherit',
debug: !!env.XSNAP_DEBUG,
netstringMaxChunkSize: NETSTRING_MAX_CHUNK_SIZE,
};

let doXSnap = xsnap;
const { XSNAP_TEST_RECORD } = env;
if (XSNAP_TEST_RECORD) {
console.log('SwingSet xs-worker tracing:', { XSNAP_TEST_RECORD });
let serial = 0;
doXSnap = opts => {
const workerTrace =
path.resolve(`${XSNAP_TEST_RECORD}/${serial}`) + path.sep;
serial += 1;
fs.mkdirSync(workerTrace, { recursive: true });
return recordXSnap(opts, workerTrace, {
writeFileSync: fs.writeFileSync,
});
};
}

/**
* @param {string} vatID
* @param {string} name
* @param {(request: Uint8Array) => Promise<Uint8Array>} handleCommand
* @param {boolean} [metered]
* @param {boolean} [reload]
*/
async function startXSnap(
vatID,
name,
handleCommand,
metered,
reload = false,
) {
const meterOpts = metered ? {} : { meteringLimit: 0 };
if (snapStore && reload) {
// console.log('startXSnap from', { snapshotHash });
return snapStore.loadSnapshot(vatID, async snapshot => {
const xs = doXSnap({
snapshot,
name,
handleCommand,
...meterOpts,
...xsnapOpts,
});
await xs.isReady();
return xs;
});
}
// console.log('fresh xsnap', { snapStore: snapStore });
const worker = doXSnap({ handleCommand, name, ...meterOpts, ...xsnapOpts });

for (const bundle of bundles) {
bundle.moduleFormat === 'getExport' ||
bundle.moduleFormat === 'nestedEvaluate' ||
Fail`unexpected: ${bundle.moduleFormat}`;
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
await worker.evaluate(`(${bundle.source}\n)()`.trim());
}
return worker;
}
return startXSnap;
}

/**
*
* @param {SwingStoreKernelStorage} kernelStorage
Expand Down Expand Up @@ -272,8 +188,9 @@ export async function makeSwingsetController(
];
const startXSnap = makeStartXSnap(bundles, {
snapStore: kernelStorage.snapStore,
env,
spawn,
debug: !!env.XSNAP_DEBUG,
workerTraceRootPath: env.XSNAP_TEST_RECORD,
});

const kernelEndowments = {
Expand Down
8 changes: 7 additions & 1 deletion packages/SwingSet/src/controller/initializeKernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ function makeVatRootObjectSlot() {
return makeVatSlot('object', true, 0);
}

export function initializeKernel(config, kernelStorage, verbose = false) {
export async function initializeKernel(config, kernelStorage, options = {}) {
const { verbose = false } = options;
const logStartup = verbose ? console.debug : () => 0;
insistStorageAPI(kernelStorage.kvStore);

Expand Down Expand Up @@ -156,6 +157,10 @@ export function initializeKernel(config, kernelStorage, verbose = false) {

// ----------------------------------------------------------------------

/**
* @param {import('../types-internal.js').VatID} bootstrapVatID
* @returns {string} the KPID of the bootstrap message result promise
*/
function enqueueBootstrap(bootstrapVatID) {
// we invoke obj[0].bootstrap with an object that contains 'vats'.
insistVatID(bootstrapVatID);
Expand Down Expand Up @@ -212,6 +217,7 @@ export function initializeKernel(config, kernelStorage, verbose = false) {
const args = kunser(m.serialize(harden([vatObj0s, deviceObj0s])));
const rootKref = exportRootObject(kernelKeeper, bootstrapVatID);
const resultKpid = queueToKref(rootKref, 'bootstrap', args, 'panic');
assert(resultKpid); // appease tsc: 'panic' ensures a kpid is returned
kernelKeeper.incrementRefCount(resultKpid, 'external');
return resultKpid;
}
Expand Down
6 changes: 5 additions & 1 deletion packages/SwingSet/src/controller/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ function sortObjectProperties(obj, firsts = []) {
* @param {SwingStoreKernelStorage} kernelStorage
* @param {InitializationOptions} initializationOptions
* @param {{ env?: Record<string, string | undefined > }} runtimeOptions
* @returns {Promise<string | undefined>} KPID of the bootstrap message result promise
*/
export async function initializeSwingset(
config,
Expand Down Expand Up @@ -573,5 +574,8 @@ export async function initializeSwingset(
if (verbose) {
kdebugEnable(true);
}
return initializeKernel(kconfig, kernelStorage);

// returns the kpid of the bootstrap() result
const bootKpid = await initializeKernel(kconfig, kernelStorage);
return bootKpid;
}
95 changes: 95 additions & 0 deletions packages/SwingSet/src/controller/startXSnap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import fs from 'fs';
import path from 'path';
import { Fail } from '@agoric/assert';
import { type as osType } from 'os';
import { xsnap, recordXSnap } from '@agoric/xsnap';

const NETSTRING_MAX_CHUNK_SIZE = 12_000_000;

/**
* @param {{ moduleFormat: string, source: string }[]} bundles
* @param {{
* snapStore?: SnapStore,
* spawn: typeof import('child_process').spawn
* debug?: boolean,
* workerTraceRootPath?: string,
* }} options
*/
export function makeStartXSnap(bundles, options) {
// our job is to simply curry some authorities and settings into the
// 'startXSnap' function we return
const { snapStore, spawn, debug = false, workerTraceRootPath } = options;

let doXSnap = xsnap;

if (workerTraceRootPath) {
let serial = 0;
const makeNextTraceDir = () => {
const rel = `${workerTraceRootPath}/${serial}`;
const workerTrace = path.resolve(rel) + path.sep;
serial += 1;
return workerTrace;
};
doXSnap = opts => {
const workerTraceDir = makeNextTraceDir();
console.log('SwingSet xs-worker tracing:', { workerTraceDir });
fs.mkdirSync(workerTraceDir, { recursive: true });
return recordXSnap(opts, workerTraceDir, {
writeFileSync: fs.writeFileSync,
});
};
}

/** @type { import('@agoric/xsnap/src/xsnap').XSnapOptions } */
const xsnapOpts = {
os: osType(),
spawn,
stdout: 'inherit',
stderr: 'inherit',
debug,
netstringMaxChunkSize: NETSTRING_MAX_CHUNK_SIZE,
};

/**
* @param {string} vatID
* @param {string} name
* @param {(request: Uint8Array) => Promise<Uint8Array>} handleCommand
* @param {boolean} [metered]
* @param {boolean} [reload]
*/
async function startXSnap(
vatID,
name,
handleCommand,
metered,
reload = false,
) {
const meterOpts = metered ? {} : { meteringLimit: 0 };
if (snapStore && reload) {
// console.log('startXSnap from', { snapshotHash });
return snapStore.loadSnapshot(vatID, async snapshot => {
const xs = doXSnap({
snapshot,
name,
handleCommand,
...meterOpts,
...xsnapOpts,
});
await xs.isReady();
return xs;
});
}
// console.log('fresh xsnap', { snapStore: snapStore });
const worker = doXSnap({ handleCommand, name, ...meterOpts, ...xsnapOpts });

for (const bundle of bundles) {
bundle.moduleFormat === 'getExport' ||
bundle.moduleFormat === 'nestedEvaluate' ||
Fail`unexpected: ${bundle.moduleFormat}`;
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
await worker.evaluate(`(${bundle.source}\n)()`.trim());
}
return worker;
}
return startXSnap;
}
2 changes: 1 addition & 1 deletion packages/SwingSet/test/bundling/test-bundles-kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { initializeKernel } from '../../src/controller/initializeKernel.js';
test('install bundle', async t => {
const endowments = makeKernelEndowments();
const { kvStore } = endowments.kernelStorage;
initializeKernel({}, endowments.kernelStorage);
await initializeKernel({}, endowments.kernelStorage);
const kernel = buildKernel(endowments, {}, {});
await kernel.start(); // empty queue

Expand Down
6 changes: 3 additions & 3 deletions packages/SwingSet/test/test-abandon-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { extractMethod } from '../src/lib/kdebug.js';
import { makeKernelEndowments, buildDispatch } from './util.js';
import { kser, kunser, kslot } from '../src/lib/kmarshal.js';

const makeKernel = () => {
const makeKernel = async () => {
const endowments = makeKernelEndowments();
const { kvStore } = endowments.kernelStorage;
initializeKernel({}, endowments.kernelStorage);
await initializeKernel({}, endowments.kernelStorage);
const kernel = buildKernel(endowments, {}, {});
return { kernel, kvStore };
};
Expand Down Expand Up @@ -77,7 +77,7 @@ async function doAbandon(t, reachable) {
// vatB abandons it
// vatA should retain the object
// sending to the abandoned object should get an error
const { kernel, kvStore } = makeKernel();
const { kernel, kvStore } = await makeKernel();
await kernel.start();

const {
Expand Down
8 changes: 4 additions & 4 deletions packages/SwingSet/test/test-gc-kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ function makeEndowments() {
};
}

function makeKernel() {
async function makeKernel() {
const endowments = makeEndowments();
const { kvStore } = endowments.kernelStorage;
initializeKernel({}, endowments.kernelStorage);
await initializeKernel({}, endowments.kernelStorage);
const kernel = buildKernel(endowments, {}, {});
return { kernel, kvStore };
}
Expand Down Expand Up @@ -110,7 +110,7 @@ async function prep(t, options = {}) {
sendToBob = true,
sendPromiseToCarol = true,
} = options;
const { kernel, kvStore } = makeKernel();
const { kernel, kvStore } = await makeKernel();
await kernel.start();

const vrefs = {}; // track vrefs within vats
Expand Down Expand Up @@ -549,7 +549,7 @@ test('mode24B', async t => {
});

test('retire before drop is error', async t => {
const { kernel } = makeKernel();
const { kernel } = await makeKernel();
await kernel.start();

const amyForAlice = 'o+101';
Expand Down
Loading

0 comments on commit 7a6e197

Please sign in to comment.