Skip to content

Commit 9d06026

Browse files
committed
Add benchmark results
1 parent 3f5f03b commit 9d06026

File tree

4 files changed

+142
-121
lines changed

4 files changed

+142
-121
lines changed

Cargo.toml

-8
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,3 @@ criterion = "0.5.1"
1717
[[bench]]
1818
name = "benchmark"
1919
harness = false
20-
21-
[[bench]]
22-
name = "icon_benchmark"
23-
harness = false
24-
25-
[[bench]]
26-
name = "mask_benchmark"
27-
harness = false

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
# Avatar-rs
22

3-
Library for generating semi-random avatars.
3+
Rust library designed for generating semi-random avatars, inspired by GitHub's default avatars. It's simple to use and blazing fast, making it perfect for applications that require quick avatar generation.
44

5-
Inspired by Github's default avatars.
5+
## Features
6+
7+
- **Consistent Output** 🌱: Generate consistent avatars using a seed value.
8+
- **High Performance** 🚀:
9+
- Icons are generated in less than 90 µs on an Intel Core i7-8650U.
10+
11+
- Icon generation and saving to memory in less than 600 µs, though this can vary based on disk performance and system load.
612

713
## Usage
814

benches/benchmark.rs

+8-111
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,22 @@
1-
use avatar_rs::{BLOCK_WIDTH, BLUE_COLOR, GRAY_COLOR, IMG_HEIGHT, IMG_WIDTH, NUM_BLOCKS, PADDING};
1+
use avatar_rs::Icon;
22
use criterion::{Criterion, black_box, criterion_group, criterion_main};
3-
use image::{Rgb, RgbImage};
4-
use rand::{Rng, SeedableRng};
5-
use rayon::prelude::*;
63

74
use avatar_rs;
85

