Skip to content

asc_gather_datablock

产品支持情况

  • Ascend 950PR/Ascend 950DT:支持
  • Atlas A3 训练系列产品/Atlas A3 推理系列产品:不支持
  • Atlas A2 训练系列产品/Atlas A2 推理系列产品:不支持
  • Atlas 200I/500 A2 推理产品:不支持
  • Atlas 推理系列产品AI Core:不支持
  • Atlas 推理系列产品Vector Core:不支持
  • Atlas 训练系列产品:不支持

功能说明

头文件路径为:"c_api/reg_compute/gather/ub_gather.h"

给定源操作数在Unified Buffer(UB)中的基地址和索引,根据索引位置将源操作数按DataBlock收集到目的操作数中。每个DataBlock长度为32B。

其中,index中仅前8个元素有效,每个元素对应一个DataBlock。例如,第一个元素为96(3 * 32),表示选取DataBlock3写入dst中对应的位置。

函数原型

支持掩码控制

C
// 通过引用参数输出结果(占位符形式)
__simd_callee__ inline void asc_gather_datablock(vector_<dst_dtype>& dst,
                                                 __ubuf__ <src_dtype>* src,
                                                 vector_uint32_t index,
                                                 vector_bool mask)

// 通过函数返回值返回结果(占位符形式)
__simd_callee__ inline vector_<dst_dtype> asc_gather_datablock(__ubuf__ <src_dtype>* src,
                                                               vector_uint32_t index,
                                                               vector_bool mask)

表1 支持的数据类型组合

dst类型src类型函数返回值形式
vector_int4x2_tint4b_tvector_int4x2_t
vector_int8_tint8_tvector_int8_t
vector_uint8_tuint8_tvector_uint8_t
vector_fp4x2_e2m1_tfp4x2_e2m1_tvector_fp4x2_e2m1_t
vector_fp4x2_e1m2_tfp4x2_e1m2_tvector_fp4x2_e1m2_t
vector_hifloat8_thifloat8_tvector_hifloat8_t
vector_fp8_e8m0_tfp8_e8m0_tvector_fp8_e8m0_t
vector_fp8_e5m2_tfp8_e5m2_tvector_fp8_e5m2_t
vector_fp8_e4m3fn_tfp8_e4m3fn_tvector_fp8_e4m3fn_t
vector_int16_tint16_tvector_int16_t
vector_uint16_tuint16_tvector_uint16_t
vector_halfhalfvector_half
vector_bfloat16_tbfloat16_tvector_bfloat16_t
vector_int32_tint32_tvector_int32_t
vector_uint32_tuint32_tvector_uint32_t
vector_floatfloatvector_float
vector_int64_tint64_t不支持
vector_uint64_tuint64_t不支持

函数原型典型示例

C
// 通过引用参数输出结果示例:int8_t类型
__simd_callee__ inline void asc_gather_datablock(vector_int8_t& dst,
                                                 __ubuf__ int8_t* src,
                                                 vector_uint32_t index,
                                                 vector_bool mask)

// 通过函数返回值返回结果示例:int8_t类型
__simd_callee__ inline vector_int8_t asc_gather_datablock(__ubuf__ int8_t* src,
                                                          vector_uint32_t index,
                                                          vector_bool mask)

无掩码控制(占位符形式)

C
// 通过引用参数输出结果
__simd_callee__ inline void asc_gather_datablock(vector_<dst_dtype>& dst,
                                                 __ubuf__ <src_dtype>* src,
                                                 vector_uint32_t index)

// 通过函数返回值返回结果
__simd_callee__ inline vector_<dst_dtype> asc_gather_datablock(__ubuf__ <src_dtype>* src,
                                                               vector_uint32_t index)

表2 支持的数据类型组合

dst类型src类型函数返回值形式
vector_int4x2_tint4b_tvector_int4x2_t
vector_int8_tint8_tvector_int8_t
vector_uint8_tuint8_tvector_uint8_t
vector_fp4x2_e2m1_tfp4x2_e2m1_tvector_fp4x2_e2m1_t
vector_fp4x2_e1m2_tfp4x2_e1m2_tvector_fp4x2_e1m2_t
vector_hifloat8_thifloat8_tvector_hifloat8_t
vector_fp8_e8m0_tfp8_e8m0_tvector_fp8_e8m0_t
vector_fp8_e5m2_tfp8_e5m2_tvector_fp8_e5m2_t
vector_fp8_e4m3fn_tfp8_e4m3fn_tvector_fp8_e4m3fn_t
vector_int16_tint16_tvector_int16_t
vector_uint16_tuint16_tvector_uint16_t
vector_halfhalfvector_half
vector_bfloat16_tbfloat16_tvector_bfloat16_t
vector_int32_tint32_tvector_int32_t
vector_uint32_tuint32_tvector_uint32_t
vector_floatfloatvector_float
vector_int64_tint64_t不支持
vector_uint64_tuint64_t不支持

