Skip to content

Commit

Permalink
Merge pull request #8239 from Agoric/swingset-perf-tool
Browse files Browse the repository at this point in the history
SwingSet benchmarking tool, phase 1
  • Loading branch information
mergify[bot] authored Aug 29, 2023
2 parents 3ce0599 + 9777c3a commit d56e0f7
Show file tree
Hide file tree
Showing 16 changed files with 613 additions and 58 deletions.
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();
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,
{},
[],
{},
{ 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,
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

0 comments on commit d56e0f7

Please sign in to comment.