9-
pub fn draw_2(seed: u64, canvas: &mut RgbImage) {
10-
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
11-
let block_types: Vec<(Option<Rgb<u8>>, Option<Rgb<u8>>, Option<Rgb<u8>>)> = (0..NUM_BLOCKS)
12-
.map(|_| {
13-
(
14-
rng.random_bool(0.5).then(|| BLUE_COLOR),
15-
rng.random_bool(0.5).then(|| BLUE_COLOR),
16-
rng.random_bool(0.5).then(|| BLUE_COLOR),
17-
)
18-
})
19-
.collect();
20-
21-
fn index(i: u32) -> usize {
22-
match i {
23-
x if x <= PADDING + 70 => 0,
24-
x if x >= PADDING + 70 && x <= PADDING + 140 => 1,
25-
x if x >= PADDING + 140 && x <= PADDING + 210 => 2,
26-
x if x >= PADDING + 210 && x <= PADDING + 280 => 3,
27-
x if x >= PADDING + 280 && x <= PADDING + 350 => 4,
28-
x if x >= PADDING + 350 && x <= PADDING + 420 => 5,
29-
_ => unimplemented!(),
30-
}
31-
}
32-
33-
canvas
34-
.par_enumerate_pixels_mut()
35-
.filter(|&(x, y, _)| {
36-
x > PADDING && x < IMG_WIDTH - PADDING && y > PADDING && y < IMG_HEIGHT - PADDING
37-
})
38-
.for_each(|(x, y, pixel)| {
39-
if let Some((a, b, c)) = block_types.get(index(y)) {
40-
if let Some(color) = a {
41-
if x > PADDING + BLOCK_WIDTH * 0 && x < PADDING + BLOCK_WIDTH * 1 {
42-
*pixel = *color;
43-
}
44-
if x > PADDING + BLOCK_WIDTH * 4 && x < PADDING + BLOCK_WIDTH * 5 {
45-
*pixel = *color;
46-
}
47-
}
48-
if let Some(color) = b {
49-
if x >= PADDING + BLOCK_WIDTH * 1 && x <= PADDING + BLOCK_WIDTH * 2 {
50-
*pixel = *color;
51-
}
52-
if x >= PADDING + BLOCK_WIDTH * 3 && x <= PADDING + BLOCK_WIDTH * 4 {
53-
*pixel = *color;
54-
}
55-
}
56-
if let Some(color) = c {
57-
if x >= PADDING + BLOCK_WIDTH * 2 && x <= PADDING + BLOCK_WIDTH * 3 {
58-
*pixel = *color;
59-
}
60-
}
61-
}
62-
});
63-
}
64-
65-
pub fn draw_1(seed: u64, canvas: &mut RgbImage) {
66-
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
67-
for block_index in (0..NUM_BLOCKS).map(|v| v * 70) {
68-
let base = PADDING + block_index;
69-
let block_a_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
70-
let block_b_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
71-
let block_c_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
72-
73-
// A
74-
if let Some(pixel) = block_a_type {
75-
for y in base..base + 70 {
76-
for x in PADDING + 0..PADDING + 70 {
77-
canvas.put_pixel(x, y, pixel);
78-
}
79-
// A's reflection
80-
for x in PADDING + 280..PADDING + 350 {
81-
canvas.put_pixel(x, y, pixel);
82-
}
83-
}
84-
}
85-
86-
// B
87-
if let Some(pixel) = block_b_type {
88-
for y in base..base + 70 {
89-
for x in PADDING + 70..PADDING + 140 {
90-
canvas.put_pixel(x, y, pixel);
91-
}
92-
// B's reflection
93-
for x in PADDING + 210..PADDING + 280 {
94-
canvas.put_pixel(x, y, pixel);
95-
}
96-
}
97-
}
98-
99-
// C
100-
if let Some(pixel) = block_c_type {
101-
for y in base..base + 70 {
102-
for x in PADDING + 140..PADDING + 210 {
103-
canvas.put_pixel(x, y, pixel);
104-
}
105-
}
106-
}
107-
}
6+
fn benchmark_init(c: &mut Criterion) {
7+
c.bench_function("icon_init", |b| b.iter(|| black_box(Icon::new(12345))));
1088
}
1099

110-
fn benchmark_draw_1(c: &mut Criterion) {
111-
let mut canvas = RgbImage::from_pixel(IMG_WIDTH, IMG_HEIGHT, GRAY_COLOR);
112-
c.bench_function("draw_1", |b| b.iter(|| draw_1(black_box(42), &mut canvas)));
10+
fn benchmark_save(c: &mut Criterion) {
11+
c.bench_function("icon_save", |b| {
12+
b.iter(|| Icon::new(12345).save("test.png").unwrap())
13+
});
11314
}
11415

115-
fn benchmark_draw_2(c: &mut Criterion) {
116-
let mut canvas = RgbImage::from_pixel(IMG_WIDTH, IMG_HEIGHT, GRAY_COLOR);
117-
c.bench_function("draw_2", |b| b.iter(|| draw_2(black_box(42), &mut canvas)));
118-
}
11916
criterion_group! {
12017
name = benches;
12118
config = Criterion::default().sample_size(1000);
122-
targets = benchmark_draw_1, benchmark_draw_2
19+
targets = benchmark_init, benchmark_save
12320
}
12421

12522
criterion_main!(benches);

benches/draw_benchmark.rs

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use avatar_rs::{BLOCK_WIDTH, BLUE_COLOR, GRAY_COLOR, IMG_HEIGHT, IMG_WIDTH, NUM_BLOCKS, PADDING};
2+
use criterion::{Criterion, black_box, criterion_group, criterion_main};
3+
use image::{Rgb, RgbImage};
4+
use rand::{Rng, SeedableRng};
5+
use rayon::prelude::*;
6+
7+
use avatar_rs;
8+
9+
pub fn draw_2(seed: u64, canvas: &mut RgbImage) {
10+
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
11+
let block_types: Vec<(Option<Rgb<u8>>, Option<Rgb<u8>>, Option<Rgb<u8>>)> = (0..NUM_BLOCKS)
12+
.map(|_| {
13+
(
14+
rng.random_bool(0.5).then(|| BLUE_COLOR),
15+
rng.random_bool(0.5).then(|| BLUE_COLOR),
16+
rng.random_bool(0.5).then(|| BLUE_COLOR),
17+
)
18+
})
19+
.collect();
20+
21+
fn index(i: u32) -> usize {
22+
match i {
23+
x if x <= PADDING + 70 => 0,
24+
x if x >= PADDING + 70 && x <= PADDING + 140 => 1,
25+
x if x >= PADDING + 140 && x <= PADDING + 210 => 2,
26+
x if x >= PADDING + 210 && x <= PADDING + 280 => 3,
27+
x if x >= PADDING + 280 && x <= PADDING + 350 => 4,
28+
x if x >= PADDING + 350 && x <= PADDING + 420 => 5,
29+
_ => unimplemented!(),
30+
}
31+
}
32+
33+
canvas
34+
.par_enumerate_pixels_mut()
35+
.filter(|&(x, y, _)| {
36+
x > PADDING && x < IMG_WIDTH - PADDING && y > PADDING && y < IMG_HEIGHT - PADDING
37+
})
38+
.for_each(|(x, y, pixel)| {
39+
if let Some((a, b, c)) = block_types.get(index(y)) {
40+
if let Some(color) = a {
41+
if x > PADDING + BLOCK_WIDTH * 0 && x < PADDING + BLOCK_WIDTH * 1 {
42+
*pixel = *color;
43+
}
44+
if x > PADDING + BLOCK_WIDTH * 4 && x < PADDING + BLOCK_WIDTH * 5 {
45+
*pixel = *color;
46+
}
47+
}
48+
if let Some(color) = b {
49+
if x >= PADDING + BLOCK_WIDTH * 1 && x <= PADDING + BLOCK_WIDTH * 2 {
50+
*pixel = *color;
51+
}
52+
if x >= PADDING + BLOCK_WIDTH * 3 && x <= PADDING + BLOCK_WIDTH * 4 {
53+
*pixel = *color;
54+
}
55+
}
56+
if let Some(color) = c {
57+
if x >= PADDING + BLOCK_WIDTH * 2 && x <= PADDING + BLOCK_WIDTH * 3 {
58+
*pixel = *color;
59+
}
60+
}
61+
}
62+
});
63+
}
64+
65+
pub fn draw_1(seed: u64, canvas: &mut RgbImage) {
66+
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
67+
for block_index in (0..NUM_BLOCKS).map(|v| v * 70) {
68+
let base = PADDING + block_index;
69+
let block_a_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
70+
let block_b_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
71+
let block_c_type = rng.random_bool(0.5).then(|| BLUE_COLOR);
72+
73+
// A
74+
if let Some(pixel) = block_a_type {
75+
for y in base..base + 70 {
76+
for x in PADDING + 0..PADDING + 70 {
77+
canvas.put_pixel(x, y, pixel);
78+
}
79+
// A's reflection
80+
for x in PADDING + 280..PADDING + 350 {
81+
canvas.put_pixel(x, y, pixel);
82+
}
83+
}
84+
}
85+
86+
// B
87+
if let Some(pixel) = block_b_type {
88+
for y in base..base + 70 {
89+
for x in PADDING + 70..PADDING + 140 {
90+
canvas.put_pixel(x, y, pixel);
91+
}
92+
// B's reflection
93+
for x in PADDING + 210..PADDING + 280 {
94+
canvas.put_pixel(x, y, pixel);
95+
}
96+
}
97+
}
98+
99+
// C
100+
if let Some(pixel) = block_c_type {
101+
for y in base..base + 70 {
102+
for x in PADDING + 140..PADDING + 210 {
103+
canvas.put_pixel(x, y, pixel);
104+
}
105+
}
106+
}
107+
}
108+
}
109+
110+
fn benchmark_draw_1(c: &mut Criterion) {
111+
let mut canvas = RgbImage::from_pixel(IMG_WIDTH, IMG_HEIGHT, GRAY_COLOR);
112+
c.bench_function("draw_1", |b| b.iter(|| draw_1(black_box(42), &mut canvas)));
113+
}
114+
115+
fn benchmark_draw_2(c: &mut Criterion) {
116+
let mut canvas = RgbImage::from_pixel(IMG_WIDTH, IMG_HEIGHT, GRAY_COLOR);
117+
c.bench_function("draw_2", |b| b.iter(|| draw_2(black_box(42), &mut canvas)));
118+
}
119+
120+
criterion_group! {
121+
name = benches;
122+
config = Criterion::default().sample_size(1000);
123+
targets = benchmark_draw_1, benchmark_draw_2
124+
}
125+
126+
criterion_main!(benches);

0 commit comments

Comments
 (0)