Skip to main content

Meter

Struct Meter 

Source
pub struct Meter { /* private fields */ }
Expand description

One run’s budget as a safepoint charges it: a handle every task thread can hold at once, over counters that need no lock.

§Why this is not a &mut Budget

It used to be. crate::host::HostRegistry::with_budget locked a mutex, handed the closure a &mut Budget, and unlocked — at every call and at every return, because every call and every return is a safepoint. Issue #182 measured what that cost: on benches/call, with_budget plus pthread_mutex_lock plus pthread_mutex_unlock were 36% of the run against the predecessor’s execute at 46%.

The lock was not protecting anything that needed one. A safepoint adds to fuel_spent, reads an atomic flag, compares against a limit fixed before the run, and every so often reads a clock that started before the run. None of that is a multi-field invariant two threads could tear; the counters were plain integers because the struct holding them happened to be reached by &mut, not because anything wanted them to be. So they are atomics, this is the &self view of them, and the mutex is left to what installs a budget and what reads the counters back.

§What is still the mutex’s

crate::host::HostRegistry::with_budget still exists and still locks. It is how a budget is installed, how cove run --stats reads what a run spent, and how the charges that are not per-instruction are made — a host call, a spawn, a task that ended. Every one of those is bounded by something far more expensive than a lock, and moving them would have been churn without a number behind it.

§Taking one, and restarts

A Meter names the accounting of the run it was taken from rather than “whatever budget the registry holds now”. Budget::restart gives its budget fresh accounting, so a Meter taken before a restart charges the run that ended. Both backends therefore take theirs where a run begins: Vm::new and Interpreter::new take one, and invoke_within and run_entry_within take another immediately after installing the budget they were handed. A registry’s budget cannot be replaced by any other route — set_budget needs &mut HostRegistry and a backend holds the registry by shared reference for as long as it exists — so those are all the places a stale one could come from.

Implementations§

Source§

impl Meter

Source

pub fn limits(&self) -> &Limits

The limits the run was given, which do not change while it lasts.

Source

pub fn is_cancelled(&self) -> bool

Whether the run has been cancelled from outside.

The run’s flag, which every task of it shares. A task’s own flag and a bounded call’s belong to one thread, and crate::interp::stopped_here is where those two are read.

Source

pub fn safepoint(&self, fuel: u64) -> Result<(), Stopped>

Checks cancellation, the deadline, and fuel in one call. Both backends call this at their safepoints. fuel is the cost of the work performed since the last one.

The order the three questions are asked in is the whole of what a caller can observe about this, and it is the order they were asked in when a mutex was held across all three.

Source

pub fn spend(&self, fuel: u64)

Adds fuel to the run’s total without asking whether the run may continue.

A backend that charges fuel in batches holds some between two safepoints, and the safepoint is where that holding is spent. A run that ends anywhere else — by raising, by being stopped, by a task thread finishing — reaches no further safepoint, so what it had gathered would simply not be counted, and fuel_spent would report less work than the run did. This is where the last of it is put back, and it decides nothing: the run is already over, and a second stop raised here would be answering a question nobody asked.

Source

pub fn fuel_spent(&self) -> u64

Total fuel spent so far, for reporting.

Source

pub fn elapsed(&self) -> Duration

Wall-clock time elapsed since the run started.

Source

pub fn to_runtime_error(&self, stopped: Stopped) -> RuntimeError

Converts why execution stopped into a RuntimeError naming the limit and its configured value, quoting ADR 0001’s position that these are runtime controls rather than termination proofs.

Trait Implementations§

Source§

impl Clone for Meter

Source§

fn clone(&self) -> Meter

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Meter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Meter

§

impl RefUnwindSafe for Meter

§

impl Send for Meter

§

impl Sync for Meter

§

impl Unpin for Meter

§

impl UnsafeUnpin for Meter

§

impl UnwindSafe for Meter

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.