From c5b2b9242dc5e9398cff1e8d0102a118cfbbbd6a Mon Sep 17 00:00:00 2001 From: chenyu Date: Thu, 23 Jul 2026 02:02:44 -0400 Subject: [PATCH] python speed tweak for compile3 (#17147) --- tinygrad/engine/realize.py | 6 ++++-- tinygrad/schedule/rangeify.py | 2 +- tinygrad/uop/symbolic.py | 5 ++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tinygrad/engine/realize.py b/tinygrad/engine/realize.py index 3a64d7b0bf..482133e3ce 100644 --- a/tinygrad/engine/realize.py +++ b/tinygrad/engine/realize.py @@ -89,11 +89,13 @@ def optimize_local_size(call:UOp, prg:UOp) -> UOp|None: if prg.arg.local_size is not None or not Device[device].renderer.has_local or not all_int(prg.arg.global_size): return None if (local_size:=local_size_cache.get(prg.key)) is None: - bufs = [UOp.from_buffer(b.allocate()) for b in bufs_from_ast(prg.src[0], device)] + # reuse one loaded runtime across candidates, only launch dims vary + bufs, runtime = [b.allocate() for b in bufs_from_ast(prg.src[0], device)], get_runtime(device, prg, cache=False) def try_exec(local_size): try: new_gs = tuple(g//l if g%l == 0 else g/l for g,l in zip(prg.arg.global_size, local_size)) - return time_call(prg.replace(arg=replace(prg.arg, global_size=new_gs, local_size=tuple(local_size))).call(*bufs)) + return runtime(*[bufs[i].get_buf(device) for i in prg.arg.globals], global_size=new_gs, local_size=(*local_size,), + vals=prg.arg.vals({}), wait=True) except Exception: return float('inf') MAX_WORKGROUP = 1024 diff --git a/tinygrad/schedule/rangeify.py b/tinygrad/schedule/rangeify.py index bd1a3162ee..400649d7ea 100644 --- a/tinygrad/schedule/rangeify.py +++ b/tinygrad/schedule/rangeify.py @@ -60,9 +60,9 @@ pm_mops = PatternMatcher([ # 0. do some cleanup rewrites, mostly copied from the old stuff def fix_store_hazard(target:UOp, src:UOp): + if (base:=target.base) not in src.backward_slice_with_self: return None # PERMUTE and FLIP reorder indices, SHRINK can have overlapping regions when dest is also shrunk unsafe = {Ops.PERMUTE, Ops.FLIP} | ({Ops.SHRINK} if target.op_in_backward_slice_with_self(Ops.SHRINK) else set()) - base = target.base reaches_base: dict[UOp, bool] = {} for s in src.toposort(gate=lambda s: s.op is not Ops.CONTIGUOUS): reaches_base[s] = s is base or any(reaches_base.get(c) for c in s.src) diff --git a/tinygrad/uop/symbolic.py b/tinygrad/uop/symbolic.py index 3d07200640..fffa74a2fe 100644 --- a/tinygrad/uop/symbolic.py +++ b/tinygrad/uop/symbolic.py @@ -332,9 +332,8 @@ def uop_given_valid(valid:UOp, uop:UOp, try_simplex=True) -> UOp: for candidate in candidates: # if every branch in candidate gives the same simplified uop, we can rewrite the uop - newuops = [uop.substitute({X:newX}) for X,newX in candidate] - if any(u is uop for u in newuops): continue # if any branch doesnt appear in uop, skip - newuops = [u.simplify().substitute({newX:X}).simplify() for (X,newX),u in zip(candidate,newuops)] + if any(X not in uop.backward_slice_with_self for X,_ in candidate): continue # skip if a branch var isn't in uop + newuops = [uop.substitute({X:newX}).simplify().substitute({newX:X}).simplify() for X,newX in candidate] if all_same(newuops): uop = newuops[0] elif uop.op is Ops.STACK and len(uop.src) == 2: if all_same([uops.src[0] for uops in newuops]): uop = uop.replace(src=(newuops[0].src[0], uop.src[1]))