Skip to content

Commit

Permalink
Merge pull request #82 from bastion-rs/bastion-executor-docs
Browse files Browse the repository at this point in the history
Bastion Executor Documentation
  • Loading branch information
vertexclique committed Nov 10, 2019
2 parents f913def + 28ac438 commit c7e7899
Show file tree
Hide file tree
Showing 18 changed files with 350 additions and 40 deletions.
93 changes: 92 additions & 1 deletion bastion-executor/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,94 @@
# Bastion Executor

SMP enabled NUMA-aware executor for Rust
<table align=left style='float: left; margin: 4px 10px 0px 0px; border: 1px solid #000000;'>
<tr>
<td>Latest Release</td>
<td>
<a href="https://crates.io/crates/bastion">
<img alt="Crates.io" src="https://img.shields.io/crates/v/bastion-executor.svg?style=popout-square">
</a>
</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>License</td>
<td>
<a href="https://github.com/bastion-rs/bastion/blob/master/LICENSE">
<img alt="Crates.io" src="https://img.shields.io/crates/l/bastion.svg?style=popout-square">
</a>
</td>
</tr>
<tr>
<td>Build Status</td>
<td>
<a href="https://actions-badge.atrox.dev/bastion-rs/bastion/goto">
<img alt="Build Status" src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fbastion-rs%2Fbastion%2Fbadge&style=flat" />
</a>
</td>
</tr>
<tr>
<td>Downloads</td>
<td>
<a href="https://crates.io/crates/bastion-executor">
<img alt="Crates.io" src="https://img.shields.io/crates/d/bastion-executor.svg?style=popout-square">
</a>
</td>
</tr>
<tr>
<td>Discord</td>
<td>
<a href="https://discord.gg/DqRqtRT">
<img src="https://img.shields.io/discord/628383521450360842.svg?logo=discord" />
</a>
</td>
</tr>
</table>

Bastion Executor is NUMA-aware SMP based Fault-tolerant Executor

Bastion Executor is a highly-available, fault-tolerant, async communication
oriented executor. Bastion's main idea is supplying a fully async runtime
with fault-tolerance to work on heavy loads.

Main differences between other executors are:
* Uses SMP based execution scheme to exploit cache affinity on multiple cores and execution is
equally distributed over the system resources, which means utilizing the all system.
* Uses NUMA-aware allocation for scheduler's queues and exploit locality on server workloads.
* Tailored for creating middleware and working with actor model like concurrency and distributed communication.

