Hey folks,
Since the performance counter (type 0) has been introduced, there were a few requests for improvement. One of the main pain points was the difficulty of using the performance counter with async code. After each await
point the counter gets reset, so the developer is responsible for storing the counter before the await
point and then adding it to the number of instructions after the await
…
This per-call instruction counter is to facilitate the instrumentation of the async code. Let us know what do you think about the following proposal?
Proposal
Consider the following call graph: canister A calls canister B, which calls back canister A.
// Canister A
fn a_1() {
// Block 1
assert!(counter(1) > 0);
assert!(counter(1) < 1);
call(b_1).await;
// Block 5
assert!(counter(1) > 1 + 3);
assert!(counter(1) < 1 + 3 + 5);
reply();
}
fn a_2() {
// Block 3
assert!(counter(1) > 1);
assert!(counter(1) < 1 + 3);
reply();
}
// Canister B
fn b_1() {
// Block 2
assert!(counter(1) > 0);
assert!(counter(1) < 2);
call(a_2).await
// Block 4
assert!(counter(1) > 2);
assert!(counter(1) < 2 + 4);
reply();
}
Note, at the end of the execution of the call graph, the counter type 1 returns:
- In canister A – the number of instructions executed in blocks 1, 3 and 5.
- In canister B – the number of instructions executed in blocks 2 and 4.
Risk Considerations
Passing the executed number of instructions between the parent and the child call contexts is a potential security risk (side channel attack). The implementation should share the instructions information only when the caller and the callee canister IDs are the same.