Skip to content

Commit

Permalink
Merge pull request #341 from near/bench
Browse files Browse the repository at this point in the history
gas and storage benchmarks
  • Loading branch information
ailisp authored Feb 14, 2023
2 parents d0dce58 + a7878ad commit 343a062
Show file tree
Hide file tree
Showing 30 changed files with 1,229 additions and 1 deletion.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ jobs:
run: test -z "$(git status --porcelain)"
- name: Run tests
run: pnpm test
if: matrix.os == 'ubuntu-latest'
1 change: 1 addition & 0 deletions benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
457 changes: 457 additions & 0 deletions benchmark/README.md

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions benchmark/__tests__/test-deploy-contract.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Worker } from "near-workspaces";
import test from "ava";
import {
formatGas,
gasBreakdown,
logGasBreakdown,
logGasDetail,
} from "./util.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the test contract.
const callerContract = await root.createSubAccount("caller", {
initialBalance: "1000N",
});
await callerContract.deploy("build/deploy-contract.wasm");

const callerContractRs = await root.createSubAccount("callrs", {
initialBalance: "1000N",
});
await callerContractRs.deploy("res/deploy_contract.wasm");
// Test users
const ali = await root.createSubAccount("ali");
const bob = await root.createSubAccount("bob");
const carl = await root.createSubAccount("carl");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = {
root,
callerContract,
ali,
bob,
carl,
callerContractRs,
};
});

test("JS promise batch deploy contract and call", async (t) => {
const { bob, callerContract } = t.context.accounts;

let r = await bob.callRaw(callerContract, "deploy_contract", "", {
gas: "300 Tgas",
});
// console.log(JSON.stringify(r, null, 2));
let deployed = callerContract.getSubAccount("a");
t.deepEqual(JSON.parse(Buffer.from(r.result.status.SuccessValue, "base64")), {
currentAccountId: deployed.accountId,
signerAccountId: bob.accountId,
predecessorAccountId: callerContract.accountId,
input: "abc",
});

t.log(
"Gas used to convert transaction to receipt: ",
formatGas(r.result.transaction_outcome.outcome.gas_burnt)
);
t.log(
"Gas used to execute the receipt (actual contract call): ",
formatGas(r.result.receipts_outcome[0].outcome.gas_burnt)
);
let map = gasBreakdown(r.result.receipts_outcome[0].outcome);
logGasBreakdown(map, t);
t.log(
"Gas used to execute the cross contract call: ",
formatGas(r.result.receipts_outcome[1].outcome.gas_burnt)
);
map = gasBreakdown(r.result.receipts_outcome[1].outcome);
logGasBreakdown(map, t);
t.log(
"Gas used to refund unused gas for cross contract call: ",
formatGas(r.result.receipts_outcome[2].outcome.gas_burnt)
);
t.log(
"Gas used to refund unused gas: ",
formatGas(r.result.receipts_outcome[3].outcome.gas_burnt)
);
t.log(
"Total gas used: ",
formatGas(
r.result.transaction_outcome.outcome.gas_burnt +
r.result.receipts_outcome[0].outcome.gas_burnt +
r.result.receipts_outcome[1].outcome.gas_burnt +
r.result.receipts_outcome[2].outcome.gas_burnt +
r.result.receipts_outcome[3].outcome.gas_burnt
)
);
});

test("RS promise batch deploy contract and call", async (t) => {
const { bob, callerContractRs } = t.context.accounts;

let r = await bob.callRaw(callerContractRs, "deploy_contract", "", {
gas: "300 Tgas",
});
// console.log(JSON.stringify(r, null, 2));
let deployed = callerContractRs.getSubAccount("a");
t.deepEqual(JSON.parse(Buffer.from(r.result.status.SuccessValue, "base64")), {
currentAccountId: deployed.accountId,
signerAccountId: bob.accountId,
predecessorAccountId: callerContractRs.accountId,
input: "abc",
});

t.log(
"Gas used to convert transaction to receipt: ",
formatGas(r.result.transaction_outcome.outcome.gas_burnt)
);
t.log(
"Gas used to execute the receipt (actual contract call): ",
formatGas(r.result.receipts_outcome[0].outcome.gas_burnt)
);
let map = gasBreakdown(r.result.receipts_outcome[0].outcome);
logGasBreakdown(map, t);
t.log(
"Gas used to execute the cross contract call: ",
formatGas(r.result.receipts_outcome[1].outcome.gas_burnt)
);
map = gasBreakdown(r.result.receipts_outcome[1].outcome);
logGasBreakdown(map, t);
t.log(
"Gas used to refund unused gas for cross contract call: ",
formatGas(r.result.receipts_outcome[2].outcome.gas_burnt)
);
t.log(
"Gas used to refund unused gas: ",
formatGas(r.result.receipts_outcome[3].outcome.gas_burnt)
);
t.log(
"Total gas used: ",
formatGas(
r.result.transaction_outcome.outcome.gas_burnt +
r.result.receipts_outcome[0].outcome.gas_burnt +
r.result.receipts_outcome[1].outcome.gas_burnt +
r.result.receipts_outcome[2].outcome.gas_burnt +
r.result.receipts_outcome[3].outcome.gas_burnt
)
);
});
86 changes: 86 additions & 0 deletions benchmark/__tests__/test-expensive-calc.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the test contract.
const expensiveContract = await root.devDeploy("build/expensive-calc.wasm");
const expensiveContractRs = await root.devDeploy("res/expensive_calc.wasm");

