簡體   English   中英

為什么同時使用 numba.cuda 和 CuPy 從 GPU 傳輸數據這么慢?

[英]Why it is so slow to transfer data from GPU when use numba.cuda and CuPy at the same time?

我從 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)

output 是:

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 arrays 和矩陣的函數。 這些函數工作正常,但是在運行這些函數后,當我需要進行一些修改時,甚至調用類似out.shape的東西都非常慢(我的矩陣和 arrays 非常大)。

我不確定這里發生了什么,因為 cupy 也使用 cuda,所以當我調用a + b時,它應該在 GPU 上運行,但是當我調用out[2]來檢查 out[2] 的值時幾乎沒有時間消耗. 但是第一種情況的消耗是超高的。

要了解您的代碼 output,至少需要注意兩件事:

  1. 在 CUDA 中,kernel 啟動通常配置為指示網格配置(塊數,每個塊的線程數)。 一個 numba CUDA kernel 啟動通常會在 kernel ZDBC16FB4CAA5BDA98EDAD77 之前的方括號中顯示網格配置:

     kernel_name[grid_configuration](kernel_arguments)

    在 numba CUDA 中,在語法上允許省略方括號和網格配置,這具有[1,1]的網格配置的隱含含義(一個塊,由一個線程組成)。 您的 kernel 使用或多或少的任意網格配置,因為它采用了網格步長循環 然而,這並不意味着網格配置無關緊要。 它對性能很重要。 [1,1]的網格配置將提供令人沮喪的性能,並且永遠不應在性能很重要的 CUDA kernel 啟動中使用。 因此,我們可以通過更改您的 kernel 調用來糾正此問題,例如:

     add[1024,256](a, b, out)

    這將啟動一個由 1024 個塊組成的網格,每個塊有 256 個線程。

  2. 在 CUDA、kernel 啟動是異步的。 這意味着啟動 kernel 的主機代碼將啟動啟動,但不會等待 kernel 完成 這同樣適用於 numba CUDA kernel 發射。 因此,kernel 發射本身的時序測量通常會令人困惑。 出於計時目的,這可以通過強制 CPU 線程在計時區域內等待來調整,直到 kernel 完成。 在 numba CUDA 中,我們可以通過以下方式完成此操作:

     cuda.synchronize()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM