虽然GPU加速数学计算,但是将内核移动到GPU以执行高速会有一个固定的开销 .
我正在使用cupy和numba . 我第一次执行使用cupy的GPU版本numpy的函数调用时,它非常慢 . 但第二次它很快 .
我意识到我不明白内核或GPU代码是如何运行到GPU的 . 在操作上我想要更好地理解这一点,以便我可以知道我做的事情何时会由于某些内核传输而意外地创建一个缓慢的步骤 . 所以我需要一些规则或经验法则来理解这个概念 .
例如,如果我将两个存储在GPU上的杯状阵列相乘,我可能会写出C = A * B.
在某些时候,乘法上的过度重载必须在GPU上编码,并且它自动需要也将被循环包裹,将其分解为块和线程 . 所以这个代码可能是一些被传输到GPU的内核 . 我猜测,下次我打电话给C * D时,GPU不再需要被教导意味着什么,所以它会很快 .
但是在某些时候我会想象GPU需要清除旧代码,因此*或者当时没有使用的其他操作可能会从内存中刷新,所以稍后当A * B的调用再次发生时,将会有一个及时惩罚在GPU上重新编译它 .
或者我想象 . 如果我是对的,我怎么知道这些内核何时会停留或消失?
如果我错了,这不是它的工作方式或者还有其他一些缓慢的步骤(我假设数据已经被传输到GPU上的数组)那么这个缓慢的步骤是什么以及如何组织事情以便付出代价它尽量少?
我试图避免编写显式的numba线程管理内核,就像在cuda中一样,但只使用标准的numba @njit,@ vectorize,@ stencil装饰器 . 同样在Cupy中,我想在numpy语法的层面上工作,而不是深入到线程管理中 .
我已经阅读了很多这方面的文档,但它们只是引用了内核的开销,而不是当它们得到报酬以及如何控制它以致我感到困惑时 .
1 回答
我还没有完整的答案 . 但到目前为止,我得到的最大线索来自于阅读当前未记录的函数@ cupy.fuse(),这使得它比支持内核启动成本的@numba.jit文档更清晰 . 我还没有找到与Contexts的联系,但是@talonmies推荐了这个联系 .
见https://gist.github.com/unnonouno/877f314870d1e3a2f3f45d84de78d56c
关键的例子就是这个
@ cupy.fuse()注释掉foo( . )会慢三倍,因为每个“”都涉及内核加载和内核免费 . Fusion将所有添加内容合并到一个内核中,因此启动和免费都是付费的 . 对于典型的2018 GPU,小于100万的matricies,add()速度非常快,以及发布和免费是主导时代 .
我希望我能在@fuse上找到一些文档 . 例如,它是否以@jit的方式展开内部函数 . 我可以通过堆叠@jit和@fuse实现这一目标吗?
然而,当numba支付成本时,我仍然处于黑暗中 .