### Install Dependencies Source: https://github.com/cann/ops-transformer/blob/master/examples/fast_kernel_launch_example/README.md Installs the necessary Python packages for the example. Ensure you are in the `examples/fast_kernel_launch_example` directory. ```sh python3 -m pip install -r requirements.txt ``` -------------------------------- ### Initialize and Setup Devices for A3/A5 Source: https://github.com/cann/ops-transformer/blob/master/mc2/moe_distribute_dispatch_v2/docs/aclnnMoeDistributeDispatchV2.md This example initializes ACL and sets up devices, contexts, and streams for dispatch and combine operations on A3/A5 devices. It also prepares device IDs for Hccl communication. ```cpp int run_example_on_A3A5() { int ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclInit failed. ret = %d\n", ret); return ret); aclrtStream dispatchV2Stream[DEV_NUM]; aclrtStream combineV2Stream[DEV_NUM]; aclrtContext context[DEV_NUM]; for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { ret = aclrtSetDevice(rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetDevice failed. ret = %d\n", ret); return ret); ret = aclrtCreateContext(&context[rankId], rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateContext failed. ret = %d\n", ret); return ret); ret = aclrtCreateStream(&dispatchV2Stream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed. ret = %d\n", ret); return ret); ret = aclrtCreateStream(&combineV2Stream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed. ret = %d\n", ret); return ret); } int32_t devicesEp[TP_WORLD_SIZE][EP_WORLD_SIZE]; for (int32_t tpId = 0; tpId < TP_WORLD_SIZE; tpId++) { ``` -------------------------------- ### Initialize and Setup Devices for A2 Source: https://github.com/cann/ops-transformer/blob/master/mc2/moe_distribute_dispatch_v2/docs/aclnnMoeDistributeDispatchV2.md This example initializes ACL, sets up devices, creates contexts and streams for dispatch and combine operations on A2 devices. It also initializes Hccl communication for expert parallelism. ```cpp int run_example_on_A2() { int ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclInit failed, ret = %d\n", ret); return ret); aclrtStream dispatchV2Stream[DEV_NUM_A2]; aclrtStream combineV2Stream[DEV_NUM_A2]; aclrtContext context[DEV_NUM_A2]; for (uint32_t rankId = 0; rankId < DEV_NUM_A2; rankId++) { ret = aclrtSetDevice(rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetDevice failed, ret = %d\n", ret); return ret); ret = aclrtCreateContext(&context[rankId], rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateContext failed, ret = %d\n", ret); return ret); ret = aclrtCreateStream(&dispatchV2Stream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed, ret = %d\n", ret); return ret); ret = aclrtCreateStream(&combineV2Stream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed, ret = %d\n", ret); return ret); } int32_t devicesEp[EP_WORLD_SIZE_A2]; for (int32_t epId = 0; epId < EP_WORLD_SIZE_A2; epId++) { devicesEp[epId] = epId; } HcclComm commsEp[EP_WORLD_SIZE_A2]; ret = HcclCommInitAll(EP_WORLD_SIZE_A2, devicesEp, commsEp); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclCommInitAll ep failed, ret %d\n", ret); return ret); Args args[DEV_NUM_A2]; std::vector> threads(DEV_NUM_A2); for (uint32_t rankId = 0; rankId < DEV_NUM_A2; rankId++) { uint32_t epRankId = rankId / TP_WORLD_SIZE_A2; uint32_t tpRankId = rankId % TP_WORLD_SIZE_A2; args[rankId].rankId = rankId; args[rankId].epRankId = epRankId; args[rankId].tpRankId = tpRankId; args[rankId].hcclEpComm = commsEp[epRankId]; args[rankId].dispatchV2Stream = dispatchV2Stream[rankId]; args[rankId].combineV2Stream = combineV2Stream[rankId]; args[rankId].context = context[rankId]; threads[rankId].reset(new(std::nothrow) std::thread(&launchOneThreadDispatchV2AndCombineV2_A2, std::ref(args[rankId]))); } for(uint32_t rankId = 0; rankId < DEV_NUM_A2; rankId++) { threads[rankId]->join(); } aclFinalize(); LOG_PRINT("[INFO] aclFinalize success\n"); return 0; } ``` -------------------------------- ### ACL Initialization and Device Setup Source: https://github.com/cann/ops-transformer/blob/master/mc2/moe_update_expert/docs/aclnnMoeUpdateExpert.md Initializes the ACL library and sets up multiple devices, creating contexts and streams for each. This is the starting point for ACL operations on the device. ```c #define DEV_NUM 8 #define TP_WORLD_SIZE 2 #define EP_WORLD_SIZE 4 int main(int argc, char *argv[]) { int ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclInit failed, ret = %d\n", ret); return ret); aclrtStream eplbStream[DEV_NUM]; aclrtStream dispatchStream[DEV_NUM]; aclrtStream combineStream[DEV_NUM]; aclrtContext context[DEV_NUM]; for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { ret = aclrtSetDevice(rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetDevice failed, ret = %d\n", ret); return ret); ret = aclrtCreateContext(&context[rankId], rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateContext failed, ret = %d\n", ret); return ret); ret = aclrtCreateStream(&eplbStream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed, ret = %d\n", ret); return ret); ret = aclrtCreateStream(&dispatchStream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed, ret = %d\n", ret); return ret); ret = aclrtCreateStream(&combineStream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed, ret = %d\n", ret); return ret); } int32_t devicesEp[TP_WORLD_SIZE][EP_WORLD_SIZE]; for (int32_t tpId = 0; tpId < TP_WORLD_SIZE; tpId++) { for (int32_t epId = 0; epId < EP_WORLD_SIZE; epId++) { devicesEp[tpId][epId] = epId * TP_WORLD_SIZE + tpId; } } HcclComm commsEp[TP_WORLD_SIZE][EP_WORLD_SIZE]; for (int32_t tpId = 0; tpId < TP_WORLD_SIZE; tpId++) { ret = HcclCommInitAll(EP_WORLD_SIZE, devicesEp[tpId], commsEp[tpId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclCommInitAll ep %d failed, ret %d\n", tpId, ret); return ret); } int32_t devicesTp[EP_WORLD_SIZE][TP_WORLD_SIZE]; for (int32_t epId = 0; epId < EP_WORLD_SIZE; epId++) { ``` -------------------------------- ### C++ Example: ACL Initialization and Device Setup Source: https://github.com/cann/ops-transformer/blob/master/mc2/batch_mat_mul_reduce_scatter_allto_all/docs/aclnnBatchMatMulReduceScatterAlltoAll.md Sets up the necessary ACL environment for multi-device operations, including initializing ACL, creating contexts, and streams for each device. This is a prerequisite for using advanced communication and computation APIs. ```cpp int main(int argc, char *argv[]) { // 本样例基于Atlas A3实现,必须在Atlas A3上运行 int ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclInit failed. ret = %d \n", ret); return ret); aclrtStream stream[DEV_NUM]; aclrtContext context[DEV_NUM]; for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { ret = aclrtSetDevice(rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetDevice failed. ret = %d \n", ret); return ret); ret = aclrtCreateContext(&context[rankId], rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateContext failed. ret = %d \n", ret); return ret); ret = aclrtCreateStream(&stream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed. ret = %d \n", ret); return ret); } int32_t devicesEp[DEV_NUM]; int32_t devicesTp[DEV_NUM]; // 初始化ep域 ep = 4 {0,2,4,6} {1,3,5,7} HcclComm commsEp[DEV_NUM]; for (int i = 0; i < TP_WORLD_SIZE; i++) { for (int j =0; j < EP_WORLD_SIZE; j++) { devicesEp[j + i * EP_WORLD_SIZE] = i + j * TP_WORLD_SIZE; } ret = HcclCommInitAll(EP_WORLD_SIZE, &devicesEp[i * EP_WORLD_SIZE], &commsEp[i * EP_WORLD_SIZE]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclCommInitAll ep world %d failed. ret = %d \n", i, ret); return ret); } // 初始化tp域 tp = 4 {0,1},{2,3},{4,5},{6,7} ``` -------------------------------- ### Operator Development Examples Overview Source: https://github.com/cann/ops-transformer/blob/master/examples/README.md Provides a summary of available operator development examples, including their purpose and links to detailed development and calling guides. ```text |样例目录| 样例介绍 |算子开发|算子调用 | |---|------------------|---|---| | add_example | 实现两个张量相加功能的算子。 | 算子端到端开发过程参见[AI Core算子开发指南](../docs/zh/develop/aicore_develop_guide.md)。 |调用样例参见[README](add_example/README.md)| | mc2/all_gather_add | 先进行 AllGather 集合通信,再执行逐元素相加。 | 算子端到端开发过程参见[AI Core算子开发指南](./mc2/all_gather_add/docs/AllGatherAdd算子设计实现介绍.md)。 |调用样例参见[README](mc2/all_gather_add/README.md)| ``` -------------------------------- ### ACL Initialization and Collective Communication Setup Source: https://github.com/cann/ops-transformer/blob/master/mc2/inplace_matmul_all_reduce_add_rms_norm/docs/aclnnInplaceWeightQuantMatmulAllReduceAddRmsNorm.md Example of initializing ACL and setting up collective communication domains for distributed operations. ```C++ int main(int argc, char *argv[]) { int ret; int32_t devices[ndev]; for (int i = 0; i < ndev; i++) { devices[i] = i; } HcclComm comms[128]; ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); // 初始化集合通信域 for (int i = 0; i < ndev; i++) { ret = aclrtSetDevice(devices[i]); ``` -------------------------------- ### C++ ACL NN AlltoAllMatmul Example Source: https://github.com/cann/ops-transformer/blob/master/mc2/allto_all_matmul/docs/aclnnAlltoAllMatmul.md Demonstrates the setup and execution of the AlltoAllMatmul operator using ACL. Includes tensor creation, memory allocation, and data transfer for multi-device communication. ```cpp #include #include #include #include #include "aclnnop/aclnn_allto_all_matmul.h" int ndev = 2; #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 &shape) { int64_t shapeSize = 1; for (auto i: shape) { shapeSize *= i; } return shapeSize; } template int CreateAclTensor(const std::vector &hostData, const std::vector &shape, void **deviceAddr, aclDataType dataType, aclTensor **tensor) { auto size = GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 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); // 计算连续tensor的strides std::vector strides(shape.size(), 1); for (int64_t i = shape.size() - 2; i >= 0; i--) { strides[i] = shape[i + 1] * strides[i + 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } struct Args { uint32_t rankId; HcclComm hcclComm; aclrtStream stream; aclrtContext context; }; int launchOneThreadAlltoAllMatmul(Args &args) { int ret; ret = aclrtSetCurrentContext(args.context); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetCurrentContext failed. ERROR: %d\n", ret); return ret); char hcom_name[128] = {0}; ret = HcclGetCommName(args.hcclComm, hcom_name); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclGetCommName failed. ret = %d \n", ret); return -1); LOG_PRINT("[INFO] rank %d hcom: %s stream: %p, context : %p\n", args.rankId, hcom_name, args.stream, args.context); std::vector x1Shape = {32, 64}; std::vector x2Shape = {64 * ndev, 128}; std::vector biasShape = {128}; std::vector outShape = {32 / ndev, 128}; std::vector alltoalloutShape = {32 / ndev, 64 * ndev}; void *x1DeviceAddr = nullptr; void *x2DeviceAddr = nullptr; void *biasDeviceAddr = nullptr; void *outDeviceAddr = nullptr; void *alltoalloutDeviceAddr = nullptr; aclTensor *x1 = nullptr; aclTensor *x2 = nullptr; aclTensor *bias = nullptr; aclTensor *out = nullptr; aclTensor *alltoallout = nullptr; int64_t a2aAxes[2] = {-2, -1}; aclIntArray* alltoAllAxesOptional = aclCreateIntArray(a2aAxes, static_cast(2)); uint64_t workspaceSize = 0; aclOpExecutor *executor; void *workspaceAddr = nullptr; long long x1ShapeSize = GetShapeSize(x1Shape); long long x2ShapeSize = GetShapeSize(x2Shape); long long biasShapeSize = GetShapeSize(biasShape); long long outShapeSize = GetShapeSize(outShape); long long alltoalloutShapeSize = GetShapeSize(alltoalloutShape); std::vector x1HostData(x1ShapeSize, 1); std::vector x2HostData(x2ShapeSize, 1); std::vector biasHostData(biasShapeSize, 1); std::vector outHostData(outShapeSize, 0); std::vector alltoalloutHostData(alltoalloutShapeSize, 0); // 创建 tensor ret = CreateAclTensor(x1HostData, x1Shape, &x1DeviceAddr, aclDataType::ACL_FLOAT16, &x1); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(x2HostData, x2Shape, &x2DeviceAddr, aclDataType::ACL_FLOAT16, &x2); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(biasHostData, biasShape, &biasDeviceAddr, aclDataType::ACL_FLOAT16, &bias); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT16, &out); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(alltoalloutHostData, alltoalloutShape, &alltoalloutDeviceAddr, aclDataType::ACL_FLOAT16, &alltoallout); CHECK_RET(ret == ACL_SUCCESS, return ret); // 调用第一段接口 ``` -------------------------------- ### ACL NN AlltoAllQuantMatmulV2 Execution Example Source: https://github.com/cann/ops-transformer/blob/master/mc2/allto_all_matmul/docs/aclnnAlltoAllQuantMatmulV2.md This snippet demonstrates the complete workflow for using aclnnAlltoAllQuantMatmulV2, including tensor creation, workspace allocation, function calls, synchronization, and resource deallocation. It requires prior setup of ACL and Hccl environments. ```cpp long long x1ShapeSize = GetShapeSize(x1Shape); long long x2ShapeSize = GetShapeSize(x2Shape); long long biasShapeSize = GetShapeSize(biasShape); long long x2ScaleShapeSize = GetShapeSize(x2ScaleShape); long long outShapeSize = GetShapeSize(outShape); long long allToAllOutShapeSize = GetShapeSize(allToAllOutShape); std::vector x1HostData(x1ShapeSize, 1); std::vector x2HostData(x2ShapeSize, 1); std::vector biasHostData(biasShapeSize, 1); std::vector x2ScaleHostData(x2ScaleShapeSize, 1); std::vector outHostData(outShapeSize, 0); std::vector allToAllOutHostData(allToAllOutShapeSize, 0); // 创建 tensor ret = CreateAclTensor(x1HostData, x1Shape, &x1DeviceAddr, aclDataType::ACL_FLOAT16, &x1); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(x2HostData, x2Shape, &x2DeviceAddr, aclDataType::ACL_FLOAT8_E5M2, &x2); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(biasHostData, biasShape, &biasDeviceAddr, aclDataType::ACL_FLOAT, &bias); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(x2ScaleHostData, x2ScaleShape, &x2ScaleDeviceAddr, aclDataType::ACL_FLOAT, &x2Scale); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(allToAllOutHostData, allToAllOutShape, &allToAllOutDeviceAddr, aclDataType::ACL_FLOAT16, &allToAllOut); CHECK_RET(ret == ACL_SUCCESS, return ret); // 调用第一段接口 ret = aclnnAlltoAllQuantMatmulV2GetWorkspaceSize(x1, x2, bias, x1ScaleOptional, x2Scale, commScaleOptional, x1OffsetOptional, x2OffsetOptional, hcom_name, "ccu", alltoAllAxesOptional, x1QuantMode, x2QuantMode, commQuantMode, commQuantDtype, x1QuantDtype, groupSize, false, false, out, allToAllOut, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAlltoAllQuantMatmulV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 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); } // 调用第二段接口 ret = aclnnAlltoAllQuantMatmulV2(workspaceAddr, workspaceSize, executor, args.stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAlltoAllQuantMatmulV2 failed. ERROR: %d\n", ret); return ret); //(固定写法)同步等待任务执行结束 ret = aclrtSynchronizeStreamWithTimeout(args.stream, 10000); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); LOG_PRINT("device%d aclnnAlltoAllQuantMatmulV2 execute success \n", args.rankId); // 释放device资源,需要根据具体API的接口定义修改 if (x1 != nullptr) { aclDestroyTensor(x1); } if (x2 != nullptr) { aclDestroyTensor(x2); } if (bias != nullptr) { aclDestroyTensor(bias); } if (x2Scale != nullptr) { aclDestroyTensor(x2Scale); } if (out != nullptr) { aclDestroyTensor(out); } if (allToAllOut != nullptr) { aclDestroyTensor(allToAllOut); } if (x1DeviceAddr != nullptr) { aclrtFree(x1DeviceAddr); } if (x2DeviceAddr != nullptr) { aclrtFree(x2DeviceAddr); } if (biasDeviceAddr != nullptr) { aclrtFree(biasDeviceAddr); } if (outDeviceAddr != nullptr) { aclrtFree(outDeviceAddr); } if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(args.stream); HcclCommDestroy(args.hcclComm); aclrtDestroyContext(args.context); aclrtResetDevice(args.rankId); return 0; } ``` -------------------------------- ### Initialize and Configure Devices for Distributed Training Source: https://github.com/cann/ops-transformer/blob/master/mc2/moe_distribute_combine_setup/docs/aclnnMoeDistributeCombineSetup.md Initializes ACL, sets up devices, creates streams for combine setup and teardown, and initializes HCCL communication. This is typically used at the start of a distributed training job. ```cpp int ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclInit failed. ret = %d \n", ret); return ret); aclrtStream combineSetupStream[DEV_NUM]; aclrtStream combineTeardownStream[DEV_NUM]; aclrtContext context[DEV_NUM]; for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { ret = aclrtSetDevice(rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetDevice failed. ret = %d \n", ret); return ret); ret = aclrtCreateContext(&context[rankId], rankId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateContext failed. ret = %d \n", ret); return ret); ret = aclrtCreateStream(&combineSetupStream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed. ret = %d \n", ret); return ret); ret = aclrtCreateStream(&combineTeardownStream[rankId]); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtCreateStream failed. ret = %d \n", ret); return ret); } int32_t devices[DEV_NUM]; for (int i = 0; i < DEV_NUM; i++) { devices[i] = i; } HcclComm comms[DEV_NUM]; ret = HcclCommInitAll(DEV_NUM, devices, comms); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclCommInitAll failed. ret = %d \n", ret); return ret); Args args[DEV_NUM]; std::vector> threads(DEV_NUM); for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { args[rankId].rankId = rankId; args[rankId].epRankId = rankId; args[rankId].hcclEpComm = comms[rankId]; args[rankId].combinesetupstream = combineSetupStream[rankId]; args[rankId].combineteardownstream = combineTeardownStream[rankId]; args[rankId].context = context[rankId]; threads[rankId].reset(new (std::nothrow) std::thread(&LaunchOneProcess, std::ref(args[rankId]))); } for (uint32_t rankId = 0; rankId < DEV_NUM; rankId++) { threads[rankId]->join(); } aclFinalize(); return 0; } ``` -------------------------------- ### C++ Example for aclnnGroupedMatmulFinalizeRoutingWeightNz Source: https://github.com/cann/ops-transformer/blob/master/gmm/grouped_matmul_finalize_routing/docs/aclnnGroupedMatmulFinalizeRoutingWeightNz.md This snippet shows the complete process of calling aclnnGroupedMatmulFinalizeRoutingWeightNz, including getting workspace size, allocating memory, executing the operator, synchronizing the stream, and handling resources. It requires prior setup of input tensors and a stream. ```cpp std::unique_ptr rowIndexTensorPtr(rowIndex, aclDestroyTensor); std::unique_ptr rowIndexDeviceAddrPtr(rowIndexDeviceAddr, aclrtFree); CHECK_RET(ret == ACL_SUCCESS, return ret); // 创建out aclTensor ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); std::unique_ptr outTensorPtr(out, aclDestroyTensor); std::unique_ptr outDeviceAddrPtr(outDeviceAddr, aclrtFree); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API,需要修改为具体的Api名称 uint64_t workspaceSize = 0; aclOpExecutor *executor; void *workspaceAddr = nullptr; // 调用aclnnTransMatmulWeight第一段接口 ret = aclnnTransMatmulWeightGetWorkspaceSize(w, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTransMatmulWeightGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); //根据第一段接口计算出的workspaceSize申请device内存 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); } // 调用aclnnTransMatmulWeight第二段接口 ret = aclnnTransMatmulWeight(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTransMatmulWeight failed. ERROR: %d\n", ret); return ret); // 调用aclnnGroupedMatmulFinalizeRoutingWeightNz第一段接口 workspaceSize = 0; ret = aclnnGroupedMatmulFinalizeRoutingWeightNzGetWorkspaceSize(x, w, scale, nullptr, pertokenScale, groupList, sharedInput, logit, rowIndex, dtype, shareInputWeight, sharedInputOffset, transposeX, transposeW, groupListType, out, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGroupedMatmulFinalizeRoutingWeightNzGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); //根据第一段接口计算出的workspaceSize申请device内存 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); } // 调用aclnnGroupedMatmulFinalizeRoutingWeightNz第二段接口 ret = aclnnGroupedMatmulFinalizeRoutingWeightNz(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGroupedMatmulFinalizeRoutingWeightNz failed. ERROR: %d\n", ret); return ret); // 4. (固定写法)同步等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 auto size = GetShapeSize(outShape); std::vector 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[%lld] is: %f\n", i, resultData[i]); } // 6. 释放aclTensor资源,需要根据具体API的接口定义修改 aclDestroyTensor(x); aclDestroyTensor(w); aclDestroyTensor(scale); aclDestroyTensor(pertokenScale); aclDestroyTensor(groupList); aclDestroyTensor(sharedInput); aclDestroyTensor(logit); aclDestroyTensor(rowIndex); aclDestroyTensor(out); // 7.释放device资源,需要根据具体API的接口定义修改 aclrtFree(xDeviceAddr); aclrtFree(wDeviceAddr); aclrtFree(scaleDeviceAddr); aclrtFree(pertokenScaleDeviceAddr); aclrtFree(groupListDeviceAddr); aclrtFree(sharedInputDeviceAddr); aclrtFree(logitDeviceAddr); aclrtFree(rowIndexDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; } ``` -------------------------------- ### C++ Quant All Reduce Example for Ascend 950 Source: https://github.com/cann/ops-transformer/blob/master/mc2/quant_all_reduce/docs/aclnnQuantAllReduce.md This C++ code demonstrates how to use the aclnnQuantAllReduce API for quantized all-reduce operations. It includes setup for HCCL communication, tensor creation, and calls to get workspace size. Ensure HCCL and ACLNN libraries are correctly linked. ```Cpp #include #include #include #include #include #include "hccl/hccl.h" #include "aclnnop/aclnn_quant_all_reduce.h" using namespace std; #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) constexpr int DEV_NUM = 2; // 设备数量 int64_t GetShapeSize(const std::vector &shape) { int64_t shape_size = 1; for (auto i : shape) { shape_size *= i; } return shape_size; } template int CreateAclTensor(const std::vector &hostData, const std::vector &shape, void **deviceAddr, aclDataType dataType, aclTensor **tensor) { auto size = GetShapeSize(shape) * sizeof(T); auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc failed. ret: %d\n", ret); return ret); ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMemcpy failed. ret: %d\n", ret); return ret); std::vector strides(shape.size(), 1); for (int64_t i = shape.size() - 2; i >= 0; i--) { strides[i] = shape[i +1] * strides[i + 1]; } *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } struct Args { uint32_t rankId; HcclComm hcclComm; aclrtStream stream; aclrtContext context; }; int LaunchOneThreadQuantAllReduce(Args &args) { int ret = aclrtSetCurrentContext(args.context); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtSetCurrentContext failed. ret = %d\n", ret); return ret); char hcomName[128] = {0}; ret = HcclGetCommName(args.hcclComm, hcomName); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] HcclGetCommName failed. ret = %d\n", ret); return -1); LOG_PRINT("[INFO] rank = %d, hcomName = %s, stream = %p\n", args.rankId, hcomName, args.stream); std::vector xShape = {1024, 5120}; // (bs, H) std::vector scalesShape = {1024, 80, 2}; // (bs, H/64, 2) std::vector outputShape = {1024, 5120}; // (bs, H) void *xDeviceAddr = nullptr; void *scalesDeviceAddr = nullptr; void *outputDeviceAddr = nullptr; void *workspaceAddr = nullptr; aclTensor *x = nullptr; aclTensor *scales = nullptr; aclTensor *output = nullptr; uint64_t workspaceSize = 0; aclOpExecutor *executor = nullptr; long long xShapeSize = GetShapeSize(xShape); long long scalesShapeSize = GetShapeSize(scalesShape); long long outputShapeSize = GetShapeSize(outputShape); std::vector xHostData(xShapeSize, 0); std::vector scalesHostData(scalesShapeSize, 0); std::vector outputHostData(outputShapeSize, 0); // 创建tensor ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT8_E5M2, &x); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(scalesHostData, scalesShape, &scalesDeviceAddr, aclDataType::ACL_FLOAT8_E8M0, &scales); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(outputHostData, outputShape, &outputDeviceAddr, aclDataType::ACL_FLOAT16, &output); CHECK_RET(ret == ACL_SUCCESS, return ret); // 调用第一阶段接口 ret = aclnnQuantAllReduceGetWorkspaceSize( x, scales, hcomName, "sum", output, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclnnQuantAllReduceGetWorkspaceSize failed. ret = %d \n", ret); return ret); // 根据第一阶段接口计算出的workspaceSize申请device内存 if (workspaceSize > 0) { ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc workspace failed. ret = %d \n", ret); return ret); } // 调用第二阶段接口 ``` -------------------------------- ### MoeInitRouting Initialization and Execution Example Source: https://github.com/cann/ops-transformer/blob/master/moe/moe_init_routing/docs/aclnnMoeInitRouting.md This snippet shows the complete process of initializing MoeInitRouting, including getting workspace size, allocating device memory, calling the initialization function, synchronizing the stream, and copying results back to the host. It also includes resource cleanup. ```cpp ret = aclnnMoeInitRoutingGetWorkspaceSize(x, rowIdx, expertIdx, activeNum, expandedXOut, expandedRowIdxOut, expandedExpertIdxOut, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMoeInitRoutingGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 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); } // 调用aclnnMoeInitRouting第二段接口 ret = aclnnMoeInitRouting(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMoeInitRouting failed. ERROR: %d\n", ret); return ret); // 4. 固定写法,同步等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 auto expandedXSize = GetShapeSize(expandedXOutShape); std::vector expandedXData(expandedXSize, 0); ret = aclrtMemcpy(expandedXData.data(), expandedXData.size() * sizeof(expandedXData[0]), expandedXOutDeviceAddr, expandedXSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); for (int64_t i = 0; i < expandedXSize; i++) { LOG_PRINT("expandedXData[%ld] is: %f\n", i, expandedXData[i]); } auto expandedRowIdxSize = GetShapeSize(idxOutShape); std::vector expandedRowIdxData(expandedRowIdxSize, 0); ret = aclrtMemcpy(expandedRowIdxData.data(), expandedRowIdxData.size() * sizeof(expandedRowIdxData[0]), expandedRowIdxOutDeviceAddr, expandedRowIdxSize * sizeof(int32_t), 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 < expandedRowIdxSize; i++) { LOG_PRINT("expandedRowIdxData[%ld] is: %d\n", i, expandedRowIdxData[i]); } auto expandedExpertIdxSize = GetShapeSize(idxOutShape); std::vector expandedExpertIdxData(expandedExpertIdxSize, 0); ret = aclrtMemcpy(expandedExpertIdxData.data(), expandedExpertIdxData.size() * sizeof(expandedExpertIdxData[0]), expandedExpertIdxOutDeviceAddr, expandedExpertIdxSize * sizeof(int32_t), 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 < expandedExpertIdxSize; i++) { LOG_PRINT("expandedExpertIdxData[%ld] is: %d\n", i, expandedExpertIdxData[i]); } // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 aclDestroyTensor(x); aclDestroyTensor(rowIdx); aclDestroyTensor(expertIdx); aclDestroyTensor(expandedXOut); aclDestroyTensor(expandedRowIdxOut); aclDestroyTensor(expandedExpertIdxOut); // 7. 释放device资源,需要根据具体API的接口定义修改 aclrtFree(xDeviceAddr); aclrtFree(rowIdxDeviceAddr); aclrtFree(expertIdxDeviceAddr); aclrtFree(expandedXOutDeviceAddr); aclrtFree(expandedRowIdxOutDeviceAddr); aclrtFree(expandedExpertIdxOutDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; ``` -------------------------------- ### Get Workspace Size for Combine Setup Source: https://github.com/cann/ops-transformer/blob/master/mc2/moe_distribute_combine_setup/docs/aclnnMoeDistributeCombineSetup.md Retrieves the required workspace size and executor for the combine setup operation. This must be called before aclnnMoeDistributeCombineSetup. ```cpp aclnnStatus aclnnMoeDistributeCombineSetupGetWorkspaceSize( const aclTensor* expandX, const aclTensor* expertIds, const aclTensor* assistInfoForCombine, const char* groupEp, int64_t epWorldSize, int64_t epRankId, int64_t moeExpertNum, int64_t expertShardType, int64_t sharedExpertNum, int64_t sharedExpertRankNum, int64_t globalBs, int64_t commQuantMode, int64_t commType, const char* commAlg, aclTensor* quantExpandXOut, aclTensor* commCmdInfoOut, uint64_t* workspaceSize, aclOpExecutor** executor) ``` -------------------------------- ### Run an Example Operator Source: https://github.com/cann/ops-transformer/blob/master/docs/QUICKSTART.md Execute a specific operator example, such as 'add_example', in eager mode with custom vendor settings. ```bash bash build.sh --run_example add_example eager cust --vendor_name=custom ```