Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primary caching 10: latest-at cache invalidation #4726

Merged
merged 6 commits into from
Jan 15, 2024

Conversation

teh-cmc
Copy link
Member

@teh-cmc teh-cmc commented Jan 8, 2024

This implements cache invalidation via a StoreSubscriber.

We keep track of the timestamps to invalidate in the StoreSubscriber, but we only do the actual removal of components at query time.
This is similar to how we handle bucket sorting in the main store: doing it at query time has the benefit that the frame time effectively behaves as natural micro-batching mechanism that vastly improves performance.


Part of the primary caching series of PR (index search, joins, deserialization):


Checklist

  • I have read and agree to Contributor Guide and the Code of Conduct
  • I've included a screenshot or gif (if applicable)
  • I have tested the web demo (if applicable):
  • The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG

crates/re_query/src/query.rs Outdated Show resolved Hide resolved
crates/re_query_cache/src/query.rs Show resolved Hide resolved
crates/re_query_cache/tests/latest_at.rs Show resolved Hide resolved
crates/re_query_cache/tests/latest_at.rs Show resolved Hide resolved
crates/re_query_cache/src/cache.rs Outdated Show resolved Hide resolved
crates/re_query_cache/src/cache.rs Outdated Show resolved Hide resolved
crates/re_query_cache/src/cache.rs Outdated Show resolved Hide resolved
@teh-cmc teh-cmc marked this pull request as ready for review January 9, 2024 11:59
teh-cmc added a commit that referenced this pull request Jan 10, 2024
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
teh-cmc added a commit that referenced this pull request Jan 10, 2024
Make it possible to toggle primary caching on and off at runtime, for
both latest-at and range queries.


![image](https://github.com/rerun-io/rerun/assets/2910679/46404d8d-ea27-441c-9bae-ba5e3476adef)


---

Part of the primary caching series of PR (index search, joins,
deserialization):
- #4592
- #4593
- #4659
- #4680 
- #4681
- #4698
- #4711
- #4712
- #4721 
- #4726
teh-cmc added a commit that referenced this pull request Jan 10, 2024
Integrates the cached APIs with the 2D & 3D spatial views, which is a
pretty tough thing to do because there's a lot of abstraction going on
in there.

`main` vs. cache disabled vs. cache enable (5950X, Arch):
```
group                        main                                    primcache_5_uncached                        primcache_5_cached                  
-----                        ----                                    --------------------                        ------------------                  
Points3D/load_all            1.68     10.1±0.14ms  94.2 MElem/sec        1.00      6.0±0.07ms 157.9 MElem/sec    1.01      6.1±0.06ms 155.7 MElem/sec
Points3D/load_colors         1.44      3.8±0.02ms 252.6 MElem/sec        1.00      2.6±0.05ms 364.0 MElem/sec    1.07      2.8±0.06ms 339.5 MElem/sec
Points3D/load_picking_ids    15.16  1859.6±7.01µs 512.9 MElem/sec        1.01    124.3±3.92µs   7.5 GElem/sec    1.00    122.7±3.86µs   7.6 GElem/sec 
Points3D/load_positions      2.29    420.1±0.76µs   2.2 GElem/sec        1.03    189.3±7.44µs   4.9 GElem/sec    1.00    183.4±5.56µs   5.1 GElem/sec 
Points3D/load_radii          1.46      3.3±0.04ms 290.1 MElem/sec        1.05      2.4±0.03ms 404.8 MElem/sec    1.00      2.2±0.00ms 423.9 MElem/sec
Points3D/query_archetype     2.51    676.1±7.59ns        ? ?/sec     15859.98      4.3±0.06ms         ? ?/sec    1.00    268.9±3.39ns         ? ?/sec 
```

---

Part of the primary caching series of PR (index search, joins,
deserialization):
- #4592
- #4593
- #4659
- #4680 
- #4681
- #4698
- #4711
- #4712
- #4721 
- #4726
@teh-cmc teh-cmc force-pushed the cmc/primcache_9_latestat_timeless branch 2 times, most recently from 9f14857 to b70ef8f Compare January 15, 2024 11:32
Base automatically changed from cmc/primcache_9_latestat_timeless to main January 15, 2024 11:35
teh-cmc added a commit that referenced this pull request Jan 15, 2024
Introduces a dedicated cache bucket for timeless data and properly
forwards the information through all APIs downstream.

---

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
@teh-cmc teh-cmc removed the do-not-merge Do not merge this PR label Jan 15, 2024
@teh-cmc teh-cmc force-pushed the cmc/primcache_10_latestat_invalidation branch from 25d3469 to 6b63320 Compare January 15, 2024 11:37
@teh-cmc
Copy link
Member Author

teh-cmc commented Jan 15, 2024

I'm not a big fan of adding singletons to our code base. Can't we have a per-store cache live in EntityDb instead?

Then we don't need to check store_id on invalidation events, and we don't need to worry about dropped stores.

I do intend to get rid of the static global as soon as everything has landed (that will be the last PR in this series, basically). I just don't want to deal with even more integration issues our my way there.

@teh-cmc teh-cmc merged commit 68de772 into main Jan 15, 2024
32 of 36 checks passed
@teh-cmc teh-cmc deleted the cmc/primcache_10_latestat_invalidation branch January 15, 2024 12:03
teh-cmc added a commit that referenced this pull request Jan 15, 2024
)

