Skip to content

Commit 0a9af73

Browse files
Add xdsl benchmark (#403)
1 parent 29cd683 commit 0a9af73

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

pyperformance/data-files/benchmarks/MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ unpack_sequence <local>
9797
unpickle <local:pickle>
9898
unpickle_list <local:pickle>
9999
unpickle_pure_python <local:pickle>
100+
xdsl <local>
100101
xml_etree <local>
101102

102103

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[project]
2+
name = "pyperformance_bm_xdsl"
3+
requires-python = ">=3.10"
4+
dependencies = ["pyperf", "xdsl==0.46.0"]
5+
urls = {repository = "https://github.com/python/pyperformance"}
6+
dynamic = ["version"]
7+
8+
[tool.pyperformance]
9+
name = "xdsl"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
xdsl==0.46.0
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
Benchmark constant folding over a module of integer addition of constants using
3+
xDSL's pattern rewriting machinery. The workload module is generated by the
4+
``get_constant_folding_module()`` function, which is then transformed by the
5+
``xdsl.transforms.test_constant_folding.TestConstantFoldingPass`` xDSL
6+
transformation pass.
7+
8+
xDSL is a Python-native compiler framework built around SSA-based intermediate
9+
representations. It re-implements many of MLIR's data structures and methods in
10+
Python. This benchmark exercises the simple pattern rewriting transformation of
11+
constant folding. This is a fair proxy for pattern rewriting transformations in
12+
general, which are a major component of MLIR-like compilers in lowering passes.
13+
14+
Pattern rewriting in both xDSL and MLIR is a pointer-chasing, unstructured
15+
workload, which makes it hard to optimise ahead-of-time. This diminishes the
16+
traditional performance advantage of ahead-of-time compiled languages such as
17+
C++ over dynamic languages such as Python -- making it an interesting benchmark.
18+
More information about the design and impact of this benchmark can be found in
19+
the Master's thesis ``Performance and Dynamism in User-extensible Compiler
20+
Infrastructures'', which is `available on GitHub
21+
<https://github.com/EdmundGoodman/masters-project>`_.
22+
"""
23+
24+
import random
25+
26+
import pyperf
27+
28+
from xdsl.context import Context
29+
from xdsl.dialects.arith import AddiOp, Arith, ConstantOp
30+
from xdsl.dialects.builtin import (
31+
Builtin,
32+
IntegerAttr,
33+
ModuleOp,
34+
i32,
35+
)
36+
from xdsl.dialects.test import TestOp
37+
from xdsl.ir import Operation
38+
from xdsl.transforms.test_constant_folding import TestConstantFoldingPass
39+
40+
41+
RANDOM_SEED = 0
42+
43+
44+
def get_constant_folding_module(size: int = 100) -> ModuleOp:
45+
"""Generate an integer addition constant folding workload of a given size.
46+
47+
The output of running the command
48+
`print(WorkloadBuilder().constant_folding_module(size=5))` is shown
49+
below:
50+
51+
```mlir
52+
"builtin.module"() ({
53+
%0 = "arith.constant"() {"value" = 865 : i32} : () -> i32
54+
%1 = "arith.constant"() {"value" = 395 : i32} : () -> i32
55+
%2 = "arith.addi"(%1, %0) : (i32, i32) -> i32
56+
%3 = "arith.constant"() {"value" = 777 : i32} : () -> i32
57+
%4 = "arith.addi"(%3, %2) : (i32, i32) -> i32
58+
%5 = "arith.constant"() {"value" = 912 : i32} : () -> i32
59+
"test.op"(%4) : (i32) -> ()
60+
}) : () -> ()
61+
```
62+
"""
63+
assert size >= 0
64+
random.seed(RANDOM_SEED)
65+
ops: list[Operation] = []
66+
ops.append(ConstantOp(IntegerAttr(random.randint(1, 1000), i32)))
67+
for i in range(1, size + 1):
68+
if i % 2 == 0:
69+
ops.append(AddiOp(ops[i - 1], ops[i - 2]))
70+
else:
71+
ops.append(ConstantOp(IntegerAttr(random.randint(1, 1000), i32)))
72+
ops.append(TestOp([ops[(size // 2) * 2]]))
73+
return ModuleOp(ops)
74+
75+
76+
def bench_xdsl_constant_folding(loops: int, size: int) -> float:
77+
"""Benchmark constant folding integer additions with xDSL."""
78+
ctx = Context(allow_unregistered=True)
79+
ctx.load_dialect(Arith)
80+
ctx.load_dialect(Builtin)
81+
constant_folding_pass = TestConstantFoldingPass()
82+
constant_folding_workload = get_constant_folding_module(size)
83+
84+
range_it = range(loops)
85+
t0 = pyperf.perf_counter()
86+
for _ in range_it:
87+
constant_folding_workload_mutable = constant_folding_workload.clone()
88+
constant_folding_pass.apply(ctx, constant_folding_workload_mutable)
89+
return pyperf.perf_counter() - t0
90+
91+
92+
def add_cmdline_args(cmd, args):
93+
"""Add command line arguments to a pyperf runner"""
94+
cmd.extend(("--size", str(args.size)))
95+
96+
97+
if __name__ == "__main__":
98+
runner = pyperf.Runner(add_cmdline_args=add_cmdline_args)
99+
runner.metadata["description"] = "Benchmark xDSL constant folding integer addition"
100+
runner.argparser.add_argument(
101+
"--size",
102+
type=int,
103+
default=1000,
104+
help="Number of integer additions (default: 1000)",
105+
)
106+
args = runner.parse_args()
107+
runner.bench_time_func("xdsl_constant_fold", bench_xdsl_constant_folding, args.size)

0 commit comments

Comments
 (0)