SchedulingStateMachine

Struct SchedulingStateMachine 

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

A high-level struct, managing the overall scheduling of tasks, to be used by solana-unified-scheduler-pool.

Implementations§

Source§

impl SchedulingStateMachine

Source

pub fn has_no_running_task(&self) -> bool

Source

pub fn has_no_active_task(&self) -> bool

Source

pub fn has_unblocked_task(&self) -> bool

Source

pub fn has_runnable_task(&self) -> bool

Source

pub fn unblocked_task_queue_count(&self) -> usize

Source

pub fn schedule_task(&mut self, task: Task) -> Option<Task>

Schedules given task, returning it if successful.

Returns Some(task) if it’s immediately scheduled. Otherwise, returns None, indicating the scheduled task is blocked currently.

Note that this function takes ownership of the task to allow for future optimizations.

Source

pub fn buffer_task(&mut self, task: Task)

Adds given task to internal buffer, even if it’s immediately schedulable otherwise.

Put differently, buffering means to force the task to be blocked unconditionally after normal scheduling processing.

Thus, the task is internally retained inside this SchedulingStateMachine, whether the task is blocked or not. Eventually, the buffered task will be returned by one of later invocations schedule_next_unblocked_task().

Note that this function takes ownership of the task to allow for future optimizations.

Source

pub fn schedule_or_buffer_task( &mut self, task: Task, force_buffering: bool, ) -> Option<Task>

Schedules or buffers given task, returning successful one unless buffering is forced.

Refer to schedule_task() and buffer_task() for the difference between scheduling and buffering respectively.

Note that this function takes ownership of the task to allow for future optimizations.

Source

pub fn schedule_next_unblocked_task(&mut self) -> Option<Task>

Source

pub fn deschedule_task(&mut self, task: &Task)

Deschedules given scheduled task.

This must be called exactly once for all scheduled tasks to uphold both SchedulingStateMachine and UsageQueue internal state consistency at any given moment of time. It’s serious logic error to call this twice with the same task or none at all after scheduling. Similarly, calling this with not scheduled task is also forbidden.

Note that this function intentionally doesn’t take ownership of the task to avoid dropping tasks inside SchedulingStateMachine to provide an offloading-based optimization opportunity for callers.

Source

pub fn create_task( transaction: RuntimeTransaction<SanitizedTransaction>, index: usize, usage_queue_loader: &mut impl FnMut(Pubkey) -> UsageQueue, ) -> Task

Creates a new task with RuntimeTransaction<SanitizedTransaction> with all of its corresponding UsageQueues preloaded.

Closure (usage_queue_loader) is used to delegate the (possibly multi-threaded) implementation of UsageQueue look-up by pubkey to callers. It’s the caller’s responsibility to ensure the same instance is returned from the closure, given a particular pubkey.

Closure is used here to delegate the responsibility of primary ownership of UsageQueue (and caching/pruning if any) to the caller. SchedulingStateMachine guarantees that all of shared owndership of UsageQueues are released and UsageQueue state is identical to just after created, if has_no_active_task() is true. Also note that this is desired for separation of concern.

Source

pub fn create_block_production_task( transaction: RuntimeTransaction<SanitizedTransaction>, index: usize, consumed_block_size: BlockSize, usage_queue_loader: &mut impl FnMut(Pubkey) -> UsageQueue, ) -> Task

Source

pub fn reinitialize(&mut self)

Rewind the inactive state machine to be initialized

This isn’t called reset to indicate this isn’t safe to call this at any given moment. This panics if the state machine hasn’t properly been finished (i.e. there should be no active task) to uphold invariants of UsageQueues.

This method is intended to reuse SchedulingStateMachine instance (to avoid its unsafe constructor as much as possible) and its (possibly cached) associated UsageQueues for processing other slots.

There’s a related method called clear_and_reinitialize().

Source

pub fn clear_and_reinitialize(&mut self) -> usize

Clear all buffered tasks and immediately rewind the state machine to be initialized

This method may panic if there are tasks which has been scheduled but hasn’t been descheduled yet (called active tasks). This is due to the invocation of reinitialize() at last. On the other hand, it’s guaranteed not to panic otherwise. That’s because the first clearing step effectively relaxes the runtime invariant of reinitialize() by making the state machine inactive beforehand. After a successful operation, this method returns the number of cleared tasks.

Somewhat surprisingly, the clearing logic is same as the normal (de-)scheduling operation because it is still the fastest way to just clear all tasks, under the consideration of potential later use of UsageQueues. That’s because state_machine doesn’t maintain the global list of tasks. Maintaining such one would incur a needless overhead on scheduling, which isn’t strictly needed otherwise.

Moreover, the descheduling operation is rather heavily optimized to begin with. All collection ops are just O(1) over total N of addresses accessed by all active tasks with no amortized mem ops.

Whatever the algorithm is chosen, the ultimate goal of this operation is to clear all usage queues. Toward to that end, one may create a temporary hash set over UsageQueues on the fly alternatively. However, that would be costlier than the above usual descheduling approach due to extra mem ops and many lookups/insertions.

Source

pub unsafe fn exclusively_initialize_current_thread_for_scheduling( max_running_task_count: Option<usize>, ) -> Self

Creates a new instance of SchedulingStateMachine with its unsafe fields created as well, thus carrying over unsafe.

§Safety

Call this exactly once for each thread. See [TokenCell] for details.

Auto Trait Implementations§

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> 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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V