**NOTE:** Bastion Executor is independent of it's framework implementation.
It uses [lightproc](https://docs.rs/lightproc) to encapsulate and provide fault-tolerance to your future based workloads.
You can use your futures with [lightproc](https://docs.rs/lightproc) to run your workloads on Bastion Executor without the need to have framework.

## Example Usage

```rust
use bastion_executor::prelude::*;
use lightproc::proc_stack::ProcStack;

fn main() {
let pid = 1;
let stack = ProcStack::default()
.with_pid(pid)
.with_after_panic(move || println!("after panic {}", pid.clone()));

let handle = spawn(
async {
panic!("test");
},
stack,
);

let pid = 2;
let stack = ProcStack::default().with_pid(pid);

run(
async {
handle.await;
},
stack.clone(),
);
}
```
14 changes: 14 additions & 0 deletions bastion-executor/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
//!
//! NUMA-aware locality enabled allocator with optional fallback.
//!
//! Currently this API marked as `unstable` and can only be used with `unstable` feature.
//!
//! This allocator checks for NUMA-aware locality, and if it suitable it can start
//! this allocator with local allocation policy [MPOL_LOCAL].
//! In other cases otherwise it tries to use jemalloc.
//!
//! This allocator is an allocator called [Numanji].
//!
//! [Numanji]: https://docs.rs/numanji
//! [MPOL_LOCAL]: http://man7.org/linux/man-pages/man2/set_mempolicy.2.html
//!
unstable_api! {
// Allocation selector import
use numanji::*;
Expand Down
1 change: 0 additions & 1 deletion bastion-executor/src/blocking_pool.rs

This file was deleted.

7 changes: 6 additions & 1 deletion bastion-executor/src/distributor.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//!
//! Cache affine thread pool distributor
//!
//! Distributor provides a fair distribution of threads and pinning them to cores for fair execution.
//! It assigns threads in round-robin fashion to all cores.
use super::placement;
use super::placement::CoreId;
use super::run_queue::{Stealer, Worker};
Expand All @@ -18,7 +23,7 @@ impl Distributor {
}
}

pub fn assign(mut self) -> Vec<Stealer<LightProc>> {
pub fn assign(self) -> Vec<Stealer<LightProc>> {
let mut stealers = Vec::<Stealer<LightProc>>::new();

for core in self.cores {
Expand Down
24 changes: 21 additions & 3 deletions bastion-executor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
//!
//!
//!
//! NUMA-aware SMP based Fault-tolerant Executor
//! Bastion Executor is NUMA-aware SMP based Fault-tolerant Executor
//!
//! Bastion Executor is a highly-available, fault-tolerant, async communication
//! oriented executor. Bastion's main idea is supplying a fully async runtime
//! with fault-tolerance to work on heavy loads.
//!
//! Main differences between other executors are:
//! * Uses SMP based execution scheme to exploit cache affinity on multiple cores and execution is
//! equally distributed over the system resources, which means utilizing the all system.
//! * Uses NUMA-aware allocation for scheduler's queues and exploit locality on server workloads.
//! * Tailored for creating middleware and working with actor model like concurrency and distributed communication.
//!
//! **NOTE:** Bastion Executor is independent of it's framework implementation.
//! It uses [lightproc] to encapsulate and provide fault-tolerance to your future based workloads.
//! You can use your futures with [lightproc] to run your workloads on Bastion Executor without the need to have framework.
//!
//! [lightproc]: https://docs.rs/lightproc
//!

#![doc(
html_logo_url = "https://raw.githubusercontent.com/bastion-rs/bastion/master/img/bastion-logo.png"
)]
// Discarded lints
#![allow(clippy::if_same_then_else)]
// Force missing implementations
Expand All @@ -15,17 +33,17 @@
mod macros;

pub mod allocator;
pub mod blocking_pool;
pub mod distributor;
pub mod load_balancer;
pub mod placement;
pub mod pool;
pub mod run;
pub mod run_queue;
pub mod sleepers;
pub mod thread_recovery;
pub mod worker;

///
/// Prelude of Bastion Executor
pub mod prelude {
pub use crate::pool::*;
pub use crate::run::*;
Expand Down
24 changes: 22 additions & 2 deletions bastion-executor/src/load_balancer.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
//!
//! Module for gathering statistics about the run queues of the runtime
//!
//! Load balancer calculates sampled mean to provide average process execution amount
//! to all runtime.
//!

use super::placement;
use lazy_static::*;

use std::thread;

use super::load_balancer;
use crate::worker;
use crossbeam_utils::sync::ShardedLock;
use rustc_hash::FxHashMap;
use std::time::Duration;

///
/// Loadbalancer struct which is just a convenience wrapper over the statistics calculations.
#[derive(Debug)]
pub struct LoadBalancer();

impl LoadBalancer {
///
/// Statistics sampling thread for run queue load balancing.
pub fn sample() {
thread::Builder::new()
.name("load-balancer-thread".to_string())
Expand All @@ -36,7 +47,14 @@ impl LoadBalancer {
}
}

#[derive(Clone)]
///
/// Holding all statistics related to the run queue
///
/// Contains:
/// * Global run queue size
/// * Mean level of processes in the run queues
/// * SMP queue distributions
#[derive(Clone, Debug)]
pub struct Stats {
pub(crate) global_run_queue: usize,
pub(crate) mean_level: usize,
Expand All @@ -46,6 +64,8 @@ pub struct Stats {
unsafe impl Send for Stats {}
unsafe impl Sync for Stats {}

///
/// Static access to runtime statistics
#[inline]
pub fn stats() -> &'static ShardedLock<Stats> {
lazy_static! {
Expand Down
2 changes: 2 additions & 0 deletions bastion-executor/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
///
/// Marker of unstable API.
#[doc(hidden)]
macro_rules! unstable_api {
($($block:item)*) => {
Expand Down
11 changes: 11 additions & 0 deletions bastion-executor/src/placement.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
//!
//! Core placement configuration and management
//!
//! Placement module enables thread placement onto the cores.
//! CPU level affinity assignment is done here.

/// This function tries to retrieve information
/// on all the "cores" active on this system.
pub fn get_core_ids() -> Option<Vec<CoreId>> {
get_core_ids_helper()
}

///
/// Sets the current threads affinity
pub fn set_for_current(core_id: CoreId) {
set_for_current_helper(core_id);
}

///
/// CoreID implementation to identify system cores.
#[derive(Copy, Clone, Debug)]
pub struct CoreId {
/// Used core ID
pub id: usize,
}

Expand Down
49 changes: 46 additions & 3 deletions bastion-executor/src/pool.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
//!
//! Pool of threads to run lightweight processes
//!
//! Pool management and tracking belongs here.
//! We spawn futures onto the pool with [spawn] method of global run queue or
//! with corresponding [Worker]'s spawn method.

use super::distributor::Distributor;

use super::run_queue::{Injector, Stealer, Worker};
use super::run_queue::{Injector, Stealer};
use super::sleepers::Sleepers;
use super::worker;
use lazy_static::*;
use lightproc::prelude::*;
use std::future::Future;

use crate::load_balancer;

///
/// Spawn a process (which contains future + process stack) onto the executor from the global level.
///
/// # Example
/// ```rust
/// use bastion_executor::prelude::*;
/// use lightproc::prelude::*;
///
/// let pid = 1;
/// let stack = ProcStack::default().with_pid(pid);
///
/// let handle = spawn(
/// async {
/// panic!("test");
/// },
/// stack.clone(),
/// );
///
/// run(
/// async {
/// handle.await;
/// },
/// stack.clone(),
/// );
/// ```
pub fn spawn<F, T>(future: F, stack: ProcStack) -> RecoverableHandle<T>
where
F: Future<Output = T> + Send + 'static,
Expand All @@ -17,9 +47,18 @@ where
self::get().spawn(future, stack)
}

///
/// Pool that global run queue, stealers of the workers, and parked threads.
#[derive(Debug)]
pub struct Pool {
///
/// Global run queue implementation
pub injector: Injector<LightProc>,
///
/// Stealers of the workers
pub stealers: Vec<Stealer<LightProc>>,
///
/// Container of parked threads
pub sleepers: Sleepers,
}

Expand All @@ -30,6 +69,8 @@ impl Pool {
unimplemented!()
}

///
/// Spawn a process (which contains future + process stack) onto the executor via [Pool] interface.
pub fn spawn<F, T>(&self, future: F, stack: ProcStack) -> RecoverableHandle<T>
where
F: Future<Output = T> + Send + 'static,
Expand All @@ -45,6 +86,8 @@ impl Pool {
}
}

///
/// Acquire the static Pool reference
#[inline]
pub fn get() -> &'static Pool {
lazy_static! {
Expand Down
24 changes: 24 additions & 0 deletions bastion-executor/src/run.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//!
//! Blocking run of the async processes
//!
//!
use super::worker;
use crossbeam_utils::sync::Parker;
use lightproc::proc_stack::ProcStack;
Expand All @@ -10,6 +14,26 @@ use std::sync::Arc;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use std::{mem, panic};

///
/// This method blocks the current thread until passed future is resolved with an output (including the panic).
///
/// It is called `block_on` or `blocking` in some executors.
///
/// # Example
/// ```rust
/// use bastion_executor::prelude::*;
/// use lightproc::prelude::*;
/// let mut sum = 0;
///
/// run(
/// async {
/// (0..10_000_000).for_each(|_| {
/// sum += 1;
/// });
/// },
/// ProcStack::default(),
/// );
/// ```
pub fn run<F, T>(future: F, stack: ProcStack) -> T
where
F: Future<Output = T>,
Expand Down

0 comments on commit c7e7899

Please sign in to comment.