Ssyr2

Applicable Product

ProductSupported
Atlas 200I/500 A2 inference products×
Atlas inference products×
Atlas training products×
Atlas A3 training products/Atlas A3 inference products√
Atlas A2 training products/Atlas A2 inference products√
Ascend 950PR/Ascend 950DT×

Function Description

  • API function:\

asdBlasMakeSsyr2Plan: Initializes the Ssyr2 operator configuration corresponding to the handle. asdBlasSsyr2: Computes the outer product of single-precision vectors and adds the result to a matrix.

  • Formula:A=alpha∗x∗yT+alpha∗y∗xT+AA=alpha*x*y^T+alpha*y*x^T+A Example: The input x is:
    [ 1, 2 ]
    The input A is:
    [ [ 1,2 ], [ 3,4 ] ]
    The input y is [ 3, 4 ]
    The input uplo is U
    The input n is 2, the input lda is 2, the input incx is 1, and the input incy is 1.
    The input alpha is 2.345.
    After the asdBlasSsyr2 operator is called, the output A is:
    [ [ 15.07, 25.45 ], [ 26.45, 41.52 ] ].

Function Prototype

AspbStatus asdBlasMakeSsyr2Plan(
  asdBlasHandle handle)
AspbStatus asdBlasSsyr2(
  asdBlasHandle         handle, 
  asdBlasFillMode_t     uplo, 
  const int64_t         n, 
  const float &         alpha, 
  aclTensor *           x, 
  int64_t               incx, 
  aclTensor *           y, 
  int64_t               incy, 
  aclTensor *           A, 
  const int64_t         lda)

asdBlasMakeSsyr2Plan

  • Parameter description:

    Parameter Input/Output Description
    handle (asdBlasHandle) Input Operator handle
  • Return value:

    For details about the return values, see SiP Return Codes.

asdBlasSsyr2

  • Parameter description:

    Parameter Input/Output Description
    handle (asdBlasHandle) Input Handle of the operator.
    uplo (asdBlasFillMode_t) Input Specifies the triangular region of matrix A involved in the computation.
    • ASDBLAS_FILL_MODE_LOWER: lower triangular
    • ASDBLAS_FILL_MODE_UPPER: upper triangular
    n (int64_t) Input Number of elements in vector x, and the number of rows and columns of matrix A.
    alpha (float &) Input Alpha in the formula, a scalar scaling factor for the vector product.
    x (aclTensor *) Input
    • Corresponds to "x" in the formula.
    • Supported data type: FLOAT32.
    • Data format: ND.
    • Shape: [n]
    incx (int64_t) Input Memory address offset between adjacent elements of "x" (constrained to 1 in the current version).
    y (aclTensor *) Input
    • Corresponds to "y" in the formula.
    • Supported data type: FLOAT32.
    • Data format: ND.
    • Shape: [n]
    incy (int64_t) Input Memory address offset between adjacent elements of y (constrained to 1 in the current version).
    A (aclTensor *) Input/Output
    • Corresponds to "A" in the formula.
    • Supported data type: FLOAT32.
    • Data format: ND.
    • Shape: [n, n]
    lda (int64_t) Input Storage stride of elements in each column of matrix A (constrained to n in the current version).
  • Return value:

    For details about the return values, see SiP Return Codes.

Constraints

  • The number of input elements n is currently in the range [1, 8192].

  • The input shapes of the operator are [n], [n], and [n, n], and the output shape is [n, n].

  • During actual computation, the operator does not support high-dimensional ND operations (dimensions ≥ 3).

Calling Example

The example code is as follows. This sample is intended to provide a minimal implementation for quick start, development, and debugging of the operator. Its core goal is to demonstrate the core functionality of the operator using the simplest code, rather than providing production-grade security assurance. Users are advised not to directly use the example code for business purposes. If users apply the example code in their own real business scenarios and security issues occur, the users shall bear the consequences themselves.

#include <iostream>
#include <vector>
#include "asdsip.h"
#include "acl/acl.h"
#include "acl_meta.h"

using namespace AsdSip;

#define ASD_STATUS_CHECK(err)                                                \
    do {                                                                     \
        AsdSip::AspbStatus err_ = (err);                                     \
        if (err_ != AsdSip::ErrorType::ACL_SUCCESS) {                                      \
            std::cout << "Execute failed." << std::endl; \
            exit(-1);                                                        \
        }                                                                    \
    } while (0)

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

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

int64_t GetShapeSize(const std::vector<int64_t> &shape)
{
    int64_t shapeSize = 1;
    for (auto i : shape) {
        shapeSize *= i;
    }
    return shapeSize;
}

int Init(int32_t deviceId, aclrtStream *stream)
{
    // Boilerplate: Initialize ACL.
    auto ret = aclInit(nullptr);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
    ret = aclrtSetDevice(deviceId);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
    ret = aclrtCreateStream(stream);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
    return 0;
}

