Measure used cycles in call_with_payment

I’m trying to measure cycle consumption in my canister by taking a simple approach:

  1. Record balance_before = ic_cdk::api::canister_balance().
  2. Perform some async work (e.g. call_with_payment128, external HTTP request, etc.).
  3. Record balance_after = ic_cdk::api::canister_balance().
  4. Compute cycles_used = balance_before - balance_after.

This works fine if only one request is in-flight at a time. However, my canister has multiple “threads” running concurrently, each potentially doing its own balance_before/balance_after measurement. Because they can overlap, the final difference in cycles doesn’t necessarily correspond neatly to just one call. For instance, if two calls measure at nearly the same time, their balance deltas can interfere with each other.

Questions:

  1. Is there any built-in way (similar to call_with_payment128) that can tell me exactly how many cycles a particular call or piece of code consumed, without me doing my own balance diffs?
  2. If not, how do I accurately charge different users or subscribers for cycles in a concurrent environment?
  3. Is there some canisters examples which already implemented these logic? So I can check
1 Like

This approach will not provide you with accurate information for a couple reasons:

  1. As you already noticed, concurrent calls can interleave and skew the results.
  2. On top of that, the canister is periodically charged for memory it uses, so that will also decrease the balance.
  3. And on top of that, the canister might receive (more) ingress messages which also cost some cycles to be inducted.

As such, there’s no built-in way that can tell you exactly how many cycles a piece of code consumed. The best you can do now is measure instructions consumption (which you can then translate to cycles you require from your callers) with a tool like canbench.

1 Like