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

Min/max/if optimizations based on the insights from rival-analyze #87

Merged
merged 31 commits into from
Jan 20, 2025

Conversation

AYadrov
Copy link
Contributor

@AYadrov AYadrov commented Dec 18, 2024

This PR introduces an optimization for fmin, fmax and if operations.
Particularly speaking, sometimes the computational path of an expression is the same for a range of inputs and having an insight would speed up some evaluations.
A simple example is:
(if (> (exp x) 3) (cos x) (sin x)).
Given that exp, cos and sin are all expensive functions to compute, that would be nice to have some insights about
the condition result of (> (exp x) 3) to avoid additional computations.
As known, rival-analyze can analyze an expression for a range of input variables and conclude about error status for the whole range.
It has been observed, that rival-analyze may also give a hint on computational path of the expression.
For example, after analyzing (if (> (exp x) 3) (cos x) (sin x)) for x larger than 2, the function would provide a hint
that for any x that is larger than 2, only (cos x) should be executed.
Therefore, no (> (exp x) 3), no (sin x) should be executed at all.
This optimization has been implemented and it is supposed to speed up some particular benchmarks with a large number of fmax, fmin and if operations.

eval/run.rkt Outdated
#:unless (and (not first-iter?) repeat))
[hint (if vhint
(in-vector vhint)
(in-producer (const #t)))]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no vhint is provided then execute all the instructions and treat local hint as #t

@AYadrov AYadrov requested a review from pavpanchekha January 9, 2025 19:24
eval/main.rkt Outdated
(define-values (hint hint-converged?) (make-hint machine))
(list (ival (or bad? stuck?) (not good?)) hint hint-converged?))

(module+ test
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests represent a random testing of the hints implementation.

It samples random hyperrects in a global box of [-100, 100] and points inside these hyperrects.
The hyperrects are analyzed using rival-analyze and obtained hint is executed for points.
The tests verify that execution with hint and without hint produces the same results.
Additionally, the tests check the percentage of instruction executions being skipped by hint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the tests to a separate file? Otherwise, sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not review the tests closely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sure

Copy link
Contributor

@pavpanchekha pavpanchekha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a bunch of minor comments but this seems good to merge. Decent overall design.

.github/workflows/tests.yml Outdated Show resolved Hide resolved
eval/adjust.rkt Outdated
(define bool-reg (vector-ref vregs bool-idx))
(match* ((ival-lo bool-reg) (ival-hi bool-reg) (ival-err? bool-reg))
[(#t #t #f) ; assert and its children should not be reexecuted if it is true already
(vhint-set! bool-idx (or #f (vhint-ref bool-idx)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a no-op, right? (or #f x) is just x.

Copy link
Contributor Author

@AYadrov AYadrov Jan 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was like this:
since we are using batches, we may have duplicates and this why I made or operation.
The thing is that make-hint function first will create a mask for all the instructions,
and mark #t nodes that are roots (they always need to be executed to write some result in vreg vector).
Then it starts a traverse in the reverse order.
This line of code catches the following case:
Imagine that we have a list of expressions as:
(list '(< (cos x) 0) '(assert (< (cos x) 0)))
The algorithm first will mark roots < and assert as #t - should be executed.
And then, the algorithm will start to analyze instruction by instruction.
It will look at assert ... and figure out that assert, for example, is always true - which means that (< (cos x) 0) basically should not be executed.
And here a mistake can happen, (< (cos x) 0) actually should be executed because it is another root and some result should be written into vregs, if we mark (< (cos x) 0) as #f - there will be no output in vregs.
Therefore, the algorithm before marking anything as #f checks whether it previously was marked as #t and if not - it is safe to mark it as #f, otherwise, the instruction should be executed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I get all that. My proposal is delete this line of code entirely. If no one else wants this line of code, its hint is already set to #f (that's the default). If someone else wants it, good, we don't disturb it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right right, here this line of code is useless

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the same operation can be removed everywhere

eval/adjust.rkt Show resolved Hide resolved
eval/adjust.rkt Show resolved Hide resolved
eval/adjust.rkt Outdated Show resolved Hide resolved
eval/adjust.rkt Outdated Show resolved Hide resolved
eval/adjust.rkt Outdated Show resolved Hide resolved
eval/main.rkt Outdated
(define-values (hint hint-converged?) (make-hint machine))
(list (ival (or bad? stuck?) (not good?)) hint hint-converged?))

(module+ test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the tests to a separate file? Otherwise, sure.

eval/main.rkt Outdated
(define-values (hint hint-converged?) (make-hint machine))
(list (ival (or bad? stuck?) (not good?)) hint hint-converged?))

(module+ test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not review the tests closely.

AYadrov and others added 2 commits January 19, 2025 16:37
Co-authored-by: Pavel Panchekha <me@pavpanchekha.com>
@AYadrov AYadrov merged commit 455fd10 into main Jan 20, 2025
1 check passed
@AYadrov AYadrov deleted the min-max-optimizations branch January 20, 2025 21:23
@AYadrov AYadrov mentioned this pull request Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants