Module atomic_utilities::artificial_dep
[−]
[src]
This module provides a function that forces an artificial data dependency between two loads. Basically, the code:
val = some_atomic.load(DepOrd);
val2_ref = &val2;
val2 ref ^= val;
val2_ref ^= val; // val_2 ref now is equal to &val2, but data depends on val
loaded_val2 = *val2_ref; // Is ordered-after val as if by consume ordering
is executed. This can be far faster than fences on arm and power architectures, since the ordering is a result of data dependencies in the pipeline and not full-on fences. This still isn't free, since you must wait for the previous load to finish but it's better than a fence
Example:
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Barrier}; use std::thread; use atomic_utilities::artificial_dep::{DepOrd, dependently}; let num_run = 1000000; let atomic_val1 = Arc::new(AtomicUsize::new(0)); let atomic_val2 = Arc::new(AtomicUsize::new(0)); let start_bar = Arc::new(Barrier::new(2)); let atomic_valt1 = atomic_val1.clone(); let atomic_valt2 = atomic_val2.clone(); let start_bart = start_bar.clone(); let to_join = thread::spawn(move || { start_bart.wait(); for i in 0..num_run { atomic_valt2.store(i, Ordering::Relaxed); atomic_valt1.store(i, Ordering::Release); } }); start_bar.wait(); for _ in 0..num_run { let val1_ld = atomic_val1.load(DepOrd); let val2_ld = dependently(val1_ld, &atomic_val2, |dep_ref| dep_ref.load(Ordering::Relaxed)); assert!(val2_ld >= val1_ld); // Can fail if val2_ld is ordered_before val1_ld }
Constants
DepOrd |
The ordering that must be used for any load which has fake dependent operations |
Functions
dependently |
Ensures that loads from the value myref are ordered after the load of val. Val can be anything convertable to a usize, or any usize calculated from the base load. |
dependently_mut |
Ensures that loads from the value myref are ordered after the load of val. Val can be anything convertable to a usize, or any usize calculated from the base load. |