native/core/benches/bit_util.rs (162 lines of code) (raw):
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::{mem::size_of, time::Duration};
use rand::{rng, Rng};
use arrow::buffer::Buffer;
use comet::common::bit::{
log2, read_num_bytes_u32, read_num_bytes_u64, read_u32, read_u64, set_bits, trailing_bits,
BitReader, BitWriter,
};
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
/// Benchmark to measure bit_util performance.
/// To run this benchmark:
/// `cd core && cargo bench --bench bit_util`
/// Results will be written to "core/target/criterion/bit_util/"
fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("bit_util");
const N: usize = 1024 * 1024;
let mut writer: BitWriter = BitWriter::new(N * 10);
for _ in 0..N {
if !writer.put_vlq_int(rng().random::<u64>()) {
break;
}
}
let buffer = writer.consume();
let buffer = Buffer::from(buffer.as_slice());
// log2
for bits in (0..64).step_by(3) {
let x = 1u64 << bits;
group.bench_with_input(BenchmarkId::new("log2", bits), &x, |b, &x| {
b.iter(|| log2(black_box(x)));
});
}
// set_bits
for offset in (0..16).step_by(3) {
for length in (0..16).step_by(3) {
let x = (offset, length);
group.bench_with_input(
BenchmarkId::new("set_bits", format!("offset_{}_length_{}", x.0, x.1)),
&x,
|b, &x| {
b.iter(|| set_bits(&mut [0u8; 4], black_box(x.0), black_box(x.1)));
},
);
}
}
// get_vlq_int
group.bench_function("get_vlq_int", |b| {
b.iter(|| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
bench_get_vlq_int(&mut reader)
})
});
// get_bits
for offset in (0..32).step_by(17) {
for num_bits in (1..5).step_by(1) {
let x = (offset, num_bits);
group.bench_with_input(
BenchmarkId::new("get_bits", format!("offset_{}_num_bits_{}", x.0, x.1)),
&x,
|b, &x| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
b.iter(|| reader.get_bits(&mut [0u8; 4], black_box(x.0), black_box(x.1)));
},
);
}
}
// get_aligned
for num_bytes in (1..=size_of::<u8>()).step_by(3) {
let x = num_bytes;
group.bench_with_input(
BenchmarkId::new("get_aligned", format!("u8_num_bytes_{}", x)),
&x,
|b, &x| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
b.iter(|| reader.get_aligned::<u8>(black_box(x)));
},
);
}
for num_bytes in (1..=size_of::<u32>()).step_by(3) {
let x = num_bytes;
group.bench_with_input(
BenchmarkId::new("get_aligned", format!("u32_num_bytes_{}", x)),
&x,
|b, &x| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
b.iter(|| reader.get_aligned::<u32>(black_box(x)));
},
);
}
for num_bytes in (1..=size_of::<i32>()).step_by(3) {
let x = num_bytes;
group.bench_with_input(
BenchmarkId::new("get_aligned", format!("i32_num_bytes_{}", x)),
&x,
|b, &x| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
b.iter(|| reader.get_aligned::<i32>(black_box(x)));
},
);
}
// get_value
for num_bytes in (1..=size_of::<i32>()).step_by(3) {
let x = num_bytes * 8;
group.bench_with_input(
BenchmarkId::new("get_value", format!("i32_num_bits_{}", x)),
&x,
|b, &x| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
b.iter(|| reader.get_value::<i32>(black_box(x)));
},
);
}
// read_num_bytes_u64
for num_bytes in (1..=8).step_by(7) {
let x = num_bytes;
group.bench_with_input(
BenchmarkId::new("read_num_bytes_u64", format!("num_bytes_{}", x)),
&x,
|b, &x| {
b.iter(|| read_num_bytes_u64(black_box(x), black_box(buffer.as_slice())));
},
);
}
// read_num_bytes_u32
for num_bytes in (1..=4).step_by(3) {
let x = num_bytes;
group.bench_with_input(
BenchmarkId::new("read_num_bytes_u32", format!("num_bytes_{}", x)),
&x,
|b, &x| {
b.iter(|| read_num_bytes_u32(black_box(x), black_box(buffer.as_slice())));
},
);
}
// trailing_bits
for length in (0..=64).step_by(32) {
let x = length;
group.bench_with_input(
BenchmarkId::new("trailing_bits", format!("num_bits_{}", x)),
&x,
|b, &x| {
b.iter(|| trailing_bits(black_box(1234567890), black_box(x)));
},
);
}
// read_u64
group.bench_function("read_u64", |b| {
b.iter(|| read_u64(black_box(&[0u8; 8])));
});
// read_u32
group.bench_function("read_u32", |b| {
b.iter(|| read_u32(black_box(&[0u8; 4])));
});
// get_u32_value
group.bench_function("get_u32_value", |b| {
b.iter(|| {
let mut reader: BitReader = BitReader::new_all(buffer.slice(0));
for _ in 0..(buffer.len() * 8 / 31) {
black_box(reader.get_u32_value(black_box(31)));
}
})
});
group.finish();
}
fn bench_get_vlq_int(reader: &mut BitReader) {
while let Some(v) = reader.get_vlq_int() {
black_box(v);
}
}
fn config() -> Criterion {
Criterion::default()
.measurement_time(Duration::from_millis(500))
.warm_up_time(Duration::from_millis(500))
}
criterion_group! {
name = benches;
config = config();
targets = criterion_benchmark
}
criterion_main!(benches);