The primary cache now tracks memory statistics and display them in the
memory panel.

This immediately highlights a very stupid thing that the cache does:
missing optional components that have been turned into streams of
default values by the `ArchetypeView` are materialized as such
:man_facepalming:
- #4779


https://github.com/rerun-io/rerun/assets/2910679/876b264a-3f77-4d91-934e-aa8897bb32fe



- Fixes #4730 


---

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
teh-cmc added a commit that referenced this pull request Jan 15, 2024
**Prefer on a per-commit basis, stuff has moved around**

Range queries are back!... in the most primitive form possible.

No invalidation, no bucketing, no optimization, no nothing. Just putting
everything in place.


https://github.com/rerun-io/rerun/assets/2910679/a65281e4-9843-4598-9547-ce7e45197995

---

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
teh-cmc added a commit that referenced this pull request Jan 15, 2024
teh-cmc added a commit that referenced this pull request Jan 15, 2024
… range queries (#4793)

Our low-level range APIs used to bake the latest-at results at
`range.min - 1` into the range results, which is a big problem in a
multi tenant setting because `range(1, 10)` vs. `latestat(1) + range(2,
10)` are two completely different things.

Side-effect: a plot with a window of len 1 now behaves as expected:



https://github.com/rerun-io/rerun/assets/2910679/957ac367-35a6-4bea-9f40-59d51c556639

---

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
teh-cmc added a commit that referenced this pull request Jan 15, 2024
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
teh-cmc added a commit that referenced this pull request Jan 23, 2024
Range queries used to A) return the frame a T-1, B) accumulate state
starting at T-1 and then C) yield frames starting at T.

A) was a huge issue for many reasons, which #4793 took care of by
eliminating both A) and B).

But we need B) for range queries to be context-free, i.e. to be
guaranteed that `Range(5, 10)` and `Range(4, 10)` will return the exact
same data for frame `5`.
This is crucial for multi-tenant settings where those 2 example queries
would share the same cache.

It also is the nicer-nicer version of the range semantics that we wanted
anyway, I just didn't realize back then that it would require so little
changes, or I would've gone straight for that.

---

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
- #4851
- #4852
- #4853
- #4856
teh-cmc added a commit that referenced this pull request Jan 23, 2024
Simply add a timeless path for the range cache, and actually only
iterate over the range the user asked for (we were still blindly
iterating over everything until now).

Also some very minimal clean up related to #4832, but we have a long way
to go...
- #4832

---

- Fixes #4821 

---

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
- #4851
- #4852
- #4853
- #4856
teh-cmc added a commit that referenced this pull request Jan 23, 2024
Implement range invalidation and do a quality pass over all the size
tracking stuff in the cache.

**Range caching is now enabled by default!**

- Fixes #4809 
- Fixes #374

---

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
- #4851
- #4852
- #4853
- #4856
teh-cmc added a commit that referenced this pull request Jan 23, 2024
- Quick sanity pass over all the intermediary locks and refcounts to
make sure we don't hold anything for longer than we need.
- Get rid of all static globals and let the caches live with their
associated stores in `EntityDb`.
- `CacheKey` no longer requires a `StoreId`.

---

- Fixes #4815 

---

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
- #4851
- #4852
- #4853
- #4856
@teh-cmc teh-cmc added include in changelog and removed exclude from changelog PRs with this won't show up in CHANGELOG.md labels Feb 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
include in changelog 📉 performance Optimization, memory use, etc 🔍 re_query affects re_query itself
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants