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

adding first MVP of benchmarks, they will run on tests now, but will … #2138

Merged
merged 56 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
cb30b13
adding first MVP of benchmarks, they will run on tests now, but will …
lastmjs Sep 20, 2024
2ddaca5
refactor benchmarking into its own file, generate stable and experime…
lastmjs Sep 23, 2024
82baf84
cleanup benchmarking a bit
lastmjs Sep 24, 2024
40c735e
cleaning up a bit
lastmjs Sep 24, 2024
2c1f879
refactor many test files to pass in the canister name
lastmjs Sep 25, 2024
5d21b6d
cleanup some mistakes
lastmjs Sep 30, 2024
f18fc88
Merge branch 'main' into benchmarking
bdemann Oct 1, 2024
1fb6d75
multi canister benchmarks
bdemann Oct 8, 2024
b8eab39
add cycles and USD to output
bdemann Oct 9, 2024
d8baad1
fixup
bdemann Oct 9, 2024
a933f60
run benchmarks by default when doing tests
bdemann Oct 10, 2024
77bc0e9
add the test lifecycle event
bdemann Oct 10, 2024
111b2c2
fix bad paths
bdemann Oct 10, 2024
b004cb1
make more declarative
bdemann Oct 10, 2024
a0d07ea
pull benchmark code out into its own module
bdemann Oct 10, 2024
b478594
update formatting for multiline markdown
bdemann Oct 10, 2024
e247a87
better organization for functions
bdemann Oct 10, 2024
9d2df79
make createBenchmarksTable more declarative
bdemann Oct 10, 2024
32c9f60
only record canister method names when recording benchmarks
bdemann Oct 10, 2024
dad59b0
Add benchmarks for cross cansiter calls
bdemann Oct 10, 2024
48ca853
use actor to get actual types
bdemann Oct 10, 2024
e5b5a1e
update benchmarks
bdemann Oct 11, 2024
13b1dff
try adding names to the other canister methods
bdemann Oct 14, 2024
46c1907
add default name for functions
bdemann Oct 14, 2024
f112414
update whoami
bdemann Oct 14, 2024
c463589
update canister names
bdemann Oct 18, 2024
a7e6e15
pr_fixes
bdemann Oct 18, 2024
9fb8586
rename WASM_DATA
bdemann Oct 22, 2024
19bb81a
first pass at merging benchmarks into one file
bdemann Oct 22, 2024
64f6b7d
fix archiving of previous version
bdemann Oct 22, 2024
2366f4b
remove mutation
bdemann Oct 22, 2024
d0108ff
clean up file
bdemann Oct 22, 2024
b1b0e11
only output calculation note once
bdemann Oct 22, 2024
0e2d283
pr fixes
bdemann Oct 22, 2024
be39032
rename to record benchmarks
bdemann Oct 22, 2024
61ebc9c
update identity
bdemann Oct 22, 2024
aede13c
fix tests
bdemann Oct 22, 2024
a8633e4
update shape of benchmarking
bdemann Oct 23, 2024
a025145
pr fixes
bdemann Oct 23, 2024
55ff0a2
add fee for 1B executed instructions
bdemann Oct 23, 2024
e68ce1d
move instruction getting outside of the recording
bdemann Oct 23, 2024
30843b4
pr fixes
bdemann Oct 23, 2024
46e7feb
Merge branch 'main' into benchmarking
bdemann Oct 23, 2024
2398b08
debugging
bdemann Oct 23, 2024
fb13dbb
remove debugging
bdemann Oct 23, 2024
74eddab
update files with new format
bdemann Oct 23, 2024
786d92e
add branch back in
bdemann Oct 23, 2024
5476c50
update setting names
bdemann Oct 24, 2024
4b4f811
rename params
bdemann Oct 24, 2024
fc1f9ca
pr fixes
bdemann Oct 24, 2024
bcb0e6a
pr fixes
bdemann Oct 24, 2024
77b8d76
only do record benchmarks if there is an only
bdemann Oct 24, 2024
2150b7d
only update the previous version when the version changes
bdemann Oct 24, 2024
e8d0645
pr fixes
bdemann Oct 24, 2024
949631a
pr fixes
bdemann Oct 24, 2024
88710cc
update variable names
bdemann Oct 24, 2024
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
6 changes: 3 additions & 3 deletions .github/actions/set_run_conditions/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ runs:
# Define conditions using shell variables
AZLE_IS_MAIN_BRANCH_PUSH=${{ github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'demergent-labs/release--') }}
AZLE_IS_MAIN_BRANCH_PUSH_FROM_RELEASE_MERGE=${{ github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, 'demergent-labs/release--') }}
AZLE_IS_RELEASE_PR=${{ startsWith(github.head_ref, 'release--') }}
AZLE_IS_FEATURE_PR=${{ !startsWith(github.head_ref, 'release--') && github.ref != 'refs/heads/main' && github.event.pull_request.draft == false }}
AZLE_IS_DRAFT_PR=${{ !startsWith(github.head_ref, 'release--') && github.ref != 'refs/heads/main' && github.event.pull_request.draft == true }}
AZLE_IS_RELEASE_BRANCH_PR=${{ startsWith(github.head_ref, 'release--') }}
AZLE_IS_FEATURE_BRANCH_PR=${{ !startsWith(github.head_ref, 'release--') && github.ref != 'refs/heads/main' && github.event.pull_request.draft == false }}
AZLE_IS_FEATURE_BRANCH_DRAFT_PR=${{ !startsWith(github.head_ref, 'release--') && github.ref != 'refs/heads/main' && github.event.pull_request.draft == true }}

