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

eval: optimize iteration #7327

Merged

Conversation

anderseknert
Copy link
Member

Since we do a lot of this in Rego, I was curious to learn what the cost of that was, and if it was possible to do better. I identified the two main costs as these:

  • handleErr wrapper allocating in each iteration, even though the normal condition is to not handle an error
  • biunify callback function literal leaking to the heap in each iteration, with an high cost associated for such a simple one-liner function. While it wasn't possible to change that (as it referenced the outer scope) it was possible to inline the whole biunify flow for the array iteration case, as that turned out to be quite simple when stepped through with a debugger.

Ideally we'd be able to inline iteation over sets and objects too, but that's much more complex (see comment in code), so I left that for the future.

The numbers benchmarked are in the PR, so take a look there. The array iteration case is quite the improvement!

For reference, this amounts to about 2 million allocations less in the regal lint bundle benchmark, and a noticeable improvement in evaluation time.

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

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

Changes lgtm. The results look great! Few questions for my understanding 👇

Comment on lines +3669 to +3674
var undo undo
b, e.bindings = e.bindings.apply(b)
e.bindings.bind(b, a, e.bindings, &undo)

err := e.next(iter, a)
undo.Undo()
Copy link
Member

Choose a reason for hiding this comment

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

What is this supposed to do? Sorry not familiar with how this is expected to work.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question! The code inlined is from here: https://github.com/open-policy-agent/opa/blob/main/v1/topdown/eval.go#L1155-L1160 I can't claim to fully understand how bindings work, but if I am to guess, it resets the binding in scope for the next iteration?

Since we do a lot of this in Rego, I was curious to learn what the cost
of that was, and if it was possible to do better. I identified the two
main costs as these:

- `handleErr` wrapper allocating in each iteration, even though the
  normal condition is to not handle an error
- `biunify` callback function literal leaking to the heap in each
  iteration, with an _high_ cost associated for such a simple one-liner
  function. While it wasn't possible to change that (as it referenced
  the outer scope) it *was* possible to inline the whole biunify flow
  for the array iteration case, as that turned out to be quite simple
  when stepped through with a debugger.

Ideally we'd be able to inline iteation over sets and objects too, but
that's much more complex (see comment in code), so I left that for the
future.

The numbers benchmarked are in the PR, so take a look there. The array
iteration case is *quite* the improvement!

For reference, this amounts to about 2 million allocations less in the
`regal lint bundle` benchmark, and a noticeable improvement in
evaluation time.

Signed-off-by: Anders Eknert <[email protected]>
@anderseknert anderseknert merged commit ec130ec into open-policy-agent:main Jan 29, 2025
28 checks passed
@anderseknert anderseknert deleted the efficient-iteration branch January 29, 2025 09:14
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