-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,465 additions
and
109 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
use std::fs::File; | ||
use std::io::Write; | ||
use std::os::raw::c_int; | ||
use std::path::Path; | ||
|
||
use criterion::profiler::Profiler; | ||
use pprof::flamegraph::TextTruncateDirection; | ||
use pprof::protos::Message; | ||
use pprof::ProfilerGuard; | ||
|
||
/// Small custom profiler that can be used with Criterion to create a flamegraph for benchmarks. | ||
/// Also see [the Criterion documentation on this][custom-profiler]. | ||
/// | ||
/// ## Example on how to enable the custom profiler: | ||
/// | ||
/// ``` | ||
/// mod perf; | ||
/// use perf::FlamegraphProfiler; | ||
/// | ||
/// fn fibonacci_profiled(criterion: &mut Criterion) { | ||
/// // Use the criterion struct as normal here. | ||
/// } | ||
/// | ||
/// fn custom() -> Criterion { | ||
/// Criterion::default().with_profiler(FlamegraphProfiler::new()) | ||
/// } | ||
/// | ||
/// criterion_group! { | ||
/// name = benches; | ||
/// config = custom(); | ||
/// targets = fibonacci_profiled | ||
/// } | ||
/// ``` | ||
/// | ||
/// The neat thing about this is that it will sample _only_ the benchmark, and not other stuff like | ||
/// the setup process. | ||
/// | ||
/// Further, it will only kick in if `--profile-time <time>` is passed to the benchmark binary. | ||
/// A flamegraph will be created for each individual benchmark in its report directory under | ||
/// `profile/flamegraph.svg`. | ||
/// | ||
/// [custom-profiler]: https://bheisler.github.io/criterion.rs/book/user_guide/profiling.html#implementing-in-process-profiling-hooks | ||
pub struct FlamegraphProfiler<'a> { | ||
frequency: c_int, | ||
active_profiler: Option<ProfilerGuard<'a>>, | ||
} | ||
|
||
impl<'a> FlamegraphProfiler<'a> { | ||
#[allow(dead_code)] | ||
pub fn new(frequency: c_int) -> Self { | ||
FlamegraphProfiler { | ||
frequency, | ||
active_profiler: None, | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Profiler for FlamegraphProfiler<'a> { | ||
fn start_profiling(&mut self, _benchmark_id: &str, _benchmark_dir: &Path) { | ||
self.active_profiler = Some(ProfilerGuard::new(self.frequency).unwrap()); | ||
} | ||
|
||
fn stop_profiling(&mut self, _benchmark_id: &str, benchmark_dir: &Path) { | ||
std::fs::create_dir_all(benchmark_dir).unwrap(); | ||
let pprof_path = benchmark_dir.join("profile.pb"); | ||
let flamegraph_path = benchmark_dir.join("flamegraph.svg"); | ||
eprintln!("\nflamegraph_path = {flamegraph_path:#?}"); | ||
let flamegraph_file = File::create(&flamegraph_path) | ||
.expect("File system error while creating flamegraph.svg"); | ||
let mut options = pprof::flamegraph::Options::default(); | ||
options.hash = true; | ||
options.image_width = Some(2500); | ||
options.text_truncate_direction = TextTruncateDirection::Left; | ||
options.font_size /= 3; | ||
if let Some(profiler) = self.active_profiler.take() { | ||
let report = profiler.report().build().unwrap(); | ||
|
||
let mut file = File::create(pprof_path).unwrap(); | ||
let profile = report.pprof().unwrap(); | ||
let mut content = Vec::new(); | ||
profile.encode(&mut content).unwrap(); | ||
file.write_all(&content).unwrap(); | ||
|
||
report | ||
.flamegraph_with_options(flamegraph_file, &mut options) | ||
.expect("Error writing flamegraph"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use std::path::PathBuf; | ||
use std::sync::atomic::AtomicBool; | ||
|
||
use common::types::PointOffsetType; | ||
use criterion::measurement::Measurement; | ||
use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion}; | ||
use rand::rngs::StdRng; | ||
use rand::SeedableRng as _; | ||
use sparse::common::scores_memory_pool::ScoresMemoryPool; | ||
use sparse::common::sparse_vector::RemappedSparseVector; | ||
use sparse::common::sparse_vector_fixture::{random_positive_sparse_vector, random_sparse_vector}; | ||
use sparse::index::csr; | ||
use sparse::index::inverted_index::inverted_index_ram_builder::InvertedIndexBuilder; | ||
use sparse::index::search_context::SearchContext; | ||
mod prof; | ||
|
||
const NUM_QUERIES: usize = 2048; | ||
const MAX_SPARSE_DIM: usize = 30_000; | ||
const TOP: usize = 10; | ||
|
||
pub fn bench_search(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("search"); | ||
|
||
bench_search_random(&mut group, "random_50k", 50_000); | ||
bench_search_random(&mut group, "random_500k", 500_000); | ||
|
||
bench_search_msmarco(&mut group, "msmarco_1M", "base_1M.csr", 1.0); | ||
bench_search_msmarco(&mut group, "msmarco_full_0.25", "base_full.csr", 0.25); | ||
} | ||
|
||
fn bench_search_random<M: Measurement>(c: &mut BenchmarkGroup<M>, name: &str, num_vectors: usize) { | ||
let mut rnd = StdRng::seed_from_u64(42); | ||
|
||
// index | ||
let mut builder = InvertedIndexBuilder::new(); | ||
for idx in 0..num_vectors { | ||
let vec = random_sparse_vector(&mut rnd, MAX_SPARSE_DIM); | ||
builder.add( | ||
idx as PointOffsetType, | ||
RemappedSparseVector::new(vec.indices, vec.values).unwrap(), | ||
); | ||
} | ||
let index = builder.build(); | ||
|
||
let query_vectors = (0..NUM_QUERIES) | ||
.map(|_| { | ||
let vector = random_positive_sparse_vector(&mut rnd, MAX_SPARSE_DIM); | ||
RemappedSparseVector::new(vector.indices, vector.values).unwrap() | ||
}) | ||
.collect::<Vec<_>>(); | ||
let mut it = query_vectors.iter().cycle(); | ||
|
||
let pool = ScoresMemoryPool::new(); | ||
let stopped = AtomicBool::new(false); | ||
|
||
c.bench_function(name, |b| { | ||
b.iter(|| { | ||
SearchContext::new( | ||
it.next().unwrap().clone(), | ||
TOP, | ||
&index, | ||
pool.get(), | ||
&stopped, | ||
) | ||
.search(&|_| true) | ||
}) | ||
}); | ||
} | ||
|
||
pub fn bench_search_msmarco<M: Measurement>( | ||
c: &mut BenchmarkGroup<M>, | ||
name: &str, | ||
dataset: &str, | ||
ratio: f32, | ||
) { | ||
let base_dir = PathBuf::from(std::env::var("MSMARCO_DIR").unwrap()); | ||
|
||
let index = csr::load_index(base_dir.join(dataset), ratio).unwrap(); | ||
let query_vectors = csr::load_vec(base_dir.join("queries.dev.csr")).unwrap(); | ||
let mut it = query_vectors.iter().cycle(); | ||
|
||
let pool = ScoresMemoryPool::new(); | ||
let stopped = AtomicBool::new(false); | ||
|
||
c.bench_function(name, |b| { | ||
b.iter(|| { | ||
SearchContext::new( | ||
it.next().unwrap().clone(), | ||
TOP, | ||
&index, | ||
pool.get(), | ||
&stopped, | ||
) | ||
.search(&|_| true) | ||
}) | ||
}); | ||
} | ||
|
||
#[cfg(not(target_os = "windows"))] | ||
criterion_group! { | ||
name = benches; | ||
config = Criterion::default().with_profiler(prof::FlamegraphProfiler::new(100)); | ||
targets = bench_search, | ||
} | ||
|
||
#[cfg(target_os = "windows")] | ||
criterion_group! { | ||
name = benches; | ||
config = Criterion::default(); | ||
targets = bench_search, | ||
} | ||
|
||
criterion_main!(benches); |
Oops, something went wrong.