PyCUDAをいじってみる
とりあえず
サンプルコードをいじってみる。
import pycuda.autoinit import pycuda.driver as drv import numpy import time from pycuda.compiler import SourceModule mod = SourceModule(""" __global__ void square(float* p) { const int i = blockDim.x*blockIdx.x + threadIdx.x; p[i] *= p[i]; } """) square = mod.get_function("square") size = 4096 threads = 512 assert threads <= 512 and size % threads == 0 lst = [i for i in xrange(size)] p = numpy.array(lst, dtype=numpy.float32) # cputime s = time.time() p**2 e = time.time() cputime= e - s # gputime s = time.time() square(drv.InOut(p), block=(threads,1,1), grid=(size/threads,1)) e = time.time() gputime= e - s print "%.10f %.10f" % (cputime, gputime) print "win", ["cpu", "gpu"][cputime > gputime]
実行結果
$ python x.py 0.0000278950 0.0003490448 win cpu
C++のテンプレートを試してみる
C++のテンプレートは今のところ使えない?
import pycuda.autoinit import pycuda.driver as drv import numpy from pycuda.compiler import SourceModule mod = SourceModule(""" template<class Type> __global__ void square(Type* p) { const int i = blockDim.x*blockIdx.x + threadIdx.x; p[i] *= p[i]; } """, # デフォルトではソースコードをextern "C"で囲うため # error: this declaration may not have extern "C" linkage # などとエラーが出力されるので以下を指定 no_extern_c=True,) square = mod.get_function("square") size = 256 p = numpy.array([i for i in xrange(size)], dtype=numpy.float32) square(drv.InOut(p), block=(size,1,1))
実行結果
$ python test.py Traceback (most recent call last): File "test.py", line 17, in <module> square = mod.get_function("square") File "/usr/local/lib/python2.6/dist-packages/pycuda-0.93-py2.6-linux-x86_64.egg/pycuda/compiler.py", line 208, in get_function func = self.module.get_function(name) pycuda._driver.LogicError: cuModuleGetFunction failed: not found
2つのバイト列の平均を取る
これでwaveファイルの合成を高速化できたりしないかななどと考えながら。
import pycuda.autoinit import pycuda.driver as drv import numpy import time from pycuda.compiler import SourceModule mod = SourceModule(""" __global__ void bytesadd(unsigned char* dst, unsigned char* p, unsigned char* q) { const int i = blockDim.x*blockIdx.x + threadIdx.x; dst[i] = (unsigned char)((short)p[i] + q[i]) / 2; } """) bytesadd = mod.get_function("bytesadd") def main(): threads = 512 for i in range(2**14, 2**22, 8192): size = i if size/ threads >= 65536: break lst = [j for j in xrange(size)] p = numpy.array(lst, dtype=numpy.uint8) q = numpy.array(lst, dtype=numpy.uint8) dst = numpy.zeros(size) # cputime s = time.time() dst = (p+q)/2 e = time.time() cputime = e - s # gputime s = time.time() bytesadd(drv.Out(dst), drv.In(p), drv.In(q), block=(threads,1,1), grid=(size/threads,1)) e = time.time() gputime = e - s print ",".join(map(str,[size, gputime, cputime])) main()
実行結果
PyCUDAのドキュメントにはテンプレートエンジンを使ってループを直接アンロールしたり、組み込み変数を即値としてコードに埋め込むメタプログラミングなどが紹介されていて面白い。
http://documen.tician.de/pycuda/metaprog.html