Skip to content

Commit a5ed3a5

Browse files
committed
Refactor code structure for improved readability and maintainability
1 parent 4faf929 commit a5ed3a5

8 files changed

Lines changed: 345 additions & 4 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ name = "benchmark_locked_access"
108108
harness = false
109109
path = "benches/fixed/benchmark_locked_access.rs"
110110

111+
[[bench]]
112+
name = "bench_random_write"
113+
harness = false
114+
path = "benches/fixed/bench_random_write.rs"
111115

112116
[features]
113117
default = ["parallel"]
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// benches/fixed/bench_random_write.rs
2+
use std::time::Duration;
3+
4+
use compressed_intvec::prelude::*;
5+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
6+
use rand::{rngs::SmallRng, Rng, SeedableRng};
7+
use simple_sds_sbwt::{int_vector::IntVector as SdsIntVector, ops::Access};
8+
use succinct::int_vec::{IntVecMut, IntVector as SuccinctIntVector};
9+
use sux::prelude::{BitFieldSliceMut, BitFieldVec};
10+
11+
/// Generates a vector with uniformly random values up to a given maximum.
12+
fn generate_random_vec(size: usize, max_val_exclusive: u64) -> Vec<u64> {
13+
let mut rng = SmallRng::seed_from_u64(42);
14+
(0..size)
15+
.map(|_| rng.random_range(0..max_val_exclusive))
16+
.collect()
17+
}
18+
19+
/// The main benchmark function for random write performance.
20+
fn benchmark_random_write(c: &mut Criterion) {
21+
const VECTOR_SIZE: usize = 10_000_000;
22+
const NUM_WRITES: usize = 1_000_000;
23+
24+
// Test a range of bit widths.
25+
let bit_widths_to_test: Vec<u32> = (4..=64).step_by(4).collect();
26+
27+
// Generate a single, consistent set of random indices for all benchmarks.
28+
let mut rng = SmallRng::seed_from_u64(1337);
29+
let access_indices: Vec<usize> = (0..NUM_WRITES)
30+
.map(|_| rng.random_range(0..VECTOR_SIZE))
31+
.collect();
32+
33+
for &bit_width in &bit_widths_to_test {
34+
let mut group = c.benchmark_group(format!("RandomWrite/{}bit", bit_width));
35+
36+
// Generate the initial data and the values to be written.
37+
let initial_data = generate_random_vec(VECTOR_SIZE, 1u64 << bit_width);
38+
let access_values = generate_random_vec(NUM_WRITES, 1u64 << bit_width);
39+
40+
// --- 1. Baseline: Standard Vec with the smallest fitting type ---
41+
match bit_width {
42+
bw if bw <= 8 => {
43+
let baseline_data: Vec<u8> = initial_data.iter().map(|&v| v as u8).collect();
44+
let values_typed: Vec<u8> = access_values.iter().map(|&v| v as u8).collect();
45+
group.bench_function("Baseline_Vec<u8>/set_unchecked", |b| {
46+
b.iter_with_setup(
47+
|| baseline_data.clone(),
48+
|mut vec| {
49+
for i in 0..NUM_WRITES {
50+
unsafe {
51+
*vec.get_unchecked_mut(access_indices[i]) = values_typed[i]
52+
};
53+
}
54+
black_box(vec);
55+
},
56+
);
57+
});
58+
}
59+
bw if bw <= 16 => {
60+
let baseline_data: Vec<u16> = initial_data.iter().map(|&v| v as u16).collect();
61+
let values_typed: Vec<u16> = access_values.iter().map(|&v| v as u16).collect();
62+
group.bench_function("Baseline_Vec<u16>/set_unchecked", |b| {
63+
b.iter_with_setup(
64+
|| baseline_data.clone(),
65+
|mut vec| {
66+
for i in 0..NUM_WRITES {
67+
unsafe {
68+
*vec.get_unchecked_mut(access_indices[i]) = values_typed[i]
69+
};
70+
}
71+
black_box(vec);
72+
},
73+
);
74+
});
75+
}
76+
bw if bw <= 32 => {
77+
let baseline_data: Vec<u32> = initial_data.iter().map(|&v| v as u32).collect();
78+
let values_typed: Vec<u32> = access_values.iter().map(|&v| v as u32).collect();
79+
group.bench_function("Baseline_Vec<u32>/set_unchecked", |b| {
80+
b.iter_with_setup(
81+
|| baseline_data.clone(),
82+
|mut vec| {
83+
for i in 0..NUM_WRITES {
84+
unsafe {
85+
*vec.get_unchecked_mut(access_indices[i]) = values_typed[i]
86+
};
87+
}
88+
black_box(vec);
89+
},
90+
);
91+
});
92+
}
93+
_ => {
94+
let baseline_data: Vec<u64> = initial_data.to_vec();
95+
group.bench_function("Baseline_Vec<u64>/set_unchecked", |b| {
96+
b.iter_with_setup(
97+
|| baseline_data.clone(),
98+
|mut vec| {
99+
for i in 0..NUM_WRITES {
100+
unsafe {
101+
*vec.get_unchecked_mut(access_indices[i]) = access_values[i]
102+
};
103+
}
104+
black_box(vec);
105+
},
106+
);
107+
});
108+
}
109+
};
110+
111+
// --- 2. Setup Compressed Vectors ---
112+
let le_fixed_vec = LEFixedVec::builder()
113+
.bit_width(BitWidth::Explicit(bit_width as usize))
114+
.build(&initial_data)
115+
.unwrap();
116+
117+
let sux_bfv = BitFieldVec::<u64>::from_slice(&initial_data).unwrap();
118+
119+
let mut succinct_iv = SuccinctIntVector::<u64>::new(bit_width as usize);
120+
succinct_iv.reserve_exact(initial_data.len().try_into().unwrap());
121+
for &val in &initial_data {
122+
succinct_iv.push(val);
123+
}
124+
125+
let mut sds_iv =
126+
SdsIntVector::with_len(initial_data.len(), bit_width as usize, 0).unwrap();
127+
for (i, &val) in initial_data.iter().enumerate() {
128+
sds_iv.set(i, val);
129+
}
130+
131+
// --- 3. Benchmark compressed-intvec ---
132+
group.bench_function("LEFixedVec/set_unchecked", |b| {
133+
b.iter_with_setup(
134+
|| le_fixed_vec.clone(),
135+
|mut vec| {
136+
for i in 0..NUM_WRITES {
137+
unsafe { vec.set_unchecked(access_indices[i], access_values[i]) };
138+
}
139+
black_box(vec);
140+
},
141+
);
142+
});
143+
144+
// --- 4. Benchmark sux::BitFieldVec ---
145+
group.bench_function("sux::BitFieldVec/set_unchecked", |b| {
146+
b.iter_with_setup(
147+
|| sux_bfv.clone(),
148+
|mut vec| {
149+
for i in 0..NUM_WRITES {
150+
unsafe { vec.set_unchecked(access_indices[i], access_values[i]) };
151+
}
152+
black_box(vec);
153+
},
154+
);
155+
});
156+
157+
// --- 5. Benchmark succinct::IntVector ---
158+
group.bench_function("succinct::IntVector/set", |b| {
159+
b.iter_with_setup(
160+
|| succinct_iv.clone(),
161+
|mut vec| {
162+
for i in 0..NUM_WRITES {
163+
// `set` performs bounds checking.
164+
vec.set(access_indices[i] as u64, access_values[i]);
165+
}
166+
black_box(vec);
167+
},
168+
);
169+
});
170+
171+
// --- 6. Benchmark simple-sds-sbwt::IntVector ---
172+
group.bench_function("simple-sds-sbwt::IntVector/set", |b| {
173+
b.iter_with_setup(
174+
|| sds_iv.clone(),
175+
|mut vec| {
176+
for i in 0..NUM_WRITES {
177+
// `set` performs bounds checking.
178+
vec.set(access_indices[i], access_values[i]);
179+
}
180+
black_box(vec);
181+
},
182+
);
183+
});
184+
185+
group.finish();
186+
}
187+
}
188+
189+
criterion_group! {
190+
name = benches;
191+
config = Criterion::default()
192+
.sample_size(40)
193+
.warm_up_time(Duration::from_millis(500))
194+
.measurement_time(Duration::from_secs(8));
195+
196+
targets = benchmark_random_write
197+
}
198+
criterion_main!(benches);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<div> <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
2+
<script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.0.min.js"></script> <div id="0cfe16dd-c860-4fdd-8b0f-0a579d50dfdb" class="plotly-graph-div" style="height:900px; width:1200px;"></div> <script type="text/javascript"> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById("0cfe16dd-c860-4fdd-8b0f-0a579d50dfdb")) { Plotly.newPlot( "0cfe16dd-c860-4fdd-8b0f-0a579d50dfdb", [{"hovertemplate":"\u003cb\u003e%{text}\u003c\u002fb\u003e\u003cbr\u003eBit Width: %{x}\u003cbr\u003eTime: %{y:.2f} ms\u003cextra\u003e\u003c\u002fextra\u003e","line":{"color":"black","dash":"dash"},"mode":"lines+markers","name":"Vec\u003cT\u003e","text":["Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)","Vec (Baseline)"],"x":{"dtype":"i1","bdata":"BAgMEBQYHCAkKCwwNDg8QA=="},"y":{"dtype":"f8","bdata":"fWtN5VtvGUBxg5LBZDIWQIoFMiNJSh1Am2T\u002fpYtBG0A3QmkcqIwlQKL+Jz3bZSVA1huDiLPcJECl2frxsFMmQDO2fMlrCi5AQtoj+APzLUAjQ6F4qCcvQAsZj1IJoC5Ag3nZwGduLkDM9Vvgl+AtQM5PcRx4iS5ACgjkSQkKLkA="},"type":"scatter"},{"hovertemplate":"\u003cb\u003eLEFixedVec\u003c\u002fb\u003e\u003cbr\u003eBit Width: %{x}\u003cbr\u003eTime: %{y:.2f} ms\u003cextra\u003e\u003c\u002fextra\u003e","line":{"color":"#636EFA"},"marker":{"color":"#636EFA"},"mode":"lines+markers","name":"LEFixedVec","x":{"dtype":"i1","bdata":"BAgMEBQYHCAkKCwwNDg8QA=="},"y":{"dtype":"f8","bdata":"5EchP0PlFkCnaprEmeUjQNBvkBCSbCVAvn\u002f1ZJW6KEBwfd7t7YkuQNFruyLbdi5AptTjxkZgMkCoBi80NnUwQEnW4eiqKjVAu8eI+tOgNUDHf4EgoIA3QOUKN2HDEDdAu+CeecsxOECf7hZbG+M4QOTVp4oXYzlAok5CsklaNUA="},"type":"scatter"},{"hovertemplate":"\u003cb\u003esimple-sds-sbwt::IntVector\u003c\u002fb\u003e\u003cbr\u003eBit Width: %{x}\u003cbr\u003eTime: %{y:.2f} ms\u003cextra\u003e\u003c\u002fextra\u003e","line":{"color":"#EF553B"},"marker":{"color":"#EF553B"},"mode":"lines+markers","name":"simple-sds-sbwt::IntVector","x":{"dtype":"i1","bdata":"BAgMEBQYHCAkKCwwNDg8QA=="},"y":{"dtype":"f8","bdata":"hT+H3GVbH0DTri3uv2YjQETvo0wZYylAZraeOugUK0CWJWeBjVYwQEc4yk0WODFAW1oul2QFNUD6ValuaGwzQDu8jAfgdThAMkgL4eJUOEDRE+AFW0E6QPItB9Wh+jlAJ+AyAkXHOkD76dHmypI7QJeQxewbLDxATQPiUQbzN0A="},"type":"scatter"},{"hovertemplate":"\u003cb\u003esuccinct::IntVector\u003c\u002fb\u003e\u003cbr\u003eBit Width: %{x}\u003cbr\u003eTime: %{y:.2f} ms\u003cextra\u003e\u003c\u002fextra\u003e","line":{"color":"#00CC96"},"marker":{"color":"#00CC96"},"mode":"lines+markers","name":"succinct::IntVector","x":{"dtype":"i1","bdata":"BAgMEBQYHCAkKCwwNDg8QA=="},"y":{"dtype":"f8","bdata":"\u002f+BMK3yLIEC59HwSD+wtQCF2umdWfSxA3M4ltnpjLUDU5zo3qkAzQBQBCzBWHTRAbEyZ5XywOEC8r8qFym80QK+w4H7A3DtAUrHW9bCIPECIOS7QGzZAQCCur4h0Uz5AySleieRcQEBmLc7hI8VAQBuKBBzLaEFAyap2u8y6L0A="},"type":"scatter"},{"hovertemplate":"\u003cb\u003esux::BitFieldVec\u003c\u002fb\u003e\u003cbr\u003eBit Width: %{x}\u003cbr\u003eTime: %{y:.2f} ms\u003cextra\u003e\u003c\u002fextra\u003e","line":{"color":"#AB63FA"},"marker":{"color":"#AB63FA"},"mode":"lines+markers","name":"sux::BitFieldVec","x":{"dtype":"i1","bdata":"BAgMEBQYHCAkKCwwNDg8QA=="},"y":{"dtype":"f8","bdata":"GsDgalhBFUCwZG7Q3+kfQDL6h4VoxyVAzWRUkB63JkCk8QDsHforQD0b2OmAli1AkMNg\u002foqvMkC9aun6U4AwQEsjZvY5HzVAiF7r9+n+NUAITF+H6ZI3QOOqsu+K8TZAT\u002fy9ucQUOEDMtZ\u002fDM8M4QLxUf5esYDlA9wquaHL2DEA="},"type":"scatter"}], {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"rgb(237,237,237)","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"rgb(51,51,51)"},"error_y":{"color":"rgb(51,51,51)"},"marker":{"line":{"color":"rgb(237,237,237)","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"rgb(51,51,51)","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"rgb(51,51,51)"},"baxis":{"endlinecolor":"rgb(51,51,51)","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"rgb(51,51,51)"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"colorscale":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"colorscale":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"colorscale":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"colorscale":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"},"colorscale":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"rgb(237,237,237)"},"line":{"color":"white"}},"header":{"fill":{"color":"rgb(217,217,217)"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"tickcolor":"rgb(237,237,237)","ticklen":6,"ticks":"inside"}},"colorscale":{"sequential":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]],"sequentialminus":[[0,"rgb(20,44,66)"],[1,"rgb(90,179,244)"]]},"colorway":["#F8766D","#A3A500","#00BF7D","#00B0F6","#E76BF3"],"font":{"color":"rgb(51,51,51)"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"rgb(237,237,237)","showlakes":true,"showland":true,"subunitcolor":"white"},"hoverlabel":{"align":"left"},"hovermode":"closest","paper_bgcolor":"white","plot_bgcolor":"rgb(237,237,237)","polar":{"angularaxis":{"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside"},"bgcolor":"rgb(237,237,237)","radialaxis":{"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside"}},"scene":{"xaxis":{"backgroundcolor":"rgb(237,237,237)","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside","zerolinecolor":"white"},"yaxis":{"backgroundcolor":"rgb(237,237,237)","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside","zerolinecolor":"white"},"zaxis":{"backgroundcolor":"rgb(237,237,237)","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside","zerolinecolor":"white"}},"shapedefaults":{"fillcolor":"black","line":{"width":0},"opacity":0.3},"ternary":{"aaxis":{"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside"},"baxis":{"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside"},"bgcolor":"rgb(237,237,237)","caxis":{"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside"}},"xaxis":{"automargin":true,"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside","title":{"standoff":15},"zerolinecolor":"white"},"yaxis":{"automargin":true,"gridcolor":"white","linecolor":"white","showgrid":true,"tickcolor":"rgb(51,51,51)","ticks":"outside","title":{"standoff":15},"zerolinecolor":"white"}}},"title":{"text":"Random Write Performance\u003cbr\u003e\u003ci\u003e1M random writes on a vector of 10M elements\u003c\u002fi\u003e"},"xaxis":{"title":{"text":"Bit Width"},"dtick":4},"yaxis":{"title":{"text":"Time for 1M writes (ms, lower is better, log scale)"},"type":"log"},"legend":{"font":{"size":12},"title":{"text":"Implementation"},"x":0.01,"y":0.99,"xanchor":"left","yanchor":"top","bgcolor":"rgba(0,0,0,0)","bordercolor":"rgba(0,0,0,0)","borderwidth":1},"font":{"size":14},"margin":{"l":80,"r":80,"t":80,"b":60},"hovermode":"x unified","width":1200,"height":900}, {"responsive": true} ) }; </script> </div>

images/random_write_performance.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)