访问 CUDA 功能#

流和事件#

本节讨论 CUDA 流和事件的基本用法。有关 API 参考,请参阅 流和事件。有关它们在 CUDA 编程模型中的作用,请参考 CUDA 编程指南

CuPy 提供了高级 Python API StreamEvent,分别用于创建流和事件。数据拷贝和核函数启动被排队到 当前流 中,当前流可以通过 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 对象一样,StreamEvent 对象也可用于同步。

注意

在 CuPy 中,Stream 对象是按线程、按设备进行管理的。

注意

在 NVIDIA GPU 上,有两个流单例对象 nullptds,分别称为遗留默认流和每线程默认流。当没有使用用户定义的流时,CuPy 默认使用前者。要更改此行为,请将环境变量 CUPY_CUDA_PER_THREAD_DEFAULT_STREAM 设置为 1,参见 环境变量。这不适用于 AMD GPU。

为了与其他 Python 库中创建的流进行互操作,CuPy 提供了 ExternalStream API 来包装现有的流指针(以 Python int 形式给出)。详情请参见 互操作性

CUDA Driver 和 Runtime API#

正在建设中。有关 API 参考,请参阅 Runtime API