Skip to content

Commit

Permalink
Merge pull request #7280 from Agoric/7218-vaults-perf
Browse files Browse the repository at this point in the history
test for vaults perf
  • Loading branch information
mergify[bot] authored Mar 30, 2023
2 parents 037fad8 + 3c09849 commit 316deca
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 11 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ lib-cov
coverage
coverage.txt

# nyc test coverage
.nyc_output
# Profiling output
*.heapsnapshot

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
Expand Down
7 changes: 0 additions & 7 deletions packages/inter-protocol/src/clientSupport.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ const makeVaultProposal = (brands, opts) => {
const makeOpenOffer = (brands, opts) => {
const proposal = makeVaultProposal(brands, opts);

console.warn('vaults open give', proposal.give);
console.warn('vaults open want', proposal.want);

// NB: not really a Proposal because the brands are not remotes
// Instead they're copyRecord like "{"boardId":"board0257","iface":"Alleged: IST brand"}" to pass through the boardId
// mustMatch(harden(proposal), ProposalShape);
Expand Down Expand Up @@ -114,7 +111,6 @@ const makeAdjustOffer = (brands, opts, previousOffer) => {
*/
const makeCloseOffer = (brands, opts, previousOffer) => {
const proposal = makeVaultProposal(brands, opts);
console.warn('vaults close give', proposal.give);

return {
id: opts.offerId,
Expand Down Expand Up @@ -192,9 +188,6 @@ const makePsmSwapOffer = (instance, brands, opts) => {
opts.pair[1],
);

console.warn('psm spend give', proposal.give);
console.warn('psm spend want', proposal.want);

// NB: not really a Proposal because the brands are not remotes
// Instead they're copyRecord like "{"boardId":"board0257","iface":"Alleged: IST brand"}" to pass through the boardId
// mustMatch(harden(proposal), ProposalShape);
Expand Down
8 changes: 6 additions & 2 deletions packages/vats/test/bootstrapTests/supports.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ export const makeWalletFactoryDriver = async (
};

export const getNodeTestVaultsConfig = async (
bundleDir,
bundleDir = 'bundles',
specifier = '@agoric/vats/decentral-test-vaults-config.json',
) => {
const fullPath = await importMetaResolve(specifier, import.meta.url).then(
Expand Down Expand Up @@ -290,7 +290,11 @@ export const getNodeTestVaultsConfig = async (
* @param {string} bundleDir directory to write bundles and config to
* @param {string} [specifier] bootstrap config specifier
*/
export const makeSwingsetTestKit = async (t, bundleDir, specifier) => {
export const makeSwingsetTestKit = async (
t,
bundleDir = 'bundles',
specifier,
) => {
console.time('makeSwingsetTestKit');
const configPath = await getNodeTestVaultsConfig(bundleDir, specifier);
const { kernelStorage } = initSwingStore();
Expand Down
176 changes: 176 additions & 0 deletions packages/vats/test/bootstrapTests/test-vaults-performance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// @ts-check
/**
* @file Bootstrap stress test of vaults
*/
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';
import { PerformanceObserver, performance } from 'node:perf_hooks';
import v8 from 'node:v8';
import process from 'node:process';

import { Fail } from '@agoric/assert';
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
import { E } from '@endo/captp';
import engineGC from '@agoric/swingset-vat/src/lib-nodejs/engine-gc.js';

import { eventLoopIteration } from '@agoric/zoe/tools/eventLoopIteration.js';
import { makeAgoricNamesRemotesFromFakeStorage } from '../../tools/board-utils.js';
import { makeSwingsetTestKit, makeWalletFactoryDriver } from './supports.js';

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

let snapshotNum = 0;
const snapshotHeap = async step => {
console.log(`Snapshotting heap at step ${step}...`);
await eventLoopIteration();
try {
const t0 = performance.now();
engineGC();
const t1 = performance.now();
const memoryUsage = process.memoryUsage();
const t2 = performance.now();
const heapStats = v8.getHeapStatistics();
const t3 = performance.now();

// process.pid increments so these will be lexically sorted pathnames.
const heapSnapshot = `Heap-${process.pid}-${snapshotNum}-${step}.heapsnapshot`;
snapshotNum += 1;

v8.writeHeapSnapshot(heapSnapshot);
const heapSnapshotTime = performance.now() - t3;

console.log(`HEAP DETAILS at step${step} vaults: `, {
memoryUsage,
heapStats,
heapSnapshot,
statsTime: {
forcedGc: t1 - t0,
memoryUsage: t2 - t1,
heapStats: t3 - t2,
heapSnapshot: heapSnapshotTime,
},
});
} catch (err) {
console.warn('Failed to gather memory stats', err);
}
};

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

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

const { runUtils, storage } = swingsetTestKit;
console.timeLog('DefaultTestContext', 'swingsetTestKit');
const { EV } = runUtils;

// Wait for IbcATOM to make it into agoricNames
await EV.vat('bootstrap').consumeItem('vaultFactoryKit');
console.timeLog('DefaultTestContext', 'vaultFactoryKit');

// has to be late enough for agoricNames data to have been published
const agoricNamesRemotes = makeAgoricNamesRemotesFromFakeStorage(
swingsetTestKit.storage,
);
agoricNamesRemotes.brand.IbcATOM || Fail`IbcATOM missing from agoricNames`;
console.timeLog('DefaultTestContext', 'agoricNamesRemotes');

const walletFactoryDriver = await makeWalletFactoryDriver(
runUtils,
storage,
agoricNamesRemotes,
);
console.timeLog('DefaultTestContext', 'walletFactoryDriver');

console.timeEnd('DefaultTestContext');

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

test.before(async t => {
t.context = await makeDefaultTestContext(t);
});
test.after(async t => {
// not strictly necessary but conveys that we keep the controller around for the whole test file
await E(t.context.controller).shutdown();
});

const rows = [];
const perfObserver = new PerformanceObserver(items => {
items.getEntries().forEach(entry => {
// @ts-expect-error cast
const { vaultsOpened, round } = entry.detail;
rows.push({
name: `${round}:${vaultsOpened}`,
duration: entry.duration,
avgPerVault: entry.duration / vaultsOpened,
});
});
});
perfObserver.observe({ entryTypes: ['measure'] });

// NB: keep skipped in master because this is too long for CI
// UNTIL: https://github.com/Agoric/agoric-sdk/issues/7279
test.skip('stress vaults', async t => {
const { walletFactoryDriver } = t.context;

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

/**
* @param {number} i
* @param {number} n
* @param {number} r
*/
const openVault = async (i, n, r) => {
assert.typeof(i, 'number');
assert.typeof(n, 'number');
assert.typeof(r, 'number');

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

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

/**
* @param {number} n
* @param {number} r
*/
const openN = async (n, r) => {
t.log(`opening ${n} vaults`);
const range = [...Array(n)].map((_, i) => i + 1);
performance.mark(`start-open`);
await Promise.all(range.map(i => openVault(i, n, r)));
performance.mark(`end-open`);
performance.measure(`open-${n}-round-${r}`, {
start: 'start-open',
end: 'end-open',
detail: { vaultsOpened: n, round: r },
});
};

// clear out for a baseline
await snapshotHeap('start');
// 10 is enough to compare retention in heaps
await openN(10, 1);
await snapshotHeap('round1');
await openN(10, 2);
await snapshotHeap('round2');

// let perfObserver get the last measurement
await eventLoopIteration();

console.table(rows);
});

0 comments on commit 316deca

Please sign in to comment.