opencl perf test
ADD
test/test_llops.py
+#!/usr/bin/env python3
+import time
+import unittest
+from tqdm import trange
+import numpy as np
+from tinygrad.llops.opencl import GPUBuffer, sync, unary_op, binary_op, reduce_op
+
+def timeit(fxn, its=1000):
+ fxn()
+ st = time.monotonic()
+ for _ in trange(its):
+ fxn()
+ return its/(time.monotonic() - st)
+
+class TestBenchmarkCL(unittest.TestCase):
+ def test_benchmark_unary_nosync(self):
+ shape = (1024,1024)
+ buf = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ def fxn():
+ unary_op('1.01*a', buf, buf)
+ sync()
+ its_sec = timeit(fxn, 100000)
+ print(f"unary op (no sync) {its_sec:.2f} its/sec")
+ self.assertGreater(its_sec, 10000)
+
+ def test_benchmark_unary(self):
+ shape = (1024,1024)
+ buf = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ def fxn():
+ unary_op('1.01*a', buf, buf)
+ sync()
+ its_sec = timeit(fxn, 1000)
+ print(f"unary op {its_sec:.2f} its/sec")
+ self.assertGreater(its_sec, 1000)
+
+ def test_benchmark_binary(self):
+ shape = (1024,1024)
+ buf_a = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ buf_b = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ def fxn():
+ binary_op('a+b', buf_a, buf_b, buf_a)
+ sync()
+ its_sec = timeit(fxn, 1000)
+ print(f"binary op {its_sec:.2f} its/sec")
+ self.assertGreater(its_sec, 1000)
+
+ def test_benchmark_reduce(self):
+ shape = (1024,1024)
+ buf = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ buf_out = GPUBuffer((1024,1))
+ def fxn():
+ reduce_op('out += a', buf, buf_out)
+ sync()
+ its_sec = timeit(fxn, 100)
+ print(f"reduce op {its_sec:.2f} its/sec")
+ self.assertGreater(its_sec, 500)
+
+ def test_benchmark_reduce_full(self):
+ shape = (1024,1024)
+ buf = GPUBuffer(shape, hostbuf=np.ones(shape, dtype=np.float32))
+ buf_out = GPUBuffer((1,1))
+ def fxn():
+ reduce_op('out += a', buf, buf_out)
+ sync()
+ its_sec = timeit(fxn, 10)
+ print(f"reduce op full {its_sec:.2f} its/sec")
+ # this is terrible performance. it's a single kernel doing it all
+ #self.assertGreater(its_sec, 500)
+
+if __name__ == '__main__':
+ unittest.main()

MODIFY
tinygrad/llops/opencl.py
tinygrad/llops/opencl.py
@@ -4,21 +4,19 @@ import numpy as np
import pyopencl as cl
from tinygrad.helpers import binary_broadcast
-i32 = np.int32
-
cl_ctx, cl_queue = None, None
def require_init_gpu():
global cl_ctx, cl_queue
if cl_ctx is None:
devices = cl.get_platforms()[0].get_devices(device_type=cl.device_type.GPU)
- if len(devices) == 0:
+ if len(devices) == 0: # settle for CPU
devices = cl.get_platforms()[0].get_devices(device_type=cl.device_type.CPU)
cl_ctx = cl.Context(devices=devices)
- # this is an in-order command queue
- cl_queue = cl.CommandQueue(cl_ctx)
+ cl_queue = cl.CommandQueue(cl_ctx) # this is an in-order command queue
-def roundup(x, n=4):
- return (x+(n-1))//n * n
+i32 = np.int32
+def roundup(x, n=4): return (x+(n-1))//n * n
+def sync(): cl_queue.finish()
class GPUBuffer:
def __init__(self, shape, hostbuf=None):
@@ -37,7 +35,7 @@ class GPUBuffer:
def toCPU(self):
data = np.empty(self.shape, dtype=np.float32)
- cl_queue.finish()
+ sync()
cl.enqueue_copy(cl_queue, data, self.cl, is_blocking=True)
return data

opencl perf test