Skip to content

Commit 533a42d

Browse files
committed
spec: clarify nominal cycles and subnet metrics semantics
1 parent ffd214b commit 533a42d

4 files changed

Lines changed: 43 additions & 20 deletions

File tree

‎docs/references/ic-interface-spec/index.md‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,23 @@ Once the IC frees the resources of a canister, its id, *cycle* balances, *contro
289289

290290
:::
291291

292+
#### Cost schedules {#cost-schedules}
293+
294+
A subnet's *cost schedule* determines how the protocol charges canisters for resource use, such as instruction execution and memory usage. There are two schedules:
295+
296+
- **Normal:** applies the protocol's ordinary resource charges in cycles.
297+
- **Free:** waives these resource charges, so they do not deduct cycles from canister balances.
298+
299+
The cost schedule has no impact on explicit cycle burning: they are still burnt from canister balances.
300+
301+
#### Nominal cycles {#nominal-cycles}
302+
303+
*Nominal cycles* are accounting quantities used to measure consumption in cycle metrics.
304+
305+
For resource charges, the nominal amount is the amount calculated under the [normal cost schedule](#cost-schedules). Under that schedule, the nominal charge equals the cycles actually charged. Under a free cost schedule, resource use such as instruction execution or memory usage still records the nominal charge in metrics, while the actual charge to canister balances is zero. Nominal consumption therefore measures the accounted cost even when no cycles are deducted from a canister's balance.
306+
307+
Hence, nominal consumption metrics must not be interpreted as the number of cycles actually removed from circulation.
308+
292309
#### Canister status {#canister-status}
293310

294311
The canister status can be used to control whether the canister is processing calls:
@@ -519,7 +536,7 @@ The state tree contains information about the topology of the Internet Computer.
519536
520537
- `num_canisters` (`nat`): The number of canisters on this subnet. This is a current value, not a counter, so it decreases when canisters are deleted.
521538
- `canister_state_bytes` (`nat`): The total size of the state in bytes currently taken by canisters on this subnet. This is a current value, not a counter. Recomputing it is expensive, so it is refreshed only every 10 blocks, at heights that are multiples of 10, and reads 0 until the first refresh after this subnet was created.
522-
- `consumed_cycles_total` (`map`): The total number of cycles removed from circulation on this subnet since this subnet was created. Besides the cycles charged to the canisters currently on this subnet, this includes the cycles charged to canisters that have since been deleted, together with the balance those canisters still held when they were deleted, and the cycles consumed on behalf of the subnet itself rather than charged to any individual canister. Cycles that are charged in advance and later refunded are excluded once the refund is accounted for, so this value can also decrease. It's a map of two values, a low part of type `nat` and a high part of type `opt nat`.
539+
- `consumed_cycles_total` (`map`): The total [nominal cycles](#nominal-cycles) accounted for by the subnet. This sums the historical consumption of canisters currently on the subnet and the subnet's retained accounting for deleted canisters (including their remaining balances at deletion) and consumption on behalf of the subnet itself. Refunds of prepaid charges reduce the total. Subnet splitting preserves canister histories and redistributes them with the canisters, so the original subnet loses their contribution and the new subnet inherits consumption from before its creation. The total can therefore decrease and is not limited to consumption that occurred on this subnet. It's a map of two values, a low part of type `nat` and a high part of type `opt nat`.
523540
- `update_transactions_total` (`nat`): The total number of transactions processed on this subnet since this subnet was created, i.e., the total number of messages executed in the replicated mode. The value is monotonically non-decreasing.
524541
525542

‎docs/references/ic-interface-spec/management-canister.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -877,15 +877,15 @@ The fields returned are:
877877

878878
- `num_canisters` (`nat`): the number of canisters on the subnet. This is a current value, not a counter, so it decreases when canisters are deleted.
879879

880-
- `canister_state_bytes` (`nat`): the total size in bytes of the state taken by canisters on the subnet. This is a current value, not a counter. Recomputing it is expensive, so it is refreshed only every 10 blocks, at heights that are multiples of 10, and can therefore be up to 10 blocks staler than the other fields. It reads 0 until the first refresh after the subnet was created.
880+
- `canister_state_bytes` (`nat`): the total size in bytes of the state taken by canisters on the subnet. This is a current value, not a counter. Recomputing it is expensive, so it is refreshed only every 10 blocks, at heights that are multiples of 10. It can be up to 10 blocks behind `block_height` and up to 9 blocks behind the other aggregates. It reads 0 until the first refresh after the subnet was created.
881881

882-
- `consumed_cycles_total` (`nat`): the total number of cycles removed from circulation on the subnet. Besides the cycles charged to the canisters currently on the subnet, this includes the cycles charged to canisters that have since been deleted, together with the balance those canisters still held when they were deleted, and the cycles consumed on behalf of the subnet itself rather than charged to any individual canister. Cycles that are charged in advance and later refunded are excluded once the refund is accounted for, so this value can also decrease.
882+
- `consumed_cycles_total` (`nat`): the total [nominal cycles](./index.md#nominal-cycles) accounted for by the subnet. This sums the historical consumption of canisters currently on the subnet and the subnet's retained accounting for deleted canisters (including their remaining balances at deletion) and consumption on behalf of the subnet itself. Refunds of prepaid charges reduce the total. Subnet splitting preserves canister histories and redistributes them with the canisters, so the original subnet loses their contribution and the new subnet inherits consumption from before its creation. The total can therefore decrease and is not limited to consumption that occurred on this subnet.
883883

884884
- `update_transactions_total` (`nat`): the total number of transactions processed on the subnet, i.e., the total number of messages executed in the replicated mode. The value is monotonically non-decreasing for a given subnet.
885885

886-
- `million_round_instructions_total` (`nat`): the total number of instructions the subnet accounted for across the execution phases of all rounds, in units of one million and rounded up, so a value of `42` means 42 million instructions. Besides the executed Wasm instructions this also covers the fixed per-execution and per-canister overheads charged by the scheduler, and the charges for work performed outside of Wasm execution, such as compilation, chunk assembly, and snapshot operations. It is therefore not a Wasm instruction meter. The value is monotonically non-decreasing for a given subnet.
886+
- `million_round_instructions_total` (`nat`): the total number of instructions the subnet accounted for across the execution phases of all rounds, in units of one million and rounded up, so a value of `42` represents an underlying count from 41,000,001 through 42,000,000 instructions. Besides the executed Wasm instructions this also covers the fixed per-execution and per-canister overheads charged by the scheduler, and the charges for work performed outside of Wasm execution, such as compilation, chunk assembly, and snapshot operations. It is therefore not a Wasm instruction meter. The value is monotonically non-decreasing for a given subnet.
887887

888-
`consumed_cycles_total`, `update_transactions_total`, and `million_round_instructions_total` cover the whole lifetime of the subnet, or the period since the respective metric was introduced for subnets that predate it.
888+
`update_transactions_total` and `million_round_instructions_total` cover the whole lifetime of the subnet, or the period since the respective metric was introduced for subnets that predate it.
889889

890890
### IC method `subnet_info` {#ic-subnet_info}
891891

‎docs/references/management-canister.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,15 +602,15 @@ Returns subnet-wide metrics for a given subnet, which does not have to be the su
602602
- `block_height` (`nat`): the target subnet's current block height, i.e. the height of the block in whose execution the call is processed
603603
- `num_canisters` (`nat`): canisters on the subnet
604604
- `canister_state_bytes` (`nat`): total size of canister state in bytes
605-
- `consumed_cycles_total` (`nat`): total cycles removed from circulation on the subnet
605+
- `consumed_cycles_total` (`nat`): total [nominal cycles](ic-interface-spec/index.md#nominal-cycles) accounted for by the subnet
606606
- `update_transactions_total` (`nat`): total transactions processed on the subnet
607607
- `million_round_instructions_total` (`nat`): total instructions the subnet accounted for across the execution phases of all rounds, in units of one million and rounded up
608608

609-
Only `block_height` is as of the block that processes the call. The other five fields are aggregates refreshed at block boundaries, so they describe an earlier block, and they are not refreshed in lockstep with each other. `canister_state_bytes` is the stalest: it is recomputed only every 10 blocks, at heights that are multiples of 10, so it can be up to 10 blocks behind the others, and it reads 0 until the first recomputation after the subnet was created.
609+
Only `block_height` is as of the block that processes the call. The other five fields are aggregates refreshed at block boundaries, so they describe an earlier block, and they are not refreshed in lockstep with each other. `canister_state_bytes` is the stalest: it is recomputed only every 10 blocks, at heights that are multiples of 10, so it can be up to 10 blocks behind `block_height` and up to 9 blocks behind the other aggregates, and it reads 0 until the first recomputation after the subnet was created.
610610

611-
`update_transactions_total` and `million_round_instructions_total` only ever grow. `consumed_cycles_total` covers deleted canisters (including the balance they still held when deleted) and cycles consumed by the subnet itself, and it nets out refunds of cycles charged in advance, so it can decrease. `num_canisters` and `canister_state_bytes` are current values, not counters.
611+
`update_transactions_total` and `million_round_instructions_total` only ever grow. `consumed_cycles_total` sums the historical nominal consumption of current canisters and the subnet's retained accounting for deleted canisters (including their remaining balances at deletion) and consumption on behalf of the subnet itself. Nominal charges can increase this metric under a free cost schedule without deducting cycles from canister balances. Refunds reduce it, and subnet splitting redistributes canisters' historical contributions, so the total can decrease and can include consumption from before the receiving subnet was created. `num_canisters` and `canister_state_bytes` are current values, not counters.
612612

613-
`million_round_instructions_total` counts the executed Wasm instructions plus the scheduler's per-execution and per-canister overheads and the charges for work outside Wasm execution (compilation, chunk assembly, snapshots), so it is not a Wasm instruction meter. Like the other counters, it covers the subnet's whole lifetime, or the period since the metric was introduced for subnets that predate it.
613+
`million_round_instructions_total` counts the executed Wasm instructions plus the scheduler's per-execution and per-canister overheads and the charges for work outside Wasm execution (compilation, chunk assembly, snapshots), so it is not a Wasm instruction meter. A reported value of `42` represents an underlying count from 41,000,001 through 42,000,000 instructions. Both instruction and transaction counters cover the subnet's whole lifetime, or the period since each metric was introduced for subnets that predate it.
614614

615615
### `subnet_info`
616616

‎public/references/ic.did‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -510,25 +510,31 @@ type subnet_metrics_result = record {
510510
num_canisters : nat;
511511
// Total size in bytes of the state taken by canisters on the subnet. A
512512
// current value, not a counter. Recomputing it is expensive, so it is
513-
// refreshed only every 10 blocks, at heights that are multiples of 10, and
514-
// reads 0 until the first refresh after the subnet was created.
513+
// refreshed only every 10 blocks, at heights that are multiples of 10. It
514+
// can be up to 10 blocks behind block_height and up to 9 blocks behind the
515+
// other aggregates. Reads 0 until the first refresh after subnet creation.
515516
canister_state_bytes : nat;
516-
// Total cycles removed from circulation on the subnet: the cycles charged
517-
// to the canisters currently on the subnet, plus those charged to canisters
518-
// that have since been deleted together with the balance those canisters
519-
// still held when deleted, plus those consumed on behalf of the subnet
520-
// itself. Refunds of cycles charged in advance are netted out, so this
521-
// value can also decrease.
517+
// Nominal cycles record consumption at normal cost-schedule rates even
518+
// when resource use is free; they are not a spendable balance.
519+
// Total nominal cycles accounted for by the subnet: current canisters'
520+
// historical consumption plus the subnet's retained accounting for deleted
521+
// canisters (including their remaining balances at deletion) and consumption
522+
// on behalf of the subnet itself. Free cost schedules can produce nominal
523+
// charges without deducting cycles from canister balances. Refunds reduce
524+
// the total. Subnet splitting redistributes canisters' histories, so the
525+
// total can decrease and can include consumption from before the receiving
526+
// subnet was created. It is not limited to consumption on this subnet.
522527
consumed_cycles_total : nat;
523528
// Total number of transactions processed on the subnet, i.e. the total
524529
// number of messages executed in the replicated mode. Monotonically
525530
// non-decreasing.
526531
update_transactions_total : nat;
527532
// Total instructions the subnet accounted for across the execution phases
528533
// of all rounds, in units of one million and rounded up: a value of 42
529-
// means 42 million instructions. Besides the executed Wasm instructions it
530-
// covers the fixed per-execution and per-canister overheads charged by the
531-
// scheduler and the charges for work performed outside of Wasm execution,
534+
// represents 41,000,001 through 42,000,000 instructions. Besides the executed
535+
// Wasm instructions it covers the fixed per-execution and per-canister
536+
// overheads charged by the scheduler and the charges for work performed
537+
// outside of Wasm execution,
532538
// so it is not a Wasm instruction meter. Monotonically non-decreasing.
533539
// Unlike the four fields above, it has no counterpart under
534540
// `/subnet/<subnet_id>/metrics` in the certified state tree.

0 commit comments

Comments
 (0)