pijul nest
guest [sign in]

initial record

[?]
2paXZqkGuqYVrdei2n8ZVCtynbH1mwewHrmi87LA9cto
Jan 19, 2022, 11:40 PM
VONQCLSVYJXL6KNNKFKZS53626BSQYKIXUDDPWCEDOCLUQOW3TPQC

Dependencies

Change contents

  • file addition: src (d--r------)
    [2.1]
  • file addition: lib.rs (----------)
    [0.15]
    use rayon::prelude::*;
    #[inline(always)]
    fn validate_bounds<T>(vs: &[T], indices: &[usize]) -> bool {
    let size = vs.len();
    indices.par_iter().any(|i| *i >= size)
    }
    #[derive(Copy, Clone)]
    struct TmpRef<T: Send + Sync>(*mut T);
    unsafe impl<T: Send + Sync> Send for TmpRef<T> {}
    unsafe impl<T: Sync + Send> Sync for TmpRef<T> {}
    /// Write `value` into `slice` with the given `indices` in parallel
    pub fn writes_par<T: Copy + Send + Sync>(slice: &mut [T], value: T, indices: &[usize]) -> bool {
    let oob = validate_bounds(slice, indices);
    if oob {
    return false;
    }
    let tref = TmpRef(slice.as_mut_ptr());
    indices.par_iter().for_each(move |i| {
    let tmp = tref.clone();
    unsafe {
    let p = tmp.0.add(*i);
    p.write(value);
    }
    });
    true
    }
    /// Write `value` into `slice` with the given `indices` in parallel, discarding
    /// the writes for any out of bound indexes
    pub fn writes_par_discard<T: Copy + Send + Sync>(slice: &mut [T], value: T, indices: &[usize]) {
    let size = slice.len();
    let tref = TmpRef(slice.as_mut_ptr());
    indices.par_iter().for_each(move |i| {
    if *i < size {
    let tmp = tref.clone();
    unsafe {
    let p = tmp.0.add(*i);
    p.write(value);
    }
    }
    });
    }
  • file addition: benches (d--r------)
    [2.1]
  • file addition: main.rs (----------)
    [0.1409]
    use criterion::{black_box, criterion_group, criterion_main, Criterion};
    use slicefire::*;
    /// Sequentially write `value` into `slice` with the given `indices`
    pub fn writes<T: Copy>(slice: &mut [T], value: T, indices: &[usize]) -> bool {
    for i in indices {
    if *i >= slice.len() {
    return false;
    }
    }
    for i in indices {
    slice[*i] = value;
    }
    true
    }
    /// Sequentially write `value` into `slice` with the given `indices`, discarding
    /// the writes for any out of bound indexes
    pub fn writes_discard<T: Copy>(vs: &mut [T], val: T, indices: &[usize]) {
    for i in indices {
    if *i < vs.len() {
    vs[*i] = val;
    }
    }
    }
    #[derive(Debug, Copy, Clone)]
    #[allow(unused)]
    struct Foo {
    x: i32,
    y: i64,
    }
    impl From<i32> for Foo {
    fn from(x: i32) -> Self {
    Self { x, y: x as i64 * 2 }
    }
    }
    fn indices(size: usize) -> (Vec<usize>, Vec<Foo>) {
    let indices = (0..(size)).map(|i| i % (size - 2)).collect::<Vec<usize>>();
    let vs = (0..size).map(|v| (v as i32).into()).collect::<Vec<Foo>>();
    (indices, vs)
    }
    fn write_single_value_with_size(size: usize, c: &mut Criterion) {
    let (indices, mut vs) = indices(size);
    let val = black_box(Foo::from(10));
    c.bench_function(&format!("writes {}", size), |b| {
    b.iter(|| writes(&mut vs, black_box(val), &indices))
    });
    c.bench_function(&format!("writes_discard {}", size), |b| {
    b.iter(|| writes_discard(&mut vs, black_box(val), &indices))
    });
    c.bench_function(&format!("writes_par {}", size), |b| {
    b.iter(|| writes_par(&mut vs, black_box(val), &indices))
    });
    c.bench_function(&format!("writes_par_discard {}", size), |b| {
    b.iter(|| writes_par_discard(&mut vs, black_box(val), &indices))
    });
    }
    fn write_values_with_size(size: usize, c: &mut Criterion) {
    let (indices, mut vs) = indices(size);
    let vals = (0..20).map(|v| v.into()).collect::<Vec<Foo>>();
    let vals = &vals;
    c.bench_function(&format!("writes vals {}", size), |b| {
    b.iter(|| {
    for val in vals {
    writes(&mut vs, black_box(*val), &indices);
    }
    })
    });
    c.bench_function(&format!("write_discards vals {}", size), |b| {
    b.iter(|| {
    for val in vals {
    writes_discard(&mut vs, black_box(*val), &indices);
    }
    })
    });
    c.bench_function(&format!("writes_par vals {}", size), |b| {
    b.iter(|| {
    for val in vals {
    writes_par(&mut vs, black_box(*val), &indices);
    }
    })
    });
    c.bench_function(&format!("writes_par_discard vals {}", size), |b| {
    b.iter(|| {
    for val in vals {
    writes_par_discard(&mut vs, black_box(*val), &indices);
    }
    })
    });
    }
    fn write_values(c: &mut Criterion) {
    write_values_with_size(1_000, c);
    write_values_with_size(10_000, c);
    write_values_with_size(100_000, c);
    }
    fn write_single_value(c: &mut Criterion) {
    write_single_value_with_size(1_000, c);
    write_single_value_with_size(10_000, c);
    write_single_value_with_size(100_000, c);
    }
    criterion_group!(benches, write_single_value, write_values);
    criterion_main!(benches);
  • file addition: Cargo.toml (----------)
    [2.1]
    [package]
    name = "slicefire"
    version = "0.1.0"
    edition = "2021"
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    [dependencies]
    rayon = "1.5.1"
    [dev-dependencies]
    criterion = { version = "0.3", features = ["html_reports"]}
    [[bench]]
    name = "main"
    harness = false