Skip to content

Commit

Permalink
Add benchmarks for full state serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
dapplion committed Jan 17, 2022
1 parent 64be353 commit 2a46125
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 53 deletions.
2 changes: 1 addition & 1 deletion packages/ssz/test/lodestarTypes/phase0/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export const Validator = new ContainerType(
);

// Export as stand-alone for direct tree optimizations
export const Validators = new ListCompositeType(Validator, VALIDATOR_REGISTRY_LIMIT);
export const Validators = new ListCompositeType(ValidatorNodeStruct, VALIDATOR_REGISTRY_LIMIT);
export const Balances = new ListBasicType(UintNumber64, VALIDATOR_REGISTRY_LIMIT);
export const RandaoMixes = new VectorCompositeType(Bytes32, EPOCHS_PER_HISTORICAL_VECTOR);
export const Slashings = new VectorBasicType(Gwei, EPOCHS_PER_SLASHINGS_VECTOR);
Expand Down
51 changes: 0 additions & 51 deletions packages/ssz/test/perf/deserializationEth2.test.ts

This file was deleted.

104 changes: 104 additions & 0 deletions packages/ssz/test/perf/deserializeEth2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {itBench} from "@dapplion/benchmark";
import {BeaconState} from "../lodestarTypes/altair/types";
import * as sszPhase0 from "../lodestarTypes/phase0/sszTypes";
import * as sszAltair from "../lodestarTypes/altair/sszTypes";
import {
getAttestation,
getOnce,
getRandomState,
getSignedAggregateAndProof,
getSignedContributionAndProof,
} from "../utils/generateEth2Objs";
import {TreeViewDU} from "../../src";

describe("Deserialize frequent eth2 objects", () => {
itBench<Uint8Array, Uint8Array>({
id: "deserialize Attestation - struct",
before: () => sszPhase0.Attestation.serialize(getAttestation(0)),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszPhase0.Attestation.deserialize(bytes);
},
});

itBench<Uint8Array, Uint8Array>({
id: "deserialize Attestation - tree",
before: () => sszPhase0.Attestation.serialize(getAttestation(0)),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszPhase0.Attestation.deserializeToView(bytes);
},
});

itBench<Uint8Array, Uint8Array>({
id: "deserialize SignedAggregateAndProof - struct",
before: () => sszPhase0.SignedAggregateAndProof.serialize(getSignedAggregateAndProof(0)),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszPhase0.SignedAggregateAndProof.deserialize(bytes);
},
});

itBench<Uint8Array, Uint8Array>({
id: "deserialize SignedAggregateAndProof - tree",
before: () => sszPhase0.SignedAggregateAndProof.serialize(getSignedAggregateAndProof(0)),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszPhase0.SignedAggregateAndProof.deserializeToView(bytes);
},
});

itBench<Uint8Array, Uint8Array>({
id: "deserialize SignedContributionAndProof - struct",
before: () => sszAltair.SignedContributionAndProof.serialize(getSignedContributionAndProof(0)),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszAltair.SignedContributionAndProof.deserialize(bytes);
},
});

for (const validatorCount of [300_000]) {
// Compute once for all benchmarks only if run
const getStateVc = getOnce(() => getRandomState(validatorCount));
const getStateViewDU = getOnce(() => sszAltair.BeaconState.toViewDU(getStateVc()));

itBench<Uint8Array, Uint8Array>({
id: `BeaconState vc ${validatorCount} - deserialize tree`,
before: () => getStateViewDU().serialize(),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
sszAltair.BeaconState.deserializeToViewDU(bytes);
},
});

itBench({
id: `BeaconState vc ${validatorCount} - serialize tree`,
fn: () => {
getStateViewDU().serialize();
},
});

for (const {fieldName, fieldType} of sszAltair.BeaconState.fieldsEntries) {
// Only benchmark big data structures
if (fieldType.maxSize < 10e6 || fieldType.isBasic) {
continue;
}

itBench<Uint8Array, Uint8Array>({
id: `BeaconState.${fieldName} vc ${validatorCount} - deserialize tree`,
before: () => (getStateViewDU()[fieldName] as TreeViewDU<any>).serialize(),
beforeEach: (bytes) => bytes,
fn: (bytes) => {
fieldType.deserializeToViewDU(bytes);
},
});

itBench<BeaconState, BeaconState>({
id: `BeaconState.${fieldName} vc ${validatorCount} - serialize tree`,
fn: () => {
(getStateViewDU()[fieldName] as TreeViewDU<any>).serialize();
},
});
}
}
});
34 changes: 33 additions & 1 deletion packages/ssz/test/utils/generateEth2Objs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import * as sszAltair from "../lodestarTypes/altair/sszTypes";
import {Attestation, SignedAggregateAndProof, SignedBeaconBlock} from "../lodestarTypes/phase0/types";
import {SignedContributionAndProof} from "../lodestarTypes/altair/types";
import {SignedContributionAndProof, BeaconState} from "../lodestarTypes/altair/types";
import {BitArray} from "../../src";

// Typical mainnet numbers
const BITS_PER_ATTESTATION = 90;
const ATTESTATIONS_PER_BLOCK = 90;

export function getRandomState(validatorCount: number): BeaconState {
const state = sszAltair.BeaconState.defaultValue;
for (let i = 0; i < validatorCount; i++) {
state.balances.push(34788813514 + i);
state.currentEpochParticipation.push(3);
state.previousEpochParticipation.push(7);
state.inactivityScores.push(0);
state.validators.push({
pubkey: new Uint8Array(48),
withdrawalCredentials: new Uint8Array(32),
effectiveBalance: 32e9,
slashed: false,
activationEligibilityEpoch: i,
activationEpoch: i,
exitEpoch: Infinity,
withdrawableEpoch: Infinity,
});
}
return state;
}

export function getAttestation(i: number): Attestation {
return {
aggregationBits: getBitsSingle(120, i % 120),
Expand Down Expand Up @@ -108,3 +130,13 @@ function randomBytes(bytes: number): Uint8Array {

return uint8Arr;
}

export function getOnce<T>(fn: () => T): () => T {
let value: T | null = null;
return function () {
if (value === null) {
value = fn();
}
return value;
};
}

0 comments on commit 2a46125

Please sign in to comment.