{算子名称}算子

算子概述

{一段话描述算子的功能定位和核心运算。例如:"{op} 算子实现了{功能描述},核心运算为{运算描述}。"}

数学表达式:

{数学公式,使用纯文本。如需要可用 LaTeX 格式($$...$$)}

包含以下接口:

接口名 功能简述
aclsparseS{op} {单精度功能描述}
aclsparseD{op} {双精度功能描述}

算子执行接口

aclsparseS{op}

产品支持情况

  • Ascend 950PR / Ascend 950DT:{支持/不支持}
  • Atlas A3 训练系列产品 / Atlas A3 推理系列产品:{支持/不支持}
  • Atlas A2 训练系列产品 / Atlas A2 推理系列产品:{支持/不支持}

函数原型

aclsparseStatus_t aclsparseS{op}(aclsparseHandle_t handle, int m, int n, const float *A, ...)

参数说明

参数名 输入/输出 参数类型 说明
handle 输入 aclsparseHandle_t ops-sparse 库上下文句柄,携带 stream,Host 内存
m 输入 int {参数含义},Host 内存
A 输入 const float*(FP32) {参数含义},Device 内存

约束说明

  • m >= 0
  • n >= 0

{如无约束则写"无",不允许留空。}

支持的稀疏格式

{如算子涉及稀疏矩阵格式(CSR/COO/CSC 等),按下表列出支持情况;如不涉及稀疏格式则删除本节。}

格式 支持 说明
CSR {✅/❌} {说明}
COO {✅/❌} {说明}
CSC {✅/❌} {说明}

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例

#include <cstdio>
#include <memory>
#include <vector>

#include "acl/acl.h"
#include "cann_ops_sparse.h"

#define CHECK_RET(cond, return_expr) \
    do {                             \
        if (!(cond)) {               \
            return_expr;             \
        }                            \
    } while (0)

#define LOG_PRINT(message, ...)         \
    do {                                \
        printf(message, ##__VA_ARGS__); \
    } while (0)

class AclContext {
public:
    explicit AclContext(int32_t deviceId) : deviceId_(deviceId) {}

    ~AclContext()
    {
        if (stream_ != nullptr) {
            aclrtDestroyStream(stream_);
            stream_ = nullptr;
        }
        if (deviceSet_) {
            aclrtResetDevice(deviceId_);
            deviceSet_ = false;
        }
        if (aclInited_) {
            aclFinalize();
            aclInited_ = false;
        }
    }

    int Init()
    {
        auto ret = aclInit(nullptr);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
        aclInited_ = true;

        ret = aclrtSetDevice(deviceId_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
        deviceSet_ = true;

        ret = aclrtCreateStream(&stream_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
        return ACL_SUCCESS;
    }

    aclrtStream Stream() const { return stream_; }

private:
    int32_t deviceId_;
    aclrtStream stream_ = nullptr;
    bool aclInited_ = false;
    bool deviceSet_ = false;
};

int aclsparseS{op}Test(AclContext& ctx)
{
    aclrtStream stream = ctx.Stream();

    // 1. 创建 ops-sparse 句柄
    aclsparseHandle_t rawHandle = nullptr;
    auto sparseRet = aclsparseCreate(&rawHandle);
    CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseCreate failed. ERROR: %d\n", sparseRet);
              return sparseRet);
    std::unique_ptr<aclsparseContext, aclsparseStatus_t (*)(aclsparseHandle_t)> handlePtr(rawHandle, aclsparseDestroy);

    sparseRet = aclsparseSetStream(static_cast<aclsparseHandle_t>(handlePtr.get()), stream);
    CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseSetStream failed. ERROR: %d\n", sparseRet);
              return sparseRet);

    // 2. 设置 PointerMode(如算子含标量指针参数如 alpha、beta,须设置;否则可省略)
    // sparseRet = aclsparseSetPointerMode(static_cast<aclsparseHandle_t>(handlePtr.get()), ACL_SPARSE_POINTER_MODE_HOST);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseSetPointerMode failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);

    // 3. 创建 MatDescr(如算子需要 aclsparseMatDescr_t,须创建并配置;否则可省略)
    // aclsparseMatDescr_t matDescr = nullptr;
    // sparseRet = aclsparseCreateMatDescr(&matDescr);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseCreateMatDescr failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);
    // aclsparseSetMatType(matDescr, ACL_SPARSE_MATRIX_TYPE_GENERAL);
    // aclsparseSetMatIndexBase(matDescr, ACL_SPARSE_INDEX_BASE_ZERO);

    // 4. 准备 Host 数据
    // {按算子需求定义参数并初始化 Host 数据,如 std::vector<float> hA(m * n, 0.0f); }

    // 5. 申请 Device 内存并拷贝数据
    // {按算子需求使用 aclrtMalloc + std::unique_ptr + aclrtFree 管理 Device 内存}
    // {按算子需求使用 aclrtMemcpy 拷贝数据到 Device}

    // 6. 调用 aclsparseS{op}
    // sparseRet = aclsparseS{op}(static_cast<aclsparseHandle_t>(handlePtr.get()), ...);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseS{op} failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);

    // 7. 同步等待任务执行结束
    auto aclRet = aclrtSynchronizeStream(stream);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); return aclRet);

    // 8. 将结果从 Device 拷贝回 Host 并打印
    // {按算子需求使用 aclrtMemcpy 拷贝结果回 Host 并打印验证}

    // 9. 清理 MatDescr(如步骤 3 已创建)
    // aclsparseDestroyMatDescr(matDescr);

    return ACL_SPARSE_STATUS_SUCCESS;
}

