|
1 | | -#!/usr/bin/env python3 |
| 1 | +# RUN: %PYTHON %s |
| 2 | + |
| 3 | +# Basic conversion of KernelBench PyTorch kernels to mlir kernels, relying on |
| 4 | +# torch-mlir for the conversion. As there are a number of kernels for which |
| 5 | +# conversion fails (or is prohibitively slow/gives prohibitively large IR), |
| 6 | +# there's an ingore list. Runs the conversion in parallel. |
2 | 7 |
|
3 | 8 | import sys |
| 9 | + |
| 10 | +from concurrent.futures import ProcessPoolExecutor |
| 11 | +from dataclasses import dataclass |
4 | 12 | from pathlib import Path |
5 | 13 |
|
6 | 14 | from mlir import ir, passmanager |
7 | 15 | from lighthouse.ingress import torch as torch_ingress |
8 | 16 |
|
| 17 | +project_root = Path(__file__).parent.parent.parent.parent |
| 18 | +kernels_as_torch_folder = ( |
| 19 | + project_root / "third_party" / "KernelBench" / "KernelBench" |
| 20 | +) |
9 | 21 |
|
10 | | -kernels_as_pytorch_folder = Path(__file__).parent / "KernelBench" / "KernelBench" |
11 | | - |
12 | | -if not (kernels_as_pytorch_folder.exists() and kernels_as_pytorch_folder.is_dir()): |
| 22 | +if not kernels_as_torch_folder.is_dir(): |
13 | 23 | print( |
14 | 24 | "ERROR: KernelBench repo not found.\n" |
15 | | - "NOTE: Pull in dependency with: git submodule update " |
16 | | - + str(kernels_as_pytorch_folder.parent.relative_to(Path.cwd())) |
17 | | - + "", |
| 25 | + "NOTE: Pull in dependency with: git submodule update --init " |
| 26 | + + str(kernels_as_torch_folder.parent.relative_to(Path.cwd(), walk_up=True)), |
18 | 27 | file=sys.stderr, |
19 | 28 | ) |
20 | 29 | sys.exit(1) |
21 | 30 |
|
22 | 31 |
|
23 | | -kernels_as_pytorch_level1 = kernels_as_pytorch_folder / "level1" |
24 | | -kernels_as_pytorch_level2 = kernels_as_pytorch_folder / "level2" |
| 32 | +kernels_as_torch_level1 = kernels_as_torch_folder / "level1" |
| 33 | +kernels_as_torch_level2 = kernels_as_torch_folder / "level2" |
25 | 34 |
|
26 | | -kernels_as_mlir_folder = Path(__file__).parent / "cache" |
| 35 | +kernels_as_mlir_folder = project_root / "cache" / "ingress" / "KernelBench" |
27 | 36 | kernels_as_mlir_level1 = kernels_as_mlir_folder / "level1" |
28 | 37 | kernels_as_mlir_level1.mkdir(parents=True, exist_ok=True) |
29 | 38 | kernels_as_mlir_level2 = kernels_as_mlir_folder / "level2" |
30 | 39 | kernels_as_mlir_level2.mkdir(parents=True, exist_ok=True) |
31 | 40 |
|
| 41 | +# The following kernels won't get converted: |
32 | 42 | level1, level2 = Path("level1"), Path("level2") |
33 | 43 | ignore_list = [ |
34 | 44 | level1 / "12_Matmul_with_diagonal_matrices_.py", # torch.operator "torch.aten.diag" |
|
118 | 128 | pm = passmanager.PassManager(context=ctx) |
119 | 129 | pm.add("linalg-specialize-generic-ops") |
120 | 130 |
|
121 | | -print("Output directory:", kernels_as_mlir_folder) |
122 | | -exitcode = 0 |
123 | | -for pytorch_level, mlir_level in ( |
124 | | - (kernels_as_pytorch_level1, kernels_as_mlir_level1), |
125 | | - (kernels_as_pytorch_level2, kernels_as_mlir_level2), |
126 | | -): |
127 | | - for kernel_pytorch_file in pytorch_level.iterdir(): |
128 | | - level_and_kernel = ( |
129 | | - Path(kernel_pytorch_file.parent.name) / kernel_pytorch_file.name |
130 | | - ) |
131 | | - if level_and_kernel in ignore_list or not kernel_pytorch_file.is_file(): |
132 | | - print( |
133 | | - f"Skipping: {kernel_pytorch_file.parent.name}/{kernel_pytorch_file.name}", |
134 | | - file=sys.stderr, |
135 | | - ) |
136 | | - continue |
137 | 131 |
|
138 | | - kernel_name = kernel_pytorch_file.stem |
| 132 | +@dataclass |
| 133 | +class KernelConversionTask: |
| 134 | + name: str |
| 135 | + torch_path: Path |
| 136 | + mlir_path: Path |
| 137 | + |
139 | 138 |
|
140 | | - kernel_as_mlir_path = mlir_level / (kernel_name + ".mlir") |
141 | | - if kernel_as_mlir_path.exists(): |
142 | | - print( |
143 | | - f"Already in cache: {kernel_pytorch_file.parent.name}/{kernel_pytorch_file.name}" |
| 139 | +def tasks(): |
| 140 | + for torch_level, mlir_level in ( |
| 141 | + (kernels_as_torch_level1, kernels_as_mlir_level1), |
| 142 | + (kernels_as_torch_level2, kernels_as_mlir_level2), |
| 143 | + ): |
| 144 | + for kernel_torch_file in torch_level.iterdir(): |
| 145 | + level_and_kernel = ( |
| 146 | + Path(kernel_torch_file.parent.name) / kernel_torch_file.name |
144 | 147 | ) |
145 | | - continue |
| 148 | + kernel_torch_path = torch_level / kernel_torch_file |
| 149 | + if level_and_kernel in ignore_list or not kernel_torch_path.is_file(): |
| 150 | + print( |
| 151 | + f"Skipping: {kernel_torch_file.parent.name}/{kernel_torch_file.name}", |
| 152 | + file=sys.stderr, |
| 153 | + ) |
| 154 | + continue |
| 155 | + |
| 156 | + kernel_name = kernel_torch_file.stem |
| 157 | + |
| 158 | + kernel_mlir_path = mlir_level / (kernel_name + ".mlir") |
| 159 | + if kernel_mlir_path.exists(): |
| 160 | + print( |
| 161 | + f"Already in cache: {kernel_torch_file.parent.name}/{kernel_torch_file.name}" |
| 162 | + ) |
| 163 | + continue |
| 164 | + yield KernelConversionTask( |
| 165 | + kernel_name, torch_path=kernel_torch_path, mlir_path=kernel_mlir_path |
| 166 | + ) |
| 167 | + |
| 168 | + |
| 169 | +def process_task(task: KernelConversionTask): |
| 170 | + print(f"Processing: {task.torch_path.parent.name}/{task.torch_path.name}") |
| 171 | + |
| 172 | + try: |
| 173 | + mlir_kernel = torch_ingress.import_from_file(task.torch_path, ir_context=ctx) |
| 174 | + assert isinstance(mlir_kernel, ir.Module) |
| 175 | + except Exception as e: |
146 | 176 | print( |
147 | | - f"Processing: {kernel_pytorch_file.parent.name}/{kernel_pytorch_file.name}" |
| 177 | + f"ERROR: got the following error converting '{task.name}':\n", |
| 178 | + e, |
| 179 | + file=sys.stderr, |
148 | 180 | ) |
149 | | - mlir_kernel = torch_ingress.import_from_file( |
150 | | - kernel_pytorch_file, ir_context=ctx |
| 181 | + raise e |
| 182 | + |
| 183 | + try: |
| 184 | + pm.run(mlir_kernel.operation) # cleanup |
| 185 | + except Exception as e: |
| 186 | + print( |
| 187 | + f"ERROR: got the following error cleaning up '{task.name}':\n", |
| 188 | + e, |
| 189 | + file=sys.stderr, |
151 | 190 | ) |
152 | | - assert isinstance(mlir_kernel, ir.Module) |
| 191 | + raise e |
153 | 192 |
|
154 | | - try: |
155 | | - pm.run(mlir_kernel.operation) # cleanup |
156 | | - except Exception as e: |
157 | | - print( |
158 | | - f"ERROR: got the following error cleaning up '{kernel_name}'", |
159 | | - file=sys.stderr, |
160 | | - ) |
161 | | - raise e |
| 193 | + with task.mlir_path.open("w") as f: |
| 194 | + print("// MLIR output after conversion and clean-up:", file=f) |
| 195 | + print(mlir_kernel, file=f) |
162 | 196 |
|
163 | | - with kernel_as_mlir_path.open("w") as f: |
164 | | - print("// MLIR output after conversion and clean-up:", file=f) |
165 | | - print(mlir_kernel, file=f) |
| 197 | + |
| 198 | +print("Output directory:", kernels_as_mlir_folder) |
| 199 | +ProcessPoolExecutor().map(process_task, tasks()) |
0 commit comments