Axpy
Applicability
|
Product |
Supported |
|---|---|
|
|
√ |
|
|
√ |
|
|
√ |
|
|
√ |
|
|
x |
|
|
√ |
Function
Multiplies each element in the source operand src by a scalar and then adds the result to the corresponding element in the destination operand dst. The formula is as follows:

Prototype
- Computation of the first n data elements of a tensor
1 2
template <typename T, typename U> __aicore__ inline void Axpy(const LocalTensor<T>& dst, const LocalTensor<U>& src, const U& scalarValue, const int32_t& count)
- High-dimensional tensor sharding computation
- Bitwise mask mode
1 2
template <typename T, typename U, bool isSetMask = true> __aicore__ inline void Axpy(const LocalTensor<T>& dst, const LocalTensor<U>& src, const U& scalarValue, uint64_t mask[], const uint8_t repeatTime, const UnaryRepeatParams& repeatParams)
- Contiguous mask mode
1 2
template <typename T, typename U, bool isSetMask = true> __aicore__ inline void Axpy(const LocalTensor<T>& dst, const LocalTensor<U>& src, const U& scalarValue, uint64_t mask, const uint8_t repeatTime, const UnaryRepeatParams& repeatParams)
- Bitwise mask mode
Parameters
|
Parameter |
Description |
|---|---|
|
T |
Data type of the destination operand. For details about the data type constraints of the destination and source operands, see Table 3. For the For the For the For the For |
|
U |
Data type of the source operand. For the For the For the For the For |
|
isSetMask |
Indicates whether to set mask inside the API.
|
|
Parameter |
Input/Output |
Meaning |
|---|---|---|
|
dst |
Output |
Destination operand. The type is LocalTensor, and the supported TPosition is VECIN, VECCALC, or VECOUT. The start address of the LocalTensor must be 32-byte aligned. |
|
src |
Input |
Source operand. The type is LocalTensor, and the supported TPosition is VECIN, VECCALC, or VECOUT. The start address of the LocalTensor must be 32-byte aligned. |
|
scalarValue |
Input |
Source operand (scalar). The data type of scalarValue must be the same as that of src. |
|
count |
Input |
Number of elements involved in the computation. |
|
mask/mask[] |
Input |
mask is used to control the elements that participate in computation in each iteration.
|
|
repeatTime |
Input |
Number of repeat iterations. The vector compute unit reads 256 bytes of contiguous data for computation each time. To process the input data, the data needs to be read and computed over multiple repeats. repeatTime indicates the number of repeats. For details about this parameter, see High-dimensional Sharding APIs. |
|
repeatParams |
Input |
Parameters that control the operand address strides. This parameter is of the UnaryRepeatParams type, including the address stride of the same DataBlock between adjacent iterations of the operand and the address stride of different DataBlocks within the same iteration of the operand. For details about the address stride of the operand between adjacent iterations, see repeatStride. For details about the address stride of the operand between different data blocks in a single iteration, see dataBlockStride. |
|
src Data Type |
scalar Data Type |
dst Data Type |
PAR |
Availability |
|---|---|---|---|---|
|
half |
half |
half |
128 |
|
|
float |
float |
float |
64 |
|
|
half |
half |
float |
64 |
|
Returns
None
Restrictions
- For details about the operand address alignment requirements, see General Address Alignment Restrictions.
- For details about the constraints on operand address overlapping, see General Address Overlapping Restrictions.
- When a high-dimensional tensor sharding computation API is used, if the data types of src and scalar are half and that of dst is float, the number of source operand elements processed in one iteration must be the same as that of destination operand elements. Therefore, the first four data blocks are selected for computation in each iteration. This restriction must be taken into account when you set the Repeat stride parameter, mask parameter, and address overlapping.
Example
This example shows only part of the code used in the computation process (Compute). To run the sample code, copy the code snippet and replace the corresponding part of the Compute function in the complete sample template of More Examples.
- Example of high-dimensional tensor sharding computation (contiguous mask mode)
1 2 3 4 5 6 7 8 9 10 11
// repeatTime = 4, mask = 128, 128 elements one repeat, 512 elements total // srcLocal, scalar, and dstLocal are all of the half data type. // dstBlkStride, srcBlkStride = 1, no gap between blocks in one repeat // dstRepStride, srcRepStride = 8, no gap between repeats AscendC::Axpy(dstLocal, srcLocal, (half)2.0, 128, 4,{ 1, 1, 8, 8 }); // srcLocal and scalar are of type half, while dstLocal is of type float. // repeatTime = 8, mask = 64, 64 elements one repeat, 512 elements total // dstBlkStride, srcBlkStride = 1, no gap between blocks in one repeat // dstRepStride = 8, srcRepStride = 4, no gap between repeats AscendC::Axpy(dstLocal, srcLocal, (half)2.0, 64, 8,{ 1, 1, 8, 4 }); // Select the first four data blocks of the source operand for computation in each iteration.
- Example of high-dimensional tensor sharding computation (bitwise mask mode)
1 2 3 4 5
uint64_t mask[2] = { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; // repeatTime = 4, 128 elements per repeat, 512 elements in total. The data type is half. // dstBlkStride, srcBlkStride = 1, no gap between blocks in one repeat // dstRepStride, srcRepStride = 8, no gap between repeats AscendC::Axpy(dstLocal, srcLocal, (half)2.0, mask, 4,{ 1, 1, 8, 8 });
- Example of computing the first n data elements of a tensor
1AscendC::Axpy(dstLocal, src0Local, (half)2.0, 512);// half type
More Examples
- Complete example 1: srcLocal, scalar, and dstLocal are all of type half.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include "kernel_operator.h" class KernelAxpy { public: __aicore__ inline KernelAxpy() {} __aicore__ inline void Init(__gm__ uint8_t* srcGm, __gm__ uint8_t* dstGm) { srcGlobal.SetGlobalBuffer((__gm__ half*)srcGm); dstGlobal.SetGlobalBuffer((__gm__ half*)dstGm); pipe.InitBuffer(inQueueSrc, 1, 512 * sizeof(half)); pipe.InitBuffer(outQueueDst, 1, 512 * sizeof(half)); } __aicore__ inline void Process() { CopyIn(); Compute(); CopyOut(); } private: __aicore__ inline void CopyIn() { AscendC::LocalTensor<half> srcLocal = inQueueSrc.AllocTensor<half>(); AscendC::DataCopy(srcLocal, srcGlobal, 512); inQueueSrc.EnQue(srcLocal); } __aicore__ inline void Compute() { AscendC::LocalTensor<half> srcLocal = inQueueSrc.DeQue<half>(); AscendC::LocalTensor<half> dstLocal = outQueueDst.AllocTensor<half>(); AscendC::Duplicate(dstLocal, (half)0.0, 512); AscendC::Axpy(dstLocal, srcLocal, (half)2.0, 512); outQueueDst.EnQue<half>(dstLocal); inQueueSrc.FreeTensor(srcLocal); } __aicore__ inline void CopyOut() { AscendC::LocalTensor<half> dstLocal = outQueueDst.DeQue<half>(); AscendC::DataCopy(dstGlobal, dstLocal, 512); outQueueDst.FreeTensor(dstLocal); } private: AscendC::TPipe pipe; AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueSrc; AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueueDst; AscendC::GlobalTensor<half> srcGlobal, dstGlobal; }; extern "C" __global__ __aicore__ void kernel_vec_ternary_scalar_Axpy_half_2_half(__gm__ uint8_t* srcGm, __gm__ uint8_t* dstGm) { KernelAxpy op; op.Init(srcGm, dstGm); op.Process(); }
Result example:
Input (srcGm): [1. 1. 1. 1. 1. 1. ... 1.] Output (dstGm): [2. 2. 2. 2. 2. 2. ... 2.]
- Complete example 2: srcLocal and scalar are of type half, while dstLocal is of type float.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include "kernel_operator.h" class KernelAxpy { public: __aicore__ inline KernelAxpy() {} __aicore__ inline void Init(__gm__ uint8_t* srcGm, __gm__ uint8_t* dstGm) { srcGlobal.SetGlobalBuffer((__gm__ half*)srcGm); dstGlobal.SetGlobalBuffer((__gm__ float*)dstGm); pipe.InitBuffer(outQueueDst, 1, 512 * sizeof(float)); pipe.InitBuffer(inQueueSrc, 1, 512 * sizeof(half)); } __aicore__ inline void Process() { CopyIn(); Compute(); CopyOut(); } private: __aicore__ inline void CopyIn() { AscendC::LocalTensor<half> srcLocal = inQueueSrc.AllocTensor<half>(); AscendC::DataCopy(srcLocal, srcGlobal, 512); inQueueSrc.EnQue(srcLocal); } __aicore__ inline void Compute() { AscendC::LocalTensor<half> srcLocal = inQueueSrc.DeQue<half>(); AscendC::LocalTensor<float> dstLocal = outQueueDst.AllocTensor<float>(); AscendC::Duplicate(dstLocal, 0.0f, 512); AscendC::Axpy(dstLocal, srcLocal, (half)2.0, 64, 8, { 1, 1, 8, 4 }); outQueueDst.EnQue<float>(dstLocal); inQueueSrc.FreeTensor(srcLocal); } __aicore__ inline void CopyOut() { AscendC::LocalTensor<float> dstLocal = outQueueDst.DeQue<float>(); AscendC::DataCopy(dstGlobal, dstLocal, 512); outQueueDst.FreeTensor(dstLocal); } private: AscendC::TPipe pipe; AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueSrc; AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueueDst; AscendC::GlobalTensor<half> srcGlobal; AscendC::GlobalTensor<float> dstGlobal; }; extern "C" __global__ __aicore__ void kernel_vec_ternary_scalar_Axpy_half_2_float(__gm__ uint8_t* srcGm, __gm__ uint8_t* dstGm) { KernelAxpy op; op.Init(srcGm, dstGm); op.Process(); }
Result example:
Input (srcGm): [1. 1. 1. 1. 1. 1. ... 1.] Output (dstGm): [2. 2. 2. 2. 2. 2. ... 2.]