aclnnDivMod&aclnnInplaceDivMod
Applicable Products
- Ascend 950PR&950DT products: Supported
- Atlas A3 products: Supported
- Atlas A2 products: Supported
- Atlas 200I/500 A2 inference products: Not supported
- Atlas inference products: Not supported
- Atlas training products: Supported
Function
-
Description: Performs division calculation and selects the rounding operation based on the mode parameter.
-
Formula:
outi=inputiotheriout_i = \frac{input_i}{other_i}
Function Prototype
aclnnDivMod and aclnnInplaceDivMod implement the same function. The differences in usage are as follows. Select the appropriate operator based on your actual scenario.
- aclnnDivMod: Create a new output tensor object to store the computation result.
- aclnnInplaceDivMod: No need to create a new output tensor object. The computation result is stored directly in the memory of the input tensor.
Each operator is divided into two-phase API. Call "aclnnDivModGetWorkspaceSize" or "aclnnInplaceDivModGetWorkspaceSize" first to obtain the workspace size required for computation and the executor that contains the computation process of the operator, and then call "aclnnDivMod" or "aclnnInplaceDivMod" to perform computation.
aclnnStatus aclnnDivModGetWorkspaceSize(
const aclTensor* self,
const aclTensor* other,
int mode,
aclTensor* out,
uint64_t* workspaceSize,
aclOpExecutor** executor)
aclnnStatus aclnnDivMod(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)
aclnnStatus aclnnInplaceDivModGetWorkspaceSize(
aclTensor* selfRef,
const aclTensor* other,
int mode,
uint64_t* workspaceSize,
aclOpExecutor** executor)
aclnnStatus aclnnInplaceDivMod(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)
aclnnDivModGetWorkspaceSize
-
Parameters:
Parameter Input/Output Description Instruction data type data format Dimension(shape) non-contiguous tensor self(aclTensor*) Input Dividend, corresponding to the input self in the formula. - The data type must satisfy the data type derivation rule with the data type of other (see deduction relationship).
- The shape must satisfy the broadcast relationship with other.
FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, COMPLEX128, COMPLEX64, BFLOAT16 ND Up to 8 dimensions √ other (aclTensor*) Input Divisor, corresponding to the input other in the formula. - The data type must satisfy the data type derivation rule with the data type of self (see deduction relationship).
- shape must satisfy the broadcast relationship with self.
FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, COMPLEX128, COMPLEX64, BFLOAT16 ND No more than 8 dimensions √ mode (int) Input Specifies the rounding mode for the quotient. The enumeration values are as follows: - 0 - None: no rounding is performed by default.
- 1 - trunc: rounds the fractional part of the division toward zero.
- 2 - floor: rounds the division result down.
int - - - out (aclTensor*) Output Represents the quotient, that is, out in the formula. - The data type must be convertible from the data type derived from self and other.
- The shape must be the shape after self and other are broadcast.
FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, COMPLEX128, COMPLEX64, BFLOAT16 ND - √ workspaceSize (uint64_t*) Output Returns the size of the workspace to be requested on the Device. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which contains the operator computation flow. - - - - - - Atlas training products: BFLOAT16 data type is not supported.
- Ascend 950PR&950DT products:
- When mode is 0, the out data type supports FLOAT, FLOAT16, DOUBLE, BFLOAT16, COMPLEX128, and COMPLEX64.
- When mode is 1 or 2, the out data type supports FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, BFLOAT16, COMPLEX128, and COMPLEX64.
- When mode is 0 and the data type after derivation of self and other is an integer type or boolean type, the data type after derivation is converted to FLOAT.
-
Return value
aclnnStatus: return status code. For details, see aclnn Return Codes.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Value Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 self, other, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data types and data formats of self and other are not within the supported range. self and other do not satisfy the data type derivation rule. The derived data type cannot be converted to the type of the specified output out. The shapes of self and other cannot be broadcast. The dimensions of self and other are greater than 8. The value of mode is not in the range of 0, 1, or 2. When mode is 1 or 2, the derived data types of self and other are COMPLEX64 or COMPLEX128.
aclnnDivMod
-
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address allocated on the device. workspaceSize Input Size of the workspace allocated on the device, obtained by the first-phase API aclnnDivModGetWorkspaceSize. executor Input Executor of the op. It contains the operator computation flow. stream Input Stream for task execution. -
Return value
aclnnStatus: return status code. For details, see aclnn Return Codes.
aclnnInplaceDivModGetWorkspaceSize
-
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimensions (shape) Non-contiguous Tensor selfRef(aclTensor*) Input/Output Represents the dividend and quotient, corresponding to the inputs input and out in the formula. - The data type and the data type of other must satisfy the data type derivation rule (see deduction relationship).
- The data type must be a data type that can be converted after the derivation of selfRef and other (see conversion relationship).
- The shape must satisfy the broadcast relationship with other (see broadcast relationship).
FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, COMPLEX128, COMPLEX64 ND No more than 8 dimensions √ other (aclTensor*) Input Represents the divisor, corresponding to the input other in the formula. - The data type must satisfy the data type derivation rule together with the data type of selfRef (see deduction relationship).
- The shape must satisfy the broadcast relationship with selfRef.
FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL ND Up to 8 dimensions √ mode (int) Input Specifies the rounding mode for the quotient. The enumeration values are as follows: - 0-corresponds to None: no rounding is performed by default.
- 1-corresponds to trunc: rounds the fractional part of the division toward zero.
- 2-corresponds to floor: rounds the division result down.
int - - - workspaceSize (uint64_t*) Output Returns the workspace size to be allocated on the Device. - - - - - executor (aclOpExecutor**) Output Returns the op executor containing the operator computation flow. - - - - - - Atlas training products: BFLOAT16 data type is not supported.
- Ascend 950PR&950DT products:
- When mode is 0, the selfRef data type supports FLOAT, FLOAT16, DOUBLE, and BFLOAT16.
- When mode is 1 or 2, the selfRef data type supports FLOAT, FLOAT16, DOUBLE, INT32, INT64, INT16, INT8, UINT8, BOOL, and BFLOAT16.
- When mode is 0 and the data type after derivation of selfRef and other is an integer type or boolean type, the data type after derivation is converted to FLOAT.
-
Return value
aclnnStatus: return status code. For details, see aclnn Return Codes.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Value Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 selfRef or other is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data types and data formats of selfRef and other are not within the supported range. selfRef and other do not satisfy the data type derivation rule. The shapes of selfRef and other cannot be broadcast. The dimensions of selfRef and other are greater than 8. The value of mode is not in the range of 0, 1, or 2. When mode is 1 or 2, the data type derived from selfRef and other is COMPLEX64 or COMPLEX128.
aclnnInplaceDivMod
-
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address allocated on the Device. workspaceSize Input Size of the workspace memory allocated on the Device, obtained by calling the first-phase API aclnnInplaceDivModGetWorkspaceSize. executor Input op executor, containing the computation process of the operator. stream Input Stream for executing the task. -
Return value
aclnnStatus: return status code. For details, see aclnn Return Codes.
Constraints
- Deterministic computation:
- aclnnDivMod&aclnnInplaceDivMod defaults to a deterministic implementation.
- Atlas A2 products, Atlas A3 products: When mode is 1 (trunc mode) or 2 (floor mode), due to the limited precision of FLOAT16/BFLOAT16 data types, which cannot represent all decimals, certain errors may occur during rounding/flooring. You can choose a higher-precision data type such as FLOAT32.
Example
The sample code is for reference only. For details about compilation and execution, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_div.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)
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: resource initialization
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); aclFinalize(); return ret);
ret = aclrtCreateStream(stream);
CHECK_RET(ret == ACL_SUCCESS,
LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret);
aclrtResetDevice(deviceId); aclFinalize(); 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 the 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 aclCreateTensor 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() {
// 1. (Boilerplate) Initialize device/stream. For details, see the acl API manual.
// Set deviceId to the actual device.
int32_t 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);
// 2. Construct inputs and outputs based on the API.
std::vector<int64_t> selfShape = {4, 2};
std::vector<int64_t> otherShape = {4, 2};
std::vector<int64_t> outShape = {4, 2};
void* selfDeviceAddr = nullptr;
void* otherDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* other = nullptr;
aclTensor* out = nullptr;
std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<float> otherHostData = {1, 1, 1, 2, 2, 2, 3, 3};
std::vector<float> outHostData(8, 0);
// Create the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the other aclTensor.
ret = CreateAclTensor(otherHostData, otherShape, &otherDeviceAddr, aclDataType::ACL_FLOAT, &other);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
int mode = 2;
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// aclnnDivMod API call example
LOG_PRINT("test aclnnDivMod\n");
// 3. Call the CANN operator library API. Replace it with the actual API name.
// Call the first-phase API of aclnnDivMod
ret = aclnnDivModGetWorkspaceSize(self, other, mode, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDivModGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on the workspaceSize calculated by the first-phase API.
void* workspaceAddr = nullptr;
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
// Call the second-phase API of aclnnDivMod
ret = aclnnDivMod(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDivMod failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Wait synchronously for the task execution to finish.
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// 5. Obtain the output value and copy the result from the device side to the host side. Modify it according to the specific API definition.
auto size = GetShapeSize(outShape);
std::vector<float> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
size * sizeof(resultData[0]), 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);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
}
// aclnnInplaceDivMod API call example
LOG_PRINT("\ntest aclnnInplaceDivMod\n");
// 3. Call the CANN operator library API. Replace it with the actual API name.
// Call the first-phase API of aclnnInplaceDivMod
ret = aclnnInplaceDivModGetWorkspaceSize(self, other, mode, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceDivModGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on the workspaceSize computed by the first-phase API.
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
// Call the aclnnInplaceDivMod second-phase API.
ret = aclnnInplaceDivMod(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceDivMod failed. ERROR: %d\n", ret); return ret);
// 4. (boilerplate) Synchronously wait for the task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// 5. Obtain the output value, and copy the result from the device-side memory to the host side. Modify it based on the specific API definition.
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr,
size * sizeof(resultData[0]), 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);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
}
// 6. Release the aclTensor.
aclDestroyTensor(self);
aclDestroyTensor(other);
aclDestroyTensor(out);
// 7. Release the device resources.
aclrtFree(selfDeviceAddr);
aclrtFree(otherDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}