访问 CUDA 功能#
流和事件#
本节讨论 CUDA 流和事件的基本用法。有关 API 参考,请参阅 流和事件。有关它们在 CUDA 编程模型中的作用,请参考 CUDA 编程指南。
CuPy 提供了高级 Python API Stream
和 Event
,分别用于创建流和事件。数据拷贝和核函数启动被排队到 当前流 中,当前流可以通过 get_current_stream()
进行查询,也可以通过设置上下文管理器来更改
>>> import numpy as np
>>>
>>> a_np = np.arange(10)
>>> s = cp.cuda.Stream()
>>> with s:
... a_cp = cp.asarray(a_np) # H2D transfer on stream s
... b_cp = cp.sum(a_cp) # kernel launched on stream s
... assert s == cp.cuda.get_current_stream()
...
>>> # fall back to the previous stream in use (here the default stream)
>>> # when going out of the scope of s
或使用 use()
方法
>>> s = cp.cuda.Stream()
>>> s.use() # any subsequent operations are done on steam s
<Stream ... (device ...)>
>>> b_np = cp.asnumpy(b_cp)
>>> assert s == cp.cuda.get_current_stream()
>>> cp.cuda.Stream.null.use() # fall back to the default (null) stream
<Stream 0 (device -1)>
>>> assert cp.cuda.Stream.null == cp.cuda.get_current_stream()
事件可以手动创建,也可以通过 record()
方法创建。Event
对象可用于计时 GPU 活动(通过 get_elapsed_time()
)或设置流间依赖关系
>>> e1 = cp.cuda.Event()
>>> e1.record()
>>> a_cp = b_cp * a_cp + 8
>>> e2 = cp.cuda.get_current_stream().record()
>>>
>>> # set up a stream order
>>> s2 = cp.cuda.Stream()
>>> s2.wait_event(e2)
>>> with s2:
... # the a_cp is guaranteed updated when this copy (on s2) starts
... a_np = cp.asnumpy(a_cp)
>>>
>>> # timing
>>> e2.synchronize()
>>> t = cp.cuda.get_elapsed_time(e1, e2) # only include the compute time, not the copy time
就像 Device
对象一样,Stream
和 Event
对象也可用于同步。
注意
在 CuPy 中,Stream
对象是按线程、按设备进行管理的。
注意
在 NVIDIA GPU 上,有两个流单例对象 null
和 ptds
,分别称为遗留默认流和每线程默认流。当没有使用用户定义的流时,CuPy 默认使用前者。要更改此行为,请将环境变量 CUPY_CUDA_PER_THREAD_DEFAULT_STREAM
设置为 1,参见 环境变量。这不适用于 AMD GPU。
为了与其他 Python 库中创建的流进行互操作,CuPy 提供了 ExternalStream
API 来包装现有的流指针(以 Python int
形式给出)。详情请参见 互操作性。
CUDA Driver 和 Runtime API#
正在建设中。有关 API 参考,请参阅 Runtime API。