Loading rust_08_misc...
cargo build --release
cargo run --release
[profile.release] panic = "abort" codegen-units = 1 lto = true strip = "symbols" # reduce size, but incompatible with perf/flamegraph # debug = true # required for perf/flamegraph
[build] rustflags = ["-C", "target-cpu=native"]
fn generate_sin( samples: &mut [f32], dt: f32, freq: f32, ) { for (i, s) in samples.iter_mut().enumerate() { let t = i as f32 * dt; *s += (2.0 * std::f32::consts::PI * t * freq).sin(); } }
fn main() { let start = std::time::Instant::now(); let dt = 1.0 / 44100.0; let mut samples = vec![0.0; 50_000_000]; for f in 1..=5 { let freq = f as f32 * 100.0; generate_sin(&mut samples, dt, freq); } let duration = start.elapsed(); println!("duration: {:?}", duration); }
cargo install flamegraph
sudo apt update sudo apt install linux-tools-generic linux-tools-`uname -r`
sudo dnf install perf
sudo pacman -S perf
echo 'kernel.perf_event_paranoid = 0' | sudo sh -c 'tee -a /etc/sysctl.conf | sysctl -q -f -'
cargo flamegraph
/// Approximates sine of 2π·x with paraboloids fn unit_sine(x: f32) -> f32 { let x = x - x.floor(); let mut y = x - 0.5; y *= 16.0 * (y.abs() - 0.5); // y += 0.225 * y * (y.abs() - 1.0); // increase precision y }
// *s += (2.0 * std::f32::consts::PI * t * freq).sin(); *s += unit_sine(t * freq);
fn thread_task( title: String, delay_ms: u64, ) { for i in 0..10 { std::thread::sleep(std::time::Duration::from_millis(delay_ms)); println!("{} counting {}", title, i); } println!("leaving {}", title); }
fn main() -> Result<(), Box<dyn std::error::Error>> { // spawn a thread computing something in parallel let thread_title = String::from("thread task"); let thread_delay_ms = 100; let consumer_thread = std::thread::spawn(move || { thread_task(thread_title, thread_delay_ms); });
// compute something in the main thread for i in 0..5 { std::thread::sleep(std::time::Duration::from_millis(200)); println!("main program counting {}", i); }
// wait for the thread to terminate if let Err(e) = consumer_thread.join() { Err(format!("{:?}", e))?; }
println!("leaving main program"); Ok(()) } /* thread task counting 0 main program counting 0 thread task counting 1 thread task counting 2 main program counting 1 thread task counting 3 thread task counting 4 main program counting 2 thread task counting 5 thread task counting 6 main program counting 3 thread task counting 7 thread task counting 8 main program counting 4 thread task counting 9 leaving thread task leaving main program */
fn consumer_task( channel_receiver: std::sync::mpsc::Receiver<String> ) -> Result<(), Box<dyn std::error::Error>> { let start_time = std::time::SystemTime::now(); while let Ok(msg) = channel_receiver.recv() { // consume each incoming data let elapsed = start_time.elapsed()?; println!("consumer task received {:?} after {:?}", msg, elapsed); } println!("no more messages for consumer task"); Ok(()) }
fn main() -> Result<(), Box<dyn std::error::Error>> { // prepare a channel in order to provide the thread with some data let (channel_sender, channel_receiver) = std::sync::mpsc::channel();
// spawn a thread consuming data from this channel let consumer_thread = std::thread::spawn(move || { if let Err(e) = consumer_task(channel_receiver) { eprintln!("ERROR: {:?}", e); } });
// send data to the thread whenever we want channel_sender.send(String::from("first message"))?; for i in 0..5 { std::thread::sleep(std::time::Duration::from_millis(500)); let msg = format!("counting {}", i); channel_sender.send(msg)?; } channel_sender.send(String::from("last message"))?;
// close the channel drop(channel_sender);
// wait for the thread to terminate if let Err(e) = consumer_thread.join() { Err(format!("{:?}", e))?; }
Ok(()) } /* consumer task received "first message" after 784ns consumer task received "counting 0" after 500.130009ms consumer task received "counting 1" after 1.000132368s consumer task received "counting 2" after 1.500230532s consumer task received "counting 3" after 2.00035814s consumer task received "counting 4" after 2.500384809s consumer task received "last message" after 2.500390231s no more messages for consumer task */
use std::sync::{ atomic::{AtomicUsize, Ordering}, Arc, Mutex, };
#[derive(Debug, Default)] struct SharedState { next_n: AtomicUsize, elements: Mutex<Vec<(char, usize)>>, }
fn fibonacci(n: usize) -> usize { if n < 2 { n } else { fibonacci(n - 2) + fibonacci(n - 1) } }
fn compute_task( letter: char, limit: usize, state: &SharedState, ) -> Result<(), Box<dyn std::error::Error>> { loop { // atomic increment let n = state.next_n.fetch_add(1, Ordering::Relaxed);
// compute let fib_n = fibonacci(n); if fib_n > limit { break; }
// exclusively access the shared storage let mut elements = state.elements.lock().unwrap(); if elements.len() <= n { elements.resize(1 + n, (letter, 0)); } elements[n] = (letter, fib_n); } Ok(()) }
fn main() -> Result<(), Box<dyn std::error::Error>> { // prepare a shared state let state = Arc::new(SharedState::default()); let limit = 100_000_000;
// start many threads working with the shared state let mut threads = Vec::new(); for letter in "ABCD".chars() { threads.push(std::thread::spawn({ // clone the reference, not the state! let state = Arc::clone(&state); move || { if let Err(e) = compute_task(letter, limit, state.as_ref()) { eprintln!("ERROR: {:?}", e); } } })); }
// wait for all threads to terminate for th in threads { if let Err(e) = th.join() { Err(format!("{:?}", e))?; } }
// obtain the global result println!("{:?}", state.elements.lock().unwrap());
Ok(()) } /* [('B', 0), ('B', 1), ('B', 1), ('B', 2), ('B', 3), ('B', 5), ('B', 8), ('B', 13), ('B', 21), ('B', 34), ('B', 55), ('B', 89), ('B', 144), ('B', 233), ('B', 377), ('B', 610), ('B', 987), ('B', 1597), ('B', 2584), ('B', 4181), ('B', 6765), ('B', 10946), ('D', 17711), ('A', 28657), ('C', 46368), ('B', 75025), ('D', 121393), ('A', 196418), ('C', 317811), ('B', 514229), ('D', 832040), ('A', 1346269), ('C', 2178309), ('B', 3524578), ('D', 5702887), ('A', 9227465), ('C', 14930352), ('B', 24157817), ('D', 39088169), ('A', 63245986)] */
rustup doc --book“16.1. Using Threads to Run Code Simultaneously”
rustup doc --book“16.2. Using Message Passing to Transfer Data Between Thread”
rustup doc --book“16.3. Shared-State Concurrency”
rustup doc --rust-by-example“20.2. Channels”
rustup doc --std 'std::thread::spawn'
rustup doc --std 'std::sync::mpsc'
rustup doc --std 'std::sync::Arc'
rustup doc --std 'std::sync::atomic'
rustup doc --std 'std::sync::Mutex'