Struct HardwareTracker

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

Tracks and provides access to changing hardware information over time.

§Example

use many_cpus::HardwareTracker;

HardwareTracker::with_current_processor(|p| {
    let efficiency_class = p.efficiency_class();
    let id = p.id();

    println!(
        "Executing on processor {id}, which has the efficiency class {efficiency_class:?}"
    );
});

§Current processor

Many of the tracked parameters are related to the current processor. The meaning of “current” is simple: the current processor is whatever processor is executing the HardwareTracker code when it is called.

Unless otherwise configured, threads can move between processors, so the current processor can change over time. This means that there is a certain “time of check to time of use” discrepancy that can occur. This is unavoidable if your threads are not pinned to specific processors.

If you need certainty in the data, you must use pinned threads, with each thread assigned to execute on either a specific processor or set of processors that have the desired quality you care about (e.g. a number of processors in the same memory region). You can pin the current thread to one or more processors via ProcessorSet::pin_current_thread_to.

Implementations§

Source§

impl HardwareTracker

Source

pub fn with_current_processor<F, R>(f: F) -> R
where F: FnOnce(&Processor) -> R,

Obtains a reference to the current processor, for the duration of a callback.

If all you need is the processor ID or memory region ID, you may see better performance if you query current_processor_id() or current_memory_region_id() directly.

§Example
use many_cpus::HardwareTracker;

HardwareTracker::with_current_processor(|p| {
    let efficiency_class = p.efficiency_class();
    let id = p.id();

    println!(
        "Executing on processor {id}, which has the efficiency class {efficiency_class:?}"
    );
});
Source

pub fn current_processor_id() -> ProcessorId

The ID of the processor currently executing this thread.

Source

pub fn current_memory_region_id() -> MemoryRegionId

The memory region ID of the processor currently executing this thread.

Source

pub fn is_thread_processor_pinned() -> bool

Whether the current thread is pinned to a single processor.

Threads may be pinned to any number of processors, not just one - this only checks for the scenario where the thread is pinned to one specific processor.

This function only recognizes pinning done via the many_cpus crate. If you pin a thread using other means (e.g. libc), this function will not be able to detect it.

§Example (basic)
use many_cpus::HardwareTracker;

// Threads are typically not pinned unless you pin them yourself.
assert!(!HardwareTracker::is_thread_processor_pinned());
§Example (pinned to one processor)
use std::num::NonZero;
use std::thread;

use many_cpus::{HardwareTracker, ProcessorSet};

let one_processor = ProcessorSet::builder()
    .take(NonZero::new(1).unwrap())
    .unwrap();

thread::spawn(move || {
    one_processor.pin_current_thread_to();

    assert!(HardwareTracker::is_thread_processor_pinned());
})
.join()
.unwrap();
§Example (pinned to multiple processors)
use std::num::NonZero;
use std::thread;

use many_cpus::{HardwareTracker, ProcessorSet};

let two_processors = ProcessorSet::builder().take(NonZero::new(2).unwrap());

let Some(two_processors) = two_processors else {
    eprintln!("This example requires at least two processors");
    return;
};

thread::spawn(move || {
    two_processors.pin_current_thread_to();

    assert!(!HardwareTracker::is_thread_processor_pinned());
})
.join()
.unwrap();
Source

pub fn is_thread_memory_region_pinned() -> bool

Whether the current thread is pinned to one or more processors that are all in the same memory region.

This function only recognizes pinning done via the many_cpus crate. If you pin a thread using other means (e.g. libc), this function will not be able to detect it.

§Example (basic)
use many_cpus::HardwareTracker;

// Threads are typically not pinned unless you pin them yourself.
assert!(!HardwareTracker::is_thread_memory_region_pinned());
§Example (pinned to one processor)
use std::num::NonZero;
use std::thread;

use many_cpus::{HardwareTracker, ProcessorSet};

let one_processor = ProcessorSet::builder()
    .take(NonZero::new(1).unwrap())
    .unwrap();

thread::spawn(move || {
    one_processor.pin_current_thread_to();

    // Each processor is in exactly one memory region, so as we are
    // pinned to one processor, we are also pinned to one memory region.
    assert!(HardwareTracker::is_thread_memory_region_pinned());
})
.join()
.unwrap();
§Example (pinned to multiple processors)
use std::num::NonZero;
use std::thread;

use many_cpus::{HardwareTracker, ProcessorSet};

let two_processors = ProcessorSet::builder()
    .same_memory_region()
    .take(NonZero::new(2).unwrap());

let Some(two_processors) = two_processors else {
    eprintln!("This example requires at least two processors in the same memory region");
    return;
};

thread::spawn(move || {
    two_processors.pin_current_thread_to();

    // While we are not pinned to a single processor, all processors we are pinned to
    // are in the same memory region, so we are still pinned to one memory region.
    assert!(HardwareTracker::is_thread_memory_region_pinned());
})
.join()
.unwrap();
Source

pub fn resource_quota() -> ResourceQuota

The current hardware resource quota for the current process. This may change over time.

§Example
use many_cpus::HardwareTracker;

let quota = HardwareTracker::resource_quota();

let max_time = quota.max_processor_time();
let active_count = HardwareTracker::active_processor_count();

println!("System has {active_count} active processors");
println!("Process quota allows {max_time:.2} processor-seconds per second");

let quota_percentage = (max_time / active_count as f64) * 100.0;
println!("Process can use {quota_percentage:.1}% of total system processing power");
Source

pub fn active_processor_count() -> usize

The number of active processors on the system, including processors that are not available to the current process.

This may be useful for working with system APIs that deal with system-scoped values, instead of process-scoped values that need to consider current process limits.

§Example
use many_cpus::{HardwareTracker, ProcessorSet};

let system_processors = HardwareTracker::active_processor_count();
let available_processors = ProcessorSet::default().len();

println!("System has {system_processors} total active processors");
println!("Process can use {available_processors} of them");

if available_processors < system_processors {
    println!("Process is limited to a subset of system processors");
}

Trait Implementations§

Source§

impl Debug for HardwareTracker

Source§

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

Formats the value using the given formatter. Read more

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, 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