template <typename T>
int CreateAclTensor(const std::vector<T> &hostData, const std::vector<int64_t> &shape, void **deviceAddr,
    aclDataType dataType, aclTensor **tensor)
{
    auto size = GetShapeSize(shape) * sizeof(T);
    // Call aclrtMalloc to allocate device-side memory.
    auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
    // Call aclrtMemcpy to copy host-side data to device-side memory.
    ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);

    // Compute the strides of a contiguous tensor.
    std::vector<int64_t> strides(shape.size(), 1);
    for (int64_t i = shape.size() - 2; i >= 0; i--) {
        strides[i] = shape[i + 1] * strides[i + 1];
    }

    // Call the aclCreateTensor API to create an aclTensor.
    *tensor = aclCreateTensor(shape.data(),
        shape.size(),
        dataType,
        strides.data(),
        0,
        aclFormat::ACL_FORMAT_ND,
        shape.data(),
        shape.size(),
        *deviceAddr);
    return 0;
}

int main(int argc, char **argv)
{
    int deviceId = 0;

    aclrtStream stream;
    auto ret = Init(deviceId, &stream);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);

    int64_t n = 5;
    asdBlasFillMode_t uplo = asdBlasFillMode_t::ASDBLAS_FILL_MODE_LOWER;
    float alpha = 2.0f;
    int64_t incx = 1;
    int64_t incy = 1;
    int64_t lda = 5;

    const int64_t tensorXSize = n;

    std::vector<float> tensorInXData;
    tensorInXData.reserve(tensorXSize);
    for (int i = 0; i < tensorXSize; i++) {
        tensorInXData.push_back(1.0 + i);
    }

    const int64_t tensorYSize = n;

    std::vector<float> tensorInYData;
    tensorInYData.reserve(tensorYSize);
    for (int i = 0; i < tensorYSize; i++) {
        tensorInYData.push_back(2.0f + i);
    }

    const int64_t tensorASize = n * n;

    std::vector<float> tensorInAData;
    tensorInAData.reserve(tensorYSize);
    for (int i = 0; i < tensorASize; i++) {
        tensorInAData.push_back(1.0f);
    }

    std::cout << "alpha = " << static_cast<int32_t>(alpha) << std::endl;
    std::cout << "uplo = " << static_cast<int32_t>(uplo) << std::endl;
    std::cout << "------- input X -------" << std::endl;
    for (int64_t i = 0; i < tensorXSize; i++) {
        std::cout << tensorInXData[i] << " ";
    }
    std::cout << std::endl;
    std::cout << "------- input Y -------" << std::endl;
    for (int64_t i = 0; i < tensorYSize; i++) {
        std::cout << tensorInYData[i] << " ";
    }
    std::cout << std::endl;
    std::cout << "------- input A -------" << std::endl;
    for (int64_t i = 0; i < n; i++) {
        for (int64_t j = 0; j < n; j++)
            std::cout << tensorInAData[i * n + j] << " ";
        std::cout << std::endl;
    }

    std::vector<int64_t> xShape = {n};
    std::vector<int64_t> yShape = {n};
    std::vector<int64_t> matAShape = {n, n};

    aclTensor *inputX = nullptr;
    aclTensor *inputY = nullptr;
    aclTensor *inputA = nullptr;
    void *inputXDeviceAddr = nullptr;
    void *inputYDeviceAddr = nullptr;
    void *inputADeviceAddr = nullptr;

    ret = CreateAclTensor<float>(tensorInXData, xShape, &inputXDeviceAddr, aclDataType::ACL_FLOAT, &inputX);
    CHECK_RET(ret == ::ACL_SUCCESS, return ret);

    ret = CreateAclTensor<float>(tensorInYData, yShape, &inputYDeviceAddr, aclDataType::ACL_FLOAT, &inputY);
    CHECK_RET(ret == ::ACL_SUCCESS, return ret);

    ret = CreateAclTensor<float>(tensorInAData, matAShape, &inputADeviceAddr, aclDataType::ACL_FLOAT, &inputA);
    CHECK_RET(ret == ::ACL_SUCCESS, return ret);

    asdBlasHandle handle;
    asdBlasCreate(handle);

    size_t lwork = 0;
    void *buffer = nullptr;
    asdBlasMakeSsyr2Plan(handle);
    asdBlasGetWorkspaceSize(handle, lwork);
    std::cout << "lwork = " << lwork << std::endl;
    if (lwork > 0) {
        ret = aclrtMalloc(&buffer, static_cast<int64_t>(lwork), ACL_MEM_MALLOC_HUGE_FIRST);
        CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
    }
    asdBlasSetWorkspace(handle, buffer);
    asdBlasSetStream(handle, stream);

    ASD_STATUS_CHECK(asdBlasSsyr2(handle, uplo, n, alpha, inputX, incx, inputY, incy, inputA, lda));

    asdBlasSynchronize(handle);
    asdBlasDestroy(handle);

    ret = aclrtMemcpy(tensorInAData.data(),
        n * n * sizeof(float),
        inputADeviceAddr,
        n * n * sizeof(float),
        ACL_MEMCPY_DEVICE_TO_HOST);
    CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);

    std::cout << "------- output A -------" << std::endl;
    for (int64_t i = 0; i < n; i++) {
        for (int64_t j = 0; j < n; j++) {
            std::cout << tensorInAData[i * n + j] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << "Execute successfully." << std::endl;

    aclDestroyTensor(inputX);
    aclDestroyTensor(inputY);
    aclDestroyTensor(inputA);
    aclrtFree(inputXDeviceAddr);
    aclrtFree(inputYDeviceAddr);
    aclrtFree(inputADeviceAddr);

    aclrtDestroyStream(stream);
    aclrtResetDevice(deviceId);
    aclFinalize();
    return 0;
}