int main()
{
    AclContext ctx(0);
    auto ret = ctx.Init();
    CHECK_RET(ret == ACL_SUCCESS, return ret);

    ret = aclsparseS{op}Test(ctx);
    CHECK_RET(ret == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseS{op}Test failed. ERROR: %d\n", ret); return ret);
    return 0;
}

预期输出如下:

{按算子实际输出填写,如:}
result[0] is: xxx
result[1] is: xxx

aclsparseD{op}

产品支持情况

  • Ascend 950PR / Ascend 950DT:{支持/不支持}
  • Atlas A3 训练系列产品 / Atlas A3 推理系列产品:{支持/不支持}
  • Atlas A2 训练系列产品 / Atlas A2 推理系列产品:{支持/不支持}

函数原型

aclsparseStatus_t aclsparseD{op}(aclsparseHandle_t handle, int m, int n, const double *A, ...)

参数说明

参数名 输入/输出 参数类型 说明
handle 输入 aclsparseHandle_t ops-sparse 库上下文句柄,携带 stream,Host 内存
m 输入 int {参数含义},Host 内存
A 输入 const double*(FP64) {参数含义},Device 内存

约束说明

  • m >= 0
  • n >= 0

{如无约束则写"无",不允许留空。}

支持的稀疏格式

{如算子涉及稀疏矩阵格式(CSR/COO/CSC 等),按下表列出支持情况;如不涉及稀疏格式则删除本节。}

格式 支持 说明
CSR {✅/❌} {说明}
COO {✅/❌} {说明}
CSC {✅/❌} {说明}

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例

#include <cstdio>
#include <memory>
#include <vector>

#include "acl/acl.h"
#include "cann_ops_sparse.h"

#define CHECK_RET(cond, return_expr) \
    do {                             \
        if (!(cond)) {               \
            return_expr;             \
        }                            \
    } while (0)

#define LOG_PRINT(message, ...)         \
    do {                                \
        printf(message, ##__VA_ARGS__); \
    } while (0)

class AclContext {
public:
    explicit AclContext(int32_t deviceId) : deviceId_(deviceId) {}

    ~AclContext()
    {
        if (stream_ != nullptr) {
            aclrtDestroyStream(stream_);
            stream_ = nullptr;
        }
        if (deviceSet_) {
            aclrtResetDevice(deviceId_);
            deviceSet_ = false;
        }
        if (aclInited_) {
            aclFinalize();
            aclInited_ = false;
        }
    }

    int Init()
    {
        auto ret = aclInit(nullptr);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
        aclInited_ = true;

        ret = aclrtSetDevice(deviceId_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
        deviceSet_ = true;

        ret = aclrtCreateStream(&stream_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
        return ACL_SUCCESS;
    }

    aclrtStream Stream() const { return stream_; }

private:
    int32_t deviceId_;
    aclrtStream stream_ = nullptr;
    bool aclInited_ = false;
    bool deviceSet_ = false;
};

int aclsparseD{op}Test(AclContext& ctx)
{
    aclrtStream stream = ctx.Stream();

    // 1. 创建 ops-sparse 句柄
    aclsparseHandle_t rawHandle = nullptr;
    auto sparseRet = aclsparseCreate(&rawHandle);
    CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseCreate failed. ERROR: %d\n", sparseRet);
              return sparseRet);
    std::unique_ptr<aclsparseContext, aclsparseStatus_t (*)(aclsparseHandle_t)> handlePtr(rawHandle, aclsparseDestroy);

    sparseRet = aclsparseSetStream(static_cast<aclsparseHandle_t>(handlePtr.get()), stream);
    CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseSetStream failed. ERROR: %d\n", sparseRet);
              return sparseRet);

    // 2. 设置 PointerMode(如算子含标量指针参数如 alpha、beta,须设置;否则可省略)
    // sparseRet = aclsparseSetPointerMode(static_cast<aclsparseHandle_t>(handlePtr.get()), ACL_SPARSE_POINTER_MODE_HOST);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseSetPointerMode failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);

    // 3. 创建 MatDescr(如算子需要 aclsparseMatDescr_t,须创建并配置;否则可省略)
    // aclsparseMatDescr_t matDescr = nullptr;
    // sparseRet = aclsparseCreateMatDescr(&matDescr);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseCreateMatDescr failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);
    // aclsparseSetMatType(matDescr, ACL_SPARSE_MATRIX_TYPE_GENERAL);
    // aclsparseSetMatIndexBase(matDescr, ACL_SPARSE_INDEX_BASE_ZERO);

    // 4. 准备 Host 数据
    // {按算子需求定义参数并初始化 Host 数据,如 std::vector<double> hA(m * n, 0.0); }

    // 5. 申请 Device 内存并拷贝数据
    // {按算子需求使用 aclrtMalloc + std::unique_ptr + aclrtFree 管理 Device 内存}
    // {按算子需求使用 aclrtMemcpy 拷贝数据到 Device}

    // 6. 调用 aclsparseD{op}
    // sparseRet = aclsparseD{op}(static_cast<aclsparseHandle_t>(handlePtr.get()), ...);
    // CHECK_RET(sparseRet == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseD{op} failed. ERROR: %d\n", sparseRet);
    //           return sparseRet);

    // 7. 同步等待任务执行结束
    auto aclRet = aclrtSynchronizeStream(stream);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); return aclRet);

    // 8. 将结果从 Device 拷贝回 Host 并打印
    // {按算子需求使用 aclrtMemcpy 拷贝结果回 Host 并打印验证}

    // 9. 清理 MatDescr(如步骤 3 已创建)
    // aclsparseDestroyMatDescr(matDescr);

    return ACL_SPARSE_STATUS_SUCCESS;
}

int main()
{
    AclContext ctx(0);
    auto ret = ctx.Init();
    CHECK_RET(ret == ACL_SUCCESS, return ret);

    ret = aclsparseD{op}Test(ctx);
    CHECK_RET(ret == ACL_SPARSE_STATUS_SUCCESS, LOG_PRINT("aclsparseD{op}Test failed. ERROR: %d\n", ret); return ret);
    return 0;
}

预期输出如下:

{按算子实际输出填写,如:}
result[0] is: xxx
result[1] is: xxx