Skip to content

Commit

Permalink
slab
Browse files Browse the repository at this point in the history
  • Loading branch information
tickbh committed May 29, 2024
1 parent 5a919fa commit fff444f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "algorithm"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
authors = ["tickbh <[email protected]>"]
description = " http https proxy by rust"
description = "about algorithm data structure, now has lru/lru-k/lfu/slab/rbtree, 关于算法常用的数据结构"
repository = "https://github.com/tickbh/algorithm"
license = "Apache-2.0"
keywords = ["algorithm", "lru", "lfu", "lru-k"]
keywords = ["algorithm", "lru", "lfu", "lru-k", "slab"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -18,6 +18,5 @@ rand="0.8.5"
libc="0.2"
slab = "0.4.9"


[profile.release]
opt-level = 3
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,86 @@ fn main() {
assert!(keys.next() == None);
}
```

# slab 缓存块组,linux中缓存对象的分配器
缓存对象需实现Default,将会使对象缓存起来,避免频繁的重复申请释放带来的开销
以下我们以简单的测试来进行对比,algorithm::Slab与slab::Slab与普通的alloc
以下测试场景相对简单,可能对`slab::Slab`较为不公平

```rust
use std::{ptr, time::Instant};

use algorithm::{Reinit, Slab};

const ARRAY_SIZE: usize = 10240;
const NUM: usize = usize::MAX - 99999;
const ZERO_ARRAY: [usize; ARRAY_SIZE] = [NUM; ARRAY_SIZE];
struct TestStruct {
array: [usize; ARRAY_SIZE],
size: usize,
val: String,
}

impl Default for TestStruct {
fn default() -> Self {
Self { array: [NUM; ARRAY_SIZE], size: 0, val: "slab".to_string(), }
}
}

impl Reinit for TestStruct {
#[inline(always)]
fn reinit(&mut self) {
self.size = 0;
self.val.clear();
self.val.push_str("slab");
unsafe {
ptr::copy_nonoverlapping(&ZERO_ARRAY[0], &mut self.array[0], ARRAY_SIZE);
}
}
}

fn main() {
let times = 100000;
let now = Instant::now();
let mut slab = Slab::<TestStruct>::new();
let mut sum: usize = 0;
for i in 0..times {
let (next, test) = slab.get_reinit_next_val();
test.array[i % 20] = test.array[i % 20].wrapping_add(i % 1024);
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
slab.remove(next);
}
println!("algorithm: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);


let now = Instant::now();
let mut slab = slab::Slab::<TestStruct>::new();
let mut sum: usize = 0;
for i in 0..times {
let next = slab.insert(TestStruct::default());
let test = &mut slab[next];
test.array[i % 20] = test.array[i % 20].wrapping_add(i % 1024);
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
slab.remove(next);
}
println!("tokio::slab: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);

let now = Instant::now();
let mut sum: usize = 0;
for i in 0..times {
let mut test = TestStruct::default();
test.array[i % 20] = test.array[i % 20].wrapping_add(i % 1024);
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
drop(test);
}
println!("normal alloc: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);
}
```
最终用release命令进行输出测试,结果均为一致
但是耗时algorithm避免了申请创建的开销,耗时相对较短,做的仅仅将对象重新reinit
在此场景中tokio::slab即进行了申请又开销了插入及删除,反而耗时最长
```console
algorithm: all cost times 132ms, sum = 18446744063712505088
tokio::slab: all cost times 477ms, sum = 18446744063712505088
normal alloc: all cost times 337ms, sum = 18446744063712505088
```
40 changes: 7 additions & 33 deletions examples/slab.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

use std::{mem, ptr, time::Instant};
use std::{ptr, time::Instant};

use algorithm::{Reinit, Slab};

const ARRAY_SIZE: usize = 102400;
const ARRAY_SIZE: usize = 10240;
const NUM: usize = usize::MAX - 99999;
const ZERO_ARRAY: [usize; ARRAY_SIZE] = [NUM; ARRAY_SIZE];
struct TestStruct {
Expand All @@ -30,9 +30,8 @@ impl Reinit for TestStruct {
}
}

fn test_speed() {

let times = 10000;
fn main() {
let times = 100000;
let now = Instant::now();
let mut slab = Slab::<TestStruct>::new();
let mut sum: usize = 0;
Expand All @@ -42,8 +41,7 @@ fn test_speed() {
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
slab.remove(next);
}
println!("all cost times {}, sum = {}", now.elapsed().as_nanos(), sum);

println!("algorithm: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);

let now = Instant::now();
let mut slab = slab::Slab::<TestStruct>::new();
Expand All @@ -55,7 +53,7 @@ fn test_speed() {
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
slab.remove(next);
}
println!("all cost times {}, sum = {}", now.elapsed().as_nanos(), sum);
println!("tokio::slab: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);

let now = Instant::now();
let mut sum: usize = 0;
Expand All @@ -65,29 +63,5 @@ fn test_speed() {
sum = sum.wrapping_add(test.array[10] + test.size + test.val.len());
drop(test);
}
println!("all cost times {}, sum = {}", now.elapsed().as_nanos(), sum);
}


fn main() {
let mut slab = Slab::new();
for _ in 0..100 {
let k = slab.get_next();
slab[&k] = format!("{}", k);
}
assert!(slab.len() == 100);

for i in 0..100 {
let _ = slab.remove(i);
}

assert!(slab.len() == 0);
let k = slab.get_next();
assert!(k == 99);
assert!(slab[&k] == "99");
let k = slab.get_reinit_next();
assert!(k == 98);
assert!(slab[&k] == "");

test_speed();
println!("normal alloc: all cost times {}ms, sum = {}", now.elapsed().as_millis(), sum);
}

0 comments on commit fff444f

Please sign in to comment.