# Set individual outputs
echo "is_main_branch_push=$AZLE_IS_MAIN_BRANCH_PUSH" >> $GITHUB_OUTPUT
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
echo "AZLE_IS_FEATURE_BRANCH_PR=${{ steps.set-conditions.outputs.is_feature_branch_pr }}" >> $GITHUB_ENV
echo "AZLE_IS_FEATURE_BRANCH_DRAFT_PR=${{ steps.set-conditions.outputs.is_feature_branch_draft_pr }}" >> $GITHUB_ENV

- id: check-conditions
- name: Print environment variables
run: |
echo "AZLE_IS_MAIN_BRANCH_PUSH: $AZLE_IS_MAIN_BRANCH_PUSH"
echo "AZLE_IS_MAIN_BRANCH_PUSH_FROM_RELEASE_MERGE: $AZLE_IS_MAIN_BRANCH_PUSH_FROM_RELEASE_MERGE"
Expand Down
Binary file modified canister_templates/experimental.wasm
Binary file not shown.
Binary file modified canister_templates/stable.wasm
Binary file not shown.
5 changes: 3 additions & 2 deletions examples/basic_bitcoin/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { runTests } from 'azle/test';
import { BitcoinDaemon, startBitcoinDaemon } from './bitcoin_daemon';
import { getP2pkhAddress, getTests, P2PKH_ADDRESS_FORM } from './tests';

const canisterId = getCanisterId('basic_bitcoin');
const canisterName = 'basic_bitcoin';
const canisterId = getCanisterId(canisterName);

runTests(() => {
let bitcoinDaemon: BitcoinDaemon;
Expand All @@ -22,4 +23,4 @@ runTests(() => {
'runs basic bitcoin tests while bitcoin daemon is running',
getTests(canisterId, getP2pkhAddress, P2PKH_ADDRESS_FORM)
);
});
}, canisterName);
8 changes: 6 additions & 2 deletions examples/bitcoin_psbt/test/manual.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import { getTests } from 'basic_bitcoin/test/tests';

import { getP2wpkhAddress, P2WPKH_ADDRESS_FORM } from './tests';

const canisterId = getCanisterId('bitcoin_psbt');
const canisterName = 'bitcoin_psbt';
const canisterId = getCanisterId(canisterName);

// Allows running of the tests without starting and stopping a Bitcoin daemon
// automatically. That is to say you will need to start and stop the Bitcoin
// daemon manually. Great for running cli commands after or during the tests to
// check the state of the test network
runTests(getTests(canisterId, getP2wpkhAddress, P2WPKH_ADDRESS_FORM));
runTests(
getTests(canisterId, getP2wpkhAddress, P2WPKH_ADDRESS_FORM),
canisterName
);
5 changes: 3 additions & 2 deletions examples/bitcoin_psbt/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { getTests } from 'basic_bitcoin/test/tests';

