diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000..a966cade --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,38 @@ +name: Benchmark.js Example +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: write + deployments: write + +jobs: + benchmark: + name: Run benchmark + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 9 + - shell: bash + run: | + pnpm install --no-frozen-lockfile + cd packages/object + pnpm run benchmark + + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + name: Benchmark.js Benchmark + tool: 'benchmarkjs' + output-file-path: packages/object/benchmark-output.txt + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true + # Show alert with commit comment on detecting possible performance regression + alert-threshold: '200%' + comment-on-alert: true + fail-on-alert: true \ No newline at end of file diff --git a/packages/object/package.json b/packages/object/package.json index ede49451..5c4ac459 100644 --- a/packages/object/package.json +++ b/packages/object/package.json @@ -26,10 +26,13 @@ "build": "tsc -b", "clean": "rm -rf dist/ node_modules/", "prepack": "tsc -b", - "test": "vitest" + "test": "vitest", + "benchmark": "npx tsx tests/hashgraph.bench.ts | tee benchmark-output.txt" }, "devDependencies": { - "assemblyscript": "^0.27.29" + "assemblyscript": "^0.27.29", + "benchmark": "^2.1.4", + "tsx": "4.19.1" }, "dependencies": { "@bufbuild/protobuf": "^2.0.0", diff --git a/packages/object/tests/causallyrelated.bench.ts b/packages/object/tests/causallyrelated.bench.ts index 8f9e1a73..1eaf0963 100644 --- a/packages/object/tests/causallyrelated.bench.ts +++ b/packages/object/tests/causallyrelated.bench.ts @@ -1,5 +1,5 @@ import { bench, describe } from "vitest"; -import { AddWinsSet } from "../../crdt/src/cros/AddWinsSet/index.js"; +import { AddWinsSet } from "../../blueprints/src/AddWinsSet/index.js"; import { type Hash, TopologyObject } from "../src/index.js"; describe("AreCausallyDependent benchmark", async () => { diff --git a/packages/object/tests/hashgraph.bench.ts b/packages/object/tests/hashgraph.bench.ts new file mode 100644 index 00000000..eaa77791 --- /dev/null +++ b/packages/object/tests/hashgraph.bench.ts @@ -0,0 +1,63 @@ +import Benchmark from "benchmark"; +import { AddWinsSet } from "../../blueprints/src/AddWinsSet/index.js"; +import { TopologyObject } from "../src/index.js"; + +function benchmarkForAddWinSet( + name: string, + numCROs: number, + verticesPerCRO: number, + mergeFn: boolean, +) { + return suite.add(name, () => { + const objects: TopologyObject[] = []; + for (let i = 0; i < numCROs; i++) { + const obj: TopologyObject = new TopologyObject( + `peer${i + 1}`, + new AddWinsSet(), + ); + const cro = obj.cro as AddWinsSet; + for (let j = 0; j < verticesPerCRO; j++) { + if (i % 3 === 2) { + cro.add(j); + cro.remove(j); + } else if (i % 3 === 1) { + cro.remove(j); + cro.add(j); + } else { + cro.add(j); + } + } + objects.push(obj); + } + + if (mergeFn) { + for (let i = 0; i < objects.length; i++) { + for (let j = 0; j < objects.length; j++) { + if (i !== j) { + objects[i].merge(objects[j].hashGraph.getAllVertices()); + } + } + } + } + }); +} + +const suite = new Benchmark.Suite(); + +benchmarkForAddWinSet("Create HashGraph with 1000 vertices", 1, 1000, false); + +benchmarkForAddWinSet( + "Create 2 CROs (1000 vertices each) and Merge", + 2, + 1000, + true, +); + +suite + .on("cycle", (event) => { + console.log(String(event.target)); + }) + .on("complete", function () { + console.log(`Fastest is ${this.filter("fastest").map("name")}`); + }) + .run({ async: true }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44e6ca9d..554c00eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -409,7 +409,7 @@ importers: specifier: ^2.0.0 version: 2.2.1 '@topology-foundation/logger': - specifier: ^0.2.1-4 + specifier: ^0.2.1 version: link:../logger ts-proto: specifier: ^2.2.4 @@ -418,6 +418,12 @@ importers: assemblyscript: specifier: ^0.27.29 version: 0.27.30 + benchmark: + specifier: ^2.1.4 + version: 2.1.4 + tsx: + specifier: 4.19.1 + version: 4.19.1 packages: @@ -2451,6 +2457,9 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + benchmark@2.1.4: + resolution: {integrity: sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==} + binaryen@116.0.0-nightly.20240114: resolution: {integrity: sha512-0GZrojJnuhoe+hiwji7QFaL3tBlJoA+KFUN7ouYSDGZLSo9CKM8swQX8n/UcbR0d1VuZKU+nhogNzv423JEu5A==} hasBin: true @@ -4368,6 +4377,9 @@ packages: resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} engines: {node: '>=10'} + platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -8037,6 +8049,11 @@ snapshots: before-after-hook@2.2.3: {} + benchmark@2.1.4: + dependencies: + lodash: 4.17.21 + platform: 1.3.6 + binaryen@116.0.0-nightly.20240114: {} bintrees@1.0.2: {} @@ -10219,6 +10236,8 @@ snapshots: dependencies: find-up: 5.0.0 + platform@1.3.6: {} + possible-typed-array-names@1.0.0: {} postcss@8.4.47: