Skip to content

Commit

Permalink
chore: let makeRunUtils caller provide run policy (#10348)
Browse files Browse the repository at this point in the history
## Description

Support computron measurements in boostrap tests for performance testing by letting `makeRunUtils` caller provide a way to make a run policy.

### Security Considerations

A swingset controller relies on the run policy to be well-behaved. But the caller of `makeRunUtils` can only shoot themselves in the foot.

### Scaling Considerations

helps measure scaling issues

### Documentation Considerations

JSDocs with static types provide adequate docs for an internal tool such as this.

### Testing Considerations

Integration with a couple bootstrap tests is included.
See also #10254 .

### Upgrade Considerations

n/a
  • Loading branch information
mergify[bot] authored Dec 2, 2024
2 parents 963ebe1 + 19ae5da commit 4a76042
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 120 deletions.
15 changes: 11 additions & 4 deletions packages/SwingSet/tools/run-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { Fail, q } from '@endo/errors';
import { kunser } from '@agoric/kmarshal';
import { makeQueue } from '@endo/stream';

/** @import { ERef } from '@endo/far' */
/**
* @import { ERef } from '@endo/far'
* @import { RunPolicy } from '../src/types-external.js'
*/

/** @typedef {{ provideRunPolicy: () => RunPolicy | undefined }} RunPolicyMaker */

/**
* @param {import('../src/controller/controller.js').SwingsetController} controller
* @param {RunPolicyMaker} [perfTool]
*/
export const makeRunUtils = controller => {
export const makeRunUtils = (controller, perfTool) => {
const mutex = makeQueue();
const logRunFailure = reason =>
console.log('controller.run() failure', reason);
Expand All @@ -17,15 +23,16 @@ export const makeRunUtils = controller => {
* Wait for exclusive access to the controller, then before relinquishing that access,
* enqueue and process a delivery and return the result.
*
* @param {() => ERef<void | ReturnType<controller['queueToVatObject']>>} deliveryThunk
* @param {() => ERef<void | ReturnType<typeof controller['queueToVatObject']>>} deliveryThunk
* function for enqueueing a delivery and returning the result kpid (if any)
* @param {boolean} [voidResult] whether to ignore the result
* @returns {Promise<any>}
*/
const queueAndRun = async (deliveryThunk, voidResult = false) => {
await mutex.get();
const kpid = await deliveryThunk();
const runResultP = controller.run();
const runPolicy = perfTool && perfTool.provideRunPolicy();
const runResultP = controller.run(runPolicy);
mutex.put(runResultP.catch(logRunFailure));
await runResultP;

Expand Down
28 changes: 26 additions & 2 deletions packages/boot/test/bootstrapTests/orchestration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@ import {
makeWalletFactoryContext,
type WalletFactoryTestContext,
} from './walletFactory.js';
import {
insistManagerType,
makeRunPolicyProvider,
} from '../../tools/supports.js';

const test: TestFn<WalletFactoryTestContext> = anyTest;
const test: TestFn<
WalletFactoryTestContext & {
perfTool?: ReturnType<typeof makeRunPolicyProvider>;
}
> = anyTest;

const validatorAddress: CosmosValidatorAddress = {
value: 'cosmosvaloper1test',
Expand All @@ -25,11 +33,21 @@ const validatorAddress: CosmosValidatorAddress = {

const ATOM_DENOM = 'uatom';

const {
SLOGFILE: slogFile,
SWINGSET_WORKER_TYPE: defaultManagerType = 'local',
} = process.env;

test.before(async t => {
t.context = await makeWalletFactoryContext(
insistManagerType(defaultManagerType);
const perfTool =
defaultManagerType === 'xsnap' ? makeRunPolicyProvider() : undefined;
const ctx = await makeWalletFactoryContext(
t,
'@agoric/vm-config/decentral-itest-orchestration-config.json',
{ slogFile, defaultManagerType, perfTool },
);
t.context = { ...ctx, perfTool };
});
test.after.always(t => t.context.shutdown?.());

Expand Down Expand Up @@ -105,6 +123,7 @@ test.skip('stakeOsmo - queries', async t => {
buildProposal,
evalProposal,
runUtils: { EV },
perfTool,
} = t.context;
await evalProposal(
buildProposal('@agoric/builders/scripts/orchestration/init-stakeOsmo.js'),
Expand Down Expand Up @@ -143,6 +162,7 @@ test.serial('stakeAtom - smart wallet', async t => {
agoricNamesRemotes,
bridgeUtils: { flushInboundQueue },
readPublished,
perfTool,
} = t.context;

await evalProposal(
Expand All @@ -153,6 +173,7 @@ test.serial('stakeAtom - smart wallet', async t => {
'agoric1testStakAtom',
);

perfTool?.usePolicy(true);
await wd.sendOffer({
id: 'request-account',
invitationSpec: {
Expand All @@ -162,6 +183,9 @@ test.serial('stakeAtom - smart wallet', async t => {
},
proposal: {},
});
perfTool && t.log('makeAccount computrons', perfTool.totalCount());
perfTool?.usePolicy(false);

await flushInboundQueue();
t.like(wd.getCurrentWalletRecord(), {
offerToPublicSubscriberPaths: [
Expand Down
4 changes: 4 additions & 0 deletions packages/boot/test/bootstrapTests/price-feed-replace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ test.serial('setupVaults; run updatePriceFeeds proposals', async t => {
setupVaults,
governanceDriver: gd,
readPublished,
perfTool,
} = t.context;

await setupVaults(collateralBrandKey, managerIndex, setup);
Expand All @@ -74,7 +75,10 @@ test.serial('setupVaults; run updatePriceFeeds proposals', async t => {
roundId: 1n,
});

perfTool && perfTool.usePolicy(true);
await priceFeedDrivers[collateralBrandKey].setPrice(15.99);
perfTool && t.log('setPrice computrons', perfTool.totalCount());
perfTool && perfTool.usePolicy(false);

t.like(readPublished('priceFeed.ATOM-USD_price_feed.latestRound'), {
roundId: 2n,
Expand Down
2 changes: 2 additions & 0 deletions packages/boot/test/bootstrapTests/walletFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { makeWalletFactoryDriver } from '../../tools/drivers.js';
export const makeWalletFactoryContext = async (
t,
configSpecifier = '@agoric/vm-config/decentral-main-vaults-config.json',
opts = {},
) => {
const swingsetTestKit = await makeSwingsetTestKit(t.log, undefined, {
configSpecifier,
...opts,
});

const { runUtils, storage } = swingsetTestKit;
Expand Down
19 changes: 18 additions & 1 deletion packages/boot/tools/liquidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@agoric/vats/tools/board-utils.js';
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
import type { ExecutionContext } from 'ava';
import { insistManagerType, makeRunPolicyProvider } from './supports.js';
import { type SwingsetTestKit, makeSwingsetTestKit } from './supports.js';
import {
type GovernanceDriver,
Expand Down Expand Up @@ -305,13 +306,28 @@ export const makeLiquidationTestKit = async ({
};
};

// asserts x is type doesn't work when using arrow functions
// https://github.com/microsoft/TypeScript/issues/34523
function assertManagerType(specimen: string): asserts specimen is ManagerType {
insistManagerType(specimen);
}

export const makeLiquidationTestContext = async (
t,
io: { env?: Record<string, string | undefined> } = {},
) => {
const { env = {} } = io;
const {
SLOGFILE: slogFile,
SWINGSET_WORKER_TYPE: defaultManagerType = 'local',
} = env;
assertManagerType(defaultManagerType);
const perfTool =
defaultManagerType === 'xsnap' ? makeRunPolicyProvider() : undefined;
const swingsetTestKit = await makeSwingsetTestKit(t.log, undefined, {
slogFile: env.SLOGFILE,
slogFile,
defaultManagerType,
perfTool,
});
console.time('DefaultTestContext');

Expand Down Expand Up @@ -369,6 +385,7 @@ export const makeLiquidationTestContext = async (
refreshAgoricNamesRemotes,
walletFactoryDriver,
governanceDriver,
perfTool,
};
};

Expand Down
53 changes: 52 additions & 1 deletion packages/boot/tools/supports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { Fail } from '@endo/errors';
import {
makeRunUtils,
type RunUtils,
type RunPolicyMaker,
} from '@agoric/swingset-vat/tools/run-utils.js';
import {
boardSlottingMarshaller,
Expand All @@ -47,6 +48,11 @@ import type { BridgeHandler, IBCMethod } from '@agoric/vats';
import type { BootstrapRootObject } from '@agoric/vats/src/core/lib-boot.js';
import type { EProxy } from '@endo/eventual-send';
import type { FastUSDCCorePowers } from '@agoric/fast-usdc/src/fast-usdc.start.js';
import {
defaultBeansPerVatCreation,
defaultBeansPerXsnapComputron,
} from '@agoric/cosmic-swingset/src/sim-params.js';
import { computronCounter } from '@agoric/cosmic-swingset/src/computron-counter.js';
import { icaMocks, protoMsgMockMap, protoMsgMocks } from './ibc/mocks.js';

const trace = makeTracer('BSTSupport', false);
Expand Down Expand Up @@ -77,6 +83,7 @@ type BootstrapEV = EProxy & {

const makeBootstrapRunUtils = makeRunUtils as (
controller: SwingsetController,
perfTool?: RunPolicyMaker,
) => Omit<RunUtils, 'EV'> & { EV: BootstrapEV };

const keysToObject = <K extends PropertyKey, V>(
Expand Down Expand Up @@ -308,6 +315,7 @@ export const matchIter = (t: AvaT, iter, valueRef) => {
* @param [options.profileVats]
* @param [options.debugVats]
* @param [options.defaultManagerType]
* @param [options.perfTool]
*/
export const makeSwingsetTestKit = async (
log: (..._: any[]) => void,
Expand All @@ -321,6 +329,7 @@ export const makeSwingsetTestKit = async (
profileVats = [] as string[],
debugVats = [] as string[],
defaultManagerType = 'local' as ManagerType,
perfTool = undefined as RunPolicyMaker | undefined,
} = {},
) => {
console.time('makeBaseSwingsetTestKit');
Expand Down Expand Up @@ -538,7 +547,7 @@ export const makeSwingsetTestKit = async (

console.timeLog('makeBaseSwingsetTestKit', 'buildSwingset');

const runUtils = makeBootstrapRunUtils(controller);
const runUtils = makeBootstrapRunUtils(controller, perfTool);

const buildProposal = makeProposalExtractor({
childProcess: childProcessAmbient,
Expand Down Expand Up @@ -660,3 +669,45 @@ export const makeSwingsetTestKit = async (
};
};
export type SwingsetTestKit = Awaited<ReturnType<typeof makeSwingsetTestKit>>;

export const makeRunPolicyProvider = () => {
const c2b = defaultBeansPerXsnapComputron;
const beansPerUnit = {
// see https://cosgov.org/agoric?msgType=parameterChangeProposal&network=main
blockComputeLimit: 65_000_000n * c2b,
vatCreation: defaultBeansPerVatCreation,
xsnapComputron: c2b,
};

/** @type {ReturnType<typeof computronCounter> | undefined} */
let policy;
let counting = false;

const meter = harden({
provideRunPolicy: () => {
if (counting && !policy) {
policy = computronCounter({ beansPerUnit });
}
return policy;
},
/** @param {boolean} x */
usePolicy: x => {
counting = x;
if (!counting) {
policy = undefined;
}
},
totalCount: () => (policy?.totalBeans() || 0n) / c2b,
resetPolicy: () => (policy = undefined),
});
return meter;
};

/**
*
* @param {string} mt
* @returns {asserts mt is ManagerType}
*/
export function insistManagerType(mt) {
assert(['local', 'node-subprocess', 'xsnap', 'xs-worker'].includes(mt));
}
Loading

0 comments on commit 4a76042

Please sign in to comment.