import { getP2wpkhAddress, P2WPKH_ADDRESS_FORM } from './tests';

const canisterId = getCanisterId('bitcoin_psbt');
const canisterName = 'bitcoin_psbt';
const canisterId = getCanisterId(canisterName);

let bitcoinDaemon: BitcoinDaemon;

Expand All @@ -26,4 +27,4 @@ runTests(() => {
'runs bitcoin psbt tests while bitcoin daemon is running',
getTests(canisterId, getP2wpkhAddress, P2WPKH_ADDRESS_FORM)
);
});
}, canisterName);
7 changes: 4 additions & 3 deletions examples/ckbtc/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { createActor } from '../wallet/frontend/dfx_generated/wallet_backend';
// @ts-ignore this path may not exist when these tests are imported into other test projects
import { _SERVICE } from '../wallet/frontend/dfx_generated/wallet_backend/wallet_backend.did';

let configs = [createConfig(0), createConfig(1)];
const canisterName = 'wallet_backend';
const configs = [createConfig(0), createConfig(1)];

type BitcoinDaemon = ChildProcessWithoutNullStreams;

Expand All @@ -32,7 +33,7 @@ runTests(() => {
'run ckbtc tests while bitcoin daemon is running',
getTests(configs)
);
});
}, canisterName);