// Test users
const ali = await root.createSubAccount("ali");
const bob = await root.createSubAccount("bob");
const carl = await root.createSubAccount("carl");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = {
root,
expensiveContract,
expensiveContractRs,
ali,
bob,
carl,
};
});

test("JS expensive contract, iterate 100 times", async (t) => {
const { bob, expensiveContract } = t.context.accounts;
let r = await bob.callRaw(expensiveContract, "expensive", { n: 100 });

t.is(r.result.status.SuccessValue, "LTUw");
logGasDetail(r, t);
});

test("RS expensive contract. iterate 100 times", async (t) => {
const { bob, expensiveContractRs } = t.context.accounts;
let r = await bob.callRaw(expensiveContractRs, "expensive", { n: 100 });
t.is(r.result.status.SuccessValue, "LTUw");
logGasDetail(r, t);
});

test("JS expensive contract, iterate 10000 times", async (t) => {
const { bob, expensiveContract } = t.context.accounts;
let r = await bob.callRaw(
expensiveContract,
"expensive",
{ n: 10000 },
{ gas: BigInt(300 * 10 ** 12) }
);

t.is(r.result.status.SuccessValue, "LTUwMDA=");
logGasDetail(r, t);
});

test("RS expensive contract. iterate 10000 times", async (t) => {
const { bob, expensiveContractRs } = t.context.accounts;
let r = await bob.callRaw(expensiveContractRs, "expensive", { n: 10000 });
t.is(r.result.status.SuccessValue, "LTUwMDA=");
logGasDetail(r, t);
});

test("JS expensive contract, iterate 20000 times", async (t) => {
const { bob, expensiveContract } = t.context.accounts;
let r = await bob.callRaw(
expensiveContract,
"expensive",
{ n: 20000 },
{ gas: BigInt(300 * 10 ** 12) }
);

t.is(r.result.status.SuccessValue, "LTEwMDAw");
logGasDetail(r, t);
});

test("RS expensive contract. iterate 20000 times", async (t) => {
const { bob, expensiveContractRs } = t.context.accounts;
let r = await bob.callRaw(expensiveContractRs, "expensive", { n: 20000 });
t.is(r.result.status.SuccessValue, "LTEwMDAw");
logGasDetail(r, t);
});
72 changes: 72 additions & 0 deletions benchmark/__tests__/test-highlevel-collection.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the test contract.
const highlevelContract = await root.devDeploy(
"build/highlevel-collection.wasm"
);
const highlevelContractRs = await root.devDeploy(
"res/highlevel_collection.wasm"
);

// Test users
const ali = await root.createSubAccount("ali");
const bob = await root.createSubAccount("bob");
const carl = await root.createSubAccount("carl");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = {
root,
highlevelContract,
highlevelContractRs,
ali,
bob,
carl,
};
});

test("JS highlevel collection contract", async (t) => {
const { bob, highlevelContract } = t.context.accounts;
let r = await bob.callRaw(highlevelContract, "set", {
key: "a".repeat(100),
value: "b".repeat(100),
});
r = await bob.callRaw(highlevelContract, "set", {
key: "b".repeat(100),
value: "c".repeat(100),
});
r = await bob.callRaw(highlevelContract, "set", {
key: "c".repeat(100),
value: "d".repeat(100),
});

t.is(r.result.status.SuccessValue, "");
logGasDetail(r, t);
});

test("RS highlevel collection contract", async (t) => {
const { bob, highlevelContractRs } = t.context.accounts;
let r = await bob.callRaw(highlevelContractRs, "set", {
key: "a".repeat(100),
value: "b".repeat(100),
});
r = await bob.callRaw(highlevelContractRs, "set", {
key: "b".repeat(100),
value: "c".repeat(100),
});
r = await bob.callRaw(highlevelContractRs, "set", {
key: "c".repeat(100),
value: "d".repeat(100),
});
t.is(r.result.status.SuccessValue, "");
logGasDetail(r, t);
});
51 changes: 51 additions & 0 deletions benchmark/__tests__/test-highlevel-minimal.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the test contract.
const highlevelContract = await root.devDeploy(
"build/highlevel-minimal.wasm"
);
const highlevelContractRs = await root.devDeploy(
"res/highlevel_minimal.wasm"
);

// Test users
const ali = await root.createSubAccount("ali");
const bob = await root.createSubAccount("bob");
const carl = await root.createSubAccount("carl");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = {
root,
highlevelContract,
highlevelContractRs,
ali,
bob,
carl,
};
});

test("JS highlevel minimal contract", async (t) => {
const { bob, highlevelContract } = t.context.accounts;
let r = await bob.callRaw(highlevelContract, "empty", "");

t.is(r.result.status.SuccessValue, "");
logGasDetail(r, t);
});

test("RS highlevel minimal contract", async (t) => {
const { bob, highlevelContractRs } = t.context.accounts;
let r = await bob.callRaw(highlevelContractRs, "empty", "");

t.is(r.result.status.SuccessValue, "");
logGasDetail(r, t);
});
Loading

0 comments on commit 343a062

Please sign in to comment.