函数原型典型示例

C
// 通过引用参数输出结果示例:int8_t类型
__simd_callee__ inline void asc_gather_datablock(vector_int8_t& dst,
                                                 __ubuf__ int8_t* src,
                                                 vector_uint32_t index)

// 通过函数返回值返回结果示例:int8_t类型
__simd_callee__ inline vector_int8_t asc_gather_datablock(__ubuf__ int8_t* src,
                                                          vector_uint32_t index)

参数说明

支持掩码控制

表3 参数说明

参数名输入/输出描述
dst输出目的操作数(矢量数据寄存器),仅适用于通过引用参数输出结果的函数原型。
src输入源操作数(矢量)的起始地址。
index输入源操作数(矢量数据寄存器),表示dst中每个DataBlock在UB中相对于src的索引位置。索引位置要大于等于0且32B对齐,索引可以存在相同的值。index仅前8个数有效,单位是字节。
mask输入源操作数掩码(掩码寄存器)。DataBlock搬运的有效指示,按b32格式解释。一个DataBlock对应4bit,仅每4bit中的最低位有效。由于index仅前8个元素有效,因此mask仅使用前8个b32元素对应的bit 0、4、8、12、16、20、24、28,分别控制dst中DataBlock0至DataBlock7是否更新,其余bit无效。

无掩码控制

表4 参数说明

参数名输入/输出描述
dst输出目的操作数(矢量数据寄存器),仅适用于通过引用参数输出结果的函数原型。
src输入源操作数(矢量)的起始地址。
index输入源操作数(矢量数据寄存器),表示dst中每个DataBlock在UB中相对于src的索引位置。索引位置要大于等于0且32B对齐,索引可以存在相同的值。index仅前8个数有效,单位是字节。

矢量数据寄存器和掩码寄存器的详细说明请参见reg数据类型定义

返回值说明

  • 通过引用参数输出结果的函数原型无返回值。
  • 通过函数返回值输出结果的函数原型返回收集结果,返回值类型与对应引用输出函数原型中dst参数的类型一致(去除引用)。

约束说明

  • 通过引用参数输出结果的函数原型在非AIV上调用时直接返回。
  • 通过函数返回值输出结果的函数原型在非AIV上调用时返回对应矢量类型的默认构造值。
  • b64数据类型属于编译器软件仿真实现,通过函数返回值输出结果的函数原型不做支持。
  • 源操作数在UB中的起始地址需要32B对齐。
  • 索引位置要大于等于0且32B对齐,即一个索引值对应一个DataBlock。
  • 索引可以存在相同的值,即可以多次读取源操作数中同一个DataBlock的数据。
  • 索引值对应的数据必须在UB有效地址范围内。
  • index仅前8个元素有效。

调用示例

将代码保存为example.asc后,可通过bisheng命令编译运行,其中--npu-arch参数需根据实际产品型号指定对应的NPU架构,具体产品与NPU架构的映射关系请参考__NPU_ARCH__

以Ascend 950PR/Ascend 950DT产品(对应NPU架构为dav-3510)为例,编译运行命令如下:

Bash
bisheng example.asc -o main --npu-arch=dav-3510 && ./main
C
#include <cstdint>
#include <iostream>
#include <vector>
#include "c_api/asc_simd.h"
#include "acl/acl.h"

