Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The computation crate

Create the computation crate:

cargo new --lib computation
cd computation

orx-parallel dependency with wasm feature

Add orx-parallel dependency to implement parallel computations in par_wasm/computation/Cargo.toml:

[package]
name = "computation"
version = "0.1.0"
edition = "2024"
publish = false

[dependencies]
orx-parallel = { version = "4", default-features = false }

[features]
default = []
wasm = ["orx-parallel/wasm"]

Note that wasm feature is kept optional. This allows:

  • to use this crate as a regular Rust crate when the feature is omitted, and
  • to test the computations in isolation without WebAssembly dependencies.

Example computations

We will implement two parallel computations in par_wasm/computation/src/lib.rs as follows:

#![allow(unused)]
fn main() {
use orx_parallel::*;

fn fibonacci_term(index: usize) -> u64 {
	let mut previous = 0;
	let mut current = 1;

	for _ in 0..index {
		(previous, current) = (current, previous + current);
	}

	previous
}

pub fn calculate_fibonacci(workload: usize, num_threads: usize) -> u64 {
	(0..workload)
		.par()
		.num_threads(num_threads)
		.map(|index| fibonacci_term(index))
		.sum()
}

const MAX_MANDELBROT_ITERATIONS: u64 = 10000;

fn mandelbrot_escape_iterations(point_index: usize, workload: usize) -> u64 {
	let width = (workload as f64).sqrt().ceil() as usize;
	let height = workload.div_ceil(width);
	let x = point_index % width;
	let y = point_index / width;

	let real = -2.0 + 3.0 * x as f64 / width.saturating_sub(1).max(1) as f64;
	let imaginary = -1.5 + 3.0 * y as f64 / height.saturating_sub(1).max(1) as f64;
	let (mut z_real, mut z_imaginary) = (0.0, 0.0);

	for iteration in 1..=MAX_MANDELBROT_ITERATIONS {
		(z_real, z_imaginary) = (
			z_real * z_real - z_imaginary * z_imaginary + real,
			2.0 * z_real * z_imaginary + imaginary,
		);

		if z_real * z_real + z_imaginary * z_imaginary > 4.0 {
			return iteration;
		}
	}

	MAX_MANDELBROT_ITERATIONS
}

pub fn mandelbrot_checksum(workload: usize, num_threads: usize) -> u64 {
	(0..workload)
		.par()
		.num_threads(num_threads)
		.map(|point_index| mandelbrot_escape_iterations(point_index, workload))
		.sum()
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn calculates_fibonacci_terms() {
		assert_eq!(calculate_fibonacci(6, 2), 12);
	}

	#[test]
	fn calculates_mandelbrot_checksum() {
		assert_eq!(mandelbrot_checksum(4, 2), 6);
	}
}
}

Computations are just examples using orx-parallels parallel iterator. Briefly, calculate_fibonacci maps independent Fibonacci terms and sums them. mandelbrot_checksum maps points, calculates escape iterations, and sums the results.

.num_threads(num_threads) lets the caller control the thread limit per-computation. Omitting the .num_threads call or calling it with 0 allows to use all threads available in the pool.

Test this crate before defining WASM bindings:

cargo test

One level up into par_wasm directory:

cd ..