Performance of recreating the proj context
- Dominant language
- Rust
- Stars
- 186
- Forks
- 63
- PR merge metrics
- No merged PRs in 30d
Description
Hey all,
I am using this crate for an app that renders in real time. Big transformations are of course done asynchronously, but to my mild surprise I also had to be careful when creating a new Proj instance. I was creating several new Proj instances every frame, but that took between 8-9ms per instance. Since I only have 16ms in a frame if I aim at 60fps, creating new Proj instances every frame is a no-go. I now work around it by implementing my own crs cache where I wrap every Proj instance in an Arc. This does the job just fine, but this surely is not the most ergonomic way to use the crate. If you want to verify the timing, you can add the following test in proj.rs:
```
#[test]
fn bench_proj_creation_time() {
let n = 1000;
// Warmup (would avoid first-run initialization)
for _ in 0..100 {
let _ = Proj::new("EPSG:4326").unwrap();
}
let start = Instant::now();
for _ in 0..n {
let _ = Proj::new("EPSG:4326").unwrap();
}
let elapsed = start.elapsed();
let avg = elapsed / n;
println!("Created {} Proj instances", n);
println!("Total time: {:?}", elapsed);
println!("Mean per Proj::new: {:?}", avg);
}
```
Then run it like so:
cargo test proj::test::bench_proj_creation_time -- --nocapture
I then get:
```
Created 1000 Proj instances
Total time: 8.821968393s
Mean per Proj::new: 8.821968ms
```
In contrast, in C I get a median time of 1.4 us and in python (!) I even get a mere ~7us. I can provide those scripts as well if you so desire.
I think the big difference is that in this crate we re-create the context every time we instantiate a new Proj object:
https://github.com/georust/proj/blob/f0ab553f59ef83862ceaefcdfcdd0add7446f219/src/proj.rs#L704
I imagine that every Proj instance owning it's own context is quite convenient and secure, but seeing both the Python and C implementations avoid this makes me wonder if we cannot do the same. Is there a particular reason we do it this way? Or is it mostly a convenience thing? I imagine we could maybe utilize a OnceCell or something like it, but before I dive too deep into the rabbit hole, maybe you guys can cut my investigation short if there is a known dealbreaker or deliberate design decision that would prevent some kind of shared context.
I would love to hear your thougts.
Kind regards,
Timo Millenaar
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with src/proj.rs around line 704 to inspect how each Proj instance creates its context. Run the proposed cargo test benchmark and compare the reported creation cost; done means establishing whether context sharing is compatible with the crate's design and documenting or pursuing the resulting direction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- performance
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100