Skip to content

Commit d20e978

Browse files
committed
Merge remote-tracking branch 'origin/master' into basvandijk/namespace-bazel-remote-execution
2 parents 5fec32f + 54f3819 commit d20e978

3 files changed

Lines changed: 118 additions & 1 deletion

File tree

rs/replicated_state/src/metadata_state.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,33 @@ impl SubnetMetrics {
546546
self.consumed_cycles_ecdsa_outcalls
547547
}
548548

549+
/// Cycles consumed by Schnorr threshold-signature outcalls. Unlike ECDSA and
550+
/// HTTP outcalls, this use case has no dedicated field; it is only tracked in
551+
/// the by-use-case map (it can never originate from a deleted canister, so
552+
/// the map entry is exactly the subnet-level consumption).
553+
pub fn get_consumed_cycles_schnorr_outcalls(&self) -> NominalCycles {
554+
self.consumed_cycles_by_use_case
555+
.get(&CyclesUseCase::SchnorrOutcalls)
556+
.copied()
557+
.unwrap_or_else(NominalCycles::zero)
558+
}
559+
560+
/// Cycles consumed by VetKd outcalls. See `get_consumed_cycles_schnorr_outcalls`.
561+
pub fn get_consumed_cycles_vetkd(&self) -> NominalCycles {
562+
self.consumed_cycles_by_use_case
563+
.get(&CyclesUseCase::VetKd)
564+
.copied()
565+
.unwrap_or_else(NominalCycles::zero)
566+
}
567+
568+
/// Cycles lost due to dropped messages. See `get_consumed_cycles_schnorr_outcalls`.
569+
pub fn get_consumed_cycles_dropped_messages(&self) -> NominalCycles {
570+
self.consumed_cycles_by_use_case
571+
.get(&CyclesUseCase::DroppedMessages)
572+
.copied()
573+
.unwrap_or_else(NominalCycles::zero)
574+
}
575+
549576
pub fn get_consumed_cycles_by_use_case(&self) -> &BTreeMap<CyclesUseCase, NominalCycles> {
550577
&self.consumed_cycles_by_use_case
551578
}

