-
Notifications
You must be signed in to change notification settings - Fork 79
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
Ensure consistent results in the presence of "spirals" #817
Conversation
55f5e8b
to
0ef0fed
Compare
Rebased to get CI configuration with Python 3 only. |
Given the following variables (adapted from
What we want can be expressed as the following test. For simplicity assume the "spiral heuristic" is that the first time a spiral is detected, we break and return the default value. (In practice, it may have value to allow a spiral to go through a second loop.)
The rationale is as follows:
The difficulty is that calculate/run_formula can at the moment only return a value or raise an exception. It cannot return a value tagged with something signifying "do not cache", because whatever it returns can be used in a formula and we do not control how it's used. |
407999d
to
33c4b8d
Compare
tests/core/test_cycles.py
Outdated
|
||
|
||
def test_allowed_cycle(): | ||
def test_spiral_heuristic(): | ||
""" | ||
Calculate variable5 then variable6 then in the order order, to verify that the first calculated variable |
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.
other order
@Morendil thanks for the details. I would like to be 100 % sure. Are every spiral always stopped at the first step or would they follow max_nb_cycles ? As far as I understand, when we hit a spiral we use the default value as a heuristic but we do not set the variable at this value for that period. |
@benjello I should probably have posted an update after the above comment (with |
33c4b8d
to
04f47f5
Compare
Rebased. |
Ok @Morendil this is neat. How can we help to have this merged ASAP ? |
0927b3c
to
88a16d3
Compare
bfa5cef
to
64dec34
Compare
64dec34
to
b24a2fc
Compare
I have bad news and good news. The bad news is that we are trying too hard to not cache values involved in spirals, but these variables are recomputed a lot. So this kills performance - not just a little degradation but to the point of feeling like an infinite loop. Unusable in production, anyway. I'm reminded of the saying "There are only two hard things in Computer Science: cache invalidation and naming things." Also, much gratitude to @sandcha and @fpagnoux for the performance measurement script which identified the problem last night. The good news is that thanks to our earlier work, and in particular representing the computation stack explicitly, we should still be able to a) solve the original problem, b) simplify the code quite a bit, c) expect some modest performance gains. Our problem is that successive calls to calculate yield inconsistent results because of cached values. We can see this clearly on the first spiral detected in
Variable Instead of trying not to cache values involved in a spiral, we can use the same approach but clean the cache of the values afterwards. We check that the stack is empty, to detect returning from the initial call to
Performance on master:Premier test revenu disponible Performance on this PR, max_spiral_loops = 1:Premier test revenu disponible Performance on this PR, max_spiral_loops = 2:Premier test revenu disponible |
Unfortunately Core tests are passing but a lot of France tests are broken with this… still investigating. Later: breakage is due to a bug in Core 27. |
The strategy "partially invalidate the cache, removing variables caught in a spiral" runs into some issues. Here is a simplified version of - name: Les primes sur un mois ne sont pas moyennées
input:
Alicia:
salaire_net:
2017-01: 200
output:
rsa:
2017-01: 223
rsa_fictif:
2016-12: 0
2016-11: 535.17 - 200
2016-10: 535.17 - 200 This fails with the cache invalidation changes, because the If you try running this test on master, but interchange This is because of This confirms the urgency of openfisca/openfisca-france#1284 - and that this |
ce8b495
to
3acf725
Compare
The situation is a bit worse than I thought. This branch causes 6 errors and 12 failures in France tests. The 6 errors are due to the extra_params situation. One of the failures could be solved by max_spiral_loops=2. However, the rest (11) appear to be related to RSA. Here is a test adapted from one of the cases in
Note that we are testing
This test does not pass, because OpenFisca calculates an amount of 535.17 for This is the first computation OpenFisca performs, so it must be "the right result" for these inputs. The computed RSA of 0 must be the result of a side-effect. And in fact it turns out that (This is, expressed differently, the same issue reported by @claireleroy) |
31be591
to
47afc88
Compare
max_nb_cycles
Detailed explanation of the changes
Terminology:
This PR makes that distinction more explicit by the type of exception raised.
Previously it was the responsibility of callers (country package authors and other reusers) to control the behaviour in the presence of spirals, by setting a limit on the number of "loops" a computation can go through. In such cases, the computation is not aborted with an error but allowed to proceed after returning a default value (usually 0). This resulted in inconsistent computations in interaction with caching of computed values.
This PR removes this responsibility from the caller, and Core now "goes the extra mile" to detect this condition, and to behave more reliably - returning consistent results that do not depend on the order in which computations are performed.
Spirals are more complex to analyse in the absence of static determination of the dependency between variables, so a heuristic is applied in this PR: limit the number of loops to 1. In addition, values computed in a "spiral" configuration should not be cached. We have verified empirically that with these changes, the result of computations no longer depends on their ordering.
This PR effects the following changes:
Connected to openfisca/openfisca-france#1211