Expand description
A library for creating isolated affinities in Rust, allowing for safe and efficient data transfer between them.
This is useful in scenarios where you want to isolate data to different affinities, such as NUMA nodes, threads, or specific CPU cores. It can serve as a foundation for building a async runtime or a task scheduler that operates across multiple affinities. For example it can be used to implement a NUMA-aware task scheduler that transfers data between different NUMA nodes or a thread-per-core scheduler that transfers data between different CPU cores.
The way this would be used is by restricting how work can be scheduled on other affinities (threads,
NUMA nodes). If the runtime only allows work scheduling in a way that accepts work that can be
transferred (e.g. by using the RelocateFnOnce trait) and makes sure that transfer is called, it can
effectively isolate the affinities as the ThreadAware trait ensures the right level of separation if
implemented correctly.
ThreadAware is an ‘infectious’ trait, meaning that when you implement it for a type,
all of its fields must also implement ThreadAware and you must call their transfer methods.
However ThreadAware is provided for many common types, so you can use it out of the box for most cases.
§Feature Flags
derive(default) – Re-exports the#[derive(ThreadAware)]macro from the companionthread_aware_macroscrate. Disable to avoid pulling in proc-macro code in minimal environments:default-features = false.
§Examples
use thread_aware::{PinnedAffinity, MemoryAffinity, ThreadAware, Unaware, create_manual_pinned_affinities};
// Define a type that implements ThreadAware
#[derive(Debug, Clone)]
struct MyData {
value: i32,
}
impl ThreadAware for MyData {
fn relocated(mut self, source: MemoryAffinity, destination: PinnedAffinity) -> Self {
self.value = self.value.relocated(source, destination);
self
}
}
fn do_transfer() {
// Create two affinities
let affinities = create_manual_pinned_affinities(&[2]);
// Create an instance of MyData
let data = MyData { value: 42 };
// Transfer data from one affinity to another
let transferred_data = data.relocated(affinities[0].into(), affinities[1]);
// Use Inert to create a type that does not transfer data
struct MyInertData(i32);
let inert_data = Unaware(MyInertData(100));
let transferred_inert_data = inert_data.relocated(affinities[0].into(), affinities[1]);
}§Derive Macro Example
When the derive feature (enabled by default) is active you can simply
derive ThreadAware instead of writing the implementation manually.
use thread_aware::{ThreadAware, create_manual_pinned_affinities};
#[derive(Debug, Clone, ThreadAware)]
struct Point {
x: i32,
y: i32,
}
fn derived_example() {
let affinities = create_manual_pinned_affinities(&[2]);
let p = Point { x: 5, y: 9 };
// Transfer the value between two affinities. In this simple case the
// data just gets copied, but for complex types the generated impl
// calls `transfer` on each field.
let _p2 = p.relocated(affinities[0].into(), affinities[1]);
}If you disable default features (or the derive feature explicitly) you
can still implement ThreadAware manually as shown in the earlier example.
Re-exports§
pub use core::ThreadAware;pub use core::create_manual_memory_affinities;pub use core::create_manual_pinned_affinities;
Modules§
- core
- This module contains all the core primitives the thread aware system is built upon.
Structs§
- Arc
- Transferable reference counted type.
- Closure
- Closure
Mut - Closure
Once - A common implementation of
RelocateFnOnce - PerCore
- A strategy that stores data per processor.
- PerNuma
- A strategy that stores data per memory region.
- PerProcess
- A strategy that stores data per process.
- Pinned
Affinity - A
PinnedAffinityrepresents a specific binding to a processor and memory region. - Storage
- Type used for storing data in a affinity-aware manner.
- Unaware
- Allows transferring a value that doesn’t implement
ThreadAware
Enums§
- Memory
Affinity - An
MemoryAffinitycan be thought of as a placement in a system.
Traits§
- Relocate
Fn - A trait for callable types that can be called multiple times. This trait is used to define closures that can be called multiple times, without consuming the closure.
- Relocate
FnMut - A trait for callable types that can be called mutably. This trait is used to define closures that can be called mutably, allowing the closure to modify its internal state.
- Relocate
FnOnce - A FnOnce-like, parameterless closure whose captured values all implement
ThreadAware - Strategy
- A strategy for storing data in a affinity-aware manner.
Functions§
- relocate
- relocate_
mut - relocate_
once - Construct a
RelocateFnOnce- a closure-like object where the captured data implementThreadAware. - unaware
- Creates an
Unawarewrapper around a value.
Type Aliases§
- PerApp
Storage - Storage type that uses the
PerProcessstrategy. - PerCore
Storage - Storage type that uses the
PerCorestrategy. - PerNuma
Storage - Storage type that uses the
PerNumastrategy.
Derive Macros§
- Thread
Aware - Derive macro implementing
ThreadAwarefor structs and enums.