rs/replicated_state/src/metadata_state/tests.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ use super::subnet_call_context_manager::{
55
};
66
use super::*;
77
use crate::metadata_state::testing::SystemMetadataTesting;
8+
use crate::metrics::ReplicatedStateMetrics;
89
use crate::testing::{CanisterQueuesTesting, StreamTesting};
9-
use crate::{CanisterPriority, InputQueueType};
10+
use crate::{CanisterPriority, InputQueueType, ReplicatedState};
1011
use assert_matches::assert_matches;
1112
use ic_crypto_test_utils_canister_threshold_sigs::{
1213
CanisterThresholdSigTestEnvironment, IDkgParticipants, generate_ecdsa_presig_quadruple,
@@ -15,13 +16,16 @@ use ic_crypto_test_utils_canister_threshold_sigs::{
1516
use ic_crypto_test_utils_reproducible_rng::{ReproducibleRng, reproducible_rng};
1617
use ic_error_types::{ErrorCode, UserError};
1718
use ic_limits::MAX_INGRESS_TTL;
19+
use ic_logger::no_op_logger;
1820
use ic_management_canister_types_private::{
1921
EcdsaCurve, EcdsaKeyId, IC_00, MasterPublicKeyId, SchnorrAlgorithm, SchnorrKeyId,
2022
};
23+
use ic_metrics::MetricsRegistry;
2124
use ic_protobuf::proxy::ProxyDecodeError;
2225
use ic_protobuf::state::queues::v1 as pb_queues;
2326
use ic_protobuf::state::system_metadata::v1 as pb_metadata;
2427
use ic_registry_routing_table::CanisterIdRange;
28+
use ic_test_utilities_metrics::fetch_gauge;
2529
use ic_test_utilities_types::ids::{
2630
SUBNET_0, SUBNET_1, SUBNET_2, canister_test_id, message_test_id, node_test_id, subnet_test_id,
2731
user_test_id,
@@ -2455,6 +2459,77 @@ fn consumed_cycles_total_calculates_the_right_amount() {
24552459
);
24562460
}
24572461

2462+
/// The `replicated_state_consumed_cycles_since_replica_started` gauge is
2463+
/// computed in `ReplicatedStateMetrics::observe` by summing the per-canister
2464+
/// totals with the subnet-level use cases. This test exercises every
2465+
/// subnet-level use case that contributes to the total, so that omitting any of
2466+
/// them (as the `SchnorrOutcalls`/`VetKd`/`DroppedMessages` use cases once were)
2467+
/// would change the reported value and fail the assertion. Distinct powers of
2468+
/// two are used so that a missing use case is always detectable in the total.
2469+
#[test]
2470+
fn consumed_cycles_gauge_accounts_for_all_subnet_level_use_cases() {
2471+
// The three use cases with a dedicated scalar field are also mirrored in the
2472+
// by-use-case map (as they are in production), while `SchnorrOutcalls`,
2473+
// `VetKd` and `DroppedMessages` live only in the map.
2474+
let mut consumed_cycles_by_use_case = BTreeMap::new();
2475+
consumed_cycles_by_use_case.insert(CyclesUseCase::DeletedCanisters, NominalCycles::new(1));
2476+
consumed_cycles_by_use_case.insert(CyclesUseCase::ECDSAOutcalls, NominalCycles::new(2));
2477+
consumed_cycles_by_use_case.insert(CyclesUseCase::HTTPOutcalls, NominalCycles::new(4));
2478+
consumed_cycles_by_use_case.insert(CyclesUseCase::SchnorrOutcalls, NominalCycles::new(8));
2479+
consumed_cycles_by_use_case.insert(CyclesUseCase::VetKd, NominalCycles::new(16));
2480+
consumed_cycles_by_use_case.insert(CyclesUseCase::DroppedMessages, NominalCycles::new(32));
2481+
2482+
// The canister-level use cases are also present in the by-use-case map (in
2483+
// production they end up there via deleted canisters), but the gauge derives
2484+
// their contribution from the per-canister totals and the
2485+
// `consumed_cycles_by_deleted_canisters` scalar rather than from the map.
2486+
// Insert them with a large value to ensure they are *not* double-counted
2487+
// into the gauge total from the map.
2488+
for use_case in [
2489+
CyclesUseCase::Memory,
2490+
CyclesUseCase::ComputeAllocation,
2491+
CyclesUseCase::IngressInduction,
2492+
CyclesUseCase::Instructions,
2493+
CyclesUseCase::RequestAndResponseTransmission,
2494+
CyclesUseCase::Uninstall,
2495+
CyclesUseCase::CanisterCreation,
2496+
CyclesUseCase::BurnedCycles,
2497+
] {
2498+
consumed_cycles_by_use_case.insert(use_case, NominalCycles::new(1024));
2499+
}
2500+
2501+
let subnet_metrics = SubnetMetrics {
2502+
consumed_cycles_by_deleted_canisters: NominalCycles::new(1),
2503+
consumed_cycles_ecdsa_outcalls: NominalCycles::new(2),
2504+
consumed_cycles_http_outcalls: NominalCycles::new(4),
2505+
consumed_cycles_by_use_case,
2506+
..Default::default()
2507+
};
2508+
2509+
let mut state = ReplicatedState::new(subnet_test_id(1), SubnetType::Application);
2510+
state.metadata.subnet_metrics = subnet_metrics;
2511+
2512+
let registry = MetricsRegistry::new();
2513+
let metrics = ReplicatedStateMetrics::new(&registry);
2514+
metrics.observe(
2515+
state.metadata.own_subnet_id,
2516+
&state,
2517+
Height::new(0),
2518+
&no_op_logger(),
2519+
);
2520+
2521+
// Deleted canisters (1) + ECDSA (2) + HTTP (4) + Schnorr (8) + VetKd (16)
2522+
// + dropped messages (32) = 63. There are no canisters, so the per-canister
2523+
// contribution is zero, and the canister-level use cases inserted into the
2524+
// map above (each worth 1024) must not appear in the total.
2525+
let gauge = fetch_gauge(
2526+
&registry,
2527+
"replicated_state_consumed_cycles_since_replica_started",
2528+
)
2529+
.unwrap();
2530+
assert_eq!(gauge, 63.0);
2531+
}
2532+
24582533
#[test]
24592534
fn observe_use_case_migrates_outcalls_scalar_fields_into_use_cases() {
24602535
let mut subnet_metrics = SubnetMetrics {

rs/replicated_state/src/metrics.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,21 @@ impl ReplicatedStateMetrics {
535535
.subnet_metrics
536536
.get_consumed_cycles_http_outcalls();
537537

538+
// Add the remaining subnet-level use cases. Unlike ECDSA/HTTP outcalls
539+
// and deleted canisters, these have no dedicated scalar field, but their
540+
// getters read the by-use-case map. The canister-level use cases in that
541+
// map originate from deleted canisters and are already covered by
542+
// `get_consumed_cycles_by_deleted_canisters()`.
543+
consumed_cycles_total += state
544+
.metadata
545+
.subnet_metrics
546+
.get_consumed_cycles_schnorr_outcalls();
547+
consumed_cycles_total += state.metadata.subnet_metrics.get_consumed_cycles_vetkd();
548+
consumed_cycles_total += state
549+
.metadata
550+
.subnet_metrics
551+
.get_consumed_cycles_dropped_messages();
552+
538553
self.consumed_cycles.set(consumed_cycles_total.get() as f64);
539554

540555
self.observe_consumed_cycles_by_use_case(&consumed_cycles_total_by_use_case);

0 commit comments

Comments
 (0)