| """Kernel canonicalization + dedup for the search loop. |
| |
| The advisor's correction (recorded in CLAUDE.md): in `discovery_specialist`, diversity IS |
| the objective and `mech_of` powers a novelty-or-die REWARD. Here the objective is the |
| single FASTEST CORRECT kernel — diversity is just search exploration. So the analog of |
| `mech_of` lives HERE as **dedup**, NOT as a reward: |
| |
| - `khash(src)` : a hash that is invariant to comments, whitespace, docstrings and |
| local-variable renaming, so the search never spends a (costly) harness |
| evaluation on a kernel it already measured. This is the |
| "AST-normalize then hash" move from the LLVM-peephole plan. |
| - `knobs(src)` : extract the performance-relevant features (BLOCK size, num_warps, |
| num_stages, autotune present, ops used) — useful for steering mutation |
| and for the open-trace, never as a correctness/speed signal. |
| |
| Nothing in this file ever decides correctness or speed — that is the harness's sole job. |
| """ |
| from __future__ import annotations |
|
|
| import ast |
| import hashlib |
| import re |
|
|
|
|
| class _Canon(ast.NodeTransformer): |
| """Alpha-rename local names to positional ids and strip docstrings, so two kernels that |
| differ only cosmetically canonicalize identically.""" |
|
|
| def __init__(self): |
| self._names: dict[str, str] = {} |
|
|
| def _id(self, name: str) -> str: |
| |
| |
| if name in _KEEP or name.startswith("__"): |
| return name |
| if name not in self._names: |
| self._names[name] = f"v{len(self._names)}" |
| return self._names[name] |
|
|
| def visit_Name(self, node): |
| node.id = self._id(node.id) |
| return node |
|
|
| def visit_arg(self, node): |
| node.arg = self._id(node.arg) |
| return node |
|
|
| def visit_FunctionDef(self, node): |
| |
| if (node.body and isinstance(node.body[0], ast.Expr) |
| and isinstance(getattr(node.body[0], "value", None), ast.Constant) |
| and isinstance(node.body[0].value.value, str)): |
| node.body = node.body[1:] |
| self.generic_visit(node) |
| return node |
|
|
|
|
| |
| _KEEP = {"torch", "triton", "tl", "run", "range", "len", "float", "int", "tuple", |
| "constexpr", "self", "True", "False", "None"} |
|
|
|
|
| def canonical_src(src: str) -> str: |
| """Normalized source: parse -> strip docstrings + alpha-rename locals -> unparse. |
| Falls back to comment/whitespace stripping if the source doesn't parse standalone.""" |
| try: |
| tree = ast.parse(src) |
| tree = _Canon().visit(tree) |
| ast.fix_missing_locations(tree) |
| return ast.unparse(tree) |
| except Exception: |
| |
| no_comments = re.sub(r"#.*", "", src) |
| return re.sub(r"\s+", " ", no_comments).strip() |
|
|
|
|
| def khash(src: str) -> str: |
| return hashlib.sha1(canonical_src(src).encode()).hexdigest()[:16] |
|
|
|
|
| _INT = r"(\d+)" |
|
|
|
|
| def knobs(src: str) -> dict: |
| """Performance-relevant features (for steering mutation + the open-trace, NOT scoring).""" |
| def _find(pat, default=None, cast=int): |
| m = re.search(pat, src) |
| return cast(m.group(1)) if m else default |
| return { |
| "block": _find(rf"BLOCK\s*=\s*{_INT}"), |
| "block_n": _find(rf"BLOCK_N\s*=\s*{_INT}"), |
| "num_warps": _find(rf"num_warps\s*=\s*{_INT}"), |
| "num_stages": _find(rf"num_stages\s*=\s*{_INT}"), |
| "autotune": "autotune" in src, |
| "uses_rsqrt": "rsqrt" in src, |
| "uses_max_sub": bool(re.search(r"-\s*\w*max", src)) or "maximum" in src, |
| "n_loads": src.count("tl.load"), |
| "n_stores": src.count("tl.store"), |
| } |
|
|
|
|
| if __name__ == "__main__": |
| |
| |
| a = open(__file__.rsplit("/", 1)[0] + "/seed_kernels/rmsnorm.py").read() |
| b = "# totally different comment\n" + a.replace("acc", "accum").replace("row", "r") |
| c = a.replace("BLOCK = 1024", "BLOCK = 2048") |
| print("rmsnorm.py khash:", khash(a)) |
| print("renamed+recommented khash:", khash(b), "(== a)" if khash(a) == khash(b) else "(MISMATCH!)") |
| print("BLOCK 1024->2048 khash:", khash(c), "(distinct)" if khash(a) != khash(c) else "(collision!)") |
| print("knobs(a):", knobs(a)) |
|
|