async function startBitcoinDaemon(): Promise<BitcoinDaemon> {
if (existsSync(`.bitcoin/regtest`)) {
Expand Down Expand Up @@ -62,7 +63,7 @@ async function startBitcoinDaemon(): Promise<BitcoinDaemon> {
}

function createConfig(id: number): Config {
const walletBackendCanisterId = getCanisterId('wallet_backend');
const walletBackendCanisterId = getCanisterId(canisterName);
const identity: any = createIdentity(id);
const canister = createActor(walletBackendCanisterId, {
agentOptions: {
Expand Down
5 changes: 3 additions & 2 deletions examples/hello_world/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { runTests } from 'azle/test';
import { createActor } from './dfx_generated/hello_world';
import { getTests } from './tests';

const helloWorldCanister = createActor(getCanisterId('hello_world'), {
const canisterName = 'hello_world';
const helloWorldCanister = createActor(getCanisterId(canisterName), {
agentOptions: {
host: 'http://127.0.0.1:8000'
}
});

runTests(getTests(helloWorldCanister));
runTests(getTests(helloWorldCanister), canisterName);
44 changes: 44 additions & 0 deletions examples/hello_world_http_server/benchmarks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"backend": {
"previous": {
"version": "0.25.0",
"benchmarks": [
{
"instructions": { "__bigint__": "8136265274" },
"method_name": "init",
"timestamp": { "__bigint__": "1729788180680976591" }
},
{
"instructions": { "__bigint__": "53798727" },
"method_name": "http_request_update",
"timestamp": { "__bigint__": "1729788197889022797" }
},
{
"instructions": { "__bigint__": "47468265" },
"method_name": "http_request_update",
"timestamp": { "__bigint__": "1729788199085176603" }
},
{
"instructions": { "__bigint__": "47474297" },
"method_name": "http_request_update",
"timestamp": { "__bigint__": "1729788199623240856" }
}
]
},
"current": {
"version": "0.25.0",
"benchmarks": [
{
"instructions": { "__bigint__": "8135491182" },
"method_name": "init",
"timestamp": { "__bigint__": "1729803431300165877" }
},
{
"instructions": { "__bigint__": "53810066" },
"method_name": "http_request_update",
"timestamp": { "__bigint__": "1729803449326310198" }
}
]
}
}
}
30 changes: 30 additions & 0 deletions examples/hello_world_http_server/benchmarks.md
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Benchmarks for backend

## Current benchmarks Azle version: 0.25.0

| Id | Method Name | Instructions | Cycles | USD | USD/Million Calls | Change |
| --- | ------------------- | ------------- | ------------- | ------------- | ----------------- | ----------------------------------- |
| 0 | init | 8_135_491_182 | 6_454_786_472 | $0.0085827359 | $8_582.73 | <font color="green">-774_092</font> |
| 1 | http_request_update | 53_810_066 | 22_114_026 | $0.0000294044 | $29.40 | <font color="red">+11_339</font> |

## Baseline benchmarks Azle version: 0.25.0

| Id | Method Name | Instructions | Cycles | USD | USD/Million Calls |
| --- | ------------------- | ------------- | ------------- | ------------- | ----------------- |
| 0 | init | 8_136_265_274 | 6_455_096_109 | $0.0085831476 | $8_583.14 |
| 1 | http_request_update | 53_798_727 | 22_109_490 | $0.0000293983 | $29.39 |
| 2 | http_request_update | 47_468_265 | 19_577_306 | $0.0000260314 | $26.03 |
| 3 | http_request_update | 47_474_297 | 19_579_718 | $0.0000260346 | $26.03 |

---

**Note on calculations:**

- Cycles are calculated using the formula: base_fee + (per_instruction_fee \* number_of_instructions) + (additional_fee_per_billion \* floor(number_of_instructions / 1_000_000_000))
- base_fee: 590_000 cycles
- per_instruction_fee: 0.4 cycles
- additional_fee_per_billion: 400_000_000 cycles per billion instructions
- USD value is derived from the total cycles, where 1 trillion cycles = 1 XDR, and 1 XDR = $1.329670 (as of October 24, 2024)

For the most up-to-date XDR to USD conversion rate, please refer to the [IMF website](https://www.imf.org/external/np/fin/data/rms_sdrv.aspx).
For the most current fee information, please check the [official documentation](https://internetcomputer.org/docs/current/developer-docs/gas-cost#execution).
5 changes: 3 additions & 2 deletions examples/hello_world_http_server/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { runTests } from 'azle/test';

import { getTests } from './tests';

const canisterId = getCanisterId('backend');
const canisterName = 'backend';
const canisterId = getCanisterId(canisterName);

runTests(getTests(canisterId));
runTests(getTests(canisterId), canisterName);
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "azle",
"version": "0.24.1",
"version": "0.25.0",
"description": "TypeScript and JavaScript CDK for the Internet Computer",
"scripts": {
"typecheck": "tsc --noEmit",
Expand Down
7 changes: 6 additions & 1 deletion src/build/experimental/commands/compile/get_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ export async function getContext(
const wasmData: WasmData = {
...stableContext.wasmData,
consumer,
managementDid
managementDid,
recordBenchmarks:
process.env.npm_lifecycle_event === 'pretest' ||
bdemann marked this conversation as resolved.
Show resolved Hide resolved
process.env.npm_lifecycle_event === 'test'
? process.env.AZLE_RECORD_BENCHMARKS !== 'false'
: process.env.AZLE_RECORD_BENCHMARKS === 'true'
};

return {
Expand Down
20 changes: 20 additions & 0 deletions src/build/experimental/commands/compile/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ export function getPrelude(main: string): string {
// behave in all async situations
setTimeout(() => {
const canister = Canister.default !== undefined ? Canister.default() : Server(() => globalThis._azleNodeServer)();
if (globalThis._azleRecordBenchmarks === true) {
lastmjs marked this conversation as resolved.
Show resolved Hide resolved
const methodMeta = canister.methodMeta;

globalThis._azleCanisterMethodNames = Object.entries(methodMeta).reduce((acc, [key, value]) => {
if (value === undefined) {
return acc;
}

if (key === 'queries' || key === 'updates') {
const queriesOrUpdates = value.reduce((innerAcc, method) => {
const indexString = method.index.toString();
return { ...innerAcc, [indexString]: method.name };
}, {});
return { ...acc, ...queriesOrUpdates };
} else {
const indexString = value.index.toString();
return { ...acc, [indexString]: value.name };
}
}, {});
}

const candid = canister.getIdlType([]).accept(new DidVisitor(), {
...getDefaultVisitorData(),
Expand Down
36 changes: 36 additions & 0 deletions src/build/rust/canister/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::cell::RefCell;
use std::collections::BTreeMap;

use candid::CandidType;
use wasmedge_quickjs::{AsObject, Context};

#[derive(CandidType, Debug, Clone)]
pub struct BenchmarkEntry {
pub method_name: String,
pub instructions: u64,
pub timestamp: u64,
}

thread_local! {
pub static BENCHMARKS_REF_CELL: RefCell<Vec<BenchmarkEntry>> = RefCell::new(Vec::new());
}

pub fn record_benchmark(context: &mut Context, function_name: &str, instructions: u64) {
let timestamp = ic_cdk::api::time();

let global = context.get_global();
let method_names = global.get("_azleCanisterMethodNames");
let method_name = method_names
.get(function_name)
.and_then(|v| Some(v.to_string()?.to_string()))
.unwrap_or_else(|| function_name.to_string());

BENCHMARKS_REF_CELL.with(|benchmarks_ref_cell| {
let mut benchmarks = benchmarks_ref_cell.borrow_mut();
benchmarks.push(BenchmarkEntry {
method_name,
instructions,
timestamp,
});
});
}
26 changes: 15 additions & 11 deletions src/build/rust/canister/src/execute_method_js.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
use crate::{benchmarking::record_benchmark, run_event_loop, RUNTIME, WASM_DATA_REF_CELL};
use wasmedge_quickjs::AsObject;

use crate::{run_event_loop, RUNTIME};

#[no_mangle]
#[allow(unused)]
pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) {
let function_name = &function_index.to_string();
let pass_arg_data = if pass_arg_data == 1 { true } else { false };
let function_name = function_index.to_string();
let pass_arg_data = pass_arg_data == 1;

RUNTIME.with(|runtime| {
let mut runtime = runtime.borrow_mut();
let runtime = runtime.as_mut().unwrap();

runtime.run_with_context(|context| {
let global = context.get_global();

let callbacks = global.get("_azleCallbacks");
let method_callback = callbacks.get(function_name).unwrap();
let method_callback = callbacks.get(&function_name).unwrap();

let candid_args = if pass_arg_data {
ic_cdk::api::call::arg_data_raw()
Expand All @@ -28,20 +26,26 @@ pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) {
context.new_array_buffer(&candid_args).into();

let method_callback_function = method_callback.to_function().unwrap();

let result = method_callback_function.call(&[candid_args_js_value]);

// TODO error handling is mostly done in JS right now
// TODO we would really like wasmedge-quickjs to add
// TODO good error info to JsException and move error handling
// TODO out of our own code
match &result {
wasmedge_quickjs::JsValue::Exception(js_exception) => {
js_exception.dump_error();
panic!("TODO needs error info");
}
_ => run_event_loop(context),
};

if WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| {
wasm_data_ref_cell
.borrow()
.as_ref()
.unwrap()
.record_benchmarks
}) {
let instructions = ic_cdk::api::performance_counter(1);
record_benchmark(context, &function_name, instructions);
}
});
});
}
15 changes: 15 additions & 0 deletions src/build/rust/canister/src/init_and_post_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use wasmedge_quickjs::AsObject;
use crate::{
execute_method_js, ic, run_event_loop, wasm_binary_manipulation::get_js_code,
wasm_binary_manipulation::get_wasm_data, EXPERIMENTAL, MEMORY_MANAGER_REF_CELL, RUNTIME,
WASM_DATA_REF_CELL,
};

#[cfg(feature = "experimental")]
Expand Down Expand Up @@ -54,6 +55,10 @@ fn initialize(init: bool, function_index: i32, pass_arg_data: i32) {

let wasm_data = get_wasm_data();

WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| {
*wasm_data_ref_cell.borrow_mut() = Some(wasm_data.clone());
});

let env_vars: Vec<(&str, &str)> = wasm_data
.env_vars
.iter()
Expand Down Expand Up @@ -111,6 +116,16 @@ pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i
// TODO what do we do if there is an error in here?
context.eval_global_str("globalThis.exports = {};".to_string());
context.eval_global_str(format!("globalThis._azleExperimental = {EXPERIMENTAL};"));
let record_benchmarks = WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| {
wasm_data_ref_cell
.borrow()
.as_ref()
.unwrap()
.record_benchmarks
});
context.eval_global_str(format!(
"globalThis._azleRecordBenchmarks = {record_benchmarks};"
));
context.eval_module_str(js.to_string(), "azle_main");

run_event_loop(context);
Expand Down
Loading
Loading