diff --git a/crates/client-api-messages/src/energy.rs b/crates/client-api-messages/src/energy.rs index eace09e8da8..f03cdefd673 100644 --- a/crates/client-api-messages/src/energy.rs +++ b/crates/client-api-messages/src/energy.rs @@ -16,10 +16,6 @@ pub struct EnergyQuanta { impl EnergyQuanta { pub const ZERO: Self = EnergyQuanta { quanta: 0 }; - // per the comment on [`FunctionBudget::DEFAULT_BUDGET`]: 1 second of wasm runtime is roughtly 2 TeV - pub const PER_EXECUTION_SEC: Self = Self::new(2_000_000_000_000); - pub const PER_EXECUTION_NANOSEC: Self = Self::new(Self::PER_EXECUTION_SEC.get() / 1_000_000_000); - #[inline] pub const fn new(quanta: u128) -> Self { Self { quanta } @@ -125,46 +121,52 @@ impl fmt::Debug for EnergyBalance { } } -/// A measure of energy representing the energy budget for a reducer or any callable function. +/// A measure of the energy budget for a reducer or any callable function. /// -/// In contrast to [`EnergyQuanta`], this is represented by a 64-bit integer. This makes energy handling -/// for reducers easier, while still providing a unlikely-to-ever-be-reached maximum value (e.g. for wasmtime: -/// `(u64::MAX eV / 1000 eV/instruction) * 3 ns/instruction = 640 days`) -#[derive(Copy, Clone, From, Add, Sub, AddAssign, SubAssign)] +/// This unit is not directly convertible to `EnergyQuanta`. It is currently +/// 1:1 to wasmtime fuel, and we intend to treat it as representing a CPU +/// instruction. +#[derive(Copy, Clone, From, Add, Sub, AddAssign, SubAssign, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct FunctionBudget(u64); impl FunctionBudget { - // 1 second of wasm runtime is roughly 2 TeV, so this is - // roughly 1 minute of wasm runtime - pub const DEFAULT_BUDGET: Self = FunctionBudget(120_000_000_000_000); + /// We've generally assumed that 1 second of wasm runtime uses 2_000_000_000 fuel. + /// Currently, 1 wasmtime fuel unit is equivalent to 1 wasm instructions. Assuming + /// 1 wasm instruction compiles to 1 CPU instruction (which it doesn't), this implies + /// a 1 instruction-per-cycle abstract machine with a CPU frequency of 2GHz. + pub const PER_EXECUTION_SEC: Self = FunctionBudget(2_000_000_000); + + pub const PER_EXECUTION_NANOSEC: Self = Self(Self::PER_EXECUTION_SEC.0 / 1_000_000_000); + + /// Roughly 1 minute of runtime. + pub const DEFAULT_BUDGET: Self = FunctionBudget(Self::PER_EXECUTION_SEC.0 * 60); pub const ZERO: Self = FunctionBudget(0); pub const MAX: Self = FunctionBudget(u64::MAX); - pub fn new(v: u64) -> Self { + pub const fn new(v: u64) -> Self { Self(v) } - pub fn get(&self) -> u64 { + pub const fn get(&self) -> u64 { self.0 } - /// Convert from [`EnergyQuanta`]. Returns `None` if `energy` is too large to be represented. - pub fn from_energy(energy: EnergyQuanta) -> Option { - energy.get().try_into().ok().map(Self) + /// Convert `FunctionBudget` to `Duration` using the conversion factor + /// [`FunctionBudget::PER_EXECUTION_SEC`]. + pub fn to_duration(self) -> Duration { + Duration::from_nanos(self.0 / Self::PER_EXECUTION_NANOSEC.0) } -} -impl From for EnergyQuanta { - fn from(value: FunctionBudget) -> Self { - EnergyQuanta::new(value.0.into()) - } -} - -impl fmt::Debug for FunctionBudget { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReducerBudget") - .field(&EnergyQuanta::from(*self)) - .finish() + /// Convert `Duration` to `FunctionBudget` using the conversion factor + /// [`FunctionBudget::PER_EXECUTION_SEC`]. + /// + /// Returns `None` on overflow, which means that dur > 106.75 days. + // in order for duration_nanos * budget_per_ns >= u64::MAX: + // duration_nanos >= u64::MAX / budget_per_ns + // duration_nanos >= (9223372036854775 ns = 106.75 days) + pub fn from_duration(dur: Duration) -> Option { + let duration_nanos = u64::try_from(dur.as_nanos()).ok()?; + duration_nanos.checked_mul(Self::PER_EXECUTION_NANOSEC.get()).map(Self) } } diff --git a/crates/client-api/src/auth.rs b/crates/client-api/src/auth.rs index 329a538870e..475b250e52e 100644 --- a/crates/client-api/src/auth.rs +++ b/crates/client-api/src/auth.rs @@ -12,7 +12,7 @@ use spacetimedb::auth::token_validation::{ new_validator, DefaultValidator, TokenSigner, TokenValidationError, TokenValidator, }; use spacetimedb::auth::JwtKeys; -use spacetimedb::energy::EnergyQuanta; +use spacetimedb::energy::FunctionBudget; use spacetimedb::identity::Identity; use spacetimedb_data_structures::map::HashMap; use std::time::{Duration, SystemTime}; @@ -503,7 +503,7 @@ impl headers::Header for SpacetimeIdentityToken { } } -pub struct SpacetimeEnergyUsed(pub EnergyQuanta); +pub struct SpacetimeEnergyUsed(pub FunctionBudget); impl headers::Header for SpacetimeEnergyUsed { fn name() -> &'static http::HeaderName { static NAME: http::HeaderName = http::HeaderName::from_static("spacetime-energy-used"); @@ -515,9 +515,7 @@ impl headers::Header for SpacetimeEnergyUsed { } fn encode>(&self, values: &mut E) { - let mut buf = itoa::Buffer::new(); - let value = buf.format(self.0.get()); - values.extend([value.try_into().unwrap()]); + values.extend([self.0.get().into()]); } } diff --git a/crates/client-api/src/routes/database.rs b/crates/client-api/src/routes/database.rs index e1464814656..736a49f8b07 100644 --- a/crates/client-api/src/routes/database.rs +++ b/crates/client-api/src/routes/database.rs @@ -200,7 +200,7 @@ pub async fn call( let (status, body) = reducer_outcome_response(&owner_identity, &reducer, result.outcome); Ok(( status, - TypedHeader(SpacetimeEnergyUsed(result.energy_used)), + TypedHeader(SpacetimeEnergyUsed(result.execution_budget_used)), TypedHeader(SpacetimeExecutionDurationMicros(result.execution_duration)), body, ) diff --git a/crates/core/src/client/message_handlers_v1.rs b/crates/core/src/client/message_handlers_v1.rs index d6cf8fc6257..681792cb21b 100644 --- a/crates/core/src/client/message_handlers_v1.rs +++ b/crates/core/src/client/message_handlers_v1.rs @@ -1,6 +1,6 @@ use super::messages::{SubscriptionUpdateMessage, SwitchedServerMessage, ToProtocol, TransactionUpdateMessage}; use super::{ClientConnection, DataMessage, MessageHandleError, Protocol}; -use crate::energy::EnergyQuanta; +use crate::energy::FunctionBudget; use crate::host::module_host::{EventStatus, ModuleEvent, ModuleFunctionCall}; use crate::host::{FunctionArgs, ReducerId}; use crate::identity::Identity; @@ -179,7 +179,7 @@ impl MessageExecutionError { }, status: EventStatus::FailedInternal(format!("{:#}", err)), reducer_return_value: None, - energy_quanta_used: EnergyQuanta::ZERO, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::ZERO, request_id: Some(RequestId::default()), timer: None, diff --git a/crates/core/src/client/messages.rs b/crates/core/src/client/messages.rs index 798596b5bca..4c635ed6def 100644 --- a/crates/core/src/client/messages.rs +++ b/crates/core/src/client/messages.rs @@ -7,6 +7,7 @@ use crate::subscription::websocket_building::{brotli_compress, decide_compressio use bytes::{BufMut, Bytes, BytesMut}; use bytestring::ByteString; use derive_more::From; +use spacetimedb_client_api_messages::energy::EnergyQuanta; use spacetimedb_client_api_messages::websocket::common::{self as ws_common, RowListLen as _}; use spacetimedb_client_api_messages::websocket::v1::{self as ws_v1}; use spacetimedb_client_api_messages::websocket::v2 as ws_v2; @@ -408,7 +409,12 @@ impl ToProtocol for TransactionUpdateMessage { args, request_id, }, - energy_quanta_used: event.energy_quanta_used, + // This conversion is lying. We used to tell the client how much eV a transaction + // used, but now the database just tracks cpu usage, and it's converted to energy + // elsewhere. So, we just pretend that this is `EnergyQuanta` when it's actually + // a different unit, and it doesn't really matter to the client anyway. + // TODO(noa): maybe we could just have this be zero, unconditionally? + energy_quanta_used: EnergyQuanta::new(event.execution_budget_used.get().into()), total_host_execution_duration: event.host_execution_duration.into(), caller_connection_id: event.caller_connection_id.unwrap_or(ConnectionId::ZERO), }; diff --git a/crates/core/src/energy.rs b/crates/core/src/energy.rs index c66378e07a5..446d36c9ced 100644 --- a/crates/core/src/energy.rs +++ b/crates/core/src/energy.rs @@ -17,7 +17,7 @@ pub trait EnergyMonitor: Send + Sync + 'static { fn record_reducer( &self, fingerprint: &FunctionFingerprint<'_>, - energy_used: EnergyQuanta, + execution_budget_used: FunctionBudget, execution_duration: Duration, ); fn record_disk_usage(&self, database: &Database, replica_id: u64, disk_usage: u64, period: Duration); @@ -36,7 +36,7 @@ impl EnergyMonitor for NullEnergyMonitor { fn record_reducer( &self, _fingerprint: &FunctionFingerprint<'_>, - _energy_used: EnergyQuanta, + _execution_budget_used: FunctionBudget, _execution_duration: Duration, ) { } diff --git a/crates/core/src/host/host_controller.rs b/crates/core/src/host/host_controller.rs index 0abf4c5579a..549ec8b8cea 100644 --- a/crates/core/src/host/host_controller.rs +++ b/crates/core/src/host/host_controller.rs @@ -8,7 +8,7 @@ use crate::database_logger::DatabaseLogger; use crate::db::persistence::PersistenceProvider; use crate::db::relational_db::{self, spawn_view_cleanup_loop, DiskSizeFn, RelationalDB, Txdata}; use crate::db::{self, spawn_tx_metrics_recorder}; -use crate::energy::{EnergyMonitor, EnergyQuanta, NullEnergyMonitor}; +use crate::energy::{EnergyMonitor, FunctionBudget, NullEnergyMonitor}; use crate::host::v8::V8Runtime; use crate::host::ProcedureCallError; use crate::messages::control_db::{Database, HostType}; @@ -135,7 +135,7 @@ impl HostRuntimes { #[derive(Clone, Debug)] pub struct ReducerCallResult { pub outcome: ReducerOutcome, - pub energy_used: EnergyQuanta, + pub execution_budget_used: FunctionBudget, pub execution_duration: Duration, } diff --git a/crates/core/src/host/instance_env.rs b/crates/core/src/host/instance_env.rs index 0d3d41632b1..fdae2c1c229 100644 --- a/crates/core/src/host/instance_env.rs +++ b/crates/core/src/host/instance_env.rs @@ -13,7 +13,7 @@ use core::mem; use futures::TryFutureExt; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; -use spacetimedb_client_api_messages::energy::EnergyQuanta; +use spacetimedb_client_api_messages::energy::FunctionBudget; use spacetimedb_datastore::db_metrics::DB_METRICS; use spacetimedb_datastore::execution_context::Workload; use spacetimedb_datastore::locking_tx_datastore::state_view::StateView; @@ -784,7 +784,7 @@ impl InstanceEnv { request_id: None, timer: None, // The procedure will pick up the tab for the energy. - energy_quanta_used: EnergyQuanta { quanta: 0 }, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::from_millis(0), }; // Commit the tx and broadcast it. diff --git a/crates/core/src/host/module_host.rs b/crates/core/src/host/module_host.rs index 88c45a3f867..0adb2e0fab3 100644 --- a/crates/core/src/host/module_host.rs +++ b/crates/core/src/host/module_host.rs @@ -6,7 +6,6 @@ use crate::client::messages::{OneOffQueryResponseMessage, SerializableMessage}; use crate::client::{ClientActorId, ClientConnectionSender}; use crate::database_logger::{DatabaseLogger, LogLevel, Record}; use crate::db::relational_db::RelationalDB; -use crate::energy::EnergyQuanta; use crate::error::DBError; use crate::estimation::{check_row_limit, estimate_rows_scanned}; use crate::hash::Hash; @@ -208,7 +207,7 @@ pub struct ModuleEvent { pub function_call: ModuleFunctionCall, pub status: EventStatus, pub reducer_return_value: Option, - pub energy_quanta_used: EnergyQuanta, + pub execution_budget_used: FunctionBudget, pub host_execution_duration: Duration, pub request_id: Option, pub timer: Option, @@ -981,7 +980,7 @@ impl From for ViewOutcome { pub struct ViewCallResult { pub outcome: ViewOutcome, pub tx: MutTxId, - pub energy_used: FunctionBudget, + pub execution_budget_used: FunctionBudget, pub total_duration: Duration, pub abi_duration: Duration, } @@ -990,7 +989,7 @@ impl fmt::Debug for ViewCallResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ViewCallResult") .field("outcome", &self.outcome) - .field("energy_used", &self.energy_used) + .field("execution_budget_used", &self.execution_budget_used) .field("total_duration", &self.total_duration) .field("abi_duration", &self.abi_duration) .finish() @@ -1001,7 +1000,7 @@ impl ViewCallResult { pub fn default(tx: MutTxId) -> Self { Self { outcome: ViewOutcome::Success, - energy_used: FunctionBudget::ZERO, + execution_budget_used: FunctionBudget::ZERO, total_duration: Duration::ZERO, abi_duration: Duration::ZERO, tx, @@ -2062,7 +2061,7 @@ impl ModuleHost { // Increment execution stats tx = result.tx; outcome = result.outcome; - energy_used += result.energy_used; + energy_used += result.execution_budget_used; total_duration += result.total_duration; abi_duration += result.abi_duration; trapped |= trap; @@ -2076,7 +2075,7 @@ impl ModuleHost { ViewCallResult { outcome, tx, - energy_used, + execution_budget_used: energy_used, total_duration, abi_duration, }, diff --git a/crates/core/src/host/scheduler.rs b/crates/core/src/host/scheduler.rs index d3b285e9f16..e31499becc1 100644 --- a/crates/core/src/host/scheduler.rs +++ b/crates/core/src/host/scheduler.rs @@ -10,7 +10,7 @@ use anyhow::anyhow; use core::time::Duration; use futures::{FutureExt, StreamExt}; use rustc_hash::FxHashMap; -use spacetimedb_client_api_messages::energy::EnergyQuanta; +use spacetimedb_client_api_messages::energy::FunctionBudget; use spacetimedb_datastore::execution_context::{ExecutionContext, ReducerContext, Workload}; use spacetimedb_datastore::locking_tx_datastore::MutTxId; use spacetimedb_datastore::system_tables::{StFields, StScheduledFields, ST_SCHEDULED_ID}; @@ -585,7 +585,7 @@ fn refresh_views_then_commit_and_broadcast( status, reducer_return_value: None, //Keeping them 0 as it is internal transaction, not by reducer - energy_quanta_used: EnergyQuanta { quanta: 0 }, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::from_millis(0), request_id: None, timer: None, diff --git a/crates/core/src/host/v8/budget.rs b/crates/core/src/host/v8/budget.rs index 0b246b7222a..e37fbe4f8dc 100644 --- a/crates/core/src/host/v8/budget.rs +++ b/crates/core/src/host/v8/budget.rs @@ -7,13 +7,12 @@ //! so we have to invent one using time and timeouts. use super::env_on_isolate; -use crate::host::wasm_common::module_host_actor::EnergyStats; use crate::host::wasmtime::{epoch_ticker, ticks_in_duration}; use core::ptr; use core::sync::atomic::Ordering; use core::time::Duration; use core::{ffi::c_void, sync::atomic::AtomicBool}; -use spacetimedb_client_api_messages::energy::{EnergyQuanta, FunctionBudget}; +use spacetimedb_client_api_messages::energy::FunctionBudget; use std::sync::Arc; use v8::{Isolate, IsolateHandle}; @@ -115,19 +114,6 @@ fn budget_to_duration(_budget: FunctionBudget) -> Duration { Duration::MAX } -/// Returns [`EnergyStats`] for a reducer given its `budget` -/// and the `duration` it took to execute. -pub(super) fn energy_from_elapsed(budget: FunctionBudget, duration: Duration) -> EnergyStats { - let used = duration.as_nanos() * EnergyQuanta::PER_EXECUTION_NANOSEC.get(); - // in order for duration_nanos * ev_per_ns >= u64::MAX: - // duration_nanos >= u64::MAX / ev_per_ns - // duration_nanos >= (9223372036854775 ns = 106.75 days) - // so it's unlikely we'll have to worry about it - let used = FunctionBudget::new(u64::try_from(used).unwrap_or(u64::MAX)); - let remaining = budget - used; - EnergyStats { budget, remaining } -} - /// Converts a [`Duration`] to a [`ReducerBudget`]. fn duration_to_budget(_duration: Duration) -> FunctionBudget { // TODO(v8): This is fake logic that allows minimum energy usage. diff --git a/crates/core/src/host/v8/mod.rs b/crates/core/src/host/v8/mod.rs index 287d1eedf6b..9be3098283d 100644 --- a/crates/core/src/host/v8/mod.rs +++ b/crates/core/src/host/v8/mod.rs @@ -1,4 +1,3 @@ -use self::budget::energy_from_elapsed; use self::error::{ catch_exception, exception_already_thrown, log_traceback, ErrorOrException, ExcResult, ExceptionThrown, PinTryCatch, Throwable, @@ -22,9 +21,9 @@ use crate::host::module_host::{ use crate::host::scheduler::{CallScheduledFunctionResult, ScheduledFunctionParams}; use crate::host::wasm_common::instrumentation::CallTimes; use crate::host::wasm_common::module_host_actor::{ - AnonymousViewOp, DescribeError, ExecutionError, ExecutionResult, ExecutionStats, ExecutionTimings, InstanceCommon, - InstanceOp, ProcedureExecuteResult, ProcedureOp, ReducerExecuteResult, ReducerOp, ViewExecuteResult, ViewOp, - WasmInstance, + AnonymousViewOp, DescribeError, EnergyStats, ExecutionError, ExecutionResult, ExecutionStats, ExecutionTimings, + InstanceCommon, InstanceOp, ProcedureExecuteResult, ProcedureOp, ReducerExecuteResult, ReducerOp, + ViewExecuteResult, ViewOp, WasmInstance, }; use crate::host::wasm_common::{RowIters, TimingSpanSet}; use crate::host::{ModuleHost, ReducerCallError, ReducerCallResult, Scheduler}; @@ -1874,7 +1873,12 @@ where let timings = env.finish_funcall(); // Derive energy stats. - let energy = energy_from_elapsed(budget, timings.total_duration); + let energy_used = FunctionBudget::from_duration(timings.total_duration) + // The magnitude that `total_duration` would have to have to cause an overflow here is + // large enough that we don't really have to worry about it (see `from_duration` docs). + // Still, better to saturate than wrap. + .unwrap_or(FunctionBudget::MAX); + let energy = EnergyStats::from_used(budget, energy_used); // Reuse the last periodic heap sample instead of querying V8 on every call. // We use this statistic for energy tracking, so eventual consistency is fine. diff --git a/crates/core/src/host/wasm_common/module_host_actor.rs b/crates/core/src/host/wasm_common/module_host_actor.rs index 3b709fc433e..e64a20d46f8 100644 --- a/crates/core/src/host/wasm_common/module_host_actor.rs +++ b/crates/core/src/host/wasm_common/module_host_actor.rs @@ -33,7 +33,6 @@ use core::future::Future; use core::time::Duration; use prometheus::{Histogram, IntCounter, IntGauge}; use spacetimedb_auth::identity::ConnectionAuthCtx; -use spacetimedb_client_api_messages::energy::EnergyQuanta; use spacetimedb_datastore::db_metrics::DB_METRICS; use spacetimedb_datastore::error::{DatastoreError, ViewError}; use spacetimedb_datastore::execution_context::{self, ReducerContext, Workload}; @@ -111,9 +110,15 @@ impl EnergyStats { remaining: FunctionBudget::ZERO, }; + pub fn from_used(budget: FunctionBudget, used: FunctionBudget) -> Self { + // TODO: should this be a saturating_sub? + let remaining = budget - used; + Self { budget, remaining } + } + /// Returns the used energy amount. fn used(&self) -> FunctionBudget { - (self.budget.get() - self.remaining.get()).into() + self.budget - self.remaining } } @@ -233,7 +238,7 @@ pub struct ExecutionStats { } impl ExecutionStats { - fn energy_used(&self) -> FunctionBudget { + fn execution_budget_used(&self) -> FunctionBudget { self.energy.used() } @@ -632,7 +637,7 @@ impl InstanceCommon { log::info!("Database updated, {} host-type={}", stdb.database_identity(), host_type); let succeed = |info: Arc, - energy_quanta_used: EnergyQuanta, + execution_budget_used: FunctionBudget, host_execution_duration: Duration, tx: MutTxId| -> TransactionOffset { @@ -643,7 +648,7 @@ impl InstanceCommon { function_call: ModuleFunctionCall::update(), status: EventStatus::Committed(DatabaseUpdate::default()), reducer_return_value: None, - energy_quanta_used, + execution_budget_used, host_execution_duration, request_id: None, timer: None, @@ -657,7 +662,7 @@ impl InstanceCommon { let res: UpdateDatabaseResult = match res { crate::db::update::UpdateResult::Success => { - let tx_offset = succeed(self.info.clone(), FunctionBudget::ZERO.into(), Duration::ZERO, tx); + let tx_offset = succeed(self.info.clone(), FunctionBudget::ZERO, Duration::ZERO, tx); UpdateDatabaseResult::UpdatePerformed { tx_offset, durable_offset, @@ -679,7 +684,8 @@ impl InstanceCommon { stdb.report_mut_tx_metrics(reducer, tx_metrics, None); UpdateDatabaseResult::ErrorExecutingMigration(anyhow::anyhow!(msg)) } else { - let tx_offset = succeed(self.info.clone(), out.energy_used.into(), out.total_duration, tx); + let tx_offset = + succeed(self.info.clone(), out.execution_budget_used, out.total_duration, tx); UpdateDatabaseResult::UpdatePerformed { tx_offset, durable_offset, @@ -687,7 +693,7 @@ impl InstanceCommon { } } crate::db::update::UpdateResult::RequiresClientDisconnect => { - let tx_offset = succeed(self.info.clone(), FunctionBudget::ZERO.into(), Duration::ZERO, tx); + let tx_offset = succeed(self.info.clone(), FunctionBudget::ZERO, Duration::ZERO, tx); UpdateDatabaseResult::UpdatePerformedWithClientDisconnect { tx_offset, durable_offset, @@ -934,7 +940,7 @@ impl InstanceCommon { }; // Account for view execution in reducer reporting metrics - vm_metrics.report_energy_used(out.energy_used); + vm_metrics.report_execution_budget_used(out.execution_budget_used); vm_metrics.report_total_duration(out.total_duration); vm_metrics.report_abi_duration(out.abi_duration); @@ -947,7 +953,7 @@ impl InstanceCommon { reducer_return_value = None; } - let energy_quanta_used = result.stats.energy_used().into(); + let execution_budget_used = result.stats.execution_budget_used(); let total_duration = result.stats.total_duration(); let event = ModuleEvent { @@ -961,7 +967,7 @@ impl InstanceCommon { }, status, reducer_return_value, - energy_quanta_used, + execution_budget_used, host_execution_duration: total_duration, request_id, timer, @@ -970,7 +976,7 @@ impl InstanceCommon { let res = ReducerCallResult { outcome: ReducerOutcome::from(&event.status), - energy_used: energy_quanta_used, + execution_budget_used, execution_duration: total_duration, }; @@ -1013,13 +1019,12 @@ impl InstanceCommon { let result = vm_call_function(budget); let stats: &ExecutionStats = result.as_ref(); - let energy_used = stats.energy.used(); - let energy_quanta_used = energy_used.into(); + let execution_budget_used = stats.energy.used(); let timings = &stats.timings; let memory_allocation = stats.memory_allocation; self.energy_monitor - .record_reducer(&energy_fingerprint, energy_quanta_used, timings.total_duration); + .record_reducer(&energy_fingerprint, execution_budget_used, timings.total_duration); if self.allocated_memory != memory_allocation { self.metric_wasm_memory_bytes.set(memory_allocation as i64); self.allocated_memory = memory_allocation; @@ -1029,7 +1034,7 @@ impl InstanceCommon { function_span .record("timings.total_duration", tracing::field::debug(timings.total_duration)) - .record("energy.used", tracing::field::debug(energy_used)); + .record("energy.used", tracing::field::debug(execution_budget_used)); result } @@ -1270,7 +1275,7 @@ impl InstanceCommon { let res = ViewCallResult { outcome, tx, - energy_used: result.stats.energy_used(), + execution_budget_used: result.stats.execution_budget_used(), total_duration: result.stats.total_duration(), abi_duration: result.stats.abi_duration(), }; @@ -1322,7 +1327,7 @@ impl InstanceCommon { out.tx = result.tx; out.outcome = result.outcome; - out.energy_used += result.energy_used; + out.execution_budget_used += result.execution_budget_used; out.total_duration += result.total_duration; out.abi_duration += result.abi_duration; @@ -1517,8 +1522,8 @@ impl VmMetrics { self.reducer_plus_query_duration.clone().with_timer(start) } - fn report_energy_used(&self, energy_used: FunctionBudget) { - self.reducer_fuel_used.inc_by(energy_used.get()); + fn report_execution_budget_used(&self, execution_budget_used: FunctionBudget) { + self.reducer_fuel_used.inc_by(execution_budget_used.get()); } fn report_total_duration(&self, duration: Duration) { @@ -1531,10 +1536,10 @@ impl VmMetrics { /// Reports some VM metrics. fn report(&self, stats: &ExecutionStats) { - let energy_used = stats.energy.used(); + let execution_budget_used = stats.energy.used(); let reducer_duration = stats.timings.total_duration; let abi_time = stats.timings.wasm_instance_env_call_times.sum(); - self.report_energy_used(energy_used); + self.report_execution_budget_used(execution_budget_used); self.report_total_duration(reducer_duration); self.report_abi_duration(abi_time); } diff --git a/crates/core/src/host/wasmtime/mod.rs b/crates/core/src/host/wasmtime/mod.rs index 8bf760ae64b..84b950318e6 100644 --- a/crates/core/src/host/wasmtime/mod.rs +++ b/crates/core/src/host/wasmtime/mod.rs @@ -1,7 +1,7 @@ use self::wasm_instance_env::WasmInstanceEnv; use super::wasm_common::module_host_actor::{InitializationError, WasmModuleHostActor, WasmModuleInstance}; use super::wasm_common::{abi, ModuleCreationError}; -use crate::energy::{EnergyQuanta, FunctionBudget}; +use crate::energy::FunctionBudget; use crate::error::NodesError; use crate::module_host_context::ModuleCreationContext; use crate::util::jobs::AllocatedJobCore; @@ -153,7 +153,7 @@ impl WasmtimeFuel {} impl From for WasmtimeFuel { fn from(v: FunctionBudget) -> Self { - // ReducerBudget being u64 is load-bearing here - if it was u128 and v was ReducerBudget::MAX, + // FunctionBudget being u64 is load-bearing here - if it was u128 and v was FunctionBudget::MAX, // truncating this result would mean that with set_store_fuel(budget.into()), get_store_fuel() // would be wildly different than the original `budget`, and the energy usage for the reducer // would be u64::MAX even if it did nothing. ask how I know. @@ -167,12 +167,6 @@ impl From for FunctionBudget { } } -impl From for EnergyQuanta { - fn from(fuel: WasmtimeFuel) -> Self { - EnergyQuanta::new(u128::from(fuel.0)) - } -} - pub trait WasmPointee { type Pointer; fn write_to(self, mem: &mut MemView, ptr: Self::Pointer) -> Result<(), MemError>; diff --git a/crates/core/src/host/wasmtime/wasmtime_module.rs b/crates/core/src/host/wasmtime/wasmtime_module.rs index 0690120eb16..10e7bcd909a 100644 --- a/crates/core/src/host/wasmtime/wasmtime_module.rs +++ b/crates/core/src/host/wasmtime/wasmtime_module.rs @@ -719,7 +719,6 @@ fn get_memory_size(store: &Store) -> usize { #[cfg(test)] mod tests { use super::*; - use crate::energy::EnergyQuanta; #[test] fn test_fuel() { @@ -730,8 +729,8 @@ mod tests { let budget = FunctionBudget::DEFAULT_BUDGET; set_store_fuel(&mut store, budget.into()); store.set_fuel(store.get_fuel().unwrap() - 10).unwrap(); - let remaining: EnergyQuanta = get_store_fuel(&store).into(); - let used = EnergyQuanta::from(budget) - remaining; - assert_eq!(used, EnergyQuanta::new(10)); + let remaining: FunctionBudget = get_store_fuel(&store).into(); + let used = budget - remaining; + assert_eq!(used, FunctionBudget::new(10)); } } diff --git a/crates/core/src/sql/execute.rs b/crates/core/src/sql/execute.rs index 476a73a9a45..035b0196b6a 100644 --- a/crates/core/src/sql/execute.rs +++ b/crates/core/src/sql/execute.rs @@ -3,7 +3,7 @@ use std::time::Duration; use super::ast::SchemaViewer; use crate::db::relational_db::RelationalDB; -use crate::energy::EnergyQuanta; +use crate::energy::FunctionBudget; use crate::error::DBError; use crate::estimation::{check_row_limit, estimate_rows_scanned}; use crate::host::module_host::{ @@ -204,7 +204,7 @@ fn run_inner( }, status: EventStatus::Committed(DatabaseUpdate::default()), reducer_return_value: None, - energy_quanta_used: EnergyQuanta::ZERO, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::ZERO, request_id: None, timer: None, diff --git a/crates/core/src/subscription/module_subscription_actor.rs b/crates/core/src/subscription/module_subscription_actor.rs index c7cb2337bcf..17f617ab49d 100644 --- a/crates/core/src/subscription/module_subscription_actor.rs +++ b/crates/core/src/subscription/module_subscription_actor.rs @@ -1895,7 +1895,7 @@ mod tests { use futures::FutureExt; use itertools::Itertools; use pretty_assertions::assert_matches; - use spacetimedb_client_api_messages::energy::EnergyQuanta; + use spacetimedb_client_api_messages::energy::FunctionBudget; use spacetimedb_client_api_messages::websocket::{common::RowListLen as _, v1 as ws_v1, v2 as ws_v2}; use spacetimedb_commitlog::{commitlog, repo}; use spacetimedb_data_structures::map::{HashCollectionExt as _, HashMap}; @@ -2101,7 +2101,7 @@ mod tests { function_call: ModuleFunctionCall::default(), status: EventStatus::Committed(DatabaseUpdate::default()), reducer_return_value: None, - energy_quanta_used: EnergyQuanta { quanta: 0 }, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::from_millis(0), request_id: None, timer: None, diff --git a/crates/core/src/subscription/module_subscription_manager.rs b/crates/core/src/subscription/module_subscription_manager.rs index 03c3392942f..0700846fc74 100644 --- a/crates/core/src/subscription/module_subscription_manager.rs +++ b/crates/core/src/subscription/module_subscription_manager.rs @@ -2211,7 +2211,7 @@ mod tests { use crate::{ client::{ClientActorId, ClientConfig, ClientConnectionSender, ClientName}, db::relational_db::{tests_utils::TestDB, RelationalDB}, - energy::EnergyQuanta, + energy::FunctionBudget, host::{ module_host::{DatabaseUpdate, EventStatus, ModuleEvent, ModuleFunctionCall}, ArgsTuple, @@ -3183,7 +3183,7 @@ mod tests { }, status: EventStatus::Committed(DatabaseUpdate::default()), reducer_return_value: None, - energy_quanta_used: EnergyQuanta::ZERO, + execution_budget_used: FunctionBudget::ZERO, host_execution_duration: Duration::default(), request_id: None, timer: None,