---
title: 如何高效处理Ascend C非对齐数据？优化技巧全解析-官方技术文章-昇腾社区
description: 本文介绍如何高效处理Ascend C非对齐数据。
keywords: Ascend,如何高效处理,非对齐数据,优化技巧全解,官方技术文章,昇腾社区,引言,数据非对齐的典型场景
url: https://www.hiascend.com/developer/techArticles/20250627-1?envFlag=1
section: (其他)
---

# 如何高效处理Ascend C非对齐数据？优化技巧全解析-官方技术文章-昇腾社区

URL: https://www.hiascend.com/developer/techArticles/20250627-1?envFlag=1
描述: 本文介绍如何高效处理Ascend C非对齐数据。
关键词: Ascend,如何高效处理,非对齐数据,优化技巧全解,官方技术文章,昇腾社区,引言,数据非对齐的典型场景

官方技术文章 [了解详情](https://www.hiascend.com/zh/developer/techArticles)

如何高效处理Ascend C非对齐数据？优化技巧全解析

如何高效处理Ascend C非对齐数据？优化技巧全解析

昇腾CANNAscend C

发表于: 2025/06/27

## 1 引言

对于Ascend C算子开发者而言，为了更高效地操作变量，通常需要满足相应的数据对齐要求。例如在使用DataCopy接口进行数据传输时，必须确保搬运的数据长度和操作数在UB上的起始地址为32字节对齐；在进行向量计算时，操作数的起始地址也需满足32字节对齐的要求。然而，在大多数场景下，会遇到大量非对齐的数据情况。本文提供了完整的处理方案，帮助开发者更加灵活地应对数据非对齐的情况。

## 2 数据非对齐的典型场景

首先介绍一些非对齐搬运和计算的实例。下文描述中的Global指Global Memory上的tensor，Local指Local Memory上的tensor。

l非对齐搬入

当需要从Global拷贝11个half数值到Local时，为保证搬运的数据长度32字节对齐，使用DataCopy拷贝16个half（32B）数据到Local上，Local[11]~Local[15]被设置成无效数据-1。

l非对齐搬出

当需要从Local拷贝11个half数值到Global时，为保证搬运的数据长度32字节对齐，使用DataCopy拷贝16个half（32B）数据到Global上，Global[11]~Global[15]被设置成无效数据-1。

l矢量计算起始地址非32字节对齐的错误示例

矢量计算时需要保证起始地址32字节对齐，如下的示例中，从Local1[7]，即LocalTensor的第8个数开始计算，起始地址不满足32字节对齐，是错误示例。

## 3 DataCopyPad接口提供非对齐数据搬运功能

目前，对于Atlas A2 训练系列产品、Atlas 800I A2 推理产品、A200I A2 Box 异构组件、Atlas A3 训练系列产品、Atlas A3 推理系列产品以及Atlas 200I/500 A2 推理产品，DataCopyPad接口提供了非对齐数据搬运的功能，开发者可以使用该接口解决非对齐场景下的数据搬运问题。下面介绍该接口的基本用法，关于DataCopyPad接口的详细介绍，请参考：DataCopyPad API参考 [了解详情](https://www.hiascend.com/document/detail/zh/canncommercial/81RC1/apiref/ascendcopapi/atlasascendc_api_07_0265.html)，使用DataCopyPad的完整示例，请参考DataCopyPad样例（工程化算子开发） [了解详情](https://gitee.com/ascend/samples/tree/89e7cb94aedf7a55d6eb54a01902f137b7fb42ab/operator/ascendc/0_introduction/18_unaligned_wholereduces_frameworklaunch)和DataCopyPad样例（kernel直调） [了解详情](https://gitee.com/ascend/samples/tree/89e7cb94aedf7a55d6eb54a01902f137b7fb42ab/operator/ascendc/0_introduction/17_unaligned_reducemin_kernellaunch)。

使用DataCopyPad接口时，主要关注DataCopyExtParams和DataCopyPadExtParams的参数配置，DataCopyExtParams用于控制搬运的数据块大小、步长间隔等信息，DataCopyPadExtParams用于控制Pad补齐的相关信息。

表1-1 DataCopyExtParams结构体参数定义

| 参数名称 | 含义 |
| --- | ---|
| blockCount | 指定该指令包含的连续传输数据块个数。 |
| blockLen | 指定该指令每个连续传输数据块长度，该指令支持非对齐搬运，每个连续传输数据块长度单位为Byte。 |
| srcStride | 源操作数，相邻连续数据块的间隔（前面一个数据块的尾与后面数据块的头的间隔）。 如果源操作数的逻辑位置为VECIN/VECOUT，则单位为dataBlock(32Bytes)。如果源操作数的逻辑位置为GM，则单位为Byte。 |
| dstStride | 目的操作数，相邻连续数据块间的间隔（前面一个数据块的尾与后面数据块的头的间隔）。 如果目的操作数的逻辑位置为VECIN/VECOUT，则单位为dataBlock(32Bytes)，如果目的操作数的逻辑位置为GM，则单位为Byte。 |

表1-2 DataCopyPadExtParams<T>结构体参数定义

| 参数名称 | 含义 |
| --- | ---|
| isPad | 是否需要填充用户自定义的数据，取值范围：true，false。 true：填充padding value。 false：表示用户不需要指定填充值，会默认填充随机值。 |
| leftPadding | 连续搬运数据块左侧需要补充的数据范围，单位为元素个数。 |
| rightPadding | 连续搬运数据块右侧需要补充的数据范围，单位为元素个数。 |
| paddingValue | 左右两侧需要填充的数据值，需要保证在数据占用字节范围内。 |

接下来我们通过Global Memory->Local Memory和Local Memory->Global Memory通路的DataCopyPad接口参数配置示例来进一步了解DataCopyPad接口的使用方法。

对于Global Memory->Local Memory（GM->VECIN/VECOUT）的数据搬运，各参数使用说明如下：

l   当blockLen+leftPadding+rightPadding满足32字节对齐时，isPad为false，左右两侧填充的数据值会默认为随机值；否则为paddingValue。

l当blockLen+leftPadding+rightPadding不满足32字节对齐时，框架会填充一些假数据dummy，保证填充后的数据（左右填充的数据+blockLen+假数据）为32字节对齐。若leftPadding、rightPadding都为0：dummy会默认填充待搬运数据块的第一个元素值；若leftPadding/rightPadding不为0：isPad为false，左右两侧填充的数据值和dummy值均为随机值；否则为paddingValue。

配置示例1：

l   blockLen为64，每个连续传输数据块包含64Bytes；srcStride为1，因为源操作数的逻辑位置为GM，srcStride的单位为Byte，也就是说源操作数相邻数据块之间间隔1Byte；dstStride为1，因为目的操作数的逻辑位置为VECIN/VECOUT，dstStride的单位为dataBlock(32Bytes)，也就是说目的操作数相邻数据块之间间隔1个dataBlock。

l   blockLen+leftPadding+rightPadding满足32字节对齐，isPad为false，左右两侧填充的数据值会默认为随机值；否则为paddingValue。此处示例中，leftPadding、rightPadding均为0，则不填充。

lblockLen+leftPadding+rightPadding不满足32字节对齐时，框架会填充一些假数据dummy，保证填充后的数据（左右填充的数据+blockLen+假数据）为32字节对齐。leftPadding/rightPadding不为0：若isPad为false，左右两侧填充的数据值和dummy值均为随机值；否则为paddingValue。

l   配置示例2：

−           blockLen为47，每个连续传输数据块包含47Bytes；srcStride为1，表示源操作数相邻数据块之间间隔1Byte；dstStride为1，表示目的操作数相邻数据块之间间隔1个dataBlock。

−           blockLen+leftPadding+rightPadding不满足32字节对齐，leftPadding、rightPadding均为0：dummy会默认填充待搬运数据块的第一个元素值。

−blockLen+leftPadding+rightPadding不满足32字节对齐，leftPadding/rightPadding不为0：若isPad为false，左右两侧填充的数据值和dummy值均为随机值；否则为paddingValue。

对于Local Memory->Global Memory（VECIN/VECOUT->GM）的数据搬运，不需要开发者自行填充数据，所以无需关注DataCopyPadExtParams，仅需要关注DataCopyExtParams。

当每个连续传输数据块长度blockLen不满足32字节对齐，由于UB要求32字节对齐，框架在搬出时会自动补充一些假数据来保证对齐，但在当搬到GM时会自动将填充的假数据丢弃掉。

下图呈现了该场景下需要传入的DataCopyParams示例和假数据补齐的原理。blockLen为47，每个连续传输数据块包含47Bytes，不满足32字节对齐；srcStride为1，表示源操作数相邻数据块之间间隔1个dataBlock；dstStride为1，表示目的操作数相邻数据块之间间隔1Byte。框架在搬出时会自动补充17Bytes的假数据来保证对齐，搬到GM时再自动将填充的假数据丢弃掉。

## 4 不支持DataCopyPad接口的产品，如何处理非对齐数据

然而，某些型号（如Atlas 推理系列产品和Atlas 训练系列产品 ），目前仍不支持DataCopyPad接口，需要参考如下方案处理。

由于搬入时搬运的数据长度必须保证32字节对齐。数据长度非对齐的情况下，从Global逐行搬运Tensor数据到Local中，Local中每行都存在冗余数据。

搬入后，进行矢量计算时对冗余数据的处理方式有以下几种：

l   冗余数据参与计算。一般用于elewise计算场景。

l   通过mask参数掩掉冗余数据。一般用于轴归约计算等场景。

l   通过Duplicate逐行清零。计算前，针对每一行数据，调用基础API Duplicate对冗余数据位置填充0值。

l   通过Pad一次性清零。计算前，针对多行数据，可以采用高阶API Pad接口对冗余数据一次性清零。

由于搬出时搬运的数据长度和操作数的起始地址（UB上）必须保证32字节对齐，搬出时可以选择去除冗余数据或者带着冗余数据搬出的方式。

l   使用UnPad接口去除冗余数据后搬出。待搬出的有效数据总长度满足32字节对齐时，可使用高阶API UnPad接口去除冗余数据并完整搬出。

l   使用GatherMask收集有效数据后搬出。待搬出的有效数据总长度大于等于32字节时，可使用GatherMask重新收集有效数据，保证搬出的有效数据起始地址和数据长度32字节对齐。

l   带冗余数据搬出。注意多核处理时开启原子加（使用SetAtomicAdd接口），防止数据踩踏。

下面分别对上述几种处理方案做详细说明，相关代码样例请参考样例介绍 [了解详情](https://www.hiascend.com/document/detail/zh/canncommercial/81RC1/developmentguide/opdevg/Ascendcopdevg/atlas_ascendc_10_0034.html#ZH-CN_TOPIC_0000002228885300__section6525927155019)。

l冗余数据参与计算

如下图所示，对前11个half数据进行Abs计算，冗余数据可以参与计算，不影响最终结果。步骤为：

a.使用DataCopy从GLobal搬运16个half数据到Local1中，包含冗余数据-11~-15；

b.直接使用Abs做整块计算，不用计算尾块大小，冗余数据参与计算。

l使用mask掩掉冗余数据

如下图所示，假设输入数据的shape为16 * 4，将输入数据搬入到UB后每行数据前4个half数据为有效数据，其余为冗余数据。为只对前4个half数据进行ReduceMin计算，可以通过设置mask参数的方法掩掉冗余数据。针对每行数据的处理步骤为：

a.使用DataCopy从Global搬运16个half数据到Local1中；

b.对归约计算的目的操作数Local2清零，如使用Duplicate等；

c.进行归约操作，将ReduceMin的mask模式设置为前4个数据有效，从而掩掉冗余数据。

l通过Duplicate逐行清零。

如下图所示，对于搬入后的非对齐数据，逐行进行Duplicate清零处理，步骤为：

a.使用DataCopy从Global搬运16个half数据到Local中；

b.使用基础API Duplicate，按照如下方式设置mask值，控制仅后5个元素位置有效，将冗余数据填充为0。

```
uint64_t mask0 = ((uint64_t)1 << 16) - ((uint64_t)1 << 11);  
uint64_t mask[2] = {mask0, 0};

```

l通过Pad一次性清零。

如下图所示，假设输入数据的shape为16 * 6，搬入Local后大小为16 * 16，每行都包含冗余数据，逐行清零性能较差，可以使用Pad一次性清零，步骤为：

a.将16 * 6的数据从GM上逐行搬入UB后，每行有6个有效数据；

b.使用Pad接口将冗余数据位置填充为0。（对应Pad接口使用场景为：tensor的width已32B对齐，但是有部分冗余数据）。

l使用UnPad接口去除冗余数据后搬出。

如下图所示，Local内存大小为16*16，每行中只有前6个数为有效数据， 要搬出的有效数据16 * 6满足32B对齐，可以使用UnPad接口去除冗余数据并完整搬出。步骤如下：

a.使用UnPad高阶API去除冗余值；

b.使用DataCopy搬运出连续的16 * 6个half数据到Global中。

l使用GatherMask收集有效数据后搬出。

如下图所示，为搬出19个half数据到Global中，有16-18这3个数据的搬运无法满足对齐要求，使用GatherMask对有效数据进行重新收集，收集3-18这16个数据并搬出。步骤如下：

a.完整拷贝前16个half（32B）数据到Global中；

b.使用GatherMask接口，将Local1[3]~[18]的数Gather到Local2中，Local2从对齐地址开始；

c.从Local2中搬运Gather的数据（32B整数倍）到Global中。

l带冗余数据搬出

如下图所示，有4个核参与计算，每个核拷贝出4个数，每个核上拷贝的数据长度不满足32字节对齐，采用将冗余数据一起搬出的方式，步骤如下：

a.将目标Global完整清零，可以通过在host清零或者在kernel侧用UB覆盖的方式处理；

b.将本核内的Local数据，除了要搬出的4个有效数据，其余冗余部分清零（使用Duplicate接口）；

c.使用原子累加的方式拷贝到Global，原子累加结合冗余数据清零，确保不会出现数据踩踏。

## 5 更多学习资源

欢迎访问昇腾社区Ascend C信息专区，获取Ascend C更多学习资源：https://www.hiascend.com/ascend-c [了解详情](https://www.hiascend.com/ascend-c)
