Commit 89a72af
Refactor Reproducer to Eliminate Code Duplication Using AST-Based Function Extraction (#178)
Summary:
fix #170
This PR eliminates duplicate functions between the reproducer template and utility module by implementing an automatic function extraction system using Python's AST (Abstract Syntax Tree) parser. The template file is reduced by **92%** (398 → 31 lines) while maintaining full functionality.
**Net Impact:** 4 files changed, **-40 lines** of code (443 insertions, 483 deletions)
## Problem
The reproducer system had significant code duplication:
- `example.py` (template) and `utils.py` contained **8 duplicate functions**
- Maintaining consistency required updating code in two places
- `utils.py` was missing critical functionality:
- ❌ No support for `NoneType`, `str`, `float` types
- ❌ No stride/storage offset handling (critical for non-contiguous tensors)
- ❌ No device normalization
- ❌ No error handling for tensor capture failures
## Solution
### 1. Single Source of Truth
All utility functions now live exclusively in `utils.py`. The template uses a placeholder that gets replaced with extracted code during reproducer generation.
### 2. AST-Based Function Extraction
Created `function_extractor.py` that uses Python's AST parser to:
- Extract functions and constants from source files **without importing them**
- Preserve original formatting, comments, and decorators
- Handle multi-line statements robustly
### 3. Enhanced Utility Functions
Fixed and expanded `utils.py` with:
- ✅ Support for all Python types (`NoneType`, `str`, `float`, etc.)
- ✅ Proper stride and storage offset handling for non-contiguous tensors
- ✅ Device normalization (`cuda` → `cuda:0`)
- ✅ Comprehensive error handling
## Changes Overview
### Files Modified
| File | Lines Changed | Description |
|------|---------------|-------------|
| `function_extractor.py` | **+122** (new) | AST-based extraction engine |
| `placeholder_replacer.py` | **+11** | Added handler for utility functions placeholder |
| `example.py` | **-373** | Removed all duplicate functions (92% reduction) |
| `utils.py` | **+320/-** | Enhanced with missing functionality |
### Detailed Changes
#### 1. New Module: `function_extractor.py` (+122 lines)
**Purpose:** Extract utility functions from source files using AST parsing.
**Key Functions:**
```python
def extract_utility_functions() -> str:
"""Main entry point - extracts all utility code"""
def _parse_source_file(file_path) -> tuple[ast.Module, list[str]]:
"""Parse Python file into AST and source lines"""
def _extract_assignment(tree, lines, var_name) -> str | None:
"""Extract module-level constants (e.g., TRITON_KERNELS_CUSTOM_TYPES)"""
def _extract_function(tree, lines, func_name) -> str | None:
"""Extract function definition including decorators"""
def _extract_functions(tree, lines, func_names) -> list[str]:
"""Batch extract multiple functions with error checking"""
```
**Extracted Content:**
- From `utils.py`: 8 functions + 1 constant
- From `load_tensor.py`: 1 function
- Total: ~14KB of code, 385 lines
**Advantages over inspect-based approach:**
- ✅ No module imports = no code execution = no side effects
- ✅ Unified extraction method for functions and constants
- ✅ Robust handling of decorators, multi-line statements, comments
- ✅ Uses official Python parser (not string manipulation)
#### 2. Enhanced: `utils.py` (+320 lines, restructured)
**Added Functions:**
```python
def create_args_from_json_file(json_path)
"""Load and parse JSON file"""
def _apply_stride_and_offset(tensor, shape, stride, storage_offset)
"""Apply custom stride and storage offset to tensors"""
def _create_base_tensor(arg_info)
"""Create base tensor without stride modifications"""
def _create_tensor(arg_info)
"""Create tensor with stride/offset applied"""
```
**Enhanced Functions:**
```python
def create_args_from_json(data)
# Refactored to accept parsed data instead of file path
def _create_arg_from_info(arg_info)
# Added support for:
# - NoneType, str, float types
# - Stride and storage offset handling
# - Device normalization (cuda → cuda:0)
# - tensor_capture_error handling
```
**Impact:**
- Fixes critical missing functionality
- Enables proper handling of non-contiguous tensors
- Improves type coverage
- Better error handling
#### 3. Simplified: `example.py` (-373 lines, -92%)
**Before:** 398 lines with duplicate function implementations
**After:** 31 lines with just structure and placeholders
```python
"""
This file is automatically generated by TritonParse reproducer.
It contains a smallest testing example for a Triton kernel.
"""
import torch
# {{IR_OVERRIDE_SETUP_PLACEHOLDER}}
# {{KERNEL_SYSPATH_PLACEHOLDER}}
# {{KERNEL_IMPORT_PLACEHOLDER}}
# {{UTILITY_FUNCTIONS_PLACEHOLDER}} # <- NEW: Auto-injected utility code
if __name__ == "__main__":
script_dir = Path(__file__).resolve().parent # noqa: F821
json_file = script_dir / "{{JSON_FILE_NAME_PLACEHOLDER}}"
grid, args_dict = create_args_from_json_file(str(json_file)) # noqa: F821
print("Generated kernel arguments dictionary:")
for name, arg in args_dict.items():
print(f" {name}: {arg}")
print(f"Grid: {grid}")
# {{KERNEL_INVOCATION_PLACEHOLDER}}
torch.cuda.synchronize()
print("Kernel execution finished.")
```
**Note:** `# noqa: F821` comments suppress linter warnings for identifiers that will be injected at generation time.
#### 4. Updated: `placeholder_replacer.py` (+11 lines)
**Changes:**
```python
# Added import
from tritonparse.reproducer.function_extractor import extract_utility_functions
# Added handler registration
self.register("# {{UTILITY_FUNCTIONS_PLACEHOLDER}}", self._replace_utility_functions)
# Added handler method
def _replace_utility_functions(self, code, context_bundle, **kwargs):
"""Replace the utility functions placeholder with extracted functions."""
utility_code = extract_utility_functions()
return code.replace("# {{UTILITY_FUNCTIONS_PLACEHOLDER}}", utility_code)
```
## Technical Highlights
### AST-Based Extraction
**Why AST instead of inspect?**
| Aspect | inspect Module | AST Parser |
|--------|---------------|------------|
| Module Import | Required 1 parent 197df27 commit 89a72af
File tree
4 files changed
+441
-483
lines changed- tritonparse/reproducer
- templates
4 files changed
+441
-483
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
82 | 83 | | |
83 | 84 | | |
84 | 85 | | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
85 | 89 | | |
86 | 90 | | |
87 | 91 | | |
| |||
217 | 221 | | |
218 | 222 | | |
219 | 223 | | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
220 | 231 | | |
221 | 232 | | |
222 | 233 | | |
| |||
0 commit comments