mirror of
https://github.com/tinygrad/tinygrad.git
synced 2026-08-14 12:18:28 +00:00
Compare commits
5
Commits
bt_ei
...
no_decimals
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
206b46687b | ||
|
|
78b2d76e3b | ||
|
|
4f7005f72a | ||
|
|
c2af5c806b | ||
|
|
8d35780e1a |
@@ -1,6 +1,6 @@
|
||||
import unittest
|
||||
from tinygrad import Tensor, nn
|
||||
from tinygrad.helpers import Context, GlobalCounters, CI, CPU_LVP
|
||||
from tinygrad.helpers import Context, GlobalCounters, CI, CPU_LVP, getenv
|
||||
from tinygrad.uop.ops import graph_rewrite, PatternMatcher, UPat, Ops
|
||||
|
||||
class TestRangeifyAssign(unittest.TestCase):
|
||||
@@ -31,13 +31,14 @@ class TestRangeifyEdgeCase(unittest.TestCase):
|
||||
@unittest.skipIf(CPU_LVP, "broken in LVP")
|
||||
class TestPcontig(unittest.TestCase):
|
||||
def test_flash_attention(self):
|
||||
BS, HEADS, SEQLEN, EMB = 4, 2, 16, 8
|
||||
|
||||
# bigger
|
||||
#BS, HEADS, SEQLEN, EMB = 4, 32, 1024, 64
|
||||
|
||||
# llama 8B
|
||||
#BS, HEADS, SEQLEN, EMB = 4, 32, 2048, 128
|
||||
if getenv("BIG") > 1:
|
||||
# llama 8B
|
||||
BS, HEADS, SEQLEN, EMB = 4, 32, 2048, 128
|
||||
elif getenv("BIG") > 0:
|
||||
# bigger
|
||||
BS, HEADS, SEQLEN, EMB = 4, 32, 1024, 64
|
||||
else:
|
||||
BS, HEADS, SEQLEN, EMB = 4, 2, 16, 8
|
||||
|
||||
def fa():
|
||||
Tensor.manual_seed(1337)
|
||||
|
||||
@@ -181,9 +181,9 @@ class ExecItem:
|
||||
header_color = 'magenta' if jit else ('green' if self.prg.first_run else None)
|
||||
ptm = colored(time_to_str(et, w=9), "yellow" if et > 0.01 else None) if et is not None else ""
|
||||
flops, membw, ldsbw = op_est/(et or 1e-20), mem_est/(et or 1e-20), lds_est/(et or 1e-20)
|
||||
flops_str = f"{flops*1e-9:9.2f} GFLOPS" if flops < 1e14 else colored(f"{flops*1e-12:9.2f} TFLOPS", 'green')
|
||||
mem_str = f"{membw*1e-9:6.1f}|{ldsbw*1e-9:<8.1f} GB/s" if membw < 1e13 and ldsbw < 1e15 else \
|
||||
colored(f"{membw*1e-12:6.1f}|{ldsbw*1e-12:<8.1f} TB/s", 'green')
|
||||
flops_str = f"{flops*1e-9:7.0f} GFLOPS" if flops < 1e14 else colored(f"{flops*1e-12:7.0f} TFLOPS", 'green')
|
||||
mem_str = f"{membw*1e-9:4.0f}|{ldsbw*1e-9:<6.0f} GB/s" if membw < 1e13 and ldsbw < 1e15 else \
|
||||
colored(f"{membw*1e-12:4.0f}|{ldsbw*1e-12:<6.0f} TB/s", 'green')
|
||||
print(f"{colored(f'*** {self.prg.device[:7]:7s} {GlobalCounters.kernel_count:4d}', header_color)}"+
|
||||
f" {self.prg.display_name+' '*(44-ansilen(self.prg.display_name))} arg {len(bufs):2d} mem {GlobalCounters.mem_used/1e9:6.2f} GB"+
|
||||
("" if et is None else f" tm {ptm}/{GlobalCounters.time_sum_s*1e3:9.2f}ms ({flops_str} {mem_str})")+
|
||||
|
||||
@@ -28,7 +28,7 @@ class NullAllocator(Allocator['NullDevice']):
|
||||
def _offset(self, buf, offset:int, size:int): pass
|
||||
|
||||
class NullGraph(MultiGraphRunner):
|
||||
def __call__(self, input_rawbuffers, var_vals, wait=False) -> float|None: return 1e-3
|
||||
def __call__(self, input_rawbuffers, var_vals, wait=False) -> float|None: return 1e-1
|
||||
|
||||
class NullDevice(Compiled):
|
||||
def __init__(self, device:str):
|
||||
|
||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
|
||||
from tinygrad.dtype import dtypes, AddrSpace
|
||||
from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, resolve, GroupOp, graph_rewrite, sint, AxisType
|
||||
from tinygrad.uop.symbolic import symbolic, pm_simplify_valid, pm_drop_and_clauses
|
||||
from tinygrad.helpers import argsort, all_same, cpu_profile, TracingKey, PCONTIG
|
||||
from tinygrad.helpers import argsort, all_same, cpu_profile, TracingKey, PCONTIG, colored
|
||||
|
||||
ALWAYS_CONTIGUOUS: set[Ops] = {Ops.CONTIGUOUS, Ops.ASSIGN, Ops.COPY, Ops.BUFFER, Ops.BUFFER_VIEW,
|
||||
Ops.CONST, Ops.BIND, Ops.DEVICE, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_GLOBAL,
|
||||
@@ -61,6 +61,7 @@ def create_bufferize_and_index_based_on_ranges(ctx:IndexingContext, x:UOp):
|
||||
realized_ranges = ctx.realize_map[s]
|
||||
assert isinstance(realized_ranges, list), "realize map must contain range list"
|
||||
closed_ranges = tuple([r for i,r in enumerate(ctx.range_map[s][1]) if i in realized_ranges])
|
||||
# None in the device assigns it a number later
|
||||
opts = BufferizeOpts(device=s.device) if len(ctx.range_map[s][1]) == len(realized_ranges) else BufferizeOpts(None, AddrSpace.LOCAL)
|
||||
new_src = UOp(Ops.BUFFERIZE, s.dtype, src=(new_src,)+closed_ranges, arg=opts, tag=s.tag if opts.addrspace == AddrSpace.GLOBAL else None)
|
||||
if x in ctx.range_map: new_src = new_src.index(*[r for i,r in enumerate(ctx.range_map[x][0]) if i in realized_ranges])
|
||||
@@ -188,15 +189,15 @@ def run_rangeify(tsink:UOp, debug:bool=False) -> tuple[UOp, IndexingContext]:
|
||||
rngs_valids = []
|
||||
for valid_rngs in all_rngs:
|
||||
local_rngs, valids = zip(*[(r.get_idx(), r.get_valid()) for r in valid_rngs])
|
||||
rngs_valids.append((local_rngs, valids, all_same(local_rngs)))
|
||||
rngs_valids.append((local_rngs, valids))
|
||||
|
||||
# TODO: in RANGEIFY > 1 all_all_same isn't required
|
||||
all_all_same = all(same_rngs for _,_,same_rngs in rngs_valids)
|
||||
all_all_same = all(all_same(local_rngs) for local_rngs,_ in rngs_valids)
|
||||
_out_rngs = []
|
||||
_new_rngs = []
|
||||
for i,(local_rngs,valids,same_rngs) in enumerate(rngs_valids):
|
||||
for i,(local_rngs,valids) in enumerate(rngs_valids):
|
||||
# we compare the ranges without their valids
|
||||
if all_all_same or (PCONTIG and same_rngs):
|
||||
if all_all_same or (PCONTIG and all_same(local_rngs)):
|
||||
# the new valid is the OR of all the children valids
|
||||
minimum_valid = functools.reduce(operator.or_, valids, UOp.const(dtypes.bool, False))
|
||||
_out_rngs.append(graph_rewrite(minimum_valid.where(local_rngs[0], UOp.invalid()), symbolic, name="minimum_valid"))
|
||||
@@ -230,8 +231,13 @@ def run_rangeify(tsink:UOp, debug:bool=False) -> tuple[UOp, IndexingContext]:
|
||||
rngs = tuple(rctx.new_range(s, axistype=AxisType.REDUCE) if i in x.arg[1] else r for i,(r,s) in enumerate(zip(rngs, x.src[0].shape)))
|
||||
|
||||
if debug:
|
||||
print("***" if x in rctx.realize_map else " ", len(consumer_map[x]), f"{str(x.op):20s}",
|
||||
UOp.sink().index(*rngs).render(), " -> ", UOp.sink().index(*out_rngs).render())
|
||||
realized_ranges = rctx.realize_map.get(x, None)
|
||||
disp = []
|
||||
for i, (ri, ro) in enumerate(zip([r.render() for r in rngs], [r.render() for r in out_rngs])):
|
||||
rng = f"{ri}" if ri == ro else f"{ri} -> {ro}"
|
||||
if realized_ranges is not None and i in realized_ranges: rng = colored(rng, "yellow")
|
||||
disp.append("["+rng+"]")
|
||||
print("***" if x in rctx.realize_map else " ", len(consumer_map[x]), f"{str(x.op):20s}", ''.join(disp))
|
||||
|
||||
# assign to the range map. rngs are the input ranges, out_rngs are the output ranges, from the x op.
|
||||
rctx.range_map[x] = (rngs, out_rngs)
|
||||
|
||||
@@ -178,8 +178,11 @@ def remove_bufferize(src:UOp, buf:UOp, idx:UOp):
|
||||
# if it makes it here, the bufferize is removed
|
||||
# this is the ranges replaced
|
||||
# NOTE: if buf src is a const, we don't replace it
|
||||
replaces = flatten([(k,v) for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST])
|
||||
return UOp(Ops.SUBSTITUTE, dtype=src.dtype, src=(src, UOp(Ops.NOOP, src=tuple(replaces[0::2])), UOp(Ops.NOOP, src=tuple(replaces[1::2]))))
|
||||
if getenv("REAL_SUBSTITUTE"):
|
||||
return src.substitute({k:v for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST})
|
||||
else:
|
||||
replaces = flatten([(k,v) for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST])
|
||||
return UOp(Ops.SUBSTITUTE, dtype=src.dtype, src=(src, UOp(Ops.NOOP, src=tuple(replaces[0::2])), UOp(Ops.NOOP, src=tuple(replaces[1::2]))))
|
||||
|
||||
def pre_bufferize(b:UOp, x:UOp, copy:UOp):
|
||||
nb = b.replace(src=(b.src[0].contiguous(),)+b.src[1:])
|
||||
|
||||
Reference in New Issue
Block a user