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

[python] Add walk_with_filter to walk subset of IR #7591

Merged
merged 1 commit into from
Sep 10, 2024

Conversation

uenoku
Copy link
Member

@uenoku uenoku commented Sep 7, 2024

This adds walk_with_filter python method to invoke callbacks only for subset of operations. We require GIL to call python function so this could improve performance of the tools based on Python API. This functionality could be better to be in upstream but for now we decided to add to CIRCT repo.

In the following benchmark there are 5*10^5 hw.constant ops and single hw.output op and it walks only hw.output op. The runtime is substantially faster.

import circt
from circt.dialects import hw
from circt.support import walk_with_filter

from circt.ir import (Context, Location, InsertionPoint, IntegerType,
                      IntegerAttr, Module, WalkOrder,
                      WalkResult)

n = 500000
with Context() as ctx, Location.unknown():
  circt.register_dialects(ctx)

  i32 = IntegerType.get_signless(32)

  m = Module.create()
  with InsertionPoint(m.body):

    def build(module):
      elems = []
      for i in range(n):
          elems.append(hw.ConstantOp(IntegerAttr.get(i32, i)))
    hw.HWModuleOp(name="test", body_builder=build)
  cnt = 0
  def callback(op):
    if isinstance(op.opview, hw.OutputOp):
      global cnt
      cnt += 1
    return WalkResult.ADVANCE

  from time import time
  # Benchmark walk_with_filter
  print("Starting walk_with_filter")
  start_time = time()
  walk_with_filter(m.operation, [hw.OutputOp], callback, WalkOrder.POST_ORDER)
  end_time = time()
  print(f"walk_with_filter elapsed time: {end_time - start_time:.6f} seconds cnt={cnt}")

  # Benchmark operation.walk
  print("Starting operation.walk")
  start_time = time()
  m.operation.walk(callback, WalkOrder.POST_ORDER)
  end_time = time()
  print(f"operation.walk elapsed time: {end_time - start_time:.6f} seconds cnt={cnt}")
Starting walk_with_filter
walk_with_filter elapsed time: 0.005462 seconds cnt=1
Starting operation.walk
operation.walk elapsed time: 1.061360 seconds cnt=2

Copy link
Contributor

@mikeurbach mikeurbach left a comment

Choose a reason for hiding this comment

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

Awesome, I think this will be really helpful. Looks good to me, just one minor comment about the test code.

integration_test/Bindings/Python/support/walk.py Outdated Show resolved Hide resolved
@dtzSiFive
Copy link
Contributor

I'm not a deep python expert. Does this compose with itself re:changing exception type thrown from what's caught? Presumably throwing up to outer walk will be translated to python exception and back again, that sort of thing?

Anyway this looks super useful and a huge win, great work!

@uenoku
Copy link
Member Author

uenoku commented Sep 10, 2024

I'm not a deep python expert. Does this compose with itself re:changing exception type thrown from what's caught? Presumably throwing up to outer walk will be translated to python exception and back again, that sort of thing?

Good point. Exceptions raised in a python callback is caught in IRCore.cpp and it raises another exception std::runtime_error which will be propagated to ptyhon side as RuntimeError. I followed upstream implementation for normal walk here: https://github.com/llvm/llvm-project/blob/9b67c99dc5b0d669a28b714e10e257d3988d1066/mlir/lib/Bindings/Python/IRCore.cpp#L1296-L1313

This adds `walk_with_filter` python method to invoke callbacks
only for subset of operations. We require GIL to call python function
so this could improve performance of the tools based on Python API.

```
Starting walk_with_filter
walk_with_filter elapsed time: 0.005462 seconds cnt=1
Starting operation.walk
operation.walk elapsed time: 1.061360 seconds cnt=2
```
@uenoku uenoku merged commit c433d61 into main Sep 10, 2024
4 checks passed
@uenoku uenoku deleted the dev/hidetou/walk-filter branch September 10, 2024 06: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.

3 participants