Crate thread_aware

Crate thread_aware 

Source
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 companion thread_aware_macros crate. 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
ClosureMut
ClosureOnce
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.
PinnedAffinity
A PinnedAffinity represents 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§

MemoryAffinity
An MemoryAffinity can be thought of as a placement in a system.

Traits§

RelocateFn
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.
RelocateFnMut
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.
RelocateFnOnce
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 implement ThreadAware.
unaware
Creates an Unaware wrapper around a value.

Type Aliases§

PerAppStorage
Storage type that uses the PerProcess strategy.
PerCoreStorage
Storage type that uses the PerCore strategy.
PerNumaStorage
Storage type that uses the PerNuma strategy.

Derive Macros§

ThreadAware
Derive macro implementing ThreadAware for structs and enums.