diff --git a/tinygrad/ops.py b/tinygrad/ops.py index 13f3c0531a..96ecf4f623 100644 --- a/tinygrad/ops.py +++ b/tinygrad/ops.py @@ -146,6 +146,9 @@ class Ops(FastEnum): # consts last! VCONST = auto(); CONST = auto() # noqa: E702 + # device + DEVICE = auto() + class GroupOp: Unary = {Ops.EXP2, Ops.LOG2, Ops.SIN, Ops.SQRT, Ops.RECIP, Ops.NEG} Binary = {Ops.ADD, Ops.MUL, Ops.IDIV, Ops.MAX, Ops.MOD, Ops.CMPLT, Ops.CMPNE, Ops.XOR, Ops.SHL, Ops.SHR, Ops.OR, Ops.AND, Ops.THREEFRY, @@ -290,7 +293,7 @@ class UOp(MathTrait, metaclass=UOpMetaClass): @property def shape(self) -> Tuple[sint, ...]: return unwrap(self.st).shape @property - def size(self) -> int: return self.arg[2] if self.op is Ops.BUFFER else unwrap(self.st).size + def size(self) -> int: return self.arg[-1] if self.op is Ops.BUFFER else unwrap(self.st).size # *** uop evaluation *** @@ -435,7 +438,7 @@ class UOp(MathTrait, metaclass=UOpMetaClass): from tinygrad.shape.shapetracker import ShapeTracker if op is Ops.CONST: # NOTE: we embed device on CONST with a fake BUFFER uop - fake = UOp(Ops.BUFFER, dtype.ptr(), (), (-1, device, 1)) + fake = UOp(Ops.BUFFER, dtype.ptr(), (UOp(Ops.DEVICE, arg=device),), (-1, 1)) # NOTE: BIND stays BIND, UOp.const unbinds here const_uop = arg if isinstance(arg, UOp) else UOp.const(dtype, unwrap(arg)) return UOp(Ops.VIEW, dtype, (fake, const_uop), ShapeTracker.from_shape(())).reshape((1,)*len(shape)).expand(shape) @@ -501,12 +504,13 @@ class UOp(MathTrait, metaclass=UOpMetaClass): buffer_num = itertools.count(0) @staticmethod - def new_buffer(device:str, size:int, dtype:DType) -> UOp: return UOp(Ops.BUFFER, dtype.ptr(), (), (next(UOp.buffer_num), device, size)) + def new_buffer(device:str, size:int, dtype:DType) -> UOp: + return UOp(Ops.BUFFER, dtype.ptr(), (UOp(Ops.DEVICE, arg=device),), (next(UOp.buffer_num), size)) @property def device(self) -> str: return unwrap(self._device) @functools.cached_property def _device(self) -> Optional[str]: - if self.op is Ops.BUFFER: return self.arg[1] + if self.op is Ops.DEVICE: return self.arg # TODO: why does this fail? #if self.op is Ops.COPY: return self.arg[0] return dsrcs[0]._device if len(dsrcs:=[x for x in self.src if x._device is not None]) != 0 else None diff --git a/tinygrad/viz/serve.py b/tinygrad/viz/serve.py index 62c64d38c1..5774bb1e67 100755 --- a/tinygrad/viz/serve.py +++ b/tinygrad/viz/serve.py @@ -12,8 +12,9 @@ from tinygrad.device import ProfileEvent, ProfileDeviceEvent, ProfileRangeEvent, uops_colors = {Ops.LOAD: "#ffc0c0", Ops.PRELOAD: "#ffc0c0", Ops.STORE: "#87CEEB", Ops.CONST: "#e0e0e0", Ops.VCONST: "#e0e0e0", Ops.DEFINE_GLOBAL: "#ffe0b0", Ops.DEFINE_LOCAL: "#ffe0d0", Ops.DEFINE_ACC: "#f0ffe0", Ops.REDUCE_AXIS: "#FF6B6B", Ops.RANGE: "#c8a0e0", Ops.ASSIGN: "#e0ffc0", Ops.BARRIER: "#ff8080", Ops.IF: "#c8b0c0", Ops.SPECIAL: "#c0c0ff", - Ops.INDEX: "#e8ffa0", Ops.WMMA: "#efefc0", Ops.VIEW: "#C8F9D4", **{x:"#ffffc0" for x in GroupOp.ALU}, - Ops.BLOCK: "#C4A484", Ops.BLOCKEND: "#C4A4A4", Ops.BUFFER: "#B0BDFF",} + Ops.INDEX: "#e8ffa0", Ops.WMMA: "#efefc0", Ops.VIEW: "#C8F9D4", + **{x:"#D8F9E4" for x in GroupOp.Movement}, **{x:"#ffffc0" for x in GroupOp.ALU}, Ops.THREEFRY:"#ffff80", + Ops.BLOCK: "#C4A484", Ops.BLOCKEND: "#C4A4A4", Ops.BUFFER: "#B0BDFF", Ops.COPY: "#a040a0"} # ** API spec @@ -61,13 +62,17 @@ def get_metadata(keys:List[Any], contexts:List[List[TrackedGraphRewrite]]) -> Li def uop_to_json(x:UOp) -> Dict[int, Tuple[str, str, List[int], str, str]]: assert isinstance(x, UOp) graph: Dict[int, Tuple[str, str, List[int], str, str]] = {} + excluded = set() for u in x.toposort: - if u.op is Ops.CONST: continue + if u.op in {Ops.CONST, Ops.DEVICE}: + excluded.add(u) + continue argst = ("\n".join([f"{v.shape} / {v.strides}"+(f" / {v.offset}" if v.offset else "") for v in u.arg.views])) if u.op is Ops.VIEW else str(u.arg) label = f"{str(u.op).split('.')[1]}{(' '+word_wrap(argst.replace(':', ''))) if u.arg is not None else ''}\n{str(u.dtype)}" for idx,x in enumerate(u.src): if x.op is Ops.CONST: label += f"\nCONST{idx} {x.arg:g}" - graph[id(u)] = (label, str(u.dtype), [id(x) for x in u.src if x.op is not Ops.CONST], str(u.arg), uops_colors.get(u.op, "#ffffff")) + if x.op is Ops.DEVICE: label += f"\nDEVICE{idx} {x.arg}" + graph[id(u)] = (label, str(u.dtype), [id(x) for x in u.src if x not in excluded], str(u.arg), uops_colors.get(u.op, "#ffffff")) return graph def _replace_uop(base:UOp, replaces:Dict[UOp, UOp]) -> UOp: if (found:=replaces.get(base)) is not None: return found