Skip to content

Commit

Permalink
feat: add stats collection facility to kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
FUDCo committed May 27, 2020
1 parent a2d8a2c commit 1ea7bb7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ export async function buildVatController(config, withSES = true, argv = []) {
return kernel.step();
},

getStats() {
return kernel.getStats();
},

// these are for tests

vatNameToID(vatName) {
Expand Down
6 changes: 6 additions & 0 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ export default function buildKernel(kernelEndowments) {
throw Error(`unable to process message.type ${message.type}`);
}
kernelKeeper.purgeDeadKernelPromises();
kernelKeeper.saveStats();
commitCrank();
kernelKeeper.incrementCrankNumber();
} finally {
Expand Down Expand Up @@ -748,9 +749,11 @@ export default function buildKernel(kernelEndowments) {
`replayTranscript added run-queue entries, wasn't supposed to`,
);
}
kernelKeeper.loadStats();
}

kernelKeeper.setInitialized();
kernelKeeper.saveStats();
commitCrank(); // commit "crank 0"
kernelKeeper.incrementCrankNumber();
}
Expand Down Expand Up @@ -796,6 +799,9 @@ export default function buildKernel(kernelEndowments) {
ephemeral.log.push(`${str}`);
},

getStats() {
return kernelKeeper.getStats();
},
dump() {
// note: dump().log is not deterministic, since log() does not go
// through the syscall interface (and we replay transcripts one vat at
Expand Down
82 changes: 82 additions & 0 deletions packages/SwingSet/src/kernel/state/kernelKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,68 @@ export default function makeKernelKeeper(storage) {
return storage.get(key);
}

// These are the defined kernel statistics counters. For any counter 'foo'
// that is defined here, if there is also a defined counter named 'fooMax',
// the stats collection machinery will automatically track the latter as a
// high-water mark for the former.
let kernelStats = {
kernelObjects: 0,
kernelDevices: 0,
kernelPromises: 0,
kernelPromisesMax: 0,
kpUnresolved: 0,
kpUnresolvedMax: 0,
kpFulfilledToPresence: 0,
kpFulfilledToPresenceMax: 0,
kpFulfilledToData: 0,
kpFulfilledToDataMax: 0,
kpRejected: 0,
kpRejectedMax: 0,
runQueueLength: 0,
runQueueLengthMax: 0,
syscalls: 0,
syscallSend: 0,
syscallSubscribe: 0,
syscallFulfillToData: 0,
syscallFulfillToPresence: 0,
syscallReject: 0,
syscallCallNow: 0,
dispatches: 0,
dispatchDeliver: 0,
dispatchNotifyFulfillToData: 0,
dispatchNotifyFulfillToPresence: 0,
dispatchReject: 0,
clistEntries: 0,
clistEntriesMax: 0,
};

function incStat(stat) {
kernelStats[stat] += 1;
const maxStat = `${stat}Max`;
if (
kernelStats[maxStat] !== undefined &&
kernelStats[stat] > kernelStats[maxStat]
) {
kernelStats[maxStat] = kernelStats[stat];
}
}

function decStat(stat) {
kernelStats[stat] -= 1;
}

function saveStats() {
storage.set('kernelStats', JSON.stringify(kernelStats));
}

function loadStats() {
kernelStats = JSON.parse(getRequired('kernelStats'));
}

function getStats() {
return { ...kernelStats };
}

const ephemeral = harden({
vatKeepers: new Map(), // vatID -> vatKeeper
deviceKeepers: new Map(), // deviceID -> deviceKeeper
Expand Down Expand Up @@ -142,6 +204,7 @@ export default function makeKernelKeeper(storage) {
storage.set('ko.nextID', `${id + 1}`);
const s = makeKernelSlot('object', id);
storage.set(`${s}.owner`, ownerID);
incStat('kernelObjects');
return s;
}

Expand All @@ -159,6 +222,7 @@ export default function makeKernelKeeper(storage) {
storage.set('kd.nextID', `${id + 1}`);
const s = makeKernelSlot('device', id);
storage.set(`${s}.owner`, deviceID);
incStat('kernelDevices');
return s;
}

Expand All @@ -181,6 +245,8 @@ export default function makeKernelKeeper(storage) {
storage.set(`${s}.queue.nextID`, `0`);
storage.set(`${s}.refCount`, `0`);
// queue is empty, so no state[kp$NN.queue.$NN] keys yet
incStat('kernelPromises');
incStat('kpUnresolved');
return s;
}

Expand Down Expand Up @@ -252,6 +318,8 @@ export default function makeKernelKeeper(storage) {
function fulfillKernelPromiseToPresence(kernelSlot, targetSlot) {
insistKernelType('promise', kernelSlot);
deleteKernelPromiseState(kernelSlot);
decStat('kpUnresolved');
incStat('kpFulfilledToPresence');
storage.set(`${kernelSlot}.state`, 'fulfilledToPresence');
storage.set(`${kernelSlot}.slot`, targetSlot);
}
Expand All @@ -260,6 +328,8 @@ export default function makeKernelKeeper(storage) {
insistKernelType('promise', kernelSlot);
insistCapData(capdata);
deleteKernelPromiseState(kernelSlot);
decStat('kpUnresolved');
incStat('kpFulfilledToData');
storage.set(`${kernelSlot}.state`, 'fulfilledToData');
storage.set(`${kernelSlot}.data.body`, capdata.body);
storage.set(`${kernelSlot}.data.slots`, capdata.slots.join(','));
Expand All @@ -269,6 +339,8 @@ export default function makeKernelKeeper(storage) {
insistKernelType('promise', kernelSlot);
insistCapData(capdata);
deleteKernelPromiseState(kernelSlot);
decStat('kpUnresolved');
incStat('kpRejected');
storage.set(`${kernelSlot}.state`, 'rejected');
storage.set(`${kernelSlot}.data.body`, capdata.body);
storage.set(`${kernelSlot}.data.slots`, capdata.slots.join(','));
Expand Down Expand Up @@ -320,6 +392,7 @@ export default function makeKernelKeeper(storage) {
const queue = JSON.parse(getRequired('runQueue'));
queue.push(msg);
storage.set('runQueue', JSON.stringify(queue));
incStat('runQueueLength');
}

function isRunQueueEmpty() {
Expand All @@ -336,6 +409,7 @@ export default function makeKernelKeeper(storage) {
const queue = JSON.parse(getRequired('runQueue'));
const msg = queue.shift();
storage.set('runQueue', JSON.stringify(queue));
decStat('runQueueLength');
return msg;
}

Expand Down Expand Up @@ -446,6 +520,8 @@ export default function makeKernelKeeper(storage) {
addKernelPromise,
incrementRefCount,
decrementRefCount,
incStat,
decStat,
);
ephemeral.vatKeepers.set(vatID, vk);
}
Expand Down Expand Up @@ -602,6 +678,12 @@ export default function makeKernelKeeper(storage) {
incrementCrankNumber,
purgeDeadKernelPromises,

incStat,
decStat,
saveStats,
loadStats,
getStats,

ownerOfKernelObject,
ownerOfKernelDevice,

Expand Down
5 changes: 5 additions & 0 deletions packages/SwingSet/src/kernel/state/vatKeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export function makeVatKeeper(
addKernelPromise,
incrementRefCount,
decrementRefCount,
incStat,
decStat,
) {
insistVatID(vatID);

Expand Down Expand Up @@ -85,6 +87,7 @@ export function makeVatKeeper(
}
incrementRefCount(kernelSlot, `${vatID}|vk|clist`);
const kernelKey = `${vatID}.c.${kernelSlot}`;
incStat('clistEntries');
storage.set(kernelKey, vatSlot);
storage.set(vatKey, kernelSlot);
kdebug(`Add mapping v->k ${kernelKey}<=>${vatKey}`);
Expand Down Expand Up @@ -132,6 +135,7 @@ export function makeVatKeeper(
const vatSlot = makeVatSlot(type, false, id);

const vatKey = `${vatID}.c.${vatSlot}`;
incStat('clistEntries');
storage.set(vatKey, kernelSlot);
storage.set(kernelKey, vatSlot);
kdebug(`Add mapping k->v ${kernelKey}<=>${vatKey}`);
Expand All @@ -154,6 +158,7 @@ export function makeVatKeeper(
kdebug(`Delete mapping ${kernelKey}<=>${vatKey}`);
if (storage.has(kernelKey)) {
decrementRefCount(kernelSlot, `${vatID}|del|clist`);
decStat('clistEntries');
storage.delete(kernelKey);
storage.delete(vatKey);
}
Expand Down
20 changes: 20 additions & 0 deletions packages/SwingSet/src/kernel/vatManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export default function makeVatManager(
function doSend(targetSlot, method, args, resultSlot) {
assert(`${targetSlot}` === targetSlot, 'non-string targetSlot');
insistCapData(args);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallSend');
// TODO: disable send-to-self for now, qv issue #43
const target = mapVatSlotToKernelSlot(targetSlot);
const argList = legibilizeMessageArgs(args).join(', ');
Expand Down Expand Up @@ -172,11 +174,15 @@ export default function makeVatManager(
if (!kernelKeeper.hasKernelPromise(id)) {
throw new Error(`unknown kernelPromise id '${id}'`);
}
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallSubscribe');
syscallManager.subscribe(vatID, id);
}

function doFulfillToPresence(promiseID, slot) {
insistVatType('promise', promiseID);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallFulfillToPresence');
const kpid = mapVatSlotToKernelSlot(promiseID);
const targetSlot = mapVatSlotToKernelSlot(slot);
kdebug(
Expand All @@ -189,6 +195,8 @@ export default function makeVatManager(
function doFulfillToData(promiseID, data) {
insistVatType('promise', promiseID);
insistCapData(data);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallFulfillToData');
const kpid = mapVatSlotToKernelSlot(promiseID);
const kernelSlots = data.slots.map(slot => mapVatSlotToKernelSlot(slot));
const kernelData = harden({ ...data, slots: kernelSlots });
Expand All @@ -204,6 +212,8 @@ export default function makeVatManager(
function doReject(promiseID, data) {
insistVatType('promise', promiseID);
insistCapData(data);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallReject');
const kpid = mapVatSlotToKernelSlot(promiseID);
const kernelSlots = data.slots.map(slot => mapVatSlotToKernelSlot(slot));
const kernelData = harden({ ...data, slots: kernelSlots });
Expand All @@ -223,6 +233,8 @@ export default function makeVatManager(
if (type !== 'device') {
throw new Error(`doCallNow must target a device, not ${dev}`);
}
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallCallNow');
const kernelSlots = args.slots.map(slot => mapVatSlotToKernelSlot(slot));
const kernelData = harden({ ...args, slots: kernelSlots });
// prettier-ignore
Expand Down Expand Up @@ -371,6 +383,8 @@ export default function makeVatManager(
insistVatType('promise', resultSlot);
kernelKeeper.setDecider(msg.result, vatID);
}
kernelKeeper.incStat('dispatches');
kernelKeeper.incStat('dispatchDeliver');
await doProcess(
[
'deliver',
Expand All @@ -389,6 +403,8 @@ export default function makeVatManager(
const vpid = mapKernelSlotToVatSlot(kpid);
const slot = mapKernelSlotToVatSlot(kp.slot);
vatKeeper.deleteCListEntry(kpid, vpid);
kernelKeeper.incStat('dispatches');
kernelKeeper.incStat('dispatchNotifyFulfillToPresence');
await doProcess(
['notifyFulfillToPresence', vpid, slot],
`vat[${vatID}].promise[${vpid}] fulfillToPresence failed`,
Expand All @@ -402,6 +418,8 @@ export default function makeVatManager(
slots: kp.data.slots.map(slot => mapKernelSlotToVatSlot(slot)),
});
deleteCListEntryIfEasy(kpid, vpid, kp.data);
kernelKeeper.incStat('dispatches');
kernelKeeper.incStat('dispatchNotifyFulfillToData');
await doProcess(
['notifyFulfillToData', vpid, vatData],
`vat[${vatID}].promise[${vpid}] fulfillToData failed`,
Expand All @@ -413,6 +431,8 @@ export default function makeVatManager(
slots: kp.data.slots.map(slot => mapKernelSlotToVatSlot(slot)),
});
deleteCListEntryIfEasy(kpid, vpid, kp.data);
kernelKeeper.incStat('dispatches');
kernelKeeper.incStat('dispatchReject');
await doProcess(
['notifyReject', vpid, vatData],
`vat[${vatID}].promise[${vpid}] reject failed`,
Expand Down

0 comments on commit 1ea7bb7

Please sign in to comment.