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

adopt to new meter, streaming __get_profiling #41

Merged
merged 20 commits into from
Oct 11, 2023
Merged
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
96 changes: 48 additions & 48 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ic-wasm"
version = "0.5.1"
version = "0.6.0"
authors = ["DFINITY Stiftung"]
edition = "2021"
description = "A library for performing Wasm transformations specific to canisters running on the Internet Computer"
Expand All @@ -19,7 +19,7 @@ required-features = ["exe"]

[dependencies]
walrus = "0.20.1"
candid = "0.9.0"
candid = "0.9.9"
rustc-demangle = "0.1"
thiserror = "1.0.35"

Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Usage: `ic-wasm <input.wasm> -o <output.wasm> instrument --trace-only func1 --tr
Instrumented canister has the following additional endpoints:

* `__get_cycles: () -> (int64) query`. Get the current cycle counter.
* `__get_profiling: () -> (vec { record { int32; int64 }}) query`. Get the execution trace log.
* `__get_profiling: (idx:int32) -> (vec { record { int32; int64 }}, opt int32) query`. Get the execution trace log, starting with `idx` 0. If the log is larger than 2M, it returns the first 2M of trace, and the next `idx` for the next 2M chunk.
* `__toggle_tracing: () -> ()`. Disable/enable logging the execution trace.
* `__toggle_entry: () -> ()`. Disable/enable clearing exection trace for each update call.
* `icp:public name` metadata. Used to map func_id from execution trace to function name.
Expand All @@ -110,7 +110,7 @@ When `--trace-only` flag is provided, the counter and trace logging will only ha

By default, execution trace is stored in the first few pages (up to 32 pages) of stable memory. Without any user side support, we cannot profile upgrade or code which accesses stable memory. If the canister can pre-allocate a fixed region of stable memory at `canister_init`, we can then pass this address to `ic-wasm` via the `--start-page` flag, so that the trace is written to this pre-allocated space without corrupting the rest of the stable memory access.

Another optional flag `--page-limit` specifies the number of pre-allocated pages in stable memory. By default, it's set to 30 pages. We only store trace up to `page-limit` pages, the remaining trace is dropped. Currently, due to the message size limit, we can only store 2M of trace data, which equates to roughly 30 pages. This limitation can be lifted in the future by supporting streamed output of the trace.
Another optional flag `--page-limit` specifies the number of pre-allocated pages in stable memory. By default, it's set to 4096 pages (256MB). We only store trace up to `page-limit` pages, the remaining trace is dropped.

The recommended way of pre-allocating stable memory is via the `Region` library in Motoko, and `ic-stable-structures` in Rust. But developers are free to use any other libraries or even the raw stable memory system API to pre-allocate space, as long as the developer can guarantee that the pre-allocated space is not touched by the rest of the code.

Expand All @@ -121,7 +121,7 @@ import Region "mo:base/Region";
actor {
stable let profiling = do {
let r = Region.new();
ignore Region.grow(r, 32);
ignore Region.grow(r, 4096); // Increase the page number if you need larger log space
r;
};
...
Expand All @@ -146,7 +146,7 @@ const UPGRADES: MemoryId = MemoryId::new(1);
#[ic_cdk::init]
fn init() {
let memory = MEMORY_MANAGER.with(|m| m.borrow().get(PROFILING));
memory.grow(32);
memory.grow(4096); // Increase the page number if you need larger log space
...
}
#[ic_cdk::pre_upgrade]
Expand All @@ -163,10 +163,9 @@ fn post_upgrade() {

#### Current limitations

* Without pre-allocating stable memory from user code, we cannot profile upgrade or code that accesses stable memory.
* Without pre-allocating stable memory from user code, we cannot profile upgrade or code that accesses stable memory. You can profile traces larger than 256M, if you pre-allocate large pages of stable memory and specify the `page-limit` flag. Larger traces can be fetched in a streamming fashion via `__get_profiling(idx)`.
* Since the pre-allocation happens in `canister_init`, we cannot profile `canister_init`.
* If heartbeat is present, it's hard to measure any other method calls. It's also hard to measure a specific heartbeat event.
* We only store the first 2M of profiling data.
* We cannot measure query calls.
* No concurrent calls.

Expand Down
5 changes: 5 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ enum SubCommand {
/// The number of pages of the preallocated stable memory
#[clap(short, long, requires("start_page"))]
page_limit: Option<i32>,
/// Use the new metering cost, default to false. This flag will eventually be removed and set to true after the mainnet has adapted the new metering.
#[clap(short, long)]
use_new_metering: bool,
},
}

Expand Down Expand Up @@ -113,12 +116,14 @@ fn main() -> anyhow::Result<()> {
trace_only,
start_page,
page_limit,
use_new_metering,
} => {
use ic_wasm::instrumentation::{instrument, Config};
let config = Config {
trace_only_funcs: trace_only.clone().unwrap_or(vec![]),
start_address: start_page.map(|page| page * 65536),
page_limit: *page_limit,
use_new_metering: *use_new_metering,
};
instrument(&mut m, config).map_err(|e| anyhow::anyhow!("{e}"))?;
}
Expand Down
Loading
Loading