internal-tools/benchmarks/benches/package_graph.rs (91 lines of code) (raw):
// Copyright (c) The cargo-guppy Contributors
// SPDX-License-Identifier: MIT OR Apache-2.0
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use guppy::{
graph::{DependencyDirection, PackageGraph, PackageMetadata},
PackageId,
};
use proptest::{collection::vec, prelude::*};
use proptest_ext::ValueGenerator;
use std::{collections::HashMap, time::Instant};
pub fn construct_benchmarks(c: &mut Criterion) {
c.bench_function("make_package_graph", |b| b.iter(make_package_graph));
}
pub fn query_benchmarks(c: &mut Criterion) {
let mut package_graph = make_package_graph();
let mut cache = package_graph.new_depends_cache();
let mut gen = ValueGenerator::deterministic();
c.bench_function("depends_on", |b| {
b.iter_batched_ref(
|| gen.generate(id_pairs_strategy(&package_graph)),
|package_ids| {
package_ids.iter().for_each(|(package_a, package_b)| {
let _ = package_graph.depends_on(package_a, package_b);
})
},
BatchSize::SmallInput,
)
});
c.bench_function("depends_on_cache", |b| {
b.iter_batched_ref(
|| gen.generate(id_pairs_strategy(&package_graph)),
|package_ids| {
package_ids.iter().for_each(|(package_a, package_b)| {
let _ = cache.depends_on(package_a, package_b);
})
},
BatchSize::SmallInput,
)
});
c.bench_function("into_ids", |b| {
b.iter_batched_ref(
|| gen.generate(ids_directions_strategy(&package_graph)),
|ids_directions| {
ids_directions
.iter()
.for_each(|(package_ids, query_direction, iter_direction)| {
let query = package_graph
.query_directed(package_ids.iter().copied(), *query_direction)
.unwrap();
let _: Vec<_> = query.resolve().package_ids(*iter_direction).collect();
})
},
BatchSize::SmallInput,
)
});
c.bench_function("resolve_package_name", |b| {
b.iter_custom(|iters| {
package_graph.invalidate_caches();
let start = Instant::now();
for _ in 0..iters {
let package_set = package_graph.resolve_package_name("syn");
assert_eq!(package_set.len(), 2, "2 versions of syn");
}
start.elapsed()
})
});
c.bench_function("make_package_name_hashmap", |b| {
b.iter_with_large_drop(|| {
let hashmap = make_package_name_hashmap(&package_graph);
assert_eq!(
hashmap.get("syn").map(|v| v.len()),
Some(2),
"2 versions of syn"
);
})
});
c.bench_function("make_cycles", |b| {
b.iter(|| {
package_graph.invalidate_caches();
black_box(package_graph.cycles());
})
});
}
fn make_package_graph() -> PackageGraph {
// Use this package graph as a large and representative one.
PackageGraph::from_json(include_str!(
"../../../fixtures/large/metadata_libra_9ffd93b.json"
))
.unwrap()
}
fn make_package_name_hashmap<'g>(
graph: &'g PackageGraph,
) -> HashMap<&'g str, Vec<PackageMetadata<'g>>> {
let mut hashmap: HashMap<&'g str, Vec<_>> = HashMap::new();
for package in graph.packages() {
hashmap.entry(package.name()).or_default().push(package);
}
hashmap
}
/// Generate pairs of IDs for benchmarks.
fn id_pairs_strategy(graph: &PackageGraph) -> impl Strategy<Value = Vec<(&PackageId, &PackageId)>> {
vec(
(graph.prop010_id_strategy(), graph.prop010_id_strategy()),
256,
)
}
/// Generate IDs and directions for benchmarks.
fn ids_directions_strategy(
graph: &PackageGraph,
) -> impl Strategy<Value = Vec<(Vec<&PackageId>, DependencyDirection, DependencyDirection)>> {
vec(
(
vec(graph.prop010_id_strategy(), 32),
any::<DependencyDirection>(),
any::<DependencyDirection>(),
),
16,
)
}
criterion_group!(benches, construct_benchmarks, query_benchmarks);
criterion_main!(benches);