Track whether or not let expressions failed to solve in solver#7982
Merged
Track whether or not let expressions failed to solve in solver#7982
Conversation
After mutating an expression, the solver needs to know two things: 1) Did the expression contain the variable we're solving for 2) Was the expression successfully "solved" for the variable. I.e. the variable only appears once in the leftmost position. We need to know this to know property 1 of any subexpressions (i.e. does the right child of the expression contain the variable). This drives what transformations we do in ways that are guaranteed to terminate and not take exponential time. We were tracking property 1 through lets but not property 2, and this meant we were doing unhelpful transformations in some cases. I found a case in the wild where this made a pipeline take > 1 hour to compile (I killed it after an hour). It may have been in an infinite transformation loop, or it might have just been exponential. Not sure.
| // Not in the cache, call the base class version. | ||
| debug(4) << "Mutating " << e << " (" << uses_var << ")\n"; | ||
| debug(4) << "Mutating " << e << " (" << uses_var << ", " << failed << ")\n"; | ||
| bool old_uses_var = uses_var; |
Contributor
There was a problem hiding this comment.
I sure which C++ had a terse way to express this pattern (that wasn't an RIAA class)...
Contributor
|
Does this need new test(s)? |
Member
Author
|
It's a failure to scale gracefully with large inputs. For the correctness of it, the existing solver tests are fine. |
Member
Author
|
Looks like there are some real failures to investigate |
Contributor
|
I assume this is still in-progress? |
Member
Author
|
Yes |
…ess_through_solver_lets
…//github.com/halide/Halide into abadams/track_failedness_through_solver_lets
Member
Author
|
The test failure was caused by use of an uninitialized value because I didn't check a return value. I added the must use result macro to reduce_expr_modulo to prevent this problem in future. |
…ess_through_solver_lets
…ess_through_solver_lets
Member
Author
|
Failure unrelated. Just needs an approval |
| bool reduce_expr_modulo(const Expr &e, int64_t modulus, int64_t *remainder); | ||
| bool reduce_expr_modulo(const Expr &e, int64_t modulus, int64_t *remainder, const Scope<ModulusRemainder> &scope); | ||
| HALIDE_MUST_USE_RESULT bool reduce_expr_modulo(const Expr &e, int64_t modulus, int64_t *remainder); | ||
| HALIDE_MUST_USE_RESULT bool reduce_expr_modulo(const Expr &e, int64_t modulus, int64_t *remainder, const Scope<ModulusRemainder> &scope); |
Contributor
There was a problem hiding this comment.
"must use result" should really be the default in the language, with the current behavior opt-in :-/
steven-johnson
approved these changes
Jan 26, 2024
steven-johnson
pushed a commit
that referenced
this pull request
Feb 1, 2024
* Track whether or not let expressions failed to solve in solver After mutating an expression, the solver needs to know two things: 1) Did the expression contain the variable we're solving for 2) Was the expression successfully "solved" for the variable. I.e. the variable only appears once in the leftmost position. We need to know this to know property 1 of any subexpressions (i.e. does the right child of the expression contain the variable). This drives what transformations we do in ways that are guaranteed to terminate and not take exponential time. We were tracking property 1 through lets but not property 2, and this meant we were doing unhelpful transformations in some cases. I found a case in the wild where this made a pipeline take > 1 hour to compile (I killed it after an hour). It may have been in an infinite transformation loop, or it might have just been exponential. Not sure. * Remove surplus comma * Fix use of uninitialized value that could cause bad transformation
ardier
pushed a commit
to ardier/Halide-mutation
that referenced
this pull request
Mar 3, 2024
…e#7982) * Track whether or not let expressions failed to solve in solver After mutating an expression, the solver needs to know two things: 1) Did the expression contain the variable we're solving for 2) Was the expression successfully "solved" for the variable. I.e. the variable only appears once in the leftmost position. We need to know this to know property 1 of any subexpressions (i.e. does the right child of the expression contain the variable). This drives what transformations we do in ways that are guaranteed to terminate and not take exponential time. We were tracking property 1 through lets but not property 2, and this meant we were doing unhelpful transformations in some cases. I found a case in the wild where this made a pipeline take > 1 hour to compile (I killed it after an hour). It may have been in an infinite transformation loop, or it might have just been exponential. Not sure. * Remove surplus comma * Fix use of uninitialized value that could cause bad transformation
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After mutating an expression, the solver needs to know two things:
We were tracking property 1 through lets but not property 2, and this meant we were doing unhelpful transformations in some cases. I found a case in the wild where this made a pipeline take > 1 hour to compile (I killed it after an hour). It may have been in an infinite transformation loop, or it might have just been exponential. Not sure.
As a drive-by while trying to figure out why it was taking so long I also made remainder checking cheaper in the common case of division by a constant, by avoiding a call to can_prove.