namespace {
template <typename T>
void PrintData(const char* label, const std::vector<T>& values)
{
    std::cout << label << ":";
    const size_t count = values.size() < 8 ? values.size() : 8;
    for (size_t i = 0; i < count; ++i) std::cout << ' ' << +values[i];
    if (values.size() > count) std::cout << " ...";
    std::cout << std::endl;
}

constexpr uint32_t DATA_BLOCK_SIZE = 32;
constexpr uint32_t DATA_BLOCK_COUNT = 8;
constexpr uint32_t BUFFER_BYTES = DATA_BLOCK_SIZE * DATA_BLOCK_COUNT;
constexpr uint32_t INDEX_WORDS = 64;

__simd_vf__ inline void gather_datablock_vf(
    __ubuf__ uint8_t* output, __ubuf__ uint8_t* data, __ubuf__ uint32_t* index)
{
    vector_bool gather_mask = asc_create_mask_b32(PAT_ALL);
    vector_uint32_t index_reg;
    asc_loadalign(index_reg, index);
    vector_uint8_t dst;
    asc_gather_datablock(dst, data, index_reg, gather_mask);
    vector_bool store_mask = asc_create_mask_b8(PAT_ALL);
    asc_storealign(output, dst, store_mask);
}

__global__ __vector__ void asc_gather_datablock_kernel(
    __gm__ uint8_t* output, __gm__ uint8_t* data, __gm__ uint32_t* index)
{
    asc_init();
    __ubuf__ uint8_t output_local[BUFFER_BYTES];
    __ubuf__ uint8_t data_local[BUFFER_BYTES];
    __ubuf__ uint32_t index_local[INDEX_WORDS];
    asc_copy_gm2ub_align(data_local, data, BUFFER_BYTES);
    asc_copy_gm2ub_align(index_local, index, INDEX_WORDS * sizeof(uint32_t));
    asc_sync_notify(PIPE_MTE2, PIPE_V, EVENT_ID0);
    asc_sync_wait(PIPE_MTE2, PIPE_V, EVENT_ID0);
    gather_datablock_vf(output_local, data_local, index_local);
    asc_sync_notify(PIPE_V, PIPE_MTE3, EVENT_ID0);
    asc_sync_wait(PIPE_V, PIPE_MTE3, EVENT_ID0);
    asc_copy_ub2gm_align(output, output_local, BUFFER_BYTES);
    asc_sync();
}
} // namespace

int main()
{
    std::vector<uint8_t> data(BUFFER_BYTES);
    std::vector<uint32_t> index(INDEX_WORDS);
    std::vector<uint8_t> output(BUFFER_BYTES, 0xff);
    std::vector<uint8_t> golden(BUFFER_BYTES);
    for (uint32_t i = 0; i < BUFFER_BYTES; ++i) {
        data[i] = static_cast<uint8_t>(i);
    }
    for (uint32_t b = 0; b < DATA_BLOCK_COUNT; ++b) {
        index[b] = (DATA_BLOCK_COUNT - 1 - b) * DATA_BLOCK_SIZE;
    }
    for (uint32_t b = 0; b < DATA_BLOCK_COUNT; ++b) {
        for (uint32_t j = 0; j < DATA_BLOCK_SIZE; ++j) {
            golden[b * DATA_BLOCK_SIZE + j] =
                static_cast<uint8_t>((DATA_BLOCK_COUNT - 1 - b) * DATA_BLOCK_SIZE + j);
        }
    }
    aclInit(nullptr);
    aclrtSetDevice(0);
    uint8_t* data_device = nullptr;
    aclrtMalloc(reinterpret_cast<void**>(&data_device), BUFFER_BYTES,
        ACL_MEM_MALLOC_HUGE_FIRST);
    uint32_t* index_device = nullptr;
    aclrtMalloc(reinterpret_cast<void**>(&index_device), INDEX_WORDS * sizeof(uint32_t),
        ACL_MEM_MALLOC_HUGE_FIRST);
    uint8_t* output_device = nullptr;
    aclrtMalloc(reinterpret_cast<void**>(&output_device), BUFFER_BYTES,
        ACL_MEM_MALLOC_HUGE_FIRST);
    aclrtMemcpy(data_device, data.size() * sizeof(uint8_t), data.data(), data.size() * sizeof(uint8_t),
        ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(index_device, index.size() * sizeof(uint32_t), index.data(), index.size() * sizeof(uint32_t),
        ACL_MEMCPY_HOST_TO_DEVICE);
    asc_gather_datablock_kernel<<<1, 0>>>(output_device, data_device, index_device);
    aclrtSynchronizeDevice();
    aclrtMemcpy(output.data(), output.size() * sizeof(uint8_t), output_device, output.size() * sizeof(uint8_t),
        ACL_MEMCPY_DEVICE_TO_HOST);
    PrintData("Data", data);
    PrintData("Output bytes", output);
    PrintData("Golden", golden);
    const bool passed = output == golden;
    std::cout << (passed ? "[Success] asc_gather_datablock completed."
                         : "[Failed] asc_gather_datablock output mismatch.")
              << std::endl;
    aclrtFree(data_device);
    aclrtFree(index_device);
    aclrtFree(output_device);
    aclrtResetDevice(0);
    aclFinalize();
    return passed ? 0 : 1;
}

免责声明:本站内容由 asc-devkit 仓 master 分支自动编译生成,属于持续开发版本,可能存在缺陷,仅供预览与参考。如需稳定及商用资料,请查阅官方 昇腾社区