Skip to content

Commit

Permalink
Primary caching 3: barebone latest-at caching (#4659)
Browse files Browse the repository at this point in the history
This implements the most barebone latest-at caching support.

The goal is merely to introduce all the machinery and boilerplate
required to get the primary cache running, actual caching features will
be implemented on top of this foundation in follow up PRs.

The [existing benchmark
suite](https://github.com/rerun-io/rerun/blob/790f391/crates/re_query/benches/query_benchmark.rs)
has been ported as-is to the cached APIs (5950X, Arch):
```
group                           primcache_3_vanilla                         primcache_3_cached                  
-----                           -------------------                         ------------------                  
arrow_batch_points2/insert      1.02  1015.0±11.07µs 939.6 MElem/sec      1.00   1000.0±7.37µs 953.7 MElem/sec
arrow_batch_points2/query       2.90      3.4±0.02µs 276.5 MElem/sec      1.00  1190.5±41.55ns 801.0 MElem/sec
arrow_batch_strings2/insert     1.00   1045.7±7.85µs 912.0 MElem/sec      1.00  1042.1±14.01µs 915.1 MElem/sec
arrow_batch_strings2/query      1.91     21.3±0.17µs  44.7 MElem/sec      1.00     11.2±0.04µs  85.2 MElem/sec 
arrow_mono_points2/insert       1.01   1789.2±3.40ms 545.8 KElem/sec      1.00  1773.6±23.00ms 550.6 KElem/sec
arrow_mono_points2/query        6.78  1102.4±18.79µs 885.9 KElem/sec      1.00    162.6±3.39µs   5.9 MElem/sec 
arrow_mono_strings2/insert      1.00   1777.3±5.89ms 549.5 KElem/sec      1.00   1777.3±7.53ms 549.5 KElem/sec
arrow_mono_strings2/query       6.30  1149.9±15.36µs 849.3 KElem/sec      1.00    182.5±0.41µs   5.2 MElem/sec 
```

---

Part of the primary caching series of PR (index search, joins,
deserialization):
- #4592
- #4593
- #4659
- #4680 
- #4681
- #4698
- #4711
- #4712
- #4721 
- #4726
  • Loading branch information
teh-cmc authored Jan 10, 2024
1 parent 2a41e5f commit 39dedc0
Show file tree
Hide file tree
Showing 15 changed files with 1,300 additions and 28 deletions.
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ num-traits = "0.2"
once_cell = "1.17"
ordered-float = "4.2"
parking_lot = "0.12"
paste = "1.0"
pathdiff = "0.2"
pico-args = "0.5"
ply-rs = { version = "0.1", default-features = false }
Expand All @@ -192,6 +193,7 @@ rfd = { version = "0.12", default_features = false, features = ["xdg-portal"] }
rmp-serde = "1"
ron = "0.8.0"
rust-format = "0.3"
seq-macro = "0.3"
serde = "1"
serde_bytes = "0.11"
serde_json = { version = "1", default-features = false, features = ["std"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/re_data_store/src/store_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
/// A query at a given time, for a given timeline.
///
/// Get the latest version of the data available at this time.
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct LatestAtQuery {
pub timeline: Timeline,
pub at: TimeInt,
Expand Down
2 changes: 1 addition & 1 deletion crates/re_data_ui/src/component_ui_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn add_to_registry<C: EntityDataUi + re_types::Component>(registry: &mut Com
Ok(component) => {
component.entity_data_ui(ctx, ui, verbosity, entity_path, query);
}
Err(re_query::QueryError::ComponentNotFound) => {
Err(re_query::QueryError::ComponentNotFound(_)) => {
ui.weak("(not found)");
}
Err(err) => {
Expand Down
16 changes: 8 additions & 8 deletions crates/re_log_types/benches/vec_deque_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

criterion_group!(
benches,
insert_range,
insert_many,
remove_range,
remove,
swap_remove,
Expand Down Expand Up @@ -43,7 +43,7 @@ use self::constants::*;

// ---

fn insert_range(c: &mut Criterion) {
fn insert_many(c: &mut Criterion) {
if std::env::var("CI").is_ok() {
return;
}
Expand All @@ -53,29 +53,29 @@ fn insert_range(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_deque");
group.throughput(criterion::Throughput::Elements(inserted.len() as _));

group.bench_function("insert_range/prefilled/front", |b| {
group.bench_function("insert_many/prefilled/front", |b| {
let base = create_prefilled();
b.iter(|| {
let mut v: VecDeque<i64> = base.clone();
v.insert_range(0, inserted.clone().into_iter());
v.insert_many(0, inserted.clone().into_iter());
v
});
});

group.bench_function("insert_range/prefilled/middle", |b| {
group.bench_function("insert_many/prefilled/middle", |b| {
let base = create_prefilled();
b.iter(|| {
let mut v: VecDeque<i64> = base.clone();
v.insert_range(INITIAL_NUM_ENTRIES / 2, inserted.clone().into_iter());
v.insert_many(INITIAL_NUM_ENTRIES / 2, inserted.clone().into_iter());
v
});
});

group.bench_function("insert_range/prefilled/back", |b| {
group.bench_function("insert_many/prefilled/back", |b| {
let base = create_prefilled();
b.iter(|| {
let mut v: VecDeque<i64> = base.clone();
v.insert_range(INITIAL_NUM_ENTRIES, inserted.clone().into_iter());
v.insert_many(INITIAL_NUM_ENTRIES, inserted.clone().into_iter());
v
});
});
Expand Down
2 changes: 1 addition & 1 deletion crates/re_log_types/src/time_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{TimeInt, TimeReal};

// ----------------------------------------------------------------------------

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TimeRange {
pub min: TimeInt,
Expand Down
18 changes: 9 additions & 9 deletions crates/re_log_types/src/vec_deque_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ pub trait VecDequeInsertionExt<T> {
/// at both ends of the added data.
///
/// Panics if `index` is out of bounds.
fn insert_range(&mut self, index: usize, values: impl ExactSizeIterator<Item = T>);
fn insert_many(&mut self, index: usize, values: impl ExactSizeIterator<Item = T>);
}

impl<T> VecDequeInsertionExt<T> for VecDeque<T> {
fn insert_range(&mut self, index: usize, values: impl ExactSizeIterator<Item = T>) {
fn insert_many(&mut self, index: usize, values: impl ExactSizeIterator<Item = T>) {
if index == self.len() {
self.extend(values); // has a specialization fast-path builtin
} else if index == 0 {
Expand All @@ -110,24 +110,24 @@ impl<T> VecDequeInsertionExt<T> for VecDeque<T> {
}

#[test]
fn insert_range() {
fn insert_many() {
let mut v: VecDeque<i64> = vec![].into();

assert!(v.is_empty());

v.insert_range(0, [1, 2, 3].into_iter());
v.insert_many(0, [1, 2, 3].into_iter());
assert_deque_eq([1, 2, 3], v.clone());

v.insert_range(0, [4, 5].into_iter());
v.insert_many(0, [4, 5].into_iter());
assert_deque_eq([4, 5, 1, 2, 3], v.clone());

v.insert_range(2, std::iter::once(6));
v.insert_many(2, std::iter::once(6));
assert_deque_eq([4, 5, 6, 1, 2, 3], v.clone());

v.insert_range(v.len(), [7, 8, 9, 10].into_iter());
v.insert_many(v.len(), [7, 8, 9, 10].into_iter());
assert_deque_eq([4, 5, 6, 1, 2, 3, 7, 8, 9, 10], v.clone());

v.insert_range(5, [11, 12].into_iter());
v.insert_many(5, [11, 12].into_iter());
assert_deque_eq([4, 5, 6, 1, 2, 11, 12, 3, 7, 8, 9, 10], v.clone());
}

Expand Down Expand Up @@ -262,7 +262,7 @@ fn remove_range() {
assert!(v.is_empty());
assert!(v.is_sorted());

v.insert_range(0, [1, 2, 3, 4, 5, 6, 7, 8, 9].into_iter());
v.insert_many(0, [1, 2, 3, 4, 5, 6, 7, 8, 9].into_iter());
assert_deque_eq([1, 2, 3, 4, 5, 6, 7, 8, 9], v.clone());
assert!(v.is_sorted());

Expand Down
6 changes: 3 additions & 3 deletions crates/re_query/src/archetype_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ impl ComponentWithInstances {
}
let arr = self
.lookup_arrow(instance_key)
.map_or_else(|| Err(QueryError::ComponentNotFound), Ok)?;
.map_or_else(|| Err(crate::ComponentNotFoundError(C::name())), Ok)?;

let mut iter = C::from_arrow(arr.as_ref())?.into_iter();

let val = iter
.next()
.map_or_else(|| Err(QueryError::ComponentNotFound), Ok)?;
.map_or_else(|| Err(crate::ComponentNotFoundError(C::name())), Ok)?;
Ok(val)
}

Expand Down Expand Up @@ -575,7 +575,7 @@ fn lookup_value() {
let missing_value = component.lookup::<Position2D>(&InstanceKey(46));
assert!(matches!(
missing_value.err().unwrap(),
QueryError::ComponentNotFound
QueryError::ComponentNotFound(_)
));

let missing_value = component.lookup::<Color>(&InstanceKey(99));
Expand Down
18 changes: 13 additions & 5 deletions crates/re_query/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ pub use self::util::query_archetype_with_history;
#[cfg(feature = "testing")]
pub use self::query::__populate_example_store;

#[derive(Debug, Clone, Copy)]
pub struct ComponentNotFoundError(pub re_types_core::ComponentName);

impl std::fmt::Display for ComponentNotFoundError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Could not find component: {}", self.0))
}
}

impl std::error::Error for ComponentNotFoundError {}

#[derive(thiserror::Error, Debug)]
pub enum QueryError {
#[error("Tried to access a column that doesn't exist")]
Expand All @@ -31,11 +42,8 @@ pub enum QueryError {
#[error("Could not find primary component: {0}")]
PrimaryNotFound(re_types_core::ComponentName),

#[error("Could not find required component: {0}")]
RequiredComponentNotFound(re_types_core::ComponentName),

#[error("Could not find component")]
ComponentNotFound,
#[error(transparent)]
ComponentNotFound(#[from] ComponentNotFoundError),

#[error("Tried to access component of type '{actual:?}' using component '{requested:?}'")]
TypeMismatch {
Expand Down
20 changes: 20 additions & 0 deletions crates/re_query_cache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,37 @@ default = []

[dependencies]
# Rerun dependencies:
re_data_store.workspace = true
re_entity_db.workspace = true
re_format.workspace = true
re_log.workspace = true
re_log_types.workspace = true
re_query.workspace = true
re_tracing.workspace = true
re_types_core.workspace = true

# External dependencies:
ahash.workspace = true
arrow2.workspace = true
backtrace.workspace = true
document-features.workspace = true
itertools.workspace = true
nohash-hasher.workspace = true
once_cell.workspace = true
parking_lot.workspace = true
paste.workspace = true
seq-macro.workspace = true
thiserror.workspace = true
web-time.workspace = true


[dev-dependencies]
re_log_types = { workspace = true, features = ["testing"] }
re_types = { workspace = true, features = ["datagen"] }

criterion.workspace = true
mimalloc.workspace = true
rand = { workspace = true, features = ["std", "std_rng"] }
similar-asserts.workspace = true


Expand All @@ -47,3 +62,8 @@ bench = false
[[bench]]
name = "flat_vec_deque"
harness = false


[[bench]]
name = "latest_at"
harness = false
Loading

0 comments on commit 39dedc0

Please sign in to comment.