replaced atomics with a vec-wide lock, now 2x slower than before
This commit is contained in:
parent
eb1efaf694
commit
b7c1f19204
5 changed files with 189 additions and 189 deletions
58
Cargo.lock
generated
58
Cargo.lock
generated
|
@ -79,12 +79,6 @@ version = "3.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cast"
|
name = "cast"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -250,25 +244,6 @@ dependencies = [
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hash32"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heapless"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
|
||||||
dependencies = [
|
|
||||||
"hash32",
|
|
||||||
"stable_deref_trait",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
|
@ -306,12 +281,6 @@ version = "0.2.177"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libm"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.28"
|
version = "0.4.28"
|
||||||
|
@ -331,7 +300,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"libm",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -500,17 +468,6 @@ version = "0.8.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rstar"
|
|
||||||
version = "0.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"
|
|
||||||
dependencies = [
|
|
||||||
"heapless",
|
|
||||||
"num-traits",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
|
@ -576,28 +533,15 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "spacedog"
|
||||||
version = "1.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spacebench"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"criterion",
|
"criterion",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_hc",
|
"rand_hc",
|
||||||
"rstar",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stable_deref_trait"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
@ -12,3 +12,7 @@ rand_hc = "0.4.0"
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "benchmarks"
|
name = "benchmarks"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.9.2"
|
||||||
|
rand_hc = "0.4.0"
|
||||||
|
|
|
@ -1,134 +1,4 @@
|
||||||
use std::{
|
use spacedog::*;
|
||||||
sync::{
|
|
||||||
atomic::{AtomicU64, AtomicUsize, Ordering::Relaxed},
|
|
||||||
Arc, RwLock,
|
|
||||||
},
|
|
||||||
thread,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Point2d {
|
|
||||||
x: f64,
|
|
||||||
y: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
|
||||||
struct PVal {
|
|
||||||
point: usize,
|
|
||||||
val: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for PVal {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.val == other.val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for PVal {}
|
|
||||||
|
|
||||||
impl PartialOrd for PVal {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for PVal {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.val.partial_cmp(&other.val).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Spindex2d {
|
|
||||||
xpoints: Arc<Vec<AtomicUsize>>,
|
|
||||||
ypoints: Arc<Vec<AtomicUsize>>,
|
|
||||||
xs: Arc<RwLock<Vec<PVal>>>,
|
|
||||||
ys: Arc<RwLock<Vec<PVal>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Spindex2d {
|
|
||||||
pub fn new(points: &[Point2d]) -> Self {
|
|
||||||
let mut xpoints = Vec::with_capacity(points.len());
|
|
||||||
let mut ypoints = Vec::with_capacity(points.len());
|
|
||||||
let mut xs = Vec::with_capacity(points.len());
|
|
||||||
let mut ys = Vec::with_capacity(points.len());
|
|
||||||
for (i, point) in points.iter().enumerate() {
|
|
||||||
let x = PVal {
|
|
||||||
point: i,
|
|
||||||
val: point.x,
|
|
||||||
};
|
|
||||||
xs.push(x);
|
|
||||||
let y = PVal {
|
|
||||||
point: i,
|
|
||||||
val: point.y,
|
|
||||||
};
|
|
||||||
ys.push(y);
|
|
||||||
|
|
||||||
xpoints.push(AtomicUsize::new(i));
|
|
||||||
ypoints.push(AtomicUsize::new(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = Self {
|
|
||||||
xpoints: xpoints.into(),
|
|
||||||
ypoints: ypoints.into(),
|
|
||||||
xs: Arc::new(RwLock::new(xs)),
|
|
||||||
ys: Arc::new(RwLock::new(ys)),
|
|
||||||
};
|
|
||||||
|
|
||||||
index.sort();
|
|
||||||
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method assumes that the points have the same cardinality and order as the points used
|
|
||||||
/// when constructing this index. May panic if the updated points argument is longer than the
|
|
||||||
/// original points.
|
|
||||||
pub fn update(&self, points: &[Point2d]) {
|
|
||||||
let mut xs = self.xs.write().unwrap();
|
|
||||||
let mut ys = self.ys.write().unwrap();
|
|
||||||
for (i, point) in points.iter().enumerate() {
|
|
||||||
let xi = self.xpoints[i].load(Relaxed);
|
|
||||||
let yi = self.ypoints[i].load(Relaxed);
|
|
||||||
let x = PVal {
|
|
||||||
point: i,
|
|
||||||
val: point.x,
|
|
||||||
};
|
|
||||||
xs[xi] = x;
|
|
||||||
|
|
||||||
let y = PVal {
|
|
||||||
point: i,
|
|
||||||
val: point.y,
|
|
||||||
};
|
|
||||||
ys[yi] = y;
|
|
||||||
}
|
|
||||||
self.sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sort(&self) {
|
|
||||||
let xs = self.xs.clone();
|
|
||||||
let points = self.xpoints.clone();
|
|
||||||
let xhandle = thread::spawn(move || {
|
|
||||||
let mut xs = xs.write().unwrap();
|
|
||||||
xs.sort_unstable();
|
|
||||||
for (i, x) in xs.iter().enumerate() {
|
|
||||||
let p = x.point;
|
|
||||||
points[p].store(i, Relaxed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let ys = self.ys.clone();
|
|
||||||
let points = self.ypoints.clone();
|
|
||||||
let yhandle = thread::spawn(move || {
|
|
||||||
let mut ys = ys.write().unwrap();
|
|
||||||
ys.sort_unstable();
|
|
||||||
for (i, y) in ys.iter().enumerate() {
|
|
||||||
let p = y.point;
|
|
||||||
points[p].store(i, Relaxed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
xhandle.join().unwrap();
|
|
||||||
yhandle.join().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_hc::Hc128Rng;
|
use rand_hc::Hc128Rng;
|
||||||
|
@ -159,7 +29,7 @@ fn new_index(c: &mut Criterion) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_positions(c: &mut Criterion) {
|
fn _update_positions(c: &mut Criterion) {
|
||||||
c.bench_function("update positions", move |b| {
|
c.bench_function("update positions", move |b| {
|
||||||
let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1)
|
let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
139
src/lib.rs
Normal file
139
src/lib.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
use std::{
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering::Relaxed},
|
||||||
|
Arc, RwLock,
|
||||||
|
},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
|
||||||
|
pub struct Point2d {
|
||||||
|
pub x: f64,
|
||||||
|
pub y: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub struct PVal {
|
||||||
|
point: usize,
|
||||||
|
val: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PVal {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.val == other.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for PVal {}
|
||||||
|
|
||||||
|
impl PartialOrd for PVal {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for PVal {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.val.partial_cmp(&other.val).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct Spindex2d {
|
||||||
|
xpoints: Arc<RwLock<Vec<usize>>>,
|
||||||
|
ypoints: Arc<RwLock<Vec<usize>>>,
|
||||||
|
xs: Arc<RwLock<Vec<PVal>>>,
|
||||||
|
ys: Arc<RwLock<Vec<PVal>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Spindex2d {
|
||||||
|
pub fn new(points: &[Point2d]) -> Self {
|
||||||
|
let mut xpoints = Vec::with_capacity(points.len());
|
||||||
|
let mut ypoints = Vec::with_capacity(points.len());
|
||||||
|
let mut xs = Vec::with_capacity(points.len());
|
||||||
|
let mut ys = Vec::with_capacity(points.len());
|
||||||
|
for (i, point) in points.iter().enumerate() {
|
||||||
|
let x = PVal {
|
||||||
|
point: i,
|
||||||
|
val: point.x,
|
||||||
|
};
|
||||||
|
xs.push(x);
|
||||||
|
let y = PVal {
|
||||||
|
point: i,
|
||||||
|
val: point.y,
|
||||||
|
};
|
||||||
|
ys.push(y);
|
||||||
|
|
||||||
|
xpoints.push(i);
|
||||||
|
ypoints.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = Self {
|
||||||
|
xpoints: Arc::new(RwLock::new(xpoints)),
|
||||||
|
ypoints: Arc::new(RwLock::new(ypoints)),
|
||||||
|
xs: Arc::new(RwLock::new(xs)),
|
||||||
|
ys: Arc::new(RwLock::new(ys)),
|
||||||
|
};
|
||||||
|
|
||||||
|
index.sort();
|
||||||
|
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method assumes that the points have the same cardinality and order as the points used
|
||||||
|
/// when constructing this index. May panic if the updated points argument is longer than the
|
||||||
|
/// original points.
|
||||||
|
pub fn update(&self, points: &[Point2d]) {
|
||||||
|
let mut xs = self.xs.write().unwrap();
|
||||||
|
let mut ys = self.ys.write().unwrap();
|
||||||
|
let xpoints = self.xpoints.read().unwrap();
|
||||||
|
let ypoints = self.ypoints.read().unwrap();
|
||||||
|
for (i, point) in points.iter().enumerate() {
|
||||||
|
println!("hello: {i}");
|
||||||
|
let xi = xpoints[i];
|
||||||
|
let yi = ypoints[i];
|
||||||
|
let x = PVal {
|
||||||
|
point: i,
|
||||||
|
val: point.x,
|
||||||
|
};
|
||||||
|
xs[xi] = x;
|
||||||
|
|
||||||
|
let y = PVal {
|
||||||
|
point: i,
|
||||||
|
val: point.y,
|
||||||
|
};
|
||||||
|
ys[yi] = y;
|
||||||
|
}
|
||||||
|
println!("done updating points");
|
||||||
|
self.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort(&self) {
|
||||||
|
let xs = self.xs.clone();
|
||||||
|
let points = self.xpoints.clone();
|
||||||
|
let xhandle = thread::spawn(move || {
|
||||||
|
let mut xs = xs.write().unwrap();
|
||||||
|
xs.sort_unstable();
|
||||||
|
let mut points = points.write().unwrap();
|
||||||
|
for (i, x) in xs.iter().enumerate() {
|
||||||
|
let p = x.point;
|
||||||
|
points[p] = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let ys = self.ys.clone();
|
||||||
|
let points = self.ypoints.clone();
|
||||||
|
let yhandle = thread::spawn(move || {
|
||||||
|
let mut ys = ys.write().unwrap();
|
||||||
|
ys.sort_unstable();
|
||||||
|
let mut points = points.write().unwrap();
|
||||||
|
for (i, y) in ys.iter().enumerate() {
|
||||||
|
let p = y.point;
|
||||||
|
points[p] = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
xhandle.join().unwrap();
|
||||||
|
yhandle.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
43
src/main.rs
Normal file
43
src/main.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
use rand_hc::Hc128Rng;
|
||||||
|
|
||||||
|
use spacedog::*;
|
||||||
|
|
||||||
|
fn create_random_points(num_points: usize, seed: &[u8; 32]) -> Vec<[f64; 2]> {
|
||||||
|
let mut rng = Hc128Rng::from_seed(*seed);
|
||||||
|
(0..num_points).map(|_| rng.random()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
const SEED_1: &[u8; 32] = b"Gv0aHMtHkBGsUXNspGU9fLRuCWkZWHZx";
|
||||||
|
// const SEED_2: &[u8; 32] = b"km7DO4GeaFZfTcDXVpnO7ZJlgUY7hZiS";
|
||||||
|
|
||||||
|
const DEFAULT_NUM_POINTS: usize = 1_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1)
|
||||||
|
.into_iter()
|
||||||
|
.map(|[x, y]| Point2d { x, y })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut rng = Hc128Rng::from_seed(*SEED_1);
|
||||||
|
|
||||||
|
let jitters: Vec<_> = points
|
||||||
|
.iter()
|
||||||
|
.map(|p| {
|
||||||
|
let x = p.x + rng.random_range(-5.0..=5.0);
|
||||||
|
let y = p.y + rng.random_range(-5.0..=5.0);
|
||||||
|
Point2d { x, y }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let index = Spindex2d::new(&points);
|
||||||
|
|
||||||
|
for round in 0..100 {
|
||||||
|
dbg!(round);
|
||||||
|
if round % 2 == 0 {
|
||||||
|
index.update(&jitters);
|
||||||
|
} else {
|
||||||
|
index.update(&points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue