-
Notifications
You must be signed in to change notification settings - Fork 158
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
[RFC] fixpoint iteration support #603
base: master
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for salsa-rs canceled.
|
CodSpeed Performance ReportMerging #603 will not alter performanceComparing Summary
Benchmarks breakdown
|
This is very cool! (Admittedly, I say this pre-review.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. I left a few comments where I struggled understanding the implementation or had smaller suggestions.
In writing more comprehensive tests for this, I realized that it needs some changes to correctly handle multi-revision scenarios; taking it to Draft mode until I get that fixed. |
Ok, multiple-revision cases are now fixed, and we now populate the initial provisional value only lazily, in case a cycle is actually encountered, which should reduce the number of memos created by quite a lot. Also added a bunch of tests, including multiple-revision cases and one test involving durability. Still need to add cross-thread cycle tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lazy creation of the initial value is a neat improvement. Nice for taking the time to work on it !
The benchmarks show a 4-5% regression. It seems that we're now resizing some hash maps more often. Are we reporting more tracked reads than before? Could you take a look what's causing it? |
Initial experiments using this in the red-knot type checker are promising: astral-sh/ruff#14029 Not yet using it for loopy control flow in that PR, but there are cycles in the core type definitions of Python builtins and standard library, which we previously had a hacky fallback in place for using Salsa's previous cycle fallback support. Moving over to fixpoint iteration just worked, and fixed the type of a builtin impacted by the cycle. On the downside, it is a performance regression. Need to do more work there. |
* master: Improve span of maybe_update dummy implementation for better diagnostics Use `Fallback` trick for tracked function `Update` constraint, implement `Update` for `smallvec` and `compact_str` Fix Disambiguator- and IdentityMap hashing implement `HashEqLike<&T>` for `T`
* master: Add unit tests for AtomicInputAccumulatedValues and OptionalAtomicRevision Replace `crossbeam` dependency with `crossbeam-queue` Remove unnecessary `Mutex` from singleton initialization Drop unnecssary usages of `AtomicCell`
* master: Drop unnecessary `AtomicRevision` Mark `MemoTable` methods that evict entries unsafe LRU eviction at revision bump
Using an option box for cycle heads doesn't seem to have improved the overall picture in codspeed; slightly worse if anything. It did of course reduce memo size. Will look into perf more tomorrow. |
That's surprising, considering that no Benchmark uses cycle handling |
I did add one new benchmark that uses cycle handling. But that of course isn't showing any increase or decrease since it's new in this PR. |
I realized one mistake I made that could be increasing cost for code that doesn't use fixpoint; my |
Yes. We could also use I also noticed that we now have some |
I think that's what I'm already doing? Where do you see an unnecessary dereference of the Box?
Yeah I was going to ask about this / play with it more. This is in a case where I want to use a reference to a memo's I could unwrap the |
It looks like fixing the |
Ok benchmarks are now slightly improved (-2% to -5% instead of -3% to -6%). Would still like to improve more than that if we can. |
This PR removes the existing unwind-based cycle fallback support (a plus for WASM compatibility), and replaces it with support for fixpoint iteration of cycles.
To opt in to fixpoint iteration, provide two additional arguments to
salsa::tracked
on the definition of a tracked function:cycle_initial
andcycle_fn
. The former is a function which should provide a provisional starting value for fixpoint iteration on this query, and the latter is a function which has the opportunity, after each iteration that failed to converge, to decide whether to continue iterating or fallback to some fixed value. See the added test incycle_fixpoint.rs
for details.Usability points that should be covered in the documentation:
cycle_fn
andcycle_initial
on every query that might end up as the "head" of a cycle (that is, queried for its value while it is already executing.)cycle_fn
andcycle_initial
so as to cause iteration to diverge and never terminate; it's up to the user to avoid this. Techniques to avoid this include a) ensuring that cycles will converge, by defining the initial value and the queries themselves monotonically (for example, in a type-inference scenario, the initial value is the bottom, or empty, type, and types will only widen, never narrow, as the cycle iterates -- thus the cycle must eventually converge to the top type, if nowhere else), and/or b) with a larger hammer, by ensuring thatcycle_fn
respects the iteration count it is given, and always halts iteration with a fallback value if the count reaches some "too large" value.cycle_fn
andcycle_initial
such that memoized results can vary depending only on the order in which queries occur. Avoid this by minimizing the number of tracked functions that support fixpoint iteration and ensuring initial values and fallback values are consistent among tracked functions that may occur in a cycle together.cycle_fn
andcycle_initial
queries, but if the query you call re-enters the same cycle, it could lead to unexpected behavior. Take care what queries you call inside cycle recovery functions.This is an RFC pull request to get initial reviewer feedback on the design and implementation. Remaining TODO items: