我阅读了Cupy文档中关于如何一起使用Cupy和numba以及如何使用cuda来加速代码的示例。 https://docs-cupy.chainer.org/en/stable/reference/interoperability.html
我编写了一个类似的代码来测试它:
import cupy
from numba import cuda
import numpy as np
import time
@cuda.jit('void(float32[:], float32[:], float32[:])')
def add(x, y, out):
start = cuda.grid(1)
stride = cuda.gridsize(1)
for i in range(start, x.shape[0], stride):
out[i] = x[i] + y[i]
a = cupy.arange(10000000)
b = a * 2
out = cupy.zeros_like(a)
print("add function time consuming:")
s = time.time()
add(a, b, out)
e = time.time()
print(e-s)
s = time.time()
print("out[2]:")
print(out[2])
e = time.time()
print("the time of transfering out[2] out of GPU:")
print(e-s)
s = time.time()
new_OUT = a + b
print("new out[2] which only use cupy:")
print(new_OUT[2])
e = time.time()
print("the total time of running cupy addition and transfering new out[2] out of GPU:")
print(e-s)
输出为:
add function time consuming:
0.0019025802612304688
out[2]:
6
the time of transfering out[2] out of GPU:
1.5608515739440918
new out[2] which only use cupy:
6
the total time of running cupy addition and transfering new out[2] out of GPU:
0.002993345260620117
在第一个案例中,out[2]的调用怎么会如此缓慢
我正在写一些函数,需要处理一些cupy数组和矩阵。这些函数工作得很好,但是在运行这些函数之后,当我需要做一些修改时,甚至调用像out.shape
这样的函数都非常慢(我的矩阵和数组非常大)
我不确定这里发生了什么,因为cupy也使用cuda,所以当我调用a + b
时,它应该在GPU上运行,但当我调用out[2]
检查out[2]的值时,几乎没有时间。但第一种情况下的消费量超高
要理解代码输出,至少需要注意两件事:
在CUDA中,内核启动通常配置为以指示网格配置(块数、每个块的线程数)。numba CUDA内核启动通常会在内核参数之前的方括号中显示网格配置:
在numba CUDA中,语法上允许省略方括号和网格配置,其隐含含义为
[1,1]
(一个块,由一个线程组成)的网格配置。您的内核使用或多或少任意的网格配置,因为它使用了grid-stride loop。然而,这并不意味着网格配置无关紧要。这对性能很重要。网格配置[1,1]
将带来糟糕的性能,在性能重要的CUDA内核启动中不应使用。因此,我们可以通过更改内核调用来纠正这一点,例如:它将启动一个由1024个块组成的网格,每个块有256个线程
在CUDA中,内核启动是异步的。这意味着启动内核的主机代码将启动启动,但不会等待内核完成。这同样适用于numba CUDA内核的启动。因此,内核启动本身的计时测量通常会令人困惑。出于计时目的,可以通过强制CPU线程在计时区域内等待直到内核完成来调整。在numba CUDA,我们可以通过以下方式实现:
相关问题 更多 >
编程相关推荐