Stream管理

在AscendCL中,Stream是一个任务队列,应用程序通过Stream来管理任务的并行,一个Stream内部的任务保序执行,即Stream根据发送过来的任务依次执行;不同Stream中的任务并行执行。一个默认Context下会挂一个默认Stream,如果不显式创建Stream,可使用默认Stream。默认Stream作为接口入参时,直接传NULL。

AscendCL提供以下几种Stream管理机制,其中,多Stream场景下的同步等待流程请参见多Stream时的同步等待流程

单线程单Stream

调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。

#include "acl/acl.h"
// ......
// 显式创建一个Stream
aclrtStream stream;
aclrtCreateStream(&stream);

// 调用触发任务的接口,传入stream参数
aclrtMemcpyAsync(dstPtr, dstSize, srcPtr, srcSize, ACL_MEMCPY_HOST_TO_DEVICE, stream);
// 调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成。
aclrtSynchronizeStream(stream);

// Stream使用结束后,显式销毁Stream
aclrtDestroyStream(stream);
// ......

单线程多Stream

调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。

#include "acl/acl.h"
// ......
int32_t deviceId = 0 ;
uint32_t modelId1 = 0;
uint32_t modelId2 = 1;
aclrtContext context;
aclrtStream stream1;
aclrtStream stream2;

// 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context;
// 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context
 aclrtCreateContext(&context, deviceId);

 aclrtCreateStream(&stream1);
// 调用触发任务的接口,例如异步模型推理,任务下发在stream1
aclmdlDataset *input1;
aclmdlDataset *output1;
aclmdlExecuteAsync(modelId1, input1, output1, stream1);

aclrtCreateStream(&stream2);
// 调用触发任务的接口,例如异步模型推理, 任务下发在stream2
aclmdlDataset *input2;
aclmdlDataset *output2;
aclmdlExecuteAsync(modelId2, input1, output2, stream2);

// 流同步
aclrtSynchronizeStream(stream1);
aclrtSynchronizeStream(stream2);

// 释放资源
aclrtDestroyStream(stream1);
aclrtDestroyStream(stream2);
aclrtDestroyContext(context);
// ....

多线程多Stream

调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。

#include "acl/acl.h"
// ......
void runThread(aclrtStream stream) {
    int32_t deviceId =0 ;
    aclrtContext context;

    // 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context;
    // 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context
    aclrtCreateContext(&context, deviceId);
    aclrtCreateStream(&stream);

    // 调用触发任务的接口
    // ....

    // 释放资源
    aclrtDestroyStream(stream);
    aclrtDestroyContext(context);
   
}

aclrtStream stream1;
aclrtStream stream2;
// 创建2个线程,每个线程对应一个Stream
std::thread t1(runThread, stream1);
std::thread t2(runThread, stream2);
// 显式调用join函数确保结束线程
t1.join();
t2.join();

多Stream时的同步等待流程

开发应用时,如果涉及多Stream之间的任务等待,则应用程序中必须包含相关的代码逻辑,关于该场景的接口调用流程,请依次参见AscendCL接口调用流程以及本节中的说明。

图1 同步等待流程_多Stream场景

多Stream之间任务的同步等待可以利用Event实现,调用aclrtStreamWaitEvent接口阻塞指定Stream的运行,直到指定的Event完成。需在调用aclrtStreamWaitEvent接口前,先调用aclrtRecordEvent接口。调用示例请参见Stream间任务的同步等待示例代码

模型加载与执行的流程请参见基础推理应用

算子加载与执行的流程请参见单算子调用