Ascend C的编程模型

简介: Ascend C采用SPMD编程模型,实现多核并行计算。通过将数据切分为多个分片,分配给不同的计算核心(或称为block)并行处理,每个核心根据自身的block_idx执行相同代码但处理不同的数据分片,从而提高计算效率。此模型支持高效的数据并行处理,适用于大规模数据计算任务。

1 并发执行

Ascend C和cudnn相似,都是一种多核心编程的范式。想要了解Ascend C,必须得先掌握这种“多核”是怎么实现得。

多核执行,说白了就是使用CPU/GPU/Ascend的物理多核并发去执行一段流程,一般情况下,可以通过以下几种方式实现:

  1. 多线程并行处理:使用多线程可以将循环中的任务分配给多个线程同时执行,提高代码的执行效率。可以使用线程池来管理线程的创建和销毁,避免频繁创建和销毁线程的开销。
  2. 多进程并行处理:使用多进程可以将循环中的任务分配给多个进程同时执行,充分利用多核处理器的优势。可以使用multiprocessing模块来创建和管理多个进程,并通过进程间通信来实现数据的共享和同步。
  3. 向量化操作:对于一些数值计算密集型的任务,可以使用向量化操作来提高代码的执行效率。向量化操作利用了现代处理器的SIMD(Single Instruction, Multiple Data)指令集,可以同时对多个数据进行相同的操作,减少了循环的开销。在Python中,可以使用NumPy库来进行向量化操作。
  4. 并行计算框架:使用并行计算框架可以将循环中的任务分布到多个计算节点上并行执行,提高代码的执行速度。常见的并行计算框架包括Apache Hadoop、Apache Spark等。这些框架提供了分布式计算的能力,可以将任务分布到多台计算机上进行并行计算。
  5. 编译器指令OpenMP:是一种支持多平台共享内存并行编程的API,它提供了一组编译器指令和库函数,使得开发人员能够方便地将现有代码并行化,以利用多个核心或处理器进行并行执行。OpenMP支持多种编程语言和操作系统,具有易用性、可移植性和灵活性等特点。通过使用OpenMP的并行化指令,如#pragma omp parallel和#pragma omp for,可以轻松地将代码块或循环并行化,并可以通过设置线程数量来控制并行执行的程度。OpenMP还提供了特定的编译器指令来处理并发任务和循环并行化。例如,#pragma omp parallel用于创建一组线程来并行执行指定的代码块,而#pragma omp for用于并行化循环。这些指令允许开发人员精细控制并行化的程度,包括设置线程数量和使用特定的子句来指定条件并行、数据处理等。

2 Ascend C编程模型

Ascend C算子编程是SPMD(Single-Program Multiple-Data)编程。假设,从输入数据到输出数据需要经过3个阶段任务的处理(T1、T2、T3)。如下图所示,SPMD会启动一组进程,并行处理待处理的数据。对待处理数据切分,把切分后数据分片分发给不同进程处理,每个进程对自己的数据分片进行3个任务的处理。
image.png

具体到Ascend C编程模型中的应用,是将需要处理的数据被拆分并同时在多个计算核心(类比于上文介绍中的多个进程)上运行,从而获取更高的性能。多个AI Core共享相同的指令代码,每个核上的运行实例唯一的区别是block_idx不同,每个核通过不同的block_idx来识别自己的身份。block的概念类似于上文中进程的概念,block_idx就是标识进程唯一性的进程ID。并行计算过程的示意图如下图所示。
image.png

下面的代码片段取自于Ascend CAdd算子的实现代码,算子被调用时,所有的计算核心都执行相同的实现代码,入口函数的入参也是相同的。每个核上处理的数据地址需要在起始地址上增加GetBlockIdx()*BLOCK_LENGTH(每个block处理的数据长度)的偏移来获取。这样也就实现了多核并行计算的数据切分。

class KernelAdd {
   
public:
    __aicore__ inline KernelAdd() {
   }
    __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z)
    {
   
        // get start index for current core, core parallel
        xGm.SetGlobalBuffer((__gm__ half*)x + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);
        yGm.SetGlobalBuffer((__gm__ half*)y + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);
        zGm.SetGlobalBuffer((__gm__ half*)z + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);
        // pipe alloc memory to queue, the unit is Bytes
        pipe.InitBuffer(inQueueX, BUFFER_NUM, TILE_LENGTH * sizeof(half));
        pipe.InitBuffer(inQueueY, BUFFER_NUM, TILE_LENGTH * sizeof(half));
        pipe.InitBuffer(outQueueZ, BUFFER_NUM, TILE_LENGTH * sizeof(half));
    }
    ...
}

