Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: wasm file size and benchmark tests gas consumption scripts which generate a markdown table report #13

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build
build
file-sizes.json
60 changes: 60 additions & 0 deletions benchmark/__tests__/results-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import fs from "fs";
import path from "path";

const resultsFilePath = path.resolve("temp-all-test-results.json");

/**
* Reads existing test results from a JSON file if it exists.
*
* This function checks if the file specified by `resultsFilePath` exists.
* If the file is found, it reads the file's content and parses it as JSON.
* If the file does not exist, it returns an empty object.
*
* @returns {Object} The parsed JSON object from the file, or an empty object if the file does not exist.
*/
function readExistingResults() {
if (fs.existsSync(resultsFilePath)) {
try {
const fileContent = fs.readFileSync(resultsFilePath, "utf-8");
return JSON.parse(fileContent);
} catch (error) {
console.error("Failed to read or parse results file:", error);
return {};
}
}
return {};
}

/**
* Function to add test results to the report if the GENERATE_REPORT environment variable is set to "true"
* @param {string} testName - The name of the test.
* @param {Object} result - The test result object.
*/
export function addTestResults(testName, result) {
// Check if we need to generate a report
if (process.env.GENERATE_REPORT === "true") {
// Create a temporary object for the new test results
const tempResults = {
[testName]: result,
};

// Read existing results from the file
const existingResults = readExistingResults();

// Combine existing results with new test results
const combinedResults = {
...existingResults,
...tempResults,
};

try {
// Write the combined results to the file
fs.writeFileSync(
resultsFilePath,
JSON.stringify(combinedResults, null, 2)
);
} catch (error) {
console.error("Failed to write results to file:", error);
}
}
}
96 changes: 16 additions & 80 deletions benchmark/__tests__/test-deploy-contract.ava.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Worker } from "near-workspaces";
import test from "ava";
import {
formatGas,
gasBreakdown,
logGasBreakdown,
logGasDetail,
} from "./util.js";
import { generateGasObject, logTestResults } from "./util.js";
import { addTestResults } from "./results-store.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
Expand Down Expand Up @@ -47,51 +43,21 @@ test("JS promise batch deploy contract and call", async (t) => {
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: ",
// TODO: fix after near-workspaces is updated
formatGas(r.result.receipts_outcome[3]?.outcome.gas_burnt || 0)
);
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 +
// TODO: fix after near-workspaces is updated
(r.result.receipts_outcome[3]?.outcome.gas_burnt || 0)
)
);
logTestResults(r);

const gasObject = generateGasObject(r);

addTestResults("JS_promise_batch_deploy_contract_and_call", gasObject);
});

test("RS promise batch deploy contract and call", async (t) => {
Expand All @@ -100,49 +66,19 @@ test("RS promise batch deploy contract and call", async (t) => {
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: ",
// TODO: fix after near-workspaces is updated
formatGas(r.result.receipts_outcome[3]?.outcome.gas_burnt || 0)
);
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 +
// TODO: fix after near-workspaces is updated
(r.result.receipts_outcome[3]?.outcome.gas_burnt || 0)
)
);
logTestResults(r);

const gasObject = generateGasObject(r);

addTestResults("RS_promise_batch_deploy_contract_and_call", gasObject);
});
50 changes: 42 additions & 8 deletions benchmark/__tests__/test-expensive-calc.ava.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";
import { generateGasObject, logTestResults } from "./util.js";
import { addTestResults } from "./results-store.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.
// Prepare sandbox for tests, create accounts, deploy contracts, etc.
const root = worker.rootAccount;

// Deploy the test contract.
Expand Down Expand Up @@ -35,14 +36,25 @@ test("JS expensive contract, iterate 100 times", async (t) => {
let r = await bob.callRaw(expensiveContract, "expensive", { n: 100 });

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

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("JS_expensive_contract_100_times", gasObject);
});

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);

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("RS_expensive_contract_100_times", gasObject);
});

test("JS expensive contract, iterate 10000 times", async (t) => {
Expand All @@ -55,14 +67,25 @@ test("JS expensive contract, iterate 10000 times", async (t) => {
);

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

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("JS_expensive_contract_10000_times", gasObject);
});

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);

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("RS_expensive_contract_10000_times", gasObject);
});

test("JS expensive contract, iterate 20000 times", async (t) => {
Expand All @@ -75,12 +98,23 @@ test("JS expensive contract, iterate 20000 times", async (t) => {
);

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

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("JS_expensive_contract_20000_times", gasObject);
});

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);

logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("RS_expensive_contract_20000_times", gasObject);
});
15 changes: 12 additions & 3 deletions benchmark/__tests__/test-highlevel-collection.ava.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";
import { generateGasObject, logTestResults } from "./util.js";
import { addTestResults } from "./results-store.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
Expand Down Expand Up @@ -50,7 +51,11 @@ test("JS highlevel collection contract", async (t) => {
});

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

const gasObject = generateGasObject(r, true);

addTestResults("JS_highlevel_collection_contract", gasObject);
});

test("RS highlevel collection contract", async (t) => {
Expand All @@ -68,5 +73,9 @@ test("RS highlevel collection contract", async (t) => {
value: "d".repeat(100),
});
t.is(r.result.status.SuccessValue, "");
logGasDetail(r, t);
logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("RS_highlevel_collection_contract", gasObject);
});
15 changes: 12 additions & 3 deletions benchmark/__tests__/test-highlevel-minimal.ava.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logGasDetail } from "./util.js";
import { generateGasObject, logTestResults } from "./util.js";
import { addTestResults } from "./results-store.js";

test.before(async (t) => {
// Init the worker and start a Sandbox server
Expand Down Expand Up @@ -39,13 +40,21 @@ test("JS highlevel minimal contract", async (t) => {
let r = await bob.callRaw(highlevelContract, "empty", "");

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

const gasObject = generateGasObject(r, true);

addTestResults("JS_highlevel_minimal_contract", gasObject);
});

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);
logTestResults(r);

const gasObject = generateGasObject(r, true);

addTestResults("RS_highlevel_minimal_contract", gasObject);
});
Loading
Loading