Skip to content

Commit 9717077

Browse files
authored
[CI][Examples] Enable testing of examples through lit, on both x86 and Arm (#22)
Adds lit as a test dependency via pyproject.toml. Adds FileCheck as an external dependency -- for CI we use Ubuntu's llvm-dev package. Makes CI run for both x86_64 and AArch64.
1 parent aaae734 commit 9717077

File tree

10 files changed

+68
-20
lines changed

10 files changed

+68
-20
lines changed

.github/workflows/examples.yml

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ name: Lighthouse Examples
33
on:
44
workflow_dispatch:
55
push:
6+
branches:
7+
- 'main'
68
pull_request:
79

810
jobs:
911
Examples:
10-
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
arch: [x86_64, AArch64]
15+
16+
runs-on: ${{ matrix.arch == 'AArch64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
1117
steps:
1218
- uses: actions/checkout@v5
1319

@@ -16,21 +22,10 @@ jobs:
1622

1723
- name: Install the project and its dependencies
1824
run: |
19-
uv sync
25+
sudo apt-get install -y llvm-dev # Obtain FileCheck, used in testing.
2026
uv sync --extra ingress-torch-cpu
2127
22-
- name: Run MLP From File
23-
run: |-
24-
uv run python/examples/ingress/torch/mlp_from_file.py
25-
26-
- name: Run MLP From Module
27-
run: |-
28-
uv run python/examples/ingress/torch/mlp_from_model.py
29-
30-
- name: Run Compile And Run
31-
run: |-
32-
uv run python/examples/mlir/compile_and_run.py
33-
34-
- name: Run apply basic schedule to basic payload
35-
run: |-
36-
uv run python/examples/schedule/transform_a_payload_according_to_a_schedule.py
28+
- name: Run lit-enabled examples as tests
29+
run: |
30+
export FILECHECK=FileCheck-18 # Ubuntu's llvm-dev appends a version number.
31+
uv run lit python/examples # Makes sure to substitute FileCheck for $FILECHECK

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,17 @@ pip install .[ingress_torch_cpu] \
117117
--extra-index-url https://download.pytorch.org/whl \
118118
--only-binary :all:
119119
```
120+
121+
## Running tests
122+
123+
Running the tests is as simple as `lit .` in the root of the project.
124+
125+
We assume that the [`FileCheck`](https://llvm.org/docs/CommandGuide/FileCheck.html) and [`lit`](https://llvm.org/docs/CommandGuide/lit.html) executables are available on the `PATH`.
126+
127+
<details>
128+
<summary>
129+
Obtaining <code>FileCheck</code> and <code>lit</code>.
130+
</summary>
131+
To obtain the <a href="https://pypi.org/project/lit">Python package for <code>lit</code></a>, simply run <code>uv sync</code> (<code>lit</code> is included in the "dev" dependency group).
132+
In case the <code>FileCheck</code> executable happens to be available under a different name/location, e.g. as <code>FileCheck-18</code> from Ubuntu's <code>llvm-dev</code> package, set the <code>FILECHECK</code> environment variable when invoking <code>lit</code>.
133+
</details>

lit.cfg.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import os
2+
3+
import lit.formats
4+
from lit.TestingConfig import TestingConfig
5+
6+
# Imagine that, all your variables defined and with types!
7+
assert isinstance(config := eval("config"), TestingConfig)
8+
9+
config.name = "Lighthouse test suite"
10+
config.test_format = lit.formats.ShTest(True)
11+
config.test_source_root = os.path.dirname(__file__)
12+
config.test_exec_root = os.path.dirname(__file__) + "/lit.out"
13+
14+
config.substitutions.append(("%PYTHON", "uv run"))
15+
if filecheck_path := os.environ.get("FILECHECK"):
16+
config.substitutions.append(("FileCheck", filecheck_path))

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ dependencies = [
66
"mlir-python-bindings==20251118+99630eb1b"
77
]
88

9+
[dependency-groups]
10+
dev = [
11+
"lit==18.1.8" # Tool to configure, discover and run tests
12+
]
13+
914
[project.optional-dependencies]
1015
ingress_torch_mlir = [
1116
"torch-mlir==20251122.639"
@@ -66,6 +71,7 @@ name = "torch_mlir"
6671
url = "https://github.com/llvm/torch-mlir-release/releases/expanded_assets/dev-wheels"
6772
explicit = true
6873

74+
# Derive package version from version in code
6975
[build-system]
7076
requires = ["setuptools>=68", "wheel"]
7177
build-backend = "setuptools.build_meta"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
config.excludes = ["MLPModel"]

python/examples/ingress/torch/mlp_from_file.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# RUN: %PYTHON %s
2+
13
"""
24
Example demonstrating how to load a PyTorch model to MLIR using Lighthouse
35
without initializing the model class on the user's side.

python/examples/ingress/torch/mlp_from_model.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# RUN: %PYTHON %s
2+
13
"""
24
Example demonstrating how to load an already initialized PyTorch model
35
to MLIR using Lighthouse.

python/examples/lit.local.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
config.suffixes = {'.py'}

python/examples/mlir/compile_and_run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# RUN: %PYTHON %s
2+
13
import torch
24
import argparse
35

python/examples/schedule/transform_a_payload_according_to_a_schedule.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# RUN: %PYTHON %s | FileCheck %s
2+
13
# Simply demonstrates applying a schedule to a payload.
24
# To do so generates a basic payload and a basic schedule, purely as an example.
35

@@ -24,16 +26,23 @@ def example_payload() -> Module:
2426
with InsertionPoint(payload.body):
2527
matrixType = RankedTensorType.get([16, 16], F32Type.get())
2628

29+
# NB: Do the CHECKing on the transformed output:
30+
# CHECK-LABEL: result of applying schedule to payload
31+
# CHECK: func.func @fold_add_on_two_matmuls
32+
# CHECK-SAME: (%[[MATRIX_A:.*]]: {{.*}}, %[[MATRIX_B:.*]]: {{.*}}, %[[WEIGHTS:.*]]: {{.*}})
2733
@func.func(matrixType, matrixType, matrixType)
2834
def fold_add_on_two_matmuls(matrixA, matrixB, weights):
2935
empty = tensor.empty(matrixType.shape, matrixType.element_type)
3036
c0 = arith.constant(F32Type.get(), 0.0)
37+
# CHECK: %[[ZERO_INIT:.*]] = linalg.fill
3138
zero_init = linalg.fill(c0, outs=[empty])
39+
# CHECK: %[[A_X_WEIGHTS:.*]] = linalg.matmul ins(%[[MATRIX_A]], %[[WEIGHTS]]{{.*}}) outs(%[[ZERO_INIT]]
3240
A_x_weights = linalg.matmul(matrixA, weights, outs=[zero_init])
33-
empty2 = tensor.empty(matrixType.shape, matrixType.element_type)
34-
zero_init2 = linalg.fill(c0, outs=[empty2])
35-
B_x_weights = linalg.matmul(matrixB, weights, outs=[zero_init2])
41+
# CHECK: %[[RES:.*]] = linalg.matmul ins(%[[MATRIX_B]], %[[WEIGHTS]]{{.*}}) outs(%[[A_X_WEIGHTS]]
42+
B_x_weights = linalg.matmul(matrixB, weights, outs=[zero_init])
43+
# CHECK-NOT: linalg.add
3644
added = linalg.add(A_x_weights, B_x_weights, outs=[empty])
45+
# CHECK: return %[[RES]]
3746
return added
3847

3948
print(payload)

0 commit comments

Comments
 (0)