// 实现核函数
extern "C" __global__ __aicore__ void add_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z)
{
   
    // 初始化算子类,算子类提供算子初始化和核心处理等方法
    KernelAdd op;
    // 初始化函数,获取该核函数需要处理的输入输出地址,同时完成必要的内存初始化工作
    op.Init(x, y, z);
    // 核心处理函数,完成算子的数据搬运与计算等核心逻辑
    op.Process();
}

其实,也就是说,SPMD的的数据是通过偏移进行操作的。这里也产生一个疑问,如果数据的地址不是连续的,那该如何操作?是在运行之前进行地址转连续吗?

该文部分内容来自Ascend官网:
SPMD模型-编程模型-Ascend C算子开发-算子开发-CANN商用版8.0.RC2.2开发文档-昇腾社区

相关文章
|
传感器 人工智能 物联网
健康监测设备的技术革命:AI+物联网如何让你随时掌握健康数据?
健康监测设备的技术革命:AI+物联网如何让你随时掌握健康数据?
1605 19
|
SQL 前端开发 JavaScript
防止XSS跨站脚本攻击:Java过滤器
防止XSS跨站脚本攻击:Java过滤器
防止XSS跨站脚本攻击:Java过滤器
|
Web App开发 存储 缓存
RDMA优化整理(一)
简要的介绍了下RDMA的背景,并给出了一些RDMA编程优化技巧
5303 1
RDMA优化整理(一)
|
10月前
|
存储 监控 NoSQL
140_异步推理:队列管理框架 - 使用Celery处理高并发请求的独特设计
在大型语言模型(LLM)部署的实际场景中,推理服务的并发处理能力直接影响用户体验和系统稳定性。随着LLM应用的普及,如何高效处理大量并发请求成为部署优化中的关键挑战。传统的同步请求处理方式在面对突发流量时容易导致系统过载,响应延迟增加,甚至服务崩溃。异步推理通过引入队列管理机制,能够有效缓冲请求峰值,平滑系统负载,提高资源利用率,从而为LLM服务提供更稳定、更高效的并发处理能力。
848 7
|
前端开发 Linux API
【推荐100个unity插件之8】实现多人在线联机游戏——Mirror插件的使用介绍(附项目源码)
【推荐100个unity插件之8】实现多人在线联机游戏——Mirror插件的使用介绍(附项目源码)
6125 0
|
SQL 算法 安全
【MySQL】数据库视图的介绍、作用、创建、查看、删除和修改(附练习题)
文章目录 1 视图的介绍与作用 2 视图的创建 3 视图的修改 4 视图的更新 5 视图的重命名与删除 6 视图的练习 6.1 数据准备 6.2 查询平均分最高的学校名称 写在最后
【MySQL】数据库视图的介绍、作用、创建、查看、删除和修改(附练习题)
|
JavaScript 前端开发 搜索推荐
Nuxt4.0初体验:一个简约、精美、现代化的个人站点导航!
这篇文章介绍了作者使用Nuxt 4.0重构个性化站点导航网站的经历,阐述了Nuxt 4.0的新特性和优势,如更清晰的项目结构、更好的TypeScript体验、更快的CLI和开发速度等,并且分享了重构过程中的体验和项目完成效果。同时,作者还对比了Nuxt.js与Next.js两个框架的优劣,表达了自己对Nuxt.js的偏好。
840 0
Nuxt4.0初体验:一个简约、精美、现代化的个人站点导航!
|
API C语言 开发者
AscendC从入门到精通系列(五)调用基于工程开发AscendC算子
单算子API调用方式是通过C语言API直接调用已编译的自定义算子。首先,需基于AscendC算子工程完成算子的定义与实现,并通过编译脚本部署。编译后,生成的头文件和动态库支持在应用程序中直接调用算子,包括初始化AscendCL、申请资源、数据传输、计算workspace、执行算子、同步等待及资源释放等步骤。编译算子调用程序时,需正确配置CMakeLists.txt,确保头文件和动态库的路径正确。
|
存储 人工智能 算法
【AI系统】计算图的优化策略
本文深入探讨了计算图的优化策略,包括算子替换、数据类型转换、存储优化等,旨在提升模型性能和资源利用效率。特别介绍了Flash Attention算法,通过分块计算和重算策略优化Transformer模型的注意力机制,显著减少了内存访问次数,提升了计算效率。此外,文章还讨论了内存优化技术,如Inplace operation和Memory sharing,进一步减少内存消耗,提高计算性能。
1141 34
【AI系统】计算图的优化策略

热门文章

最新文章