Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwingSet benchmarking tool, phase 1 #8239

Merged
merged 9 commits into from
Aug 29, 2023
5 changes: 1 addition & 4 deletions packages/SwingSet/src/controller/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,7 @@ export async function loadSwingsetConfigFile(configPath) {
await null;
try {
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
const referrer = new URL(
configPath,
`file:///${process.cwd()}/`,
).toString();
const referrer = new URL(configPath, `file://${process.cwd()}/`).toString();
FUDCo marked this conversation as resolved.
Show resolved Hide resolved
await normalizeConfigDescriptor(config.vats, referrer, true);
await normalizeConfigDescriptor(config.bundles, referrer, false);
// await normalizeConfigDescriptor(config.devices, referrer, true); // TODO: represent devices
Expand Down
8 changes: 5 additions & 3 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,8 @@ export default function buildKernel(
*/
async function processDeliveryMessage(message) {
kdebug('');
kdebug(`processQ ${JSON.stringify(message)}`);
// prettier-ignore
kdebug(`processQ crank ${kernelKeeper.getCrankNumber()} ${JSON.stringify(message)}`);
kdebug(legibilizeMessage(message));
kernelSlog.write({
type: 'crank-start',
Expand Down Expand Up @@ -1366,8 +1367,9 @@ export default function buildKernel(
*/
async function processAcceptanceMessage(message) {
kdebug('');
kdebug(`processAcceptanceQ ${JSON.stringify(message)}`);
kdebug(legibilizeMessage(message));
// prettier-ignore
kdebug(`processAcceptanceQ crank ${kernelKeeper.getCrankNumber()} ${message.type}`);
// kdebug(legibilizeMessage(message));
kernelSlog.write({
type: 'crank-start',
crankType: 'routing',
Expand Down
11 changes: 10 additions & 1 deletion packages/boot/test/bootstrapTests/bench-vaults-performance.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const collateralBrandKey = 'ATOM';

const makeDefaultTestContext = async t => {
console.time('DefaultTestContext');
const swingsetTestKit = await makeSwingsetTestKit(t);
const swingsetTestKit = await makeSwingsetTestKit(t, 'bundles/vaults');

const { runUtils, storage } = swingsetTestKit;
console.timeLog('DefaultTestContext', 'swingsetTestKit');
Expand Down Expand Up @@ -129,6 +129,15 @@ async function stressVaults(t, dumpHeap) {

const { walletFactoryDriver } = t.context;
const wd = await walletFactoryDriver.provideSmartWallet('agoric1open');
await walletFactoryDriver.provideSmartWallet(
'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce',
);
await walletFactoryDriver.provideSmartWallet(
'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang',
);
await walletFactoryDriver.provideSmartWallet(
'agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h',
);

/**
* @param {number} i
Expand Down
85 changes: 85 additions & 0 deletions packages/boot/test/bootstrapTests/bench-vaults-stripped.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// This is a version of bench-vaults-performance.js that has had all intrinsic
// performance measurement code stripped out of it, purely implementing the
// vault benchmark test code in expectation of extrinsic measurement.

import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';

import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
import { makeAgoricNamesRemotesFromFakeStorage } from '@agoric/vats/tools/board-utils.js';
import { makeSwingsetTestKit } from './supports.js';
import { makeWalletFactoryDriver } from './drivers.js';

// presently all these tests use one collateral manager
const collateralBrandKey = 'ATOM';

const makeDefaultTestContext = async t => {
const swingsetTestKit = await makeSwingsetTestKit(t);

const { runUtils, storage: chainStorage } = swingsetTestKit;
const { EV } = runUtils;

// Wait for ATOM to make it into agoricNames
// E(bootstrap).consumeItem('vaultFactoryKit');
await EV.vat('bootstrap').consumeItem('vaultFactoryKit');

// has to be late enough for agoricNames data to have been published
const agoricNamesRemotes =
makeAgoricNamesRemotesFromFakeStorage(chainStorage);

const walletFactoryDriver = await makeWalletFactoryDriver(
runUtils,
chainStorage,
agoricNamesRemotes,
);

return { ...swingsetTestKit, walletFactoryDriver };
};

/** @type {import('ava').TestFn<Awaited<ReturnType<makeDefaultTestContext>>>} */
const test = unknownTest;

test.before(async t => {
t.context = await makeDefaultTestContext(t);
});
test.after.always(t => t.context.shutdown());

test.serial('stress vaults', async t => {
const { walletFactoryDriver } = t.context;
await walletFactoryDriver.provideSmartWallet(
'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce',
);
await walletFactoryDriver.provideSmartWallet(
'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang',
);
await walletFactoryDriver.provideSmartWallet(
'agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h',
);

const wd = await walletFactoryDriver.provideSmartWallet('agoric1open');

const openVault = async (i, n) => {
const offerId = `open-vault-${i}-of-${n}`;
await wd.executeOfferMaker(Offers.vaults.OpenVault, {
offerId,
collateralBrandKey,
wantMinted: 5,
giveCollateral: 1.0,
});

t.like(wd.getLatestUpdateRecord(), {
updated: 'offerStatus',
status: { id: offerId, numWantsSatisfied: 1 },
});
};

const openN = async n => {
const range = [...Array(n)].map((_, i) => i + 1);
await Promise.all(range.map(i => openVault(i, n)));
};

await openN(1);
await eventLoopIteration();
t.pass();
});
2 changes: 1 addition & 1 deletion packages/boot/test/bootstrapTests/supports.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ export const makeSwingsetTestKit = async (
bridgeOutbound,
kernelStorage,
configPath,
{},
[],
FUDCo marked this conversation as resolved.
Show resolved Hide resolved
{},
{ debugName: 'TESTBOOT' },
);
Expand Down
3 changes: 0 additions & 3 deletions packages/inter-protocol/src/proposals/addAssetToVault.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,7 @@ export const getManifestForAddAssetToVault = (
consume: {
bankManager: true,
agoricNamesAdmin: true,
bankMints: true,
reserveKit: true,
vBankKits: true,
FUDCo marked this conversation as resolved.
Show resolved Hide resolved
startUpgradable: true,
},
produce: { bankMints: true, vBankKits: true },
Expand All @@ -310,7 +308,6 @@ export const getManifestForAddAssetToVault = (
startUpgradable: true,
priceAuthorityAdmin: true,
priceAuthority: true,
scaledPriceAuthorityKits: true,
},
produce: {
scaledPriceAuthorityKits: true,
Expand Down
34 changes: 16 additions & 18 deletions packages/inter-protocol/src/proposals/committee-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ export const inviteCommitteeMembers = async (
const distributeInvitations = async addrInvitations => {
await Promise.all(
addrInvitations.map(async ([addr, invitationP]) => {
await reserveThenDeposit(
`econ committee member ${addr}`,
namesByAddressAdmin,
addr,
[invitationP],
);
const debugName = `econ committee member ${addr}`;
await reserveThenDeposit(debugName, namesByAddressAdmin, addr, [
invitationP,
]).catch(err => console.error(`failed deposit to ${debugName}`, err));
if (highPrioritySendersManager) {
await E(highPrioritySendersManager).add(
EC_HIGH_PRIORITY_SENDERS_NAMESPACE,
Expand All @@ -46,7 +44,9 @@ export const inviteCommitteeMembers = async (
);
};

await distributeInvitations(zip(values(voterAddresses), invitations));
// This doesn't resolve until the committee members create their smart wallets.
// Don't block bootstrap on it.
void distributeInvitations(zip(values(voterAddresses), invitations));
};

harden(inviteCommitteeMembers);
Expand Down Expand Up @@ -135,15 +135,15 @@ export const inviteToEconCharter = async (
) => {
const { creatorFacet } = E.get(econCharterKit);

await Promise.all(
values(voterAddresses).map(async addr =>
reserveThenDeposit(
`econ charter member ${addr}`,
namesByAddressAdmin,
addr,
[E(creatorFacet).makeCharterMemberInvitation()],
),
),
// This doesn't resolve until the committee members create their smart wallets.
// Don't block bootstrap on it.
void Promise.all(
values(voterAddresses).map(async addr => {
const debugName = `econ charter member ${addr}`;
reserveThenDeposit(debugName, namesByAddressAdmin, addr, [
E(creatorFacet).makeCharterMemberInvitation(),
]).catch(err => console.error(`failed deposit to ${debugName}`, err));
}),
);
};

Expand Down Expand Up @@ -176,8 +176,6 @@ export const getManifestForInviteCommittee = async (
[addGovernorsToEconCharter.name]: {
consume: {
auctioneerKit: t,
reserveGovernorCreatorFacet: t,
vaultFactoryGovernorCreator: t,
econCharterKit: t,
zoe: t,
agoricNames: t,
Expand Down
15 changes: 7 additions & 8 deletions packages/inter-protocol/src/proposals/price-feed-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,16 +218,16 @@ export const createPriceFeed = async (
*/
const addOracle = async addr => {
const invitation = await E(faKit.creatorFacet).makeOracleInvitation(addr);
await reserveThenDeposit(
`${AGORIC_INSTANCE_NAME} member ${addr}`,
namesByAddressAdmin,
addr,
[invitation],
);
const debugName = `${AGORIC_INSTANCE_NAME} member ${addr}`;
await reserveThenDeposit(debugName, namesByAddressAdmin, addr, [
invitation,
]).catch(err => console.error(`failed deposit to ${debugName}`, err));
};

trace('distributing invitations', oracleAddresses);
await Promise.all(oracleAddresses.map(addOracle));
// This doesn't resolve until oracle operators create their smart wallets.
// Don't block bootstrap on it.
void Promise.all(oracleAddresses.map(addOracle));
trace('createPriceFeed complete');
};

Expand All @@ -252,7 +252,6 @@ export const getManifestForPriceFeed = async (
chainStorage: t,
chainTimerService: t,
client: t,
contractGovernor: t,
econCharterKit: t,
economicCommitteeCreatorFacet: t,
highPrioritySendersManager: t,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ test.serial('admin price', async t => {
[operatorAddress],
);
const wallet = oracleWallets[operatorAddress];
await eventLoopIteration();
const adminOfferId = await acceptInvitation(wallet, governedPriceAggregator);

// Push a new price result /////////////////////////
Expand Down Expand Up @@ -300,6 +301,7 @@ test.serial('errors', async t => {
const { oracleWallets, governedPriceAggregator: priceAggregator } =
await setupFeedWithWallets(t, [operatorAddress]);
const wallet = oracleWallets[operatorAddress];
await eventLoopIteration();
const adminOfferId = await acceptInvitation(wallet, priceAggregator);

// TODO move to smart-wallet package when it has sufficient test supports
Expand Down
108 changes: 108 additions & 0 deletions packages/swingset-runner/demo/vaultPerfTest/vat-benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// In-swingset implementation of the vault performance benchmark from
// packages/boot/test/bootstrapTests/bench-vaults-performance.js
//
// Run with:
//
// runner --usebundlecache --chain --sbench demo/vaultPerfTest/vat-benchmark.js --benchmark ${ROUNDS} --config ../vm-config/decentral-itest-vaults-config.json run
//
// NOTE: The above incantation assumes running from the root directory of the
// swingset-runner package. If running from elsewhere, adjust the paths to
// vat-benchmark.js driver and the JSON config file (and possibly the runner
// itself, if it's not on your $PATH) accordingly.

import { E } from '@endo/eventual-send';
import { Far } from '@endo/marshal';
import { assert } from '@agoric/assert';

import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';

const log = console.log;

const collateralBrandKey = 'ATOM';

export function buildRootObject() {
let benchmarkRounds = 0;
let wallet;
let walletOffersFacet;
let brand;
let subscriber;

return Far('root', {
async setup(vats, devices) {
// XXX TODO: Some of this setup logic will be common to perhaps many
// benchmarks. The common portions should be factored out into a
// benchmark support library as we learn from experience which are the
// common parts and which are the benchmark-specific parts

log(
`benchmark setup(${JSON.stringify(vats)}, ${JSON.stringify(devices)})`,
);
await E(vats.bootstrap).consumeItem('vaultFactoryKit');

const walletFactoryStartResult = await E(vats.bootstrap).consumeItem(
'walletFactoryStartResult',
);
const agoricNames = await E(vats.bootstrap).consumeItem('agoricNames');
const atomBrand = await E(agoricNames).lookup('brand', 'ATOM');
const istBrand = await E(agoricNames).lookup('brand', 'IST');
brand = {
ATOM: atomBrand,
IST: istBrand,
};

const bankManager = await E(vats.bootstrap).consumeItem('bankManager');
const namesByAddressAdmin = await E(vats.bootstrap).consumeItem(
'namesByAddressAdmin',
);

async function provideSmartWallet(walletAddress) {
const bank = await E(bankManager).getBankForAddress(walletAddress);
return E(walletFactoryStartResult.creatorFacet)
.provideSmartWallet(walletAddress, bank, namesByAddressAdmin)
.then(([walletPresence]) => walletPresence);
}

await provideSmartWallet('agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce');
await provideSmartWallet('agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang');
await provideSmartWallet('agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h');
wallet = await provideSmartWallet('agoric1open');
walletOffersFacet = await E(wallet).getOffersFacet();

const topics = await E(wallet).getPublicTopics();
subscriber = topics.updates.subscriber;
},
async runBenchmarkRound() {
benchmarkRounds += 1;
log(`runBenchmarkRound #${benchmarkRounds}`);

const openVault = async (i, n) => {
const offerId = `open-vault-${i}-of-${n}-round-${benchmarkRounds}`;
const offer = Offers.vaults.OpenVault(
{ brand },
{
offerId,
collateralBrandKey,
wantMinted: 5,
giveCollateral: 1.0,
},
);

await E(walletOffersFacet).executeOffer(offer);

const upd = await E(subscriber).getUpdateSince();
assert(
upd.value.updated === 'offerStatus' &&
upd.value.status.id === offerId &&
upd.value.status.numWantsSatisfied === 1,
);
};

const openN = async n => {
const range = [...Array(n)].map((_, i) => i + 1);
await Promise.all(range.map(i => openVault(i, n)));
};

await openN(1);
},
});
}
Loading
Loading