已合并
aclnnSplitTensor增加输出数据类型一致的校验,及样例指针重复释放修复 #3773
sunhao_hw创建于 7月3日
aclnnSplitTensor增加输出数据类型一致的校验,及样例指针重复释放修复 #3773
已合并
sunhao_hw创建于 7月3日
5 个文件变更+734-710
@@ -235,149 +235,152 @@ aclnnStatus aclnnSplitTensor(
235#include "aclnnop/aclnn_split_tensor.h"235#include "aclnnop/aclnn_split_tensor.h"
236 236 
237#define CHECK_RET(cond, return_expr) \237#define CHECK_RET(cond, return_expr) \
238- do { \238+ do { \
239- if (!(cond)) { \239+ if (!(cond)) { \
240- return_expr; \240+ return_expr; \
241- } \241+ } \
242- } while (0)242+ } while (0)
243 243 
244-#define LOG_PRINT(message, ...) \244+#define LOG_PRINT(message, ...) \
245- do { \245+ do { \
246- printf(message, ##__VA_ARGS__); \246+ printf(message, ##__VA_ARGS__); \
247- } while (0)247+ } while (0)
248 248 
249-int64_t GetShapeSize(const std::vector<int64_t>& shape) {249+int64_t GetShapeSize(const std::vector<int64_t>& shape)
250- int64_t shapeSize = 1;250+{
251- for (auto i : shape) {251+ int64_t shapeSize = 1;
252- shapeSize *= i;252+ for (auto i : shape) {
253- }253+ shapeSize *= i;
254- return shapeSize;254+ }
255+ return shapeSize;
255}256}
256 257 
257-int Init(int32_t deviceId, aclrtStream* stream) {258+int Init(int32_t deviceId, aclrtStream* stream)
258- // 固定写法,资源初始化259+{
259- auto ret = aclInit(nullptr);260+ // 固定写法,资源初始化
260- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);261+ auto ret = aclInit(nullptr);
261- ret = aclrtSetDevice(deviceId);262+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
262- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);263+ ret = aclrtSetDevice(deviceId);
263- ret = aclrtCreateStream(stream);264+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
264- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);265+ ret = aclrtCreateStream(stream);
265- return 0;266+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
267+ return 0;
266}268}
267 269 
268template <typename T>270template <typename T>
269int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,271int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
270- aclDataType dataType, aclTensor** tensor) {272+ aclDataType dataType, aclTensor** tensor)
271- auto size = GetShapeSize(shape) * sizeof(T);273+{
272- // 调用aclrtMalloc申请device侧内存274+ auto size = GetShapeSize(shape) * sizeof(T);
273- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);275+ // 调用aclrtMalloc申请device侧内存
274- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);276+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
275- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上277+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
276- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);278+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
277- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);279+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
280+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
278 281 
279- // 计算连续tensor的strides282+ // 计算连续tensor的strides
280- std::vector<int64_t> strides(shape.size(), 1);283+ std::vector<int64_t> strides(shape.size(), 1);
281- for (int64_t i = shape.size() - 2; i >= 0; i--) {284+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
282- strides[i] = shape[i + 1] * strides[i + 1];285+ strides[i] = shape[i + 1] * strides[i + 1];
283- }
284- 
285- // 调用aclCreateTensor接口创建aclTensor
286- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
287- shape.data(), shape.size(), *deviceAddr);
288- return 0;
289-}
290- 
291-void CheckResult(const std::vector<std::vector<int64_t>> &shapeList, const std::vector<void *> addrList) {
292- for (size_t i = 0; i < shapeList.size(); i++) {
293- auto size = GetShapeSize(shapeList[i]);
294- std::vector<float> resultData(size, 0);
295- auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
296- size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
297- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
298- for (int64_t j = 0; j < size; j++) {
299- LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
300 }286 }
301- }287+ 
288+ // 调用aclCreateTensor接口创建aclTensor
289+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
290+ shape.data(), shape.size(), *deviceAddr);
291+ return 0;
302}292}
303 293 
304-int main() {294+void CheckResult(const std::vector<std::vector<int64_t>>& shapeList, const std::vector<void*> addrList)
305- // 1.(固定写法)device/stream初始化,参考acl API手册295+{
306- // 根据自己的实际device填写deviceId296+ for (size_t i = 0; i < shapeList.size(); i++) {
307- int32_t deviceId = 0;297+ auto size = GetShapeSize(shapeList[i]);
308- aclrtStream stream;298+ std::vector<float> resultData(size, 0);
309- auto ret = Init(deviceId, &stream);299+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
310- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);300+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
301+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
302+ for (int64_t j = 0; j < size; j++) {
303+ LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
304+ }
305+ }
306+}
311 307 
312- // 2.构造输入与输出,需要根据API的接口自定义构造308+int main()
313- std::vector<int64_t> selfShape = {4, 2};309+{
314- std::vector<int64_t> shape1 = {2, 2};310+ // 1.(固定写法)device/stream初始化,参考acl API手册
315- std::vector<int64_t> shape2 = {2, 2};311+ // 根据自己的实际device填写deviceId
316- uint64_t splitSections = 2;312+ int32_t deviceId = 0;
317- int64_t dim = 0;313+ aclrtStream stream;
314+ auto ret = Init(deviceId, &stream);
315+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
318 316 
319- void* selfDeviceAddr = nullptr;317+ // 2. 构造输入与输出,需要根据API的接口自定义构造
320- void* shape1DeviceAddr = nullptr;318+ std::vector<int64_t> selfShape = {4, 2};
321- void* shape2DeviceAddr = nullptr;319+ std::vector<int64_t> shape1 = {2, 2};
320+ std::vector<int64_t> shape2 = {2, 2};
321+ uint64_t splitSections = 2;
322+ int64_t dim = 0;
322 323 
323- aclTensor* self = nullptr;324+ void* selfDeviceAddr = nullptr;
324- aclTensor* shape1Addr = nullptr;325+ void* shape1DeviceAddr = nullptr;
325- aclTensor* shape2Addr = nullptr;326+ void* shape2DeviceAddr = nullptr;
326 327 
327- std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};328+ aclTensor* self = nullptr;
328- std::vector<float> shape1HostData = {0, 1, 4, 5};329+ aclTensor* shape1Addr = nullptr;
329- std::vector<float> shape2HostData = {2, 3, 6, 7};330+ aclTensor* shape2Addr = nullptr;
330 331 
331- // 创建self aclTensor332+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
332- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);333+ std::vector<float> shape1HostData = {0, 1, 4, 5};
333- CHECK_RET(ret == ACL_SUCCESS, return ret);334+ std::vector<float> shape2HostData = {2, 3, 6, 7};
334 335 
335- ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);336+ // 创建self aclTensor
336- CHECK_RET(ret == ACL_SUCCESS, return ret);337+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
337- ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);338+ CHECK_RET(ret == ACL_SUCCESS, return ret);
338- CHECK_RET(ret == ACL_SUCCESS, return ret);
339 339 
340- // 创建out aclTensorList340+ ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);
341- std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};341+ CHECK_RET(ret == ACL_SUCCESS, return ret);
342- aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());342+ ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
343- CHECK_RET(out != nullptr, return ret);343+ CHECK_RET(ret == ACL_SUCCESS, return ret);
344 344 
345- // 调用CANN算子库API,需要修改为具体的Api名称345+ // 创建out aclTensorList
346- uint64_t workspaceSize = 0;346+ std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};
347- aclOpExecutor *executor;347+ aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());
348- // 调用aclnnSplitTensor第一段接口348+ CHECK_RET(out != nullptr, return ret);
349- ret = aclnnSplitTensorGetWorkspaceSize(self, splitSections, dim, out, &workspaceSize, &executor);
350- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
351- // 根据第一段接口计算出的workspaceSize申请device内存
352- void *workspaceAddr = nullptr;
353- if (workspaceSize > 0) {
354- auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
355- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
356- }
357- // 调用aclnnSplitTensor第二段接口
358- ret = aclnnSplitTensor(workspaceAddr, workspaceSize, executor, stream);
359- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensor failed. ERROR: %d\n", ret); return ret);
360 349 
361- ret = aclrtSynchronizeStream(stream);350+ // 调用CANN算子库API,需要修改为具体的Api名称
362- CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});351+ uint64_t workspaceSize = 0;
352+ aclOpExecutor* executor;
353+ // 调用aclnnSplitTensor第一段接口
354+ ret = aclnnSplitTensorGetWorkspaceSize(self, splitSections, dim, out, &workspaceSize, &executor);
355+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
356+ // 根据第一段接口计算出的workspaceSize申请device内存
357+ void* workspaceAddr = nullptr;
358+ if (workspaceSize > 0) {
359+ auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
360+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
361+ }
362+ // 调用aclnnSplitTensor第二段接口
363+ ret = aclnnSplitTensor(workspaceAddr, workspaceSize, executor, stream);
364+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensor failed. ERROR: %d\n", ret); return ret);
363 365 
364- // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改366+ ret = aclrtSynchronizeStream(stream);
365- aclDestroyTensor(self);367+ CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});
366- aclDestroyTensorList(out);
367- aclDestroyTensor(shape1Addr);
368- aclDestroyTensor(shape2Addr);
369 368 
370- // 7.释放device资源369+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
371- aclrtFree(selfDeviceAddr);370+ aclDestroyTensor(self);
372- aclrtFree(shape1DeviceAddr);371+ aclDestroyTensorList(out);
373- aclrtFree(shape2DeviceAddr);
374- if (workspaceSize > 0) {
375- aclrtFree(workspaceAddr);
376- }
377- aclrtDestroyStream(stream);
378- aclrtResetDevice(deviceId);
379- aclFinalize();
380 372 
381- return 0;373+ // 7. 释放device 资源
374+ aclrtFree(selfDeviceAddr);
375+ aclrtFree(shape1DeviceAddr);
376+ aclrtFree(shape2DeviceAddr);
377+ if (workspaceSize > 0) {
378+ aclrtFree(workspaceAddr);
379+ }
380+ aclrtDestroyStream(stream);
381+ aclrtResetDevice(deviceId);
382+ aclFinalize();
383+ 
384+ return 0;
382}385}
383```386```
@@ -233,154 +233,157 @@ aclnnStatus aclnnSplitWithSize(
233#include "aclnnop/aclnn_split_with_size.h"233#include "aclnnop/aclnn_split_with_size.h"
234 234 
235#define CHECK_RET(cond, return_expr) \235#define CHECK_RET(cond, return_expr) \
236- do { \236+ do { \
237- if (!(cond)) { \237+ if (!(cond)) { \
238- return_expr; \238+ return_expr; \
239- } \239+ } \
240- } while (0)240+ } while (0)
241 241 
242-#define LOG_PRINT(message, ...) \242+#define LOG_PRINT(message, ...) \
243- do { \243+ do { \
244- printf(message, ##__VA_ARGS__); \244+ printf(message, ##__VA_ARGS__); \
245- } while (0)245+ } while (0)
246 246 
247-int64_t GetShapeSize(const std::vector<int64_t>& shape) {247+int64_t GetShapeSize(const std::vector<int64_t>& shape)
248- int64_t shapeSize = 1;248+{
249- for (auto i : shape) {249+ int64_t shapeSize = 1;
250- shapeSize *= i;250+ for (auto i : shape) {
251- }251+ shapeSize *= i;
252- return shapeSize;252+ }
253+ return shapeSize;
253}254}
254 255 
255-int Init(int32_t deviceId, aclrtStream* stream) {256+int Init(int32_t deviceId, aclrtStream* stream)
256- // 固定写法,资源初始化257+{
257- auto ret = aclInit(nullptr);258+ // 固定写法,资源初始化
258- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);259+ auto ret = aclInit(nullptr);
259- ret = aclrtSetDevice(deviceId);260+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
260- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);261+ ret = aclrtSetDevice(deviceId);
261- ret = aclrtCreateStream(stream);262+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
262- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);263+ ret = aclrtCreateStream(stream);
263- return 0;264+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
265+ return 0;
264}266}
265 267 
266template <typename T>268template <typename T>
267int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,269int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
268- aclDataType dataType, aclTensor** tensor) {270+ aclDataType dataType, aclTensor** tensor)
269- auto size = GetShapeSize(shape) * sizeof(T);271+{
270- // 调用aclrtMalloc申请device侧内存272+ auto size = GetShapeSize(shape) * sizeof(T);
271- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);273+ // 调用aclrtMalloc申请device侧内存
272- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);274+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
273- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上275+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
274- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);276+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
275- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);277+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
278+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
276 279 
277- // 计算连续tensor的strides280+ // 计算连续tensor的strides
278- std::vector<int64_t> strides(shape.size(), 1);281+ std::vector<int64_t> strides(shape.size(), 1);
279- for (int64_t i = shape.size() - 2; i >= 0; i--) {282+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
280- strides[i] = shape[i + 1] * strides[i + 1];283+ strides[i] = shape[i + 1] * strides[i + 1];
281- }
282- 
283- // 调用aclCreateTensor接口创建aclTensor
284- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
285- shape.data(), shape.size(), *deviceAddr);
286- return 0;
287-}
288- 
289-void CheckResult(const std::vector<std::vector<int64_t>> &shapeList, const std::vector<void *> addrList) {
290- for (size_t i = 0; i < shapeList.size(); i++) {
291- auto size = GetShapeSize(shapeList[i]);
292- std::vector<float> resultData(size, 0);
293- auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
294- size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
295- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
296- for (int64_t j = 0; j < size; j++) {
297- LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
298 }284 }
299- }285+ 
286+ // 调用aclCreateTensor接口创建aclTensor
287+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
288+ shape.data(), shape.size(), *deviceAddr);
289+ return 0;
300}290}
301 291 
302-int main() {292+void CheckResult(const std::vector<std::vector<int64_t>>& shapeList, const std::vector<void*> addrList)
303- // 1.(固定写法)device/stream初始化,参考acl API手册293+{
304- // 根据自己的实际device填写deviceId294+ for (size_t i = 0; i < shapeList.size(); i++) {
305- int32_t deviceId = 0;295+ auto size = GetShapeSize(shapeList[i]);
306- aclrtStream stream;296+ std::vector<float> resultData(size, 0);
307- auto ret = Init(deviceId, &stream);297+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
308- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);298+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
299+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
300+ for (int64_t j = 0; j < size; j++) {
301+ LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
302+ }
303+ }
304+}
309 305 
310- // 2.构造输入与输出,需要根据API的接口自定义构造306+int main()
311- std::vector<int64_t> selfShape = {5, 2};307+{
312- std::vector<int64_t> shape1 = {1, 2};308+ // 1.(固定写法)device/stream初始化,参考acl API手册
313- std::vector<int64_t> shape2 = {4, 2};309+ // 根据自己的实际device填写deviceId
314- int64_t splitValue[] = {1, 4};310+ int32_t deviceId = 0;
315- int64_t dim = 0;311+ aclrtStream stream;
312+ auto ret = Init(deviceId, &stream);
313+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
316 314 
317- void* selfDeviceAddr = nullptr;315+ // 2. 构造输入与输出,需要根据API的接口自定义构造
318- void* shape1DeviceAddr = nullptr;316+ std::vector<int64_t> selfShape = {5, 2};
319- void* shape2DeviceAddr = nullptr;317+ std::vector<int64_t> shape1 = {1, 2};
318+ std::vector<int64_t> shape2 = {4, 2};
319+ int64_t splitValue[] = {1, 4};
320+ int64_t dim = 0;
320 321 
321- aclTensor* self = nullptr;322+ void* selfDeviceAddr = nullptr;
322- aclTensor* shape1Addr = nullptr;323+ void* shape1DeviceAddr = nullptr;
323- aclTensor* shape2Addr = nullptr;324+ void* shape2DeviceAddr = nullptr;
324- aclIntArray *splitSize = nullptr;
325 325 
326- std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};326+ aclTensor* self = nullptr;
327- std::vector<float> shape1HostData = {0, 5};327+ aclTensor* shape1Addr = nullptr;
328- std::vector<float> shape2HostData = {1, 2, 3, 4, 6, 7, 8, 9};328+ aclTensor* shape2Addr = nullptr;
329+ aclIntArray* splitSize = nullptr;
329 330 
330- // 创建self aclTensor331+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
331- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);332+ std::vector<float> shape1HostData = {0, 5};
332- CHECK_RET(ret == ACL_SUCCESS, return ret);333+ std::vector<float> shape2HostData = {1, 2, 3, 4, 6, 7, 8, 9};
333 334 
334- splitSize = aclCreateIntArray(splitValue, 2);335+ // 创建self aclTensor
335- CHECK_RET(splitSize != nullptr, return ret);336+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
337+ CHECK_RET(ret == ACL_SUCCESS, return ret);
336 338 
337- ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);339+ splitSize = aclCreateIntArray(splitValue, 2);
338- CHECK_RET(ret == ACL_SUCCESS, return ret);340+ CHECK_RET(splitSize != nullptr, return ret);
339- ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
340- CHECK_RET(ret == ACL_SUCCESS, return ret);
341 341 
342- // 创建out aclTensorList342+ ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);
343- std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};343+ CHECK_RET(ret == ACL_SUCCESS, return ret);
344- aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());344+ ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
345- CHECK_RET(out != nullptr, return ret);345+ CHECK_RET(ret == ACL_SUCCESS, return ret);
346 346 
347- // 调用CANN算子库API,需要修改为具体的Api名称347+ // 创建out aclTensorList
348- uint64_t workspaceSize = 0;348+ std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};
349- aclOpExecutor *executor;349+ aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());
350- // 调用aclnnSplitWithSize第一段接口350+ CHECK_RET(out != nullptr, return ret);
351- ret = aclnnSplitWithSizeGetWorkspaceSize(self, splitSize, dim, out, &workspaceSize, &executor);
352- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSizeGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
353- // 根据第一段接口计算出的workspaceSize申请device内存
354- void *workspaceAddr = nullptr;
355- if (workspaceSize > 0) {
356- auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
357- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
358- }
359- // 调用aclnnSplitWithSize第二段接口
360- ret = aclnnSplitWithSize(workspaceAddr, workspaceSize, executor, stream);
361- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSize failed. ERROR: %d\n", ret); return ret);
362 351 
363- ret = aclrtSynchronizeStream(stream);352+ // 调用CANN算子库API,需要修改为具体的Api名称
364- CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});353+ uint64_t workspaceSize = 0;
354+ aclOpExecutor* executor;
355+ // 调用aclnnSplitWithSize第一段接口
356+ ret = aclnnSplitWithSizeGetWorkspaceSize(self, splitSize, dim, out, &workspaceSize, &executor);
357+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSizeGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
358+ // 根据第一段接口计算出的workspaceSize申请device内存
359+ void* workspaceAddr = nullptr;
360+ if (workspaceSize > 0) {
361+ auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
362+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
363+ }
364+ // 调用aclnnSplitWithSize第二段接口
365+ ret = aclnnSplitWithSize(workspaceAddr, workspaceSize, executor, stream);
366+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSize failed. ERROR: %d\n", ret); return ret);
365 367 
366- // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改368+ ret = aclrtSynchronizeStream(stream);
367- aclDestroyTensor(self);369+ CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});
368- aclDestroyIntArray(splitSize);
369- aclDestroyTensorList(out);
370- aclDestroyTensor(shape1Addr);
371- aclDestroyTensor(shape2Addr);
372 370 
373- // 7.释放device资源371+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
374- aclrtFree(selfDeviceAddr);372+ aclDestroyTensor(self);
375- aclrtFree(shape1DeviceAddr);373+ aclDestroyIntArray(splitSize);
376- aclrtFree(shape2DeviceAddr);374+ aclDestroyTensorList(out);
377- if (workspaceSize > 0) {
378- aclrtFree(workspaceAddr);
379- }
380- aclrtDestroyStream(stream);
381- aclrtResetDevice(deviceId);
382- aclFinalize();
383 375 
384- return 0;376+ // 7. 释放device 资源
377+ aclrtFree(selfDeviceAddr);
378+ aclrtFree(shape1DeviceAddr);
379+ aclrtFree(shape2DeviceAddr);
380+ if (workspaceSize > 0) {
381+ aclrtFree(workspaceAddr);
382+ }
383+ aclrtDestroyStream(stream);
384+ aclrtResetDevice(deviceId);
385+ aclFinalize();
386+ 
387+ return 0;
385}388}
386```389```
@@ -16,148 +16,151 @@
16#include "aclnnop/aclnn_split_tensor.h"16#include "aclnnop/aclnn_split_tensor.h"
17 17 
18#define CHECK_RET(cond, return_expr) \18#define CHECK_RET(cond, return_expr) \
19- do { \19+ do { \
20- if (!(cond)) { \20+ if (!(cond)) { \
21- return_expr; \21+ return_expr; \
22- } \22+ } \
23- } while (0)23+ } while (0)
24 24 
25-#define LOG_PRINT(message, ...) \25+#define LOG_PRINT(message, ...) \
26- do { \26+ do { \
27- printf(message, ##__VA_ARGS__); \27+ printf(message, ##__VA_ARGS__); \
28- } while (0)28+ } while (0)
29 29 
30-int64_t GetShapeSize(const std::vector<int64_t>& shape) {30+int64_t GetShapeSize(const std::vector<int64_t>& shape)
31- int64_t shapeSize = 1;31+{
32- for (auto i : shape) {32+ int64_t shapeSize = 1;
33- shapeSize *= i;33+ for (auto i : shape) {
34- }34+ shapeSize *= i;
35- return shapeSize;35+ }
36+ return shapeSize;
36}37}
37 38 
38-int Init(int32_t deviceId, aclrtStream* stream) {39+int Init(int32_t deviceId, aclrtStream* stream)
39- // 固定写法,资源初始化40+{
40- auto ret = aclInit(nullptr);41+ // 固定写法,资源初始化
41- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);42+ auto ret = aclInit(nullptr);
42- ret = aclrtSetDevice(deviceId);43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
43- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);44+ ret = aclrtSetDevice(deviceId);
44- ret = aclrtCreateStream(stream);45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
45- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);46+ ret = aclrtCreateStream(stream);
46- return 0;47+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
48+ return 0;
47}49}
48 50 
49template <typename T>51template <typename T>
50int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,52int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51- aclDataType dataType, aclTensor** tensor) {53+ aclDataType dataType, aclTensor** tensor)
52- auto size = GetShapeSize(shape) * sizeof(T);54+{
53- // 调用aclrtMalloc申请device侧内存55+ auto size = GetShapeSize(shape) * sizeof(T);
54- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);56+ // 调用aclrtMalloc申请device侧内存
55- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);57+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上58+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);59+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);60+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
61+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
59 62 
60- // 计算连续tensor的strides63+ // 计算连续tensor的strides
61- std::vector<int64_t> strides(shape.size(), 1);64+ std::vector<int64_t> strides(shape.size(), 1);
62- for (int64_t i = shape.size() - 2; i >= 0; i--) {65+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
63- strides[i] = shape[i + 1] * strides[i + 1];66+ strides[i] = shape[i + 1] * strides[i + 1];
64- }
65- 
66- // 调用aclCreateTensor接口创建aclTensor
67- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
68- shape.data(), shape.size(), *deviceAddr);
69- return 0;
70-}
71- 
72-void CheckResult(const std::vector<std::vector<int64_t>> &shapeList, const std::vector<void *> addrList) {
73- for (size_t i = 0; i < shapeList.size(); i++) {
74- auto size = GetShapeSize(shapeList[i]);
75- std::vector<float> resultData(size, 0);
76- auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
77- size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
78- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
79- for (int64_t j = 0; j < size; j++) {
80- LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
81 }67 }
82- }68+ 
69+ // 调用aclCreateTensor接口创建aclTensor
70+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
71+ shape.data(), shape.size(), *deviceAddr);
72+ return 0;
83}73}
84 74 
85-int main() {75+void CheckResult(const std::vector<std::vector<int64_t>>& shapeList, const std::vector<void*> addrList)
86- // 1.(固定写法)device/stream初始化,参考acl API手册76+{
87- // 根据自己的实际device填写deviceId77+ for (size_t i = 0; i < shapeList.size(); i++) {
88- int32_t deviceId = 0;78+ auto size = GetShapeSize(shapeList[i]);
89- aclrtStream stream;79+ std::vector<float> resultData(size, 0);
90- auto ret = Init(deviceId, &stream);80+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
91- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);81+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
82+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
83+ for (int64_t j = 0; j < size; j++) {
84+ LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
85+ }
86+ }
87+}
92 88 
93- // 2. 构造输入与输出,需要根据API的接口自定义构造89+int main()
94- std::vector<int64_t> selfShape = {4, 2};90+{
95- std::vector<int64_t> shape1 = {2, 2};91+ // 1.(固定写法)device/stream初始化,参考acl API手册
96- std::vector<int64_t> shape2 = {2, 2};92+ // 根据自己的实际device填写deviceId
97- uint64_t splitSections = 2;93+ int32_t deviceId = 0;
98- int64_t dim = 0;94+ aclrtStream stream;
95+ auto ret = Init(deviceId, &stream);
96+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
99 97 
100- void* selfDeviceAddr = nullptr;98+ // 2. 构造输入与输出,需要根据API的接口自定义构造
101- void* shape1DeviceAddr = nullptr;99+ std::vector<int64_t> selfShape = {4, 2};
102- void* shape2DeviceAddr = nullptr;100+ std::vector<int64_t> shape1 = {2, 2};
101+ std::vector<int64_t> shape2 = {2, 2};
102+ uint64_t splitSections = 2;
103+ int64_t dim = 0;
103 104 
104- aclTensor* self = nullptr;105+ void* selfDeviceAddr = nullptr;
105- aclTensor* shape1Addr = nullptr;106+ void* shape1DeviceAddr = nullptr;
106- aclTensor* shape2Addr = nullptr;107+ void* shape2DeviceAddr = nullptr;
107 108 
108- std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};109+ aclTensor* self = nullptr;
109- std::vector<float> shape1HostData = {0, 1, 4, 5};110+ aclTensor* shape1Addr = nullptr;
110- std::vector<float> shape2HostData = {2, 3, 6, 7};111+ aclTensor* shape2Addr = nullptr;
111 112 
112- // 创建self aclTensor113+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
113- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);114+ std::vector<float> shape1HostData = {0, 1, 4, 5};
114- CHECK_RET(ret == ACL_SUCCESS, return ret);115+ std::vector<float> shape2HostData = {2, 3, 6, 7};
115 116 
116- ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);117+ // 创建self aclTensor
117- CHECK_RET(ret == ACL_SUCCESS, return ret);118+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
118- ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);119+ CHECK_RET(ret == ACL_SUCCESS, return ret);
119- CHECK_RET(ret == ACL_SUCCESS, return ret);
120 120 
121- // 创建out aclTensorList121+ ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);
122- std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};122+ CHECK_RET(ret == ACL_SUCCESS, return ret);
123- aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());123+ ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
124- CHECK_RET(out != nullptr, return ret);124+ CHECK_RET(ret == ACL_SUCCESS, return ret);
125 125 
126- // 调用CANN算子库API,需要修改为具体的Api名称126+ // 创建out aclTensorList
127- uint64_t workspaceSize = 0;127+ std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};
128- aclOpExecutor *executor;128+ aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());
129- // 调用aclnnSplitTensor第一段接口129+ CHECK_RET(out != nullptr, return ret);
130- ret = aclnnSplitTensorGetWorkspaceSize(self, splitSections, dim, out, &workspaceSize, &executor);
131- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
132- // 根据第一段接口计算出的workspaceSize申请device内存
133- void *workspaceAddr = nullptr;
134- if (workspaceSize > 0) {
135- auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
136- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
137- }
138- // 调用aclnnSplitTensor第二段接口
139- ret = aclnnSplitTensor(workspaceAddr, workspaceSize, executor, stream);
140- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensor failed. ERROR: %d\n", ret); return ret);
141 130 
142- ret = aclrtSynchronizeStream(stream);131+ // 调用CANN算子库API,需要修改为具体的Api名称
143- CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});132+ uint64_t workspaceSize = 0;
133+ aclOpExecutor* executor;
134+ // 调用aclnnSplitTensor第一段接口
135+ ret = aclnnSplitTensorGetWorkspaceSize(self, splitSections, dim, out, &workspaceSize, &executor);
136+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
137+ // 根据第一段接口计算出的workspaceSize申请device内存
138+ void* workspaceAddr = nullptr;
139+ if (workspaceSize > 0) {
140+ auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
141+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
142+ }
143+ // 调用aclnnSplitTensor第二段接口
144+ ret = aclnnSplitTensor(workspaceAddr, workspaceSize, executor, stream);
145+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitTensor failed. ERROR: %d\n", ret); return ret);
144 146 
145- // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改147+ ret = aclrtSynchronizeStream(stream);
146- aclDestroyTensor(self);148+ CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});
147- aclDestroyTensorList(out);
148- aclDestroyTensor(shape1Addr);
149- aclDestroyTensor(shape2Addr);
150 149 
151- // 7. 释放device 资源150+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
152- aclrtFree(selfDeviceAddr);151+ aclDestroyTensor(self);
153- aclrtFree(shape1DeviceAddr);152+ aclDestroyTensorList(out);
154- aclrtFree(shape2DeviceAddr);
155- if (workspaceSize > 0) {
156- aclrtFree(workspaceAddr);
157- }
158- aclrtDestroyStream(stream);
159- aclrtResetDevice(deviceId);
160- aclFinalize();
161 153 
162- return 0;154+ // 7. 释放device 资源
155+ aclrtFree(selfDeviceAddr);
156+ aclrtFree(shape1DeviceAddr);
157+ aclrtFree(shape2DeviceAddr);
158+ if (workspaceSize > 0) {
159+ aclrtFree(workspaceAddr);
160+ }
161+ aclrtDestroyStream(stream);
162+ aclrtResetDevice(deviceId);
163+ aclFinalize();
164+ 
165+ return 0;
163}166}
@@ -16,153 +16,156 @@
16#include "aclnnop/aclnn_split_with_size.h"16#include "aclnnop/aclnn_split_with_size.h"
17 17 
18#define CHECK_RET(cond, return_expr) \18#define CHECK_RET(cond, return_expr) \
19- do { \19+ do { \
20- if (!(cond)) { \20+ if (!(cond)) { \
21- return_expr; \21+ return_expr; \
22- } \22+ } \
23- } while (0)23+ } while (0)
24 24 
25-#define LOG_PRINT(message, ...) \25+#define LOG_PRINT(message, ...) \
26- do { \26+ do { \
27- printf(message, ##__VA_ARGS__); \27+ printf(message, ##__VA_ARGS__); \
28- } while (0)28+ } while (0)
29 29 
30-int64_t GetShapeSize(const std::vector<int64_t>& shape) {30+int64_t GetShapeSize(const std::vector<int64_t>& shape)
31- int64_t shapeSize = 1;31+{
32- for (auto i : shape) {32+ int64_t shapeSize = 1;
33- shapeSize *= i;33+ for (auto i : shape) {
34- }34+ shapeSize *= i;
35- return shapeSize;35+ }
36+ return shapeSize;
36}37}
37 38 
38-int Init(int32_t deviceId, aclrtStream* stream) {39+int Init(int32_t deviceId, aclrtStream* stream)
39- // 固定写法,资源初始化40+{
40- auto ret = aclInit(nullptr);41+ // 固定写法,资源初始化
41- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);42+ auto ret = aclInit(nullptr);
42- ret = aclrtSetDevice(deviceId);43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
43- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);44+ ret = aclrtSetDevice(deviceId);
44- ret = aclrtCreateStream(stream);45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
45- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);46+ ret = aclrtCreateStream(stream);
46- return 0;47+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
48+ return 0;
47}49}
48 50 
49template <typename T>51template <typename T>
50int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,52int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51- aclDataType dataType, aclTensor** tensor) {53+ aclDataType dataType, aclTensor** tensor)
52- auto size = GetShapeSize(shape) * sizeof(T);54+{
53- // 调用aclrtMalloc申请device侧内存55+ auto size = GetShapeSize(shape) * sizeof(T);
54- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);56+ // 调用aclrtMalloc申请device侧内存
55- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);57+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上58+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);59+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);60+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
61+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
59 62 
60- // 计算连续tensor的strides63+ // 计算连续tensor的strides
61- std::vector<int64_t> strides(shape.size(), 1);64+ std::vector<int64_t> strides(shape.size(), 1);
62- for (int64_t i = shape.size() - 2; i >= 0; i--) {65+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
63- strides[i] = shape[i + 1] * strides[i + 1];66+ strides[i] = shape[i + 1] * strides[i + 1];
64- }
65- 
66- // 调用aclCreateTensor接口创建aclTensor
67- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
68- shape.data(), shape.size(), *deviceAddr);
69- return 0;
70-}
71- 
72-void CheckResult(const std::vector<std::vector<int64_t>> &shapeList, const std::vector<void *> addrList) {
73- for (size_t i = 0; i < shapeList.size(); i++) {
74- auto size = GetShapeSize(shapeList[i]);
75- std::vector<float> resultData(size, 0);
76- auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
77- size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
78- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
79- for (int64_t j = 0; j < size; j++) {
80- LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
81 }67 }
82- }68+ 
69+ // 调用aclCreateTensor接口创建aclTensor
70+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
71+ shape.data(), shape.size(), *deviceAddr);
72+ return 0;
83}73}
84 74 
85-int main() {75+void CheckResult(const std::vector<std::vector<int64_t>>& shapeList, const std::vector<void*> addrList)
86- // 1.(固定写法)device/stream初始化,参考acl API手册76+{
87- // 根据自己的实际device填写deviceId77+ for (size_t i = 0; i < shapeList.size(); i++) {
88- int32_t deviceId = 0;78+ auto size = GetShapeSize(shapeList[i]);
89- aclrtStream stream;79+ std::vector<float> resultData(size, 0);
90- auto ret = Init(deviceId, &stream);80+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), addrList[i],
91- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);81+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
82+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return);
83+ for (int64_t j = 0; j < size; j++) {
84+ LOG_PRINT("result[%ld] is: %f\n", j, resultData[j]);
85+ }
86+ }
87+}
92 88 
93- // 2. 构造输入与输出,需要根据API的接口自定义构造89+int main()
94- std::vector<int64_t> selfShape = {5, 2};90+{
95- std::vector<int64_t> shape1 = {1, 2};91+ // 1.(固定写法)device/stream初始化,参考acl API手册
96- std::vector<int64_t> shape2 = {4, 2};92+ // 根据自己的实际device填写deviceId
97- int64_t splitValue[] = {1, 4};93+ int32_t deviceId = 0;
98- int64_t dim = 0;94+ aclrtStream stream;
95+ auto ret = Init(deviceId, &stream);
96+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
99 97 
100- void* selfDeviceAddr = nullptr;98+ // 2. 构造输入与输出,需要根据API的接口自定义构造
101- void* shape1DeviceAddr = nullptr;99+ std::vector<int64_t> selfShape = {5, 2};
102- void* shape2DeviceAddr = nullptr;100+ std::vector<int64_t> shape1 = {1, 2};
101+ std::vector<int64_t> shape2 = {4, 2};
102+ int64_t splitValue[] = {1, 4};
103+ int64_t dim = 0;
103 104 
104- aclTensor* self = nullptr;105+ void* selfDeviceAddr = nullptr;
105- aclTensor* shape1Addr = nullptr;106+ void* shape1DeviceAddr = nullptr;
106- aclTensor* shape2Addr = nullptr;107+ void* shape2DeviceAddr = nullptr;
107- aclIntArray *splitSize = nullptr;
108 108 
109- std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};109+ aclTensor* self = nullptr;
110- std::vector<float> shape1HostData = {0, 5};110+ aclTensor* shape1Addr = nullptr;
111- std::vector<float> shape2HostData = {1, 2, 3, 4, 6, 7, 8, 9};111+ aclTensor* shape2Addr = nullptr;
112+ aclIntArray* splitSize = nullptr;
112 113 
113- // 创建self aclTensor114+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
114- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);115+ std::vector<float> shape1HostData = {0, 5};
115- CHECK_RET(ret == ACL_SUCCESS, return ret);116+ std::vector<float> shape2HostData = {1, 2, 3, 4, 6, 7, 8, 9};
116 117 
117- splitSize = aclCreateIntArray(splitValue, 2);118+ // 创建self aclTensor
118- CHECK_RET(splitSize != nullptr, return ret);119+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
120+ CHECK_RET(ret == ACL_SUCCESS, return ret);
119 121 
120- ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);122+ splitSize = aclCreateIntArray(splitValue, 2);
121- CHECK_RET(ret == ACL_SUCCESS, return ret);123+ CHECK_RET(splitSize != nullptr, return ret);
122- ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
123- CHECK_RET(ret == ACL_SUCCESS, return ret);
124 124 
125- // 创建out aclTensorList125+ ret = CreateAclTensor(shape1HostData, shape1, &shape1DeviceAddr, aclDataType::ACL_FLOAT, &shape1Addr);
126- std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};126+ CHECK_RET(ret == ACL_SUCCESS, return ret);
127- aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());127+ ret = CreateAclTensor(shape2HostData, shape2, &shape2DeviceAddr, aclDataType::ACL_FLOAT, &shape2Addr);
128- CHECK_RET(out != nullptr, return ret);128+ CHECK_RET(ret == ACL_SUCCESS, return ret);
129 129 
130- // 调用CANN算子库API,需要修改为具体的Api名称130+ // 创建out aclTensorList
131- uint64_t workspaceSize = 0;131+ std::vector<aclTensor*> tmp = {shape1Addr, shape2Addr};
132- aclOpExecutor *executor;132+ aclTensorList* out = aclCreateTensorList(tmp.data(), tmp.size());
133- // 调用aclnnSplitWithSize第一段接口133+ CHECK_RET(out != nullptr, return ret);
134- ret = aclnnSplitWithSizeGetWorkspaceSize(self, splitSize, dim, out, &workspaceSize, &executor);
135- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSizeGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
136- // 根据第一段接口计算出的workspaceSize申请device内存
137- void *workspaceAddr = nullptr;
138- if (workspaceSize > 0) {
139- auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
140- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
141- }
142- // 调用aclnnSplitWithSize第二段接口
143- ret = aclnnSplitWithSize(workspaceAddr, workspaceSize, executor, stream);
144- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSize failed. ERROR: %d\n", ret); return ret);
145 134 
146- ret = aclrtSynchronizeStream(stream);135+ // 调用CANN算子库API,需要修改为具体的Api名称
147- CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});136+ uint64_t workspaceSize = 0;
137+ aclOpExecutor* executor;
138+ // 调用aclnnSplitWithSize第一段接口
139+ ret = aclnnSplitWithSizeGetWorkspaceSize(self, splitSize, dim, out, &workspaceSize, &executor);
140+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSizeGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
141+ // 根据第一段接口计算出的workspaceSize申请device内存
142+ void* workspaceAddr = nullptr;
143+ if (workspaceSize > 0) {
144+ auto ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
145+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
146+ }
147+ // 调用aclnnSplitWithSize第二段接口
148+ ret = aclnnSplitWithSize(workspaceAddr, workspaceSize, executor, stream);
149+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSplitWithSize failed. ERROR: %d\n", ret); return ret);
148 150 
149- // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改151+ ret = aclrtSynchronizeStream(stream);
150- aclDestroyTensor(self);152+ CheckResult({shape1, shape2}, {shape1DeviceAddr, shape2DeviceAddr});
151- aclDestroyIntArray(splitSize);
152- aclDestroyTensorList(out);
153- aclDestroyTensor(shape1Addr);
154- aclDestroyTensor(shape2Addr);
155 153 
156- // 7. 释放device 资源154+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
157- aclrtFree(selfDeviceAddr);155+ aclDestroyTensor(self);
158- aclrtFree(shape1DeviceAddr);156+ aclDestroyIntArray(splitSize);
159- aclrtFree(shape2DeviceAddr);157+ aclDestroyTensorList(out);
160- if (workspaceSize > 0) {
161- aclrtFree(workspaceAddr);
162- }
163- aclrtDestroyStream(stream);
164- aclrtResetDevice(deviceId);
165- aclFinalize();
166 158 
167- return 0;159+ // 7. 释放device 资源
160+ aclrtFree(selfDeviceAddr);
161+ aclrtFree(shape1DeviceAddr);
162+ aclrtFree(shape2DeviceAddr);
163+ if (workspaceSize > 0) {
164+ aclrtFree(workspaceAddr);
165+ }
166+ aclrtDestroyStream(stream);
167+ aclrtResetDevice(deviceId);
168+ aclFinalize();
169+ 
170+ return 0;
168}171}
@@ -25,7 +25,6 @@
25#include "opdev/tensor_view_utils.h"25#include "opdev/tensor_view_utils.h"
26#include "op_api/aclnn_check.h"26#include "op_api/aclnn_check.h"
27 27 
28- 
29using namespace op;28using namespace op;
30#ifdef __cplusplus29#ifdef __cplusplus
31extern "C" {30extern "C" {
@@ -37,255 +36,268 @@ constexpr int64_t SPLIT_LOOP_SIZE_512 = 512;
37 36 
38// 根据API定义,需要列出所能支持的所有dtype37// 根据API定义,需要列出所能支持的所有dtype
39static const std::initializer_list<DataType> DTYPE_SUPPORT_LIST = {38static const std::initializer_list<DataType> DTYPE_SUPPORT_LIST = {
40- DataType::DT_DOUBLE, DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16,39+ DataType::DT_DOUBLE, DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16,
41- DataType::DT_INT64, DataType::DT_INT32, DataType::DT_INT16, DataType::DT_INT8,40+ DataType::DT_INT64, DataType::DT_INT32, DataType::DT_INT16, DataType::DT_INT8,
42- DataType::DT_UINT8, DataType::DT_BOOL, DataType::DT_COMPLEX128, DataType::DT_COMPLEX64};41+ DataType::DT_UINT8, DataType::DT_BOOL, DataType::DT_COMPLEX128, DataType::DT_COMPLEX64};
43 42 
44static const std::initializer_list<DataType> DTYPE_SUPPORT_LIST_950 = {43static const std::initializer_list<DataType> DTYPE_SUPPORT_LIST_950 = {
45- DataType::DT_DOUBLE, DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16,44+ DataType::DT_DOUBLE, DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16, DataType::DT_INT64,
46- DataType::DT_INT64, DataType::DT_UINT64, DataType::DT_INT32, DataType::DT_UINT32, 45+ DataType::DT_UINT64, DataType::DT_INT32, DataType::DT_UINT32, DataType::DT_INT16, DataType::DT_UINT16,
47- DataType::DT_INT16, DataType::DT_UINT16, DataType::DT_INT8, DataType::DT_UINT8,46+ DataType::DT_INT8, DataType::DT_UINT8, DataType::DT_BOOL, DataType::DT_COMPLEX128, DataType::DT_COMPLEX64};
48- DataType::DT_BOOL, DataType::DT_COMPLEX128, DataType::DT_COMPLEX64};
49 47 
50-inline static bool CheckNotNull(const aclTensor *self, const aclTensorList *out) {48+inline static bool CheckNotNull(const aclTensor* self, const aclTensorList* out)
51- OP_CHECK_NULL(self, return false);49+{
52- OP_CHECK_NULL(out, return false);50+ OP_CHECK_NULL(self, return false);
53- return true;51+ OP_CHECK_NULL(out, return false);
52+ return true;
54}53}
55 54 
56-inline static bool CheckDtypeValid(const aclTensor *self, const aclTensorList *out) {55+inline static bool CheckDtypeValid(const aclTensor* self, const aclTensorList* out)
57- if (IsRegBase()) {56+{
58- OP_CHECK_DTYPE_NOT_SUPPORT(self, DTYPE_SUPPORT_LIST_950, return false);57+ if (IsRegBase()) {
59- // 检查每一个输出tensor的数据类型是否在API支持列表内58+ OP_CHECK_DTYPE_NOT_SUPPORT(self, DTYPE_SUPPORT_LIST_950, return false);
60- for (size_t index = 0; index < out->Size(); index++) {59+ // 检查每一个输出tensor的数据类型是否在API支持列表内
61- OP_CHECK_DTYPE_NOT_SUPPORT((*out)[index], DTYPE_SUPPORT_LIST_950, return false);60+ for (size_t index = 0; index < out->Size(); index++) {
61+ OP_CHECK_DTYPE_NOT_SUPPORT((*out)[index], DTYPE_SUPPORT_LIST_950, return false);
62+ }
63+ } else {
64+ OP_CHECK_DTYPE_NOT_SUPPORT(self, DTYPE_SUPPORT_LIST, return false);
65+ // 检查每一个输出tensor的数据类型是否在API支持列表内
66+ for (size_t index = 0; index < out->Size(); index++) {
67+ OP_CHECK_DTYPE_NOT_SUPPORT((*out)[index], DTYPE_SUPPORT_LIST, return false);
68+ }
69+ }
70+ // 检查所有输出tensor的数据类型是否一致
71+ if (out->Size() >= 2) {
72+ for (size_t index = 1; index < out->Size(); index++) {
73+ OP_CHECK_DTYPE_NOT_SAME((*out)[0], (*out)[index], return false);
74+ }
62 }75 }
63 return true;76 return true;
64- }
65- OP_CHECK_DTYPE_NOT_SUPPORT(self, DTYPE_SUPPORT_LIST, return false);
66- // 检查每一个输出tensor的数据类型是否在API支持列表内
67- for (size_t index = 0; index < out->Size(); index++) {
68- OP_CHECK_DTYPE_NOT_SUPPORT((*out)[index], DTYPE_SUPPORT_LIST, return false);
69- }
70- return true;
71}77}
72 78 
73-static bool CheckShape(const aclTensor *self, uint64_t splitSections, int64_t dim, const aclTensorList *out) {79+static bool CheckShape(const aclTensor* self, uint64_t splitSections, int64_t dim, const aclTensorList* out)
74- // 校验输入的长度80+{
75- OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false);81+ // 校验输入的长度
76- OP_CHECK_MIN_DIM(self, 1, return false);82+ OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false);
77- // 校验每一个输出的长度83+ OP_CHECK_MIN_DIM(self, 1, return false);
78- for (size_t index = 0; index < out->Size(); index++) {84+ // 校验每一个输出的长度
79- OP_CHECK_MAX_DIM((*out)[index], MAX_DIM_LEN, return false);85+ for (size_t index = 0; index < out->Size(); index++) {
80- }86+ OP_CHECK_MAX_DIM((*out)[index], MAX_DIM_LEN, return false);
81- // 校验输入self与dim间关系87+ }
82- int64_t selfDim = static_cast<int64_t>(self->GetViewShape().GetDimNum());88+ // 校验输入self与dim间关系
83- if ((dim >= 0 && dim >= selfDim) || (dim < 0 && dim < -selfDim)) {89+ int64_t selfDim = static_cast<int64_t>(self->GetViewShape().GetDimNum());
84- OP_LOGE(ACLNN_ERR_PARAM_NULLPTR,90+ if ((dim >= 0 && dim >= selfDim) || (dim < 0 && dim < -selfDim)) {
85- "Expected aclnnSplitTensor dim value [%ld] to be in range [%ld, %ld) but check failed.",91+ OP_LOGE(ACLNN_ERR_PARAM_NULLPTR,
86- dim, -selfDim, selfDim);92+ "Expected aclnnSplitTensor dim value [%ld] to be in range [%ld, %ld) but check failed.", dim, -selfDim,
87- return false;93+ selfDim);
88- }94+ return false;
89- size_t dimIndex = dim >= 0 ? static_cast<size_t>(dim) : static_cast<size_t>(dim + selfDim);95+ }
90- int64_t splitShape = self->GetViewShape().GetDim(dimIndex);96+ size_t dimIndex = dim >= 0 ? static_cast<size_t>(dim) : static_cast<size_t>(dim + selfDim);
91- if (splitShape != 0 && splitSections == 0) {97+ int64_t splitShape = self->GetViewShape().GetDim(dimIndex);
92- OP_LOGE(ACLNN_ERR_PARAM_NULLPTR,98+ if (splitShape != 0 && splitSections == 0) {
99+ OP_LOGE(
100+ ACLNN_ERR_PARAM_NULLPTR,
93 "Expected aclnnSplitTensor splitSections to not be zero while split dim size is not zero but got [%lu].",101 "Expected aclnnSplitTensor splitSections to not be zero while split dim size is not zero but got [%lu].",
94 splitSections);102 splitSections);
95- return false;103+ return false;
96- }
97- if (splitShape == 0 && splitSections != 0) {
98- OP_LOGE(ACLNN_ERR_PARAM_NULLPTR,
99- "Expected aclnnSplitTensor splitSections to be zero while split dim size is zero but got [%lu].",
100- splitSections);
101- return false;
102- }
103- return true;
104-}
105- 
106-inline static aclnnStatus CheckParams(const aclTensor *self, uint64_t splitSections, int64_t dim,
107- const aclTensorList *out) {
108- // 1. 检查参数是否为空指针
109- CHECK_RET(CheckNotNull(self, out), ACLNN_ERR_PARAM_NULLPTR);
110- 
111- // 2. 检查输入与输出的数据类型是否在API支持的数据类型范围之内
112- CHECK_RET(CheckDtypeValid(self, out), ACLNN_ERR_PARAM_INVALID);
113- 
114- // 3. 检查输入输出的shape支持能力
115- CHECK_RET(CheckShape(self, splitSections, dim, out), ACLNN_ERR_PARAM_INVALID);
116- 
117- return ACLNN_SUCCESS;
118-}
119- 
120-inline static aclnnStatus SplitZeroCalculation(const aclTensor *self, aclTensorList *out, aclOpExecutor *executor) {
121- auto selfCast = l0op::Cast(self, (*out)[0]->GetDataType(), executor);
122- CHECK_RET(selfCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
123- auto selfViewCopy = l0op::ViewCopy(selfCast, (*out)[0], executor);
124- CHECK_RET(selfViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
125- return ACLNN_SUCCESS;
126-}
127- 
128-static aclnnStatus SplitOnceCalculation(const aclTensor *self, const aclIntArray *splitSize, int64_t dim,
129- aclTensorList *out, aclOpExecutor *executor) {
130- // 调用SplitV算子
131- auto splitRes = l0op::SplitV(self, splitSize, dim, executor);
132- // 循环调用Cast和ViewCopy
133- if ((splitRes == nullptr) || (splitSize->Size() > out->Size()) || (splitSize->Size() > splitRes->Size())) {
134- OP_LOGE(ACLNN_ERR_PARAM_INVALID,
135- "Index value exceeds the out size range, splitSize->Size=%lu, splitRes->Size=%lu, out->Size=%lu",
136- splitSize->Size(), splitRes->Size(), out->Size());
137- return ACLNN_ERR_PARAM_INVALID;
138- }
139- for (size_t index = 0; index < splitSize->Size(); index++) {
140- CHECK_RET(CheckShapeAndScalarSame((*splitRes)[index], (*out)[index]), ACLNN_ERR_PARAM_INVALID);
141- auto splitCast = l0op::Cast((*splitRes)[index], (*out)[index]->GetDataType(), executor);
142- CHECK_RET(splitCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
143- auto splitViewCopy = l0op::ViewCopy(splitCast, (*out)[index], executor);
144- CHECK_RET(splitViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
145- }
146- return ACLNN_SUCCESS;
147-}
148- 
149-static aclnnStatus SplitLoopCalculation(const aclTensor *self, const aclIntArray *splitSize, int64_t dim,
150- aclTensorList *out, aclOpExecutor *executor) {
151- const int64_t numSplit = splitSize->Size();
152- const int64_t splitLoopSize = (!IsRegBase()) ?
153- SPLIT_LOOP_SIZE : SPLIT_LOOP_SIZE_512;
154- const int64_t loopSize = (numSplit + splitLoopSize - 1) / splitLoopSize;
155- const int64_t lastSize = (numSplit % splitLoopSize == 0) ? splitLoopSize : numSplit % splitLoopSize;
156- // 1. 根据loopSize和lastSize, 将splitSize构造为新的SplitSize
157- op::Shape selfShape = self->GetViewShape();
158- const size_t selfDim = selfShape.GetDimNum();
159- FVector<int64_t> newSplitSize;
160- FVector<aclIntArray *> splitList;
161- 
162- for (int64_t loopIndex = 0; loopIndex < loopSize; loopIndex++) {
163- int64_t newSplit = 0;
164- FVector<int64_t> chunkVector;
165- int64_t currentSplitValue = 0;
166- if (loopIndex != loopSize - 1) {
167- for (int64_t noLastIndex = 0; noLastIndex < splitLoopSize; noLastIndex++) {
168- currentSplitValue = *(splitSize->GetData() + loopIndex * splitLoopSize + noLastIndex);
169- chunkVector.emplace_back(currentSplitValue);
170- newSplit += currentSplitValue;
171- }
172- } else {
173- for (int64_t lastIndex = 0; lastIndex < lastSize; lastIndex++) {
174- currentSplitValue = *(splitSize->GetData() + loopIndex * splitLoopSize + lastIndex);
175- chunkVector.emplace_back(currentSplitValue);
176- newSplit += currentSplitValue;
177- }
178 }104 }
179- splitList.emplace_back(executor->AllocIntArray(chunkVector.data(), chunkVector.size()));105+ if (splitShape == 0 && splitSections != 0) {
180- newSplitSize.emplace_back(newSplit);106+ OP_LOGE(ACLNN_ERR_PARAM_NULLPTR,
181- }107+ "Expected aclnnSplitTensor splitSections to be zero while split dim size is zero but got [%lu].",
182- 108+ splitSections);
183- // 2. 循环调用Slice将self切成N个大块, 并对每个大块使用SplitV再次切分109+ return false;
184- FVector<const aclTensor *> splitTensorList;
185- int64_t offsetValue = 0;
186- for (size_t sliceIndex = 0; sliceIndex < newSplitSize.size(); sliceIndex++) {
187- // 计算offset, offset逐块递增
188- FVector<int64_t> offsetVector(selfDim, 0);
189- offsetValue += sliceIndex == 0 ? 0 : newSplitSize[sliceIndex - 1];
190- offsetVector[static_cast<size_t>(dim)] = offsetValue;
191- aclIntArray *offsetArray = executor->AllocIntArray(offsetVector.data(), offsetVector.size());
192- 
193- // 计算size, size与输出块大小保持一致
194- FVector<int64_t> sizeVector;
195- for (size_t selfIndex = 0; selfIndex < selfDim; selfIndex++) {
196- int64_t sizeValue =
197- selfIndex == static_cast<size_t>(dim) ? newSplitSize[sliceIndex] : selfShape.GetDim(selfIndex);
198- sizeVector.emplace_back(sizeValue);
199 }110 }
200- aclIntArray *sizeArray = executor->AllocIntArray(sizeVector.data(), sizeVector.size());111+ return true;
112+}
201 113 
202- // 调用l0op::Slice对每一块进行处理114+inline static aclnnStatus CheckParams(const aclTensor* self, uint64_t splitSections, int64_t dim,
203- auto sliceRes = l0op::Slice(self, offsetArray, sizeArray, executor);115+ const aclTensorList* out)
204- CHECK_RET(sliceRes != nullptr, ACLNN_ERR_INNER_NULLPTR);116+{
117+ // 1. 检查参数是否为空指针
118+ CHECK_RET(CheckNotNull(self, out), ACLNN_ERR_PARAM_NULLPTR);
205 119 
206- // 调用l0op::SPlitV将sliceRes进行切分120+ // 2. 检查输入与输出的数据类型是否在API支持的数据类型范围之内
207- auto splitRes = l0op::SplitV(sliceRes, splitList[sliceIndex], dim, executor);121+ CHECK_RET(CheckDtypeValid(self, out), ACLNN_ERR_PARAM_INVALID);
208- CHECK_RET(splitRes != nullptr, ACLNN_ERR_INNER_NULLPTR);122+ 
209- for (int64_t resIndex = 0; resIndex < static_cast<int64_t>(splitRes->Size()); resIndex++) {123+ // 3. 检查输入输出的shape支持能力
210- if ((resIndex + sliceIndex * splitLoopSize) >= out->Size()) {124+ CHECK_RET(CheckShape(self, splitSections, dim, out), ACLNN_ERR_PARAM_INVALID);
125+ 
126+ return ACLNN_SUCCESS;
127+}
128+ 
129+inline static aclnnStatus SplitZeroCalculation(const aclTensor* self, aclTensorList* out, aclOpExecutor* executor)
130+{
131+ auto selfCast = l0op::Cast(self, (*out)[0]->GetDataType(), executor);
132+ CHECK_RET(selfCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
133+ auto selfViewCopy = l0op::ViewCopy(selfCast, (*out)[0], executor);
134+ CHECK_RET(selfViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
135+ return ACLNN_SUCCESS;
136+}
137+ 
138+static aclnnStatus SplitOnceCalculation(const aclTensor* self, const aclIntArray* splitSize, int64_t dim,
139+ aclTensorList* out, aclOpExecutor* executor)
140+{
141+ // 调用SplitV算子
142+ auto splitRes = l0op::SplitV(self, splitSize, dim, executor);
143+ // 循环调用Cast和ViewCopy
144+ if ((splitRes == nullptr) || (splitSize->Size() > out->Size()) || (splitSize->Size() > splitRes->Size())) {
211 OP_LOGE(ACLNN_ERR_PARAM_INVALID,145 OP_LOGE(ACLNN_ERR_PARAM_INVALID,
212- "Index value exceeds the out size range, resIndex=%ld, sliceIndex=%zu, out->Size=%lu",146+ "Index value exceeds the out size range, splitSize->Size=%lu, splitRes->Size=%lu, out->Size=%lu",
213- resIndex, sliceIndex, out->Size());147+ splitSize->Size(), splitRes->Size(), out->Size());
214 return ACLNN_ERR_PARAM_INVALID;148 return ACLNN_ERR_PARAM_INVALID;
215- }
216- auto splitCast = l0op::Cast((*splitRes)[resIndex], (*out)[resIndex + sliceIndex * splitLoopSize]->GetDataType(),
217- executor);
218- CHECK_RET(splitCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
219- auto splitViewCopy = l0op::ViewCopy(splitCast, (*out)[resIndex + sliceIndex * splitLoopSize], executor);
220- CHECK_RET(splitViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
221 }149 }
222- }150+ for (size_t index = 0; index < splitSize->Size(); index++) {
223- return ACLNN_SUCCESS;151+ CHECK_RET(CheckShapeAndScalarSame((*splitRes)[index], (*out)[index]), ACLNN_ERR_PARAM_INVALID);
152+ auto splitCast = l0op::Cast((*splitRes)[index], (*out)[index]->GetDataType(), executor);
153+ CHECK_RET(splitCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
154+ auto splitViewCopy = l0op::ViewCopy(splitCast, (*out)[index], executor);
155+ CHECK_RET(splitViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
156+ }
157+ return ACLNN_SUCCESS;
224}158}
225 159 
226-aclnnStatus aclnnSplitTensorGetWorkspaceSize(const aclTensor *self, uint64_t splitSections, int64_t dim,160+static aclnnStatus SplitLoopCalculation(const aclTensor* self, const aclIntArray* splitSize, int64_t dim,
227- aclTensorList *out, uint64_t *workspaceSize, aclOpExecutor **executor) {161+ aclTensorList* out, aclOpExecutor* executor)
228- L2_DFX_PHASE_1(aclnnSplitTensor, DFX_IN(self, splitSections, dim), DFX_OUT(out));162+{
163+ const int64_t numSplit = splitSize->Size();
164+ const int64_t splitLoopSize = (!IsRegBase()) ? SPLIT_LOOP_SIZE : SPLIT_LOOP_SIZE_512;
165+ const int64_t loopSize = (numSplit + splitLoopSize - 1) / splitLoopSize;
166+ const int64_t lastSize = (numSplit % splitLoopSize == 0) ? splitLoopSize : numSplit % splitLoopSize;
167+ // 1. 根据loopSize和lastSize, 将splitSize构造为新的SplitSize
168+ op::Shape selfShape = self->GetViewShape();
169+ const size_t selfDim = selfShape.GetDimNum();
170+ FVector<int64_t> newSplitSize;
171+ FVector<aclIntArray*> splitList;
229 172 
230- // 固定写法,创建OpExecutor173+ for (int64_t loopIndex = 0; loopIndex < loopSize; loopIndex++) {
231- auto uniqueExecutor = CREATE_EXECUTOR();174+ int64_t newSplit = 0;
232- CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);175+ FVector<int64_t> chunkVector;
176+ int64_t currentSplitValue = 0;
177+ if (loopIndex != loopSize - 1) {
178+ for (int64_t noLastIndex = 0; noLastIndex < splitLoopSize; noLastIndex++) {
179+ currentSplitValue = *(splitSize->GetData() + loopIndex * splitLoopSize + noLastIndex);
180+ chunkVector.emplace_back(currentSplitValue);
181+ newSplit += currentSplitValue;
182+ }
183+ } else {
184+ for (int64_t lastIndex = 0; lastIndex < lastSize; lastIndex++) {
185+ currentSplitValue = *(splitSize->GetData() + loopIndex * splitLoopSize + lastIndex);
186+ chunkVector.emplace_back(currentSplitValue);
187+ newSplit += currentSplitValue;
188+ }
189+ }
190+ splitList.emplace_back(executor->AllocIntArray(chunkVector.data(), chunkVector.size()));
191+ newSplitSize.emplace_back(newSplit);
192+ }
233 193 
234- // 固定写法,参数检查194+ // 2. 循环调用Slice将self切成N个大块, 并对每个大块使用SplitV再次切分
235- auto ret = CheckParams(self, splitSections, dim, out);195+ FVector<const aclTensor*> splitTensorList;
236- CHECK_RET(ret == ACLNN_SUCCESS, ret);196+ int64_t offsetValue = 0;
197+ for (size_t sliceIndex = 0; sliceIndex < newSplitSize.size(); sliceIndex++) {
198+ // 计算offset, offset逐块递增
199+ FVector<int64_t> offsetVector(selfDim, 0);
200+ offsetValue += sliceIndex == 0 ? 0 : newSplitSize[sliceIndex - 1];
201+ offsetVector[static_cast<size_t>(dim)] = offsetValue;
202+ aclIntArray* offsetArray = executor->AllocIntArray(offsetVector.data(), offsetVector.size());
237 203 
238- // 修正dim取值204+ // 计算size, size与输出块大小保持一致
239- if (dim < 0) {205+ FVector<int64_t> sizeVector;
240- dim += static_cast<int64_t>(self->GetViewShape().GetDimNum());206+ for (size_t selfIndex = 0; selfIndex < selfDim; selfIndex++) {
241- }207+ int64_t sizeValue = selfIndex == static_cast<size_t>(dim) ? newSplitSize[sliceIndex] :
208+ selfShape.GetDim(selfIndex);
209+ sizeVector.emplace_back(sizeValue);
210+ }
211+ aclIntArray* sizeArray = executor->AllocIntArray(sizeVector.data(), sizeVector.size());
242 212 
243- int64_t dimSize = self->GetViewShape().GetDim(static_cast<size_t>(dim));213+ // 调用l0op::Slice对每一块进行处理
244- // 空tensor处理214+ auto sliceRes = l0op::Slice(self, offsetArray, sizeArray, executor);
245- if (self->IsEmpty()) {215+ CHECK_RET(sliceRes != nullptr, ACLNN_ERR_INNER_NULLPTR);
246- *workspaceSize = 0;216+ 
217+ // 调用l0op::SPlitV将sliceRes进行切分
218+ auto splitRes = l0op::SplitV(sliceRes, splitList[sliceIndex], dim, executor);
219+ CHECK_RET(splitRes != nullptr, ACLNN_ERR_INNER_NULLPTR);
220+ for (int64_t resIndex = 0; resIndex < static_cast<int64_t>(splitRes->Size()); resIndex++) {
221+ if ((resIndex + sliceIndex * splitLoopSize) >= out->Size()) {
222+ OP_LOGE(ACLNN_ERR_PARAM_INVALID,
223+ "Index value exceeds the out size range, resIndex=%ld, sliceIndex=%zu, out->Size=%lu", resIndex,
224+ sliceIndex, out->Size());
225+ return ACLNN_ERR_PARAM_INVALID;
226+ }
227+ auto splitCast = l0op::Cast((*splitRes)[resIndex],
228+ (*out)[resIndex + sliceIndex * splitLoopSize]->GetDataType(), executor);
229+ CHECK_RET(splitCast != nullptr, ACLNN_ERR_INNER_NULLPTR);
230+ auto splitViewCopy = l0op::ViewCopy(splitCast, (*out)[resIndex + sliceIndex * splitLoopSize], executor);
231+ CHECK_RET(splitViewCopy != nullptr, ACLNN_ERR_INNER_NULLPTR);
232+ }
233+ }
234+ return ACLNN_SUCCESS;
235+}
236+ 
237+aclnnStatus aclnnSplitTensorGetWorkspaceSize(const aclTensor* self, uint64_t splitSections, int64_t dim,
238+ aclTensorList* out, uint64_t* workspaceSize, aclOpExecutor** executor)
239+{
240+ L2_DFX_PHASE_1(aclnnSplitTensor, DFX_IN(self, splitSections, dim), DFX_OUT(out));
241+ 
242+ // 固定写法,创建OpExecutor
243+ auto uniqueExecutor = CREATE_EXECUTOR();
244+ CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
245+ 
246+ // 固定写法,参数检查
247+ auto ret = CheckParams(self, splitSections, dim, out);
248+ CHECK_RET(ret == ACLNN_SUCCESS, ret);
249+ 
250+ // 修正dim取值
251+ if (dim < 0) {
252+ dim += static_cast<int64_t>(self->GetViewShape().GetDimNum());
253+ }
254+ 
255+ int64_t dimSize = self->GetViewShape().GetDim(static_cast<size_t>(dim));
256+ // 空tensor处理
257+ if (self->IsEmpty()) {
258+ *workspaceSize = 0;
259+ uniqueExecutor.ReleaseTo(executor);
260+ return ACLNN_SUCCESS;
261+ }
262+ 
263+ // 固定写法,将输入self转换成连续的tensor
264+ auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get());
265+ CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
266+ 
267+ // 根据数据类型和输出个数判断调用对应的实现函数
268+ if (dimSize == static_cast<int64_t>(splitSections)) {
269+ // 无需调用SplitV,直接进行Cast和ViewCopy即可
270+ ret = SplitZeroCalculation(selfContiguous, out, uniqueExecutor.get());
271+ } else {
272+ // 计算输出个数, if splitSections > dimSize, split only one
273+ int64_t numSplit = (dimSize + static_cast<int64_t>(splitSections) - 1) / static_cast<int64_t>(splitSections);
274+ int64_t lastSplitSize = splitSections - (static_cast<int64_t>(splitSections) * numSplit - dimSize);
275+ // 构造算子依赖的splitSize
276+ FVector<int64_t> splitVector(numSplit, static_cast<int64_t>(splitSections));
277+ splitVector[numSplit - 1] = lastSplitSize;
278+ aclIntArray* splitSize = uniqueExecutor.get()->AllocIntArray(splitVector.data(), splitVector.size());
279+ // 在SplitV算子的AiCore场景或者输出个数超过32个时,使用循环切分
280+ if (l0op::SplitVAiCoreSupport(selfContiguous) && splitSize->Size() > SPLIT_LOOP_SIZE && !IsRegBase()) {
281+ ret = SplitLoopCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
282+ } else if (splitSize->Size() > SPLIT_LOOP_SIZE_512) {
283+ ret = SplitLoopCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
284+ } else {
285+ ret = SplitOnceCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
286+ }
287+ }
288+ CHECK_RET(ret == ACLNN_SUCCESS, ret);
289+ 
290+ // 固定写法,获取计算过程中需要使用的workspace大小
291+ *workspaceSize = uniqueExecutor->GetWorkspaceSize();
247 uniqueExecutor.ReleaseTo(executor);292 uniqueExecutor.ReleaseTo(executor);
248 return ACLNN_SUCCESS;293 return ACLNN_SUCCESS;
249- }
250- 
251- // 固定写法,将输入self转换成连续的tensor
252- auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get());
253- CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
254- 
255- // 根据数据类型和输出个数判断调用对应的实现函数
256- if (dimSize == static_cast<int64_t>(splitSections)) {
257- // 无需调用SplitV,直接进行Cast和ViewCopy即可
258- ret = SplitZeroCalculation(selfContiguous, out, uniqueExecutor.get());
259- } else {
260- // 计算输出个数, if splitSections > dimSize, split only one
261- int64_t numSplit = (dimSize + static_cast<int64_t>(splitSections) - 1) / static_cast<int64_t>(splitSections);
262- int64_t lastSplitSize = splitSections - (static_cast<int64_t>(splitSections) * numSplit - dimSize);
263- // 构造算子依赖的splitSize
264- FVector<int64_t> splitVector(numSplit, static_cast<int64_t>(splitSections));
265- splitVector[numSplit - 1] = lastSplitSize;
266- aclIntArray *splitSize = uniqueExecutor.get()->AllocIntArray(splitVector.data(), splitVector.size());
267- // 在SplitV算子的AiCore场景或者输出个数超过32个时,使用循环切分
268- if (l0op::SplitVAiCoreSupport(selfContiguous) && splitSize->Size() > SPLIT_LOOP_SIZE &&
269- !IsRegBase()) {
270- ret = SplitLoopCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
271- } else if (splitSize->Size() > SPLIT_LOOP_SIZE_512) {
272- ret = SplitLoopCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
273- } else {
274- ret = SplitOnceCalculation(selfContiguous, splitSize, dim, out, uniqueExecutor.get());
275- }
276- }
277- CHECK_RET(ret == ACLNN_SUCCESS, ret);
278- 
279- // 固定写法,获取计算过程中需要使用的workspace大小
280- *workspaceSize = uniqueExecutor->GetWorkspaceSize();
281- uniqueExecutor.ReleaseTo(executor);
282- return ACLNN_SUCCESS;
283}294}
284 295 
285-aclnnStatus aclnnSplitTensor(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream) {296+aclnnStatus aclnnSplitTensor(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)
286- L2_DFX_PHASE_2(aclnnSplitTensor);297+{
287- // 固定写法,调用框架能力,完成计算298+ L2_DFX_PHASE_2(aclnnSplitTensor);
288- return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);299+ // 固定写法,调用框架能力,完成计算
300+ return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
289}301}
290 302 
291#ifdef __cplusplus303#ifdef __cplusplus