Skip to content

Commit 04f8534

Browse files
authored
Primary caching 15: range read performance optimization (#4800)
The most obvious and most important performance optimization when doing cached range queries: only upsert data at the edges of the bucket / ring-buffer. This works because our buckets (well, singular, at the moment) are always dense. - #4793 ![image](https://github.com/rerun-io/rerun/assets/2910679/7246827c-4977-4b3f-9ef9-f8e96b8a9bea) - #4800: ![image](https://github.com/rerun-io/rerun/assets/2910679/ab78643b-a98b-4568-b510-2b8827467095) --- Part of the primary caching series of PR (index search, joins, deserialization): - #4592 - #4593 - #4659 - #4680 - #4681 - #4698 - #4711 - #4712 - #4721 - #4726 - #4773 - #4784 - #4785 - #4793 - #4800
1 parent dc8cf2d commit 04f8534

File tree

1 file changed

+69
-8
lines changed

1 file changed

+69
-8
lines changed

crates/re_query_cache/src/range.rs

+69-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,65 @@ pub struct RangeCache {
1919
pub total_size_bytes: u64,
2020
}
2121

22+
impl RangeCache {
23+
/// Given a `query`, returns N reduced queries that are sufficient to fill the missing data
24+
/// on both the front & back sides of the cache.
25+
#[inline]
26+
pub fn compute_queries(&self, query: &RangeQuery) -> impl Iterator<Item = RangeQuery> {
27+
let front = self.compute_front_query(query);
28+
let back = self.compute_back_query(query);
29+
front.into_iter().chain(back)
30+
}
31+
32+
/// Given a `query`, returns a reduced query that is sufficient to fill the missing data
33+
/// on the front side of the cache, or `None` if all the necessary data is already
34+
/// cached.
35+
pub fn compute_front_query(&self, query: &RangeQuery) -> Option<RangeQuery> {
36+
let mut reduced_query = query.clone();
37+
38+
if self.bucket.is_empty() {
39+
return Some(reduced_query);
40+
}
41+
42+
if let Some(bucket_time_range) = self.bucket.time_range() {
43+
reduced_query.range.max = TimeInt::min(
44+
reduced_query.range.max,
45+
bucket_time_range.min.as_i64().saturating_sub(1).into(),
46+
);
47+
} else {
48+
return Some(reduced_query);
49+
}
50+
51+
if reduced_query.range.max < reduced_query.range.min {
52+
return None;
53+
}
54+
55+
Some(reduced_query)
56+
}
57+
58+
/// Given a `query`, returns a reduced query that is sufficient to fill the missing data
59+
/// on the back side of the cache, or `None` if all the necessary data is already
60+
/// cached.
61+
pub fn compute_back_query(&self, query: &RangeQuery) -> Option<RangeQuery> {
62+
let mut reduced_query = query.clone();
63+
64+
if let Some(bucket_time_range) = self.bucket.time_range() {
65+
reduced_query.range.min = TimeInt::max(
66+
reduced_query.range.min,
67+
bucket_time_range.max.as_i64().saturating_add(1).into(),
68+
);
69+
} else {
70+
return Some(reduced_query);
71+
}
72+
73+
if reduced_query.range.max < reduced_query.range.min {
74+
return None;
75+
}
76+
77+
Some(reduced_query)
78+
}
79+
}
80+
2281
// --- Queries ---
2382

2483
macro_rules! impl_query_archetype_range {
@@ -80,7 +139,7 @@ macro_rules! impl_query_archetype_range {
80139
$($pov: Component + Send + Sync + 'static,)+
81140
$($comp: Component + Send + Sync + 'static,)*
82141
{
83-
re_log::trace!("fill");
142+
re_tracing::profile_scope!("fill");
84143

85144
let now = web_time::Instant::now();
86145

@@ -112,14 +171,16 @@ macro_rules! impl_query_archetype_range {
112171
let mut range_callback = |query: &RangeQuery, range_cache: &mut crate::RangeCache| {
113172
re_tracing::profile_scope!("range", format!("{query:?}"));
114173

115-
let RangeCache { bucket, total_size_bytes } = range_cache;
116-
117-
// NOTE: `+ 2` because we always grab the indicator component as well as the
118-
// instance keys.
119-
let arch_views = ::re_query::range_archetype::<A, { $N + $M + 2 }>(store, query, entity_path);
120-
*total_size_bytes += upsert_results::<A, $($pov,)+ $($comp,)*>(arch_views, bucket)?;
174+
for reduced_query in range_cache.compute_queries(query) {
175+
// NOTE: `+ 2` because we always grab the indicator component as well as the
176+
// instance keys.
177+
let arch_views =
178+
::re_query::range_archetype::<A, { $N + $M + 2 }>(store, &reduced_query, entity_path);
179+
range_cache.total_size_bytes +=
180+
upsert_results::<A, $($pov,)+ $($comp,)*>(arch_views, &mut range_cache.bucket)?;
181+
}
121182

122-
iter_results(bucket)
183+
iter_results(&range_cache.bucket)
123184
};
124185

125186

0 commit comments

Comments
 (0)