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

[DRAFT] - [perf] - wasm optimisations #6

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
node_modules
vendor
.idea
Expand Down
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
700 changes: 269 additions & 431 deletions benchmark/README.md

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions benchmark/__tests__/results-store.js
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of error handling:
If there is an error while reading or writing the file, it can cause the program to crash without any clear indication. You should wrap file operations in try-catch blocks to gracefully handle potential file system errors.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, you're right. Thanks for pointing that out.

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);
}
}
}
92 changes: 16 additions & 76 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,49 +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: ",
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
)
);
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 @@ -98,47 +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: ",
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
)
);
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