Skip to content

Commit 9886525

Browse files
committed
Add benchmarks for the global cache tracker.
1 parent d95c2a2 commit 9886525

File tree

7 files changed

+851
-3
lines changed

7 files changed

+851
-3
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

benches/README.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,23 @@ cd benches/benchsuite
99
cargo bench
1010
```
1111

12-
The tests involve downloading the index and benchmarking against some
12+
However, running all benchmarks would take many minutes, so in most cases it
13+
is recommended to just run the benchmarks relevant to whatever section of code
14+
you are working on.
15+
16+
## Benchmarks
17+
18+
There are several different kinds of benchmarks in the `benchsuite/benches` directory:
19+
20+
* `global_cache_tracker` — Benchmarks saving data to the global cache tracker
21+
database using samples of real-world data.
22+
* `resolve` — Benchmarks the resolver against simulations of real-world workspaces.
23+
* `workspace_initialization` — Benchmarks initialization of a workspace
24+
against simulations of real-world workspaces.
25+
26+
### Resolve benchmarks
27+
28+
The resolve benchmarks involve downloading the index and benchmarking against some
1329
real-world and artificial workspaces located in the [`workspaces`](workspaces)
1430
directory.
1531

@@ -21,15 +37,32 @@ faster. You can (and probably should) specify individual benchmarks to run to
2137
narrow it down to a more reasonable set, for example:
2238

2339
```sh
24-
cargo bench -- resolve_ws/rust
40+
cargo bench -p benchsuite --bench resolve -- resolve_ws/rust
2541
```
2642

2743
This will only download what's necessary for the rust-lang/rust workspace
2844
(which is about 330MB) and run the benchmarks against it (which should take
2945
about a minute). To get a list of all the benchmarks, run:
3046

3147
```sh
32-
cargo bench -- --list
48+
cargo bench -p benchsuite --bench resolve -- --list
49+
```
50+
51+
### Global cache tracker
52+
53+
The `global_cache_tracker` benchmark tests saving data to the global cache
54+
tracker database using samples of real-world data. This benchmark should run
55+
relatively quickly.
56+
57+
The real-world data is based on a capture of my personal development
58+
environment which has accumulated a large cache. So it is somewhat arbitrary,
59+
but hopefully representative of a challenging environment. Capturing of the
60+
data is done with the `capture-last-use` binary, which you can run if you need
61+
to rebuild the database. Just try to run on a system with a relatively full
62+
cache in your cargo home directory.
63+
64+
```sh
65+
cargo bench -p benchsuite --bench global_cache_tracker
3366
```
3467

3568
## Viewing reports

benches/benchsuite/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ publish = false
1111

1212
[dependencies]
1313
cargo.workspace = true
14+
cargo-util.workspace = true
1415
criterion.workspace = true
1516
flate2.workspace = true
17+
rand.workspace = true
1618
tar.workspace = true
1719
url.workspace = true
1820

@@ -26,3 +28,7 @@ harness = false
2628
[[bench]]
2729
name = "workspace_initialization"
2830
harness = false
31+
32+
[[bench]]
33+
name = "global_cache_tracker"
34+
harness = false
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//! Benchmarks for the global cache tracker.
2+
3+
use cargo::core::global_cache_tracker::{self, DeferredGlobalLastUse, GlobalCacheTracker};
4+
use cargo::util::cache_lock::CacheLockMode;
5+
use cargo::util::interning::InternedString;
6+
use cargo::util::Config;
7+
use criterion::{criterion_group, criterion_main, Criterion};
8+
use std::fs;
9+
use std::path::{Path, PathBuf};
10+
11+
// Samples of real-world data.
12+
const GLOBAL_CACHE_SAMPLE: &str = "global-cache-tracker/global-cache-sample";
13+
const GLOBAL_CACHE_RANDOM: &str = "global-cache-tracker/random-sample";
14+
15+
/// A scratch directory where the benchmark can place some files.
16+
fn root() -> PathBuf {
17+
let mut p = PathBuf::from(env!("CARGO_TARGET_TMPDIR"));
18+
p.push("bench_global_cache_tracker");
19+
p
20+
}
21+
22+
fn cargo_home() -> PathBuf {
23+
let mut p = root();
24+
p.push("chome");
25+
p
26+
}
27+
28+
fn initialize_config() -> Config {
29+
// Set up config.
30+
let shell = cargo::core::Shell::new();
31+
let homedir = cargo_home();
32+
if !homedir.exists() {
33+
fs::create_dir_all(&homedir).unwrap();
34+
}
35+
let cwd = homedir.clone();
36+
let mut config = Config::new(shell, cwd, homedir);
37+
config.nightly_features_allowed = true;
38+
config.set_search_stop_path(root());
39+
config
40+
.configure(
41+
0,
42+
false,
43+
None,
44+
false,
45+
false,
46+
false,
47+
&None,
48+
&["gc".to_string()],
49+
&[],
50+
)
51+
.unwrap();
52+
// Set up database sample.
53+
let db_path = GlobalCacheTracker::db_path(&config).into_path_unlocked();
54+
if db_path.exists() {
55+
fs::remove_file(&db_path).unwrap();
56+
}
57+
let sample = Path::new(env!("CARGO_MANIFEST_DIR")).join(GLOBAL_CACHE_SAMPLE);
58+
fs::copy(sample, &db_path).unwrap();
59+
config
60+
}
61+
62+
/// Benchmarks how long it takes to initialize `GlobalCacheTracker` with an already
63+
/// existing full database.
64+
fn global_tracker_init(c: &mut Criterion) {
65+
let config = initialize_config();
66+
let _lock = config
67+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
68+
.unwrap();
69+
c.bench_function("global_tracker_init", |b| {
70+
b.iter(|| {
71+
GlobalCacheTracker::new(&config).unwrap();
72+
})
73+
});
74+
}
75+
76+
/// Benchmarks how long it takes to save a `GlobalCacheTracker` when there are zero
77+
/// updates.
78+
fn global_tracker_empty_save(c: &mut Criterion) {
79+
let config = initialize_config();
80+
let _lock = config
81+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
82+
.unwrap();
83+
let mut deferred = DeferredGlobalLastUse::new();
84+
let mut tracker = GlobalCacheTracker::new(&config).unwrap();
85+
86+
c.bench_function("global_tracker_empty_save", |b| {
87+
b.iter(|| {
88+
deferred.save(&mut tracker).unwrap();
89+
})
90+
});
91+
}
92+
93+
fn load_random_sample() -> Vec<(InternedString, InternedString, u64)> {
94+
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join(GLOBAL_CACHE_RANDOM);
95+
fs::read_to_string(path)
96+
.unwrap()
97+
.lines()
98+
.map(|s| {
99+
let mut s = s.split(',');
100+
(
101+
s.next().unwrap().into(),
102+
s.next().unwrap().into(),
103+
s.next().unwrap().parse().unwrap(),
104+
)
105+
})
106+
.collect()
107+
}
108+
109+
/// Tests performance of updating the last-use timestamps in an already
110+
/// populated database.
111+
///
112+
/// This runs for different sizes of number of crates to update (selecting
113+
/// from the random sample stored on disk).
114+
fn global_tracker_update(c: &mut Criterion) {
115+
let config = initialize_config();
116+
let _lock = config
117+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
118+
.unwrap();
119+
let sample = Path::new(env!("CARGO_MANIFEST_DIR")).join(GLOBAL_CACHE_SAMPLE);
120+
let db_path = GlobalCacheTracker::db_path(&config).into_path_unlocked();
121+
122+
let random_sample = load_random_sample();
123+
124+
let mut group = c.benchmark_group("global_tracker_update");
125+
for size in [1, 10, 100, 500] {
126+
if db_path.exists() {
127+
fs::remove_file(&db_path).unwrap();
128+
}
129+
130+
fs::copy(&sample, &db_path).unwrap();
131+
let mut deferred = DeferredGlobalLastUse::new();
132+
let mut tracker = GlobalCacheTracker::new(&config).unwrap();
133+
group.bench_with_input(size.to_string(), &size, |b, &size| {
134+
b.iter(|| {
135+
for (encoded_registry_name, name, size) in &random_sample[..size] {
136+
deferred.mark_registry_crate_used(global_cache_tracker::RegistryCrate {
137+
encoded_registry_name: *encoded_registry_name,
138+
crate_filename: format!("{}.crate", name).into(),
139+
size: *size,
140+
});
141+
deferred.mark_registry_src_used(global_cache_tracker::RegistrySrc {
142+
encoded_registry_name: *encoded_registry_name,
143+
package_dir: *name,
144+
size: Some(*size),
145+
});
146+
}
147+
deferred.save(&mut tracker).unwrap();
148+
})
149+
});
150+
}
151+
}
152+
153+
criterion_group!(
154+
benches,
155+
global_tracker_init,
156+
global_tracker_empty_save,
157+
global_tracker_update
158+
);
159+
criterion_main!(benches);
Binary file not shown.

0 commit comments

Comments
 (0)