已合并
【PR】: sync ge_dev to master 20260309 #993
沛洋创建于 3月9日
【PR】: sync ge_dev to master 20260309 #993
已合并
共 78 个文件变更+2613-708
| @@ -1,9 +1,9 @@ | |||
| 1 | # ----------------------------------------------------------------------------------------------------------- | 1 | # ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ----------------------------------------------------------------------------------------------------------- | 9 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -456,6 +456,7 @@ if (NOT BUILD_OPEN_PROJECT) | |||
| 456 | install(TARGETS gert ge_common ge_common_base ge_executor_shared davinci_executor hybrid_executor ge_runner | 456 | install(TARGETS gert ge_common ge_common_base ge_executor_shared davinci_executor hybrid_executor ge_runner |
| 457 | ge_runner_v2 dflow_runner data_flow_base | 457 | ge_runner_v2 dflow_runner data_flow_base |
| 458 | ge_compiler aicore_utils slice air_headers | 458 | ge_compiler aicore_utils slice air_headers |
| 459 | + om2_executor | ||
| 459 | # 开发环境某些没有下载parser目录 | 460 | # 开发环境某些没有下载parser目录 |
| 460 | # _caffe_parser fmk_onnx_parser fmk_parser parser_common | 461 | # _caffe_parser fmk_onnx_parser fmk_parser parser_common |
| 461 | EXPORT air-targets | 462 | EXPORT air-targets |
| @@ -20,7 +20,7 @@ GE 提供对 PyTorch、TensorFlow 前端的友好接入能力,并同时支持 | |||
| 20 | 20 | ||
| 21 | - [构建验证](docs/build.md):介绍组件的完整构建、测试样例运行流程。 | 21 | - [构建验证](docs/build.md):介绍组件的完整构建、测试样例运行流程。 |
| 22 | - [快速开始](examples/acl/1_sample_resnet50_imagenet_classification/README.md):以 ResNet50 模型为例,介绍如何使用 ATC 工具进行模型转换,并在昇腾 AI 处理器上执行推理。 | 22 | - [快速开始](examples/acl/1_sample_resnet50_imagenet_classification/README.md):以 ResNet50 模型为例,介绍如何使用 ATC 工具进行模型转换,并在昇腾 AI 处理器上执行推理。 |
| 23 | -- [快速开始-LLM](examples/acl/2_sample_qwen_llm/README.md):以 Qwen 模型为例,介绍如何使用 ATC 工具进行LLM模型转换,并实现LLM模型的加载、执行和获取执行结果等。 | 23 | +- [快速开始-LLM](examples/acl/3_sample_qwen_llm/README.md):以 Qwen 模型为例,介绍如何使用 ATC 工具进行LLM模型转换,并实现LLM模型的加载、执行和获取执行结果等。 |
| 24 | 24 | ||
| 25 | ## 📚 文档 | 25 | ## 📚 文档 |
| 26 | 26 | ||
Dapi/acl/acl_cblas/types/op_attr.h+0-90
| @@ -1,90 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | -struct ACL_FUNC_VISIBILITY aclopAttr { | ||
| 20 | - aclopAttr() = default; | ||
| 21 | - aclopAttr(const aclopAttr &opAttr); | ||
| 22 | - | ||
| 23 | - ~aclopAttr() = default; | ||
| 24 | - | ||
| 25 | - inline const std::map<std::string, ge::GeAttrValue> &Attrs() const | ||
| 26 | - { | ||
| 27 | - return attrs_; | ||
| 28 | - } | ||
| 29 | - | ||
| 30 | - inline const std::map<std::string, ge::GeAttrValue> &EmplaceAttr(const std::string &str, ge::GeAttrValue val) | ||
| 31 | - { | ||
| 32 | - (void)attrs_.emplace(str, val); | ||
| 33 | - return attrs_; | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - inline void ClearConstBuf() | ||
| 37 | - { | ||
| 38 | - constDataBuf_.clear(); | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - inline void EmplaceConstBuf(std::string &str) | ||
| 42 | - { | ||
| 43 | - constDataBuf_.emplace_back(str); | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - inline const std::vector<std::string> &GetConstBuf() const | ||
| 47 | - { | ||
| 48 | - return constDataBuf_; | ||
| 49 | - } | ||
| 50 | - | ||
| 51 | - template<typename T> | ||
| 52 | - aclError SetAttr(const char_t *const attrName, const T val) | ||
| 53 | - { | ||
| 54 | - ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(attrName); | ||
| 55 | - const auto attrVal = ge::GeAttrValue::CreateFrom<T>(val); | ||
| 56 | - attrs_[std::string(attrName)] = attrVal; | ||
| 57 | - return ACL_SUCCESS; | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - template<typename T> | ||
| 61 | - aclError SetAttr(const char_t *const attrName, const int32_t numValues, const T *const values) | ||
| 62 | - { | ||
| 63 | - ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(attrName); | ||
| 64 | - if (numValues > 0) { | ||
| 65 | - ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(values); | ||
| 66 | - } | ||
| 67 | - std::vector<T> valueVec; | ||
| 68 | - for (int32_t i = 0; i < numValues; ++i) { | ||
| 69 | - valueVec.push_back(values[i]); | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - const auto attrValues = ge::GeAttrValue::CreateFrom<std::vector<T>>(valueVec); | ||
| 73 | - attrs_[std::string(attrName)] = attrValues; | ||
| 74 | - return ACL_SUCCESS; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - void UpdateDigest(); | ||
| 78 | - | ||
| 79 | - size_t GetDigest() const; | ||
| 80 | - | ||
| 81 | - std::string DebugString() const; | ||
| 82 | - | ||
| 83 | - bool HasAttr(const char_t *const attrName) const; | ||
| 84 | - | ||
| 85 | -private: | ||
| 86 | - std::map<std::string, ge::GeAttrValue> attrs_; | ||
| 87 | - std::vector<std::string> constDataBuf_; | ||
| 88 | - mutable size_t digest_ = 0U; | ||
| 89 | -}; | ||
| 90 | - | ||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | -#include "types/acl_op.h" | 16 | +#include "types/acl_op_inner.h" |
| 17 | 17 | ||
| 18 | struct aclGraphDumpOption { | 18 | struct aclGraphDumpOption { |
| 19 | std::string stage; | 19 | std::string stage; |
Dapi/acl/acl_op_compiler/single_op/compile/op_compile_service.h+0-60
| @@ -1,60 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | -namespace acl { | ||
| 17 | -using CompilerCreator = OpCompiler *(*)(); | ||
| 18 | - | ||
| 19 | -const int32_t ACL_ERROR_COMPILER_NOT_REGISTERED = 16; | ||
| 20 | - | ||
| 21 | -enum CompileStrategy { | ||
| 22 | - NO_COMPILER, | ||
| 23 | - NATIVE_COMPILER, | ||
| 24 | - REMOTE_COMPILER | ||
| 25 | -}; | ||
| 26 | - | ||
| 27 | -class ACL_FUNC_VISIBILITY OpCompileService { | ||
| 28 | -public: | ||
| 29 | - ~OpCompileService(); | ||
| 30 | - | ||
| 31 | - static OpCompileService &GetInstance() | ||
| 32 | - { | ||
| 33 | - static OpCompileService instance; | ||
| 34 | - return instance; | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - void RegisterCreator(const CompileStrategy strategy, const CompilerCreator creatorFn); | ||
| 38 | - | ||
| 39 | - aclError SetCompileStrategy(const CompileStrategy strategy, const std::map<std::string, std::string> &options); | ||
| 40 | - | ||
| 41 | - aclError CompileOp(const AclOp &op, std::shared_ptr<void> &modelData, size_t &modelSize) const; | ||
| 42 | - | ||
| 43 | - aclError CompileAndDumpGraph(const acl::AclOp &op, const char_t *const graphDumpPath, | ||
| 44 | - const aclGraphDumpOption *const dumpOpt) const; | ||
| 45 | - | ||
| 46 | -private: | ||
| 47 | - OpCompileService() = default; | ||
| 48 | - | ||
| 49 | - std::map<CompileStrategy, CompilerCreator> creators_; | ||
| 50 | - OpCompiler *compiler_ = nullptr; | ||
| 51 | -}; | ||
| 52 | - | ||
| 53 | -class ACL_FUNC_VISIBILITY OpCompilerRegister { | ||
| 54 | -public: | ||
| 55 | - OpCompilerRegister(const CompileStrategy strategy, const CompilerCreator creatorFn); | ||
| 56 | - ~OpCompilerRegister() = default; | ||
| 57 | -}; | ||
| 58 | -} // namespace acl | ||
| 59 | - | ||
| 60 | - | ||
Dapi/acl/acl_op_compiler/single_op/compile/op_compiler.h+0-58
| @@ -1,58 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | -namespace acl { | ||
| 26 | -struct CompileParam { | ||
| 27 | - ge::OpDescPtr opDesc; | ||
| 28 | - std::vector<ge::GeTensor> inputs; | ||
| 29 | - std::vector<ge::GeTensor> outputs; | ||
| 30 | - ge::OpEngineType engineType; | ||
| 31 | - int32_t compileFlag; | ||
| 32 | -}; | ||
| 33 | - | ||
| 34 | -class OpCompiler { | ||
| 35 | -public: | ||
| 36 | - OpCompiler() = default; | ||
| 37 | - | ||
| 38 | - virtual ~OpCompiler() = default; | ||
| 39 | - | ||
| 40 | - virtual aclError Init(const std::map<std::string, std::string> &options) = 0; | ||
| 41 | - | ||
| 42 | - aclError CompileOp(const AclOp &op, std::shared_ptr<void> &modelData, size_t &modelSize); | ||
| 43 | - | ||
| 44 | - aclError CompileAndDumpGraph(const AclOp &op, const char_t *const graphDumpPath, | ||
| 45 | - const aclGraphDumpOption *const dumpOpt); | ||
| 46 | - | ||
| 47 | -protected: | ||
| 48 | - virtual aclError DoCompile(CompileParam ¶m, std::shared_ptr<void> &modelData, size_t &modelSize) = 0; | ||
| 49 | - | ||
| 50 | - virtual aclError GenGraphAndDump(CompileParam ¶m, const char_t *const graphDumpPath, | ||
| 51 | - const aclGraphDumpOption *const dumpOpt) = 0; | ||
| 52 | - | ||
| 53 | -private: | ||
| 54 | - static aclError MakeCompileParam(const AclOp &op, CompileParam ¶m, const int32_t compileFlag); | ||
| 55 | -}; | ||
| 56 | -} // namespace acl | ||
| 57 | - | ||
| 58 | - | ||
Dapi/acl/acl_op_compiler/single_op/compile/op_kernel_selector.h+0-76
| @@ -1,76 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | -struct aclopKernelDesc { | ||
| 25 | - std::string kernelId; | ||
| 26 | - const void *stubFunc = nullptr; // no need for deallocating | ||
| 27 | - uint32_t blockDim = 0U; | ||
| 28 | - std::vector<size_t> workspaceSizes; | ||
| 29 | - std::string extendArgs; | ||
| 30 | - uint64_t timestamp = ULLONG_MAX; | ||
| 31 | - | ||
| 32 | - std::string opType; | ||
| 33 | - std::vector<aclTensorDesc> inputDescArr; | ||
| 34 | - std::vector<aclTensorDesc> outputDescArr; | ||
| 35 | - uint64_t seq = 0U; | ||
| 36 | - aclopAttr opAttr; | ||
| 37 | -}; | ||
| 38 | - | ||
| 39 | -namespace acl { | ||
| 40 | -using OpKernelDesc = aclopKernelDesc; | ||
| 41 | - | ||
| 42 | -class OpKernelSelector { | ||
| 43 | -public: | ||
| 44 | - ~OpKernelSelector() = default; | ||
| 45 | - static OpKernelSelector &GetInstance() | ||
| 46 | - { | ||
| 47 | - static OpKernelSelector instance; | ||
| 48 | - return instance; | ||
| 49 | - } | ||
| 50 | - | ||
| 51 | - bool HasSelectFunc(const std::string &opType) const; | ||
| 52 | - | ||
| 53 | - bool Register(const std::string &opType, aclopCompileFunc func); | ||
| 54 | - | ||
| 55 | - void Unregister(const std::string &opType); | ||
| 56 | - | ||
| 57 | - aclError SelectOpKernel(const AclOp &op); | ||
| 58 | - | ||
| 59 | - aclError GetOpKernelDesc(const AclOp &op, std::shared_ptr<OpKernelDesc> &desc); | ||
| 60 | - | ||
| 61 | - void SetMaxOpNum(const uint64_t maxOpNum); | ||
| 62 | - | ||
| 63 | -private: | ||
| 64 | - OpKernelSelector(); | ||
| 65 | - aclopCompileFunc GetSelectFunc(const std::string &opType); | ||
| 66 | - | ||
| 67 | - aclError InsertAclop2KernelDesc(const AclOp &op, const std::shared_ptr<OpKernelDesc> &desc) const; | ||
| 68 | - | ||
| 69 | - std::mutex mu_; | ||
| 70 | - std::map<std::string, aclopCompileFunc> selectors_; | ||
| 71 | - | ||
| 72 | - AclOpMap<std::shared_ptr<OpKernelDesc>> kernelDescMap_; | ||
| 73 | -}; | ||
| 74 | -} // namespace acl | ||
| 75 | - | ||
| 76 | - | ||
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "types/acl_op.h" | 18 | +#include "types/acl_op_inner.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
Dapi/acl/acl_op_compiler/single_op/op_executor.h+0-103
| @@ -1,103 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | - | ||
| 26 | - | ||
| 27 | - | ||
| 28 | -namespace acl { | ||
| 29 | -struct OpHandle { | ||
| 30 | - std::string opType; | ||
| 31 | - int32_t numInputs = 0; | ||
| 32 | - int32_t numOutputs = 0; | ||
| 33 | - OpModel opModel; | ||
| 34 | - std::mutex mutexForStatic; | ||
| 35 | - std::unordered_map<aclrtStream, ge::SingleOp *> cachedOperators; | ||
| 36 | - std::mutex mutexForDynamic; | ||
| 37 | - std::map<aclrtStream, ge::DynamicSingleOp *> cachedDynamicOperators; | ||
| 38 | - std::shared_ptr<aclopKernelDesc> kernelDesc; | ||
| 39 | - AclOp aclOp; | ||
| 40 | - bool isDynamic = false; | ||
| 41 | -}; | ||
| 42 | - | ||
| 43 | - | ||
| 44 | -inline void FixGeDataBuffer(const aclDataBuffer *const aclBuf, const aclMemType memType, ge::DataBuffer &geBuf) | ||
| 45 | -{ | ||
| 46 | - geBuf.data = aclBuf->data; | ||
| 47 | - geBuf.length = aclBuf->length; | ||
| 48 | - geBuf.placement = | ||
| 49 | - ((memType == ACL_MEMTYPE_DEVICE) ? static_cast<uint32_t>(memType) : static_cast<uint32_t>(ACL_MEMTYPE_HOST)); | ||
| 50 | -} | ||
| 51 | - | ||
| 52 | - | ||
| 53 | -class ACL_FUNC_VISIBILITY OpExecutor { | ||
| 54 | -public: | ||
| 55 | - static aclError CreateOpHandle(const AclOp &aclOp, OpHandle **const handle); | ||
| 56 | - | ||
| 57 | - static aclError ExecuteAsync(const AclOp &aclOp, | ||
| 58 | - const aclDataBuffer *const inputs[], | ||
| 59 | - aclDataBuffer *const outputs[], | ||
| 60 | - const aclrtStream stream); | ||
| 61 | - | ||
| 62 | - static aclError ExecuteAsync(OpHandle &opHandle, | ||
| 63 | - const aclDataBuffer *const inputs[], | ||
| 64 | - aclDataBuffer *const outputs[], | ||
| 65 | - const aclrtStream stream); | ||
| 66 | - | ||
| 67 | -private: | ||
| 68 | - static aclError LoadSingleOp(const OpModel &modelInfo, const aclrtStream stream, ge::SingleOp **const singleOp); | ||
| 69 | - | ||
| 70 | - static aclError LoadDynamicSingleOp(const OpModel &modelInfo, | ||
| 71 | - const aclrtStream stream, | ||
| 72 | - ge::DynamicSingleOp **const dynamicSingleOp); | ||
| 73 | - | ||
| 74 | - static aclError DoExecuteAsync(ge::DynamicSingleOp *const singleOp, | ||
| 75 | - const AclOp &aclOp, | ||
| 76 | - const aclDataBuffer *const inputs[], | ||
| 77 | - const aclDataBuffer *const outputs[], | ||
| 78 | - const bool executeWithExactModel = true); | ||
| 79 | - | ||
| 80 | - static aclError DoExecuteAsync(ge::SingleOp *const singleOp, | ||
| 81 | - const AclOp &aclOp, | ||
| 82 | - const aclDataBuffer *const inputs[], | ||
| 83 | - const aclDataBuffer *const outputs[], | ||
| 84 | - const bool executeWithExactModel = true); | ||
| 85 | - | ||
| 86 | - static aclError DoExecuteRT1(const AclOp &aclOp, | ||
| 87 | - const aclDataBuffer *const inputs[], | ||
| 88 | - aclDataBuffer *const outputs[], | ||
| 89 | - const aclrtStream stream, | ||
| 90 | - const OpModel *opModelPtr, | ||
| 91 | - const bool isDynamic, | ||
| 92 | - const bool isExactModel); | ||
| 93 | - | ||
| 94 | - static aclError PrepareRt2Execute(const AclOp &aclOp, OpModel *opModelPtr); | ||
| 95 | - | ||
| 96 | - static aclError DoExecuteAsync(std::shared_ptr<gert::StreamExecutor> &streamExecutor, | ||
| 97 | - const AclOp &aclOp, | ||
| 98 | - const aclrtStream stream, | ||
| 99 | - const bool executeWithExactModel = true); | ||
| 100 | -}; | ||
| 101 | -} // namespace acl | ||
| 102 | - | ||
| 103 | - | ||
Dapi/acl/acl_op_compiler/single_op/op_model_cache.h+0-55
| @@ -1,55 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | -namespace acl { | ||
| 22 | -class OpModelCache { | ||
| 23 | -public: | ||
| 24 | - OpModelCache() = default; | ||
| 25 | - | ||
| 26 | - ~OpModelCache() = default; | ||
| 27 | - | ||
| 28 | - aclError GetOpModel(const OpModelDef &modelDef, OpModel &operModel); | ||
| 29 | - | ||
| 30 | - std::shared_ptr<std::mutex> GetCacheMutex(const uint64_t id); | ||
| 31 | - | ||
| 32 | - aclError Add(const uint64_t opId, OpModel &operModel); | ||
| 33 | - | ||
| 34 | - aclError Delete(const OpModelDef &modelDef, const bool isDynamic); | ||
| 35 | - | ||
| 36 | - aclError CreateCachedExecutor(std::shared_ptr<gert::StreamExecutor> &streamExecutor, rtStream_t stream, | ||
| 37 | - const gert::ModelExecuteArg &arg, gert::ModelV2Executor *&executor); | ||
| 38 | - | ||
| 39 | - std::shared_ptr<gert::StreamExecutor> GetRT2Executor(const uint64_t id); | ||
| 40 | - | ||
| 41 | - aclError UpdateCachedExecutor(const uint64_t &id, const std::shared_ptr<gert::StreamExecutor> &executor); | ||
| 42 | - | ||
| 43 | - aclError UnloadCachedModelData(const uint64_t &id); | ||
| 44 | - | ||
| 45 | - aclError CleanCachedExecutor(rtStream_t stream); | ||
| 46 | - | ||
| 47 | - void CleanCachedModels() noexcept; | ||
| 48 | - | ||
| 49 | -private: | ||
| 50 | - std::unordered_map<uint64_t, OpModel> cachedModels_; | ||
| 51 | - std::recursive_mutex mutex_; | ||
| 52 | -}; | ||
| 53 | -} // namespace acl | ||
| 54 | - | ||
| 55 | - | ||
| @@ -28,7 +28,7 @@ add_library(acl_op_executor_impl SHARED | |||
| 28 | single_op/executor/op_task.cpp | 28 | single_op/executor/op_task.cpp |
| 29 | types/op_attr.cpp | 29 | types/op_attr.cpp |
| 30 | types/op_model.cpp | 30 | types/op_model.cpp |
| 31 | - types/acl_op.cpp | 31 | + types/acl_op_inner.cpp |
| 32 | ../common/common_inner.cpp | 32 | ../common/common_inner.cpp |
| 33 | ../common/log_inner.cpp | 33 | ../common/log_inner.cpp |
| 34 | ../common/json_parser.cpp | 34 | ../common/json_parser.cpp |
| @@ -22,7 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | -#include "types/acl_op.h" | 25 | +#include "types/acl_op_inner.h" |
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | 28 | ||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -#include "types/acl_op.h" | 22 | +#include "types/acl_op_inner.h" |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | namespace acl { | 25 | namespace acl { |
| @@ -17,7 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | -#include "types/acl_op.h" | 20 | +#include "types/acl_op_inner.h" |
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | -#include "types/acl_op.h" | 14 | +#include "types/acl_op_inner.h" |
| 15 | 15 | ||
| 16 | namespace acl { | 16 | namespace acl { |
| 17 | class OpTask { | 17 | class OpTask { |
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | -#include "types/acl_op.h" | 17 | +#include "types/acl_op_inner.h" |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | -#include "types/acl_op.h" | 17 | +#include "types/acl_op_inner.h" |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | -#include "types/acl_op.h" | 14 | +#include "types/acl_op_inner.h" |
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -#include "types/acl_op.h" | 22 | +#include "types/acl_op_inner.h" |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | 25 | ||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | -#include "types/acl_op.h" | 17 | +#include "types/acl_op_inner.h" |
| 18 | 18 | ||
| 19 | namespace acl { | 19 | namespace acl { |
| 20 | class MmRDLockGuard { | 20 | class MmRDLockGuard { |
| @@ -8,7 +8,7 @@ | |||
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | -#include "acl_op.h" | 11 | +#include "acl_op_inner.h" |
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | namespace { | 14 | namespace { |
| @@ -8,8 +8,8 @@ | |||
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | -#ifndef ACL_TYPES_ACL_OP_H | 11 | +#ifndef ACL_TYPES_ACL_OP_INNER_H |
| 12 | -#define ACL_TYPES_ACL_OP_H | 12 | +#define ACL_TYPES_ACL_OP_INNER_H |
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| @@ -68,4 +68,4 @@ public: | |||
| 68 | }; | 68 | }; |
| 69 | } // namespace acl | 69 | } // namespace acl |
| 70 | 70 | ||
| 71 | -#endif // ACL_TYPES_ACL_OP_H | 71 | +#endif // ACL_TYPES_ACL_OP_INNER_H |
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "types/acl_op.h" | 18 | +#include "types/acl_op_inner.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -#include "types/acl_op.h" | 22 | +#include "types/acl_op_inner.h" |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | namespace acl { | 25 | namespace acl { |
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | -#include "types/acl_op.h" | 17 | +#include "types/acl_op_inner.h" |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | namespace acl { | 20 | namespace acl { |
| @@ -1,9 +1,9 @@ | |||
| 1 | # ----------------------------------------------------------------------------------------------------------- | 1 | # ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ----------------------------------------------------------------------------------------------------------- | 9 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -1,9 +1,9 @@ | |||
| 1 | # ----------------------------------------------------------------------------------------------------------- | 1 | # ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ----------------------------------------------------------------------------------------------------------- | 9 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -52,6 +52,125 @@ message(STATUS "[add_es_library] Module loaded from: ${_ADD_ES_LIBRARY_CMAKE_DIR | |||
| 52 | # 7. 多个 ES 包会自动添加依赖关系,确保共享依赖只构建一次 | 52 | # 7. 多个 ES 包会自动添加依赖关系,确保共享依赖只构建一次 |
| 53 | # ====================================================================================================================== | 53 | # ====================================================================================================================== |
| 54 | 54 | ||
| 55 | +# ====================================================================================================================== | ||
| 56 | +# add_custom_command 封装宏 | ||
| 57 | +# | ||
| 58 | +# 统一封装代码生成命令,内部根据 COMBINED_COMMERCIAL_MODE 自动选择模式: | ||
| 59 | +# 单次模式(COMBINED_COMMERCIAL_MODE=FALSE):仅执行一次 gen_esb,生成 C++ API | ||
| 60 | +# 双次模式(COMBINED_COMMERCIAL_MODE=TRUE): 步骤1 代码生成 + 步骤2 历史原型库归档 | ||
| 61 | +# | ||
| 62 | +# 三处调用点(外部 gen_esb 有依赖 / 外部 gen_esb 无依赖 / 源码 gen_esb)共用此宏, | ||
| 63 | +# 仅 gen_esb 路径、LD_LIBRARY_PATH、EXCLUDE_OPS、DEPENDS、COMMENT 不同,由调用方通过参数传入。 | ||
| 64 | +# | ||
| 65 | +# 参数: | ||
| 66 | +# _gen_esb_exe gen_esb 可执行路径(字面量或生成器表达式 $<TARGET_FILE:gen_esb>) | ||
| 67 | +# _lib_dir LD_LIBRARY_PATH(run 包环境传 ${ASCEND_LIB_DIR},源码环境传空字符串) | ||
| 68 | +# _excl_ops 排除算子列表(INTERFACE 库传空字符串,其他传 ${ARG_EXCLUDE_OPS}) | ||
| 69 | +# _comment COMMENT 说明文字 | ||
| 70 | +# | ||
| 71 | +# 调用前需设置 _COMBINED_MODE_DEPENDS: | ||
| 72 | +# 有依赖时:set(_COMBINED_MODE_DEPENDS "DEPENDS;dep1;dep2") | ||
| 73 | +# 无依赖时:unset(_COMBINED_MODE_DEPENDS) | ||
| 74 | +# ====================================================================================================================== | ||
| 75 | +macro(_es_add_gen_esb_cmd _gen_esb_exe _lib_dir _excl_ops _comment) | ||
| 76 | + if (COMBINED_COMMERCIAL_MODE) | ||
| 77 | + set(_HIST_STAGE_DIR "${ARG_OUTPUT_PATH}") | ||
| 78 | + if ("${_AUTO_HISTORY_REGISTRY}" STREQUAL "${ARG_OUTPUT_PATH}") | ||
| 79 | + # 首次构建(历史库尚不存在于 CANN 路径):_AUTO_HISTORY_REGISTRY == ARG_OUTPUT_PATH, | ||
| 80 | + set(_PREPOPULATE_STAGING "") | ||
| 81 | + else () | ||
| 82 | + # 非首次构建:将 CANN 只读历史库内容合并复制到 ARG_OUTPUT_PATH | ||
| 83 | + set(_PREPOPULATE_STAGING | ||
| 84 | + COMMAND ${CMAKE_COMMAND} -E copy_directory "${_AUTO_HISTORY_REGISTRY}" "${ARG_OUTPUT_PATH}" | ||
| 85 | + COMMAND chmod u+w "${ARG_OUTPUT_PATH}/index.json" | ||
| 86 | + ) | ||
| 87 | + endif () | ||
| 88 | + | ||
| 89 | + add_custom_command( | ||
| 90 | + OUTPUT ${CODE_GEN_FLAG} | ||
| 91 | + COMMAND ${CMAKE_COMMAND} -E echo "Generating ES code (combined commercial mode) for package: ${ARG_ES_LINKABLE_AND_ALL_TARGET}" | ||
| 92 | + COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_CODE_DIR} | ||
| 93 | + COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_CODE_DIR} | ||
| 94 | + # 步骤1: 代码生成(消费历史原型库,gen_esb 自动选取窗口内历史版本对比) | ||
| 95 | + COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 96 | + ${GEN_CODE_DIR}/.gen.lock | ||
| 97 | + ${_gen_esb_exe} | ||
| 98 | + ${OPP_PROTO_PATH} | ||
| 99 | + ${GEN_CODE_DIR} | ||
| 100 | + ${MODULE_NAME} | ||
| 101 | + "${_lib_dir}" | ||
| 102 | + "${_excl_ops}" | ||
| 103 | + "" | ||
| 104 | + "" | ||
| 105 | + ${HISTORY_REGISTRY_ARG} | ||
| 106 | + "" | ||
| 107 | + "" | ||
| 108 | + # 步骤2: 归档到 ARG_OUTPUT_PATH;若已有历史库则先复制并授权,gen_esb 追加新条目 | ||
| 109 | + ${_PREPOPULATE_STAGING} | ||
| 110 | + COMMAND ${CMAKE_COMMAND} -E make_directory "${_HIST_STAGE_DIR}" | ||
| 111 | + COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 112 | + ${_HIST_STAGE_DIR}/.extract.lock | ||
| 113 | + ${_gen_esb_exe} | ||
| 114 | + ${OPP_PROTO_PATH} | ||
| 115 | + ${_HIST_STAGE_DIR} | ||
| 116 | + ${MODULE_NAME} | ||
| 117 | + "${_lib_dir}" | ||
| 118 | + "" | ||
| 119 | + ${EXTRACT_HISTORY_FLAG} | ||
| 120 | + ${RELEASE_VERSION_ARG} | ||
| 121 | + "" | ||
| 122 | + ${RELEASE_DATE_ARG} | ||
| 123 | + ${BRANCH_NAME_ARG} | ||
| 124 | + COMMAND ${CMAKE_COMMAND} -E echo "[ES] Historical prototype library generation completed: ${ARG_OUTPUT_PATH}" | ||
| 125 | + # 步骤3: 动态生成 wrapper 文件的 include 内容 | ||
| 126 | + COMMAND ${CMAKE_COMMAND} -P ${GENERATE_WRAPPER_SCRIPT} | ||
| 127 | + COMMAND ${CMAKE_COMMAND} -E touch ${CODE_GEN_FLAG} | ||
| 128 | + ${_COMBINED_MODE_DEPENDS} | ||
| 129 | + COMMENT "${_comment}" | ||
| 130 | + JOB_POOL es_gen_esb_serial | ||
| 131 | + VERBATIM | ||
| 132 | + ) | ||
| 133 | + else () | ||
| 134 | + # 历史库路径有效时:代码生成后将 CANN 历史库内容合并复制到 ARG_OUTPUT_PATH | ||
| 135 | + if (_AUTO_HISTORY_REGISTRY) | ||
| 136 | + set(_COPY_EXISTING_HISTORY | ||
| 137 | + COMMAND ${CMAKE_COMMAND} -E copy_directory "${_AUTO_HISTORY_REGISTRY}" "${ARG_OUTPUT_PATH}" | ||
| 138 | + COMMAND ${CMAKE_COMMAND} -E echo "[ES] Existing history registry copied to output: ${ARG_OUTPUT_PATH}" | ||
| 139 | + ) | ||
| 140 | + else () | ||
| 141 | + set(_COPY_EXISTING_HISTORY "") | ||
| 142 | + endif () | ||
| 143 | + add_custom_command( | ||
| 144 | + OUTPUT ${CODE_GEN_FLAG} | ||
| 145 | + COMMAND ${CMAKE_COMMAND} -E echo "Generating ES code for package: ${ARG_ES_LINKABLE_AND_ALL_TARGET}" | ||
| 146 | + COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_CODE_DIR} | ||
| 147 | + COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_CODE_DIR} | ||
| 148 | + # 单次代码生成 | ||
| 149 | + COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 150 | + ${GEN_CODE_DIR}/.gen.lock | ||
| 151 | + ${_gen_esb_exe} | ||
| 152 | + ${OPP_PROTO_PATH} | ||
| 153 | + ${GEN_CODE_DIR} | ||
| 154 | + ${MODULE_NAME} | ||
| 155 | + "${_lib_dir}" | ||
| 156 | + "${_excl_ops}" | ||
| 157 | + ${CODE_GEN_STEP_EXTRACT_FLAG} | ||
| 158 | + ${RELEASE_VERSION_ARG} | ||
| 159 | + ${HISTORY_REGISTRY_ARG} | ||
| 160 | + ${RELEASE_DATE_ARG} | ||
| 161 | + ${BRANCH_NAME_ARG} | ||
| 162 | + # 版本重复时将现有历史库复制到输出目录 | ||
| 163 | + ${_COPY_EXISTING_HISTORY} | ||
| 164 | + COMMAND ${CMAKE_COMMAND} -P ${GENERATE_WRAPPER_SCRIPT} | ||
| 165 | + COMMAND ${CMAKE_COMMAND} -E touch ${CODE_GEN_FLAG} | ||
| 166 | + ${_COMBINED_MODE_DEPENDS} | ||
| 167 | + COMMENT "${_comment}" | ||
| 168 | + JOB_POOL es_gen_esb_serial | ||
| 169 | + VERBATIM | ||
| 170 | + ) | ||
| 171 | + endif () | ||
| 172 | +endmacro() | ||
| 173 | + | ||
| 55 | function(_add_es_library_impl) | 174 | function(_add_es_library_impl) |
| 56 | # 0. 生成辅助 shell 脚本(自包含,无需外部文件) | 175 | # 0. 生成辅助 shell 脚本(自包含,无需外部文件) |
| 57 | # 在首次调用时创建 run_gen_esb_with_lock.sh 到构建目录 | 176 | # 在首次调用时创建 run_gen_esb_with_lock.sh 到构建目录 |
| @@ -63,7 +182,7 @@ function(_add_es_library_impl) | |||
| 63 | # Auto-generated by generate_es_package.cmake | 182 | # Auto-generated by generate_es_package.cmake |
| 64 | # ES code generation wrapper script with detailed logging and flock fallback | 183 | # ES code generation wrapper script with detailed logging and flock fallback |
| 65 | # | 184 | # |
| 66 | -# Args: \$1=lock_file \$2=gen_esb_path \$3=ASCEND_OPP_PATH \$4=output_dir \$5=module_name \$6=LD_LIBRARY_PATH(optional) \$7=EXCLUDE_OPS(optional) | 185 | +# Args: \$1=lock_file \$2=gen_esb_path \$3=ASCEND_OPP_PATH \$4=output_dir \$5=module_name \$6=LD_LIBRARY_PATH(optional) \$7=EXCLUDE_OPS(optional) \$8=MODE_ARG(optional, e.g. --es_mode=extract_history) \$9=RELEASE_VERSION(optional) \$10=HISTORY_REGISTRY_ARG(optional) \$11=RELEASE_DATE_ARG(optional) \$12=BRANCH_NAME_ARG(optional) |
| 67 | 186 | ||
| 68 | LOCK_FILE=\"\$1\" | 187 | LOCK_FILE=\"\$1\" |
| 69 | GEN_ESB_EXE=\"\$2\" | 188 | GEN_ESB_EXE=\"\$2\" |
| @@ -72,6 +191,11 @@ OUTPUT_DIR=\"\$4\" | |||
| 72 | MODULE_NAME=\"\$5\" | 191 | MODULE_NAME=\"\$5\" |
| 73 | LIB_PATH=\"\${6:-}\" | 192 | LIB_PATH=\"\${6:-}\" |
| 74 | EXCLUDE_OPS=\"\${7:-}\" | 193 | EXCLUDE_OPS=\"\${7:-}\" |
| 194 | +EXTRACT_HISTORY_FLAG=\"\${8:-}\" | ||
| 195 | +RELEASE_VERSION_FLAG=\"\${9:-}\" | ||
| 196 | +HISTORY_REGISTRY_ARG=\"\${10:-}\" | ||
| 197 | +RELEASE_DATE_ARG=\"\${11:-}\" | ||
| 198 | +BRANCH_NAME_ARG=\"\${12:-}\" | ||
| 75 | 199 | ||
| 76 | # Enable pipefail to ensure exit code from gen_esb is captured through pipes | 200 | # Enable pipefail to ensure exit code from gen_esb is captured through pipes |
| 77 | set -o pipefail | 201 | set -o pipefail |
| @@ -152,10 +276,10 @@ execute_gen_esb() { | |||
| 152 | else | 276 | else |
| 153 | ENV_PREFIX=\"ASCEND_OPP_PATH=\${OPP_PATH}\" | 277 | ENV_PREFIX=\"ASCEND_OPP_PATH=\${OPP_PATH}\" |
| 154 | fi | 278 | fi |
| 155 | - log_debug \"Command: \$ENV_PREFIX \\\"\${GEN_ESB_EXE}\\\" --output_dir=\\\"\${OUTPUT_DIR}\\\" --module_name=\\\"\${MODULE_NAME}\\\" --exclude_ops=\\\"\${EXCLUDE_OPS}\\\"\" | 279 | + log_debug \"Command: \$ENV_PREFIX \\\"\${GEN_ESB_EXE}\\\" --output_dir=\\\"\${OUTPUT_DIR}\\\" --module_name=\\\"\${MODULE_NAME}\\\" --exclude_ops=\\\"\${EXCLUDE_OPS}\\\" \${EXTRACT_HISTORY_FLAG} \${RELEASE_VERSION_FLAG} \${HISTORY_REGISTRY_ARG} \${RELEASE_DATE_ARG} \${BRANCH_NAME_ARG}\" |
| 156 | 280 | ||
| 157 | # Execute gen_esb directly (without env -i, with pipefail enabled) | 281 | # Execute gen_esb directly (without env -i, with pipefail enabled) |
| 158 | - if eval \"\$ENV_PREFIX \\\"\${GEN_ESB_EXE}\\\" --output_dir=\\\"\${OUTPUT_DIR}\\\" --module_name=\\\"\${MODULE_NAME}\\\" --exclude_ops=\\\"\${EXCLUDE_OPS}\\\" 2>&1 | tee -a \\\"\${DEBUG_LOG}\\\"\"; then | 282 | + if eval \"\$ENV_PREFIX \\\"\${GEN_ESB_EXE}\\\" --output_dir=\\\"\${OUTPUT_DIR}\\\" --module_name=\\\"\${MODULE_NAME}\\\" --exclude_ops=\\\"\${EXCLUDE_OPS}\\\" \${EXTRACT_HISTORY_FLAG} \${RELEASE_VERSION_FLAG} \${HISTORY_REGISTRY_ARG} \${RELEASE_DATE_ARG} \${BRANCH_NAME_ARG} 2>&1 | tee -a \\\"\${DEBUG_LOG}\\\"\"; then |
| 159 | log_debug \"[Success] gen_esb executed successfully\" | 283 | log_debug \"[Success] gen_esb executed successfully\" |
| 160 | return 0 | 284 | return 0 |
| 161 | else | 285 | else |
| @@ -310,6 +434,54 @@ exit 1 | |||
| 310 | message(STATUS "_add_es_library_impl: EXCLUDE_OPS is ${ARG_EXCLUDE_OPS}") | 434 | message(STATUS "_add_es_library_impl: EXCLUDE_OPS is ${ARG_EXCLUDE_OPS}") |
| 311 | endif () | 435 | endif () |
| 312 | 436 | ||
| 437 | + # 历史原型库相关参数 | ||
| 438 | + # 使用 cmake 变量(-D 传入);若未定义则从同名环境变量捕获。 | ||
| 439 | + # GE_ES_EXTRACT_HISTORY: bool 开关,ON 时启用历史原型库归档模式(两次 gen_esb 调用); | ||
| 440 | + # 不设置或 OFF 时走纯代码生成模式(仅生成 C++ API,不归档) | ||
| 441 | + # GE_ES_RELEASE_VERSION: 当前新版本号(例如 "8.0.RC1"),用于历史原型库归档 | ||
| 442 | + # GE_ES_RELEASE_DATE: 归档时的发布日期(可选,格式 YYYY-MM-DD,不指定则 gen_esb 使用当前日期) | ||
| 443 | + # GE_ES_BRANCH_NAME: 构建分支名(可选;master 分支自动屏蔽归档参数) | ||
| 444 | + # | ||
| 445 | + # 历史原型库路径由函数内部从 cmake 文件路径自动推导(${CANN_INSTALL_PATH}/cann/opp/history_registry/<module>), | ||
| 446 | + # 路径存在且非空时自动传 --history_registry,无需用户传参。 | ||
| 447 | + # | ||
| 448 | + # 从环境变量兜底捕获(cmake 变量未定义时生效) | ||
| 449 | + foreach(_ES_VAR GE_ES_EXTRACT_HISTORY GE_ES_RELEASE_VERSION GE_ES_RELEASE_DATE GE_ES_BRANCH_NAME) | ||
| 450 | + if (NOT DEFINED ${_ES_VAR} AND DEFINED ENV{${_ES_VAR}}) | ||
| 451 | + set(${_ES_VAR} "$ENV{${_ES_VAR}}") | ||
| 452 | + message(STATUS "[ES] Captured from environment variable: ${_ES_VAR}=${${_ES_VAR}}") | ||
| 453 | + endif () | ||
| 454 | + endforeach () | ||
| 455 | + | ||
| 456 | + # master 分支:屏蔽全部归档参数,走纯代码生成模式;历史原型库路径仍传递(用于生成带重载 C++ API) | ||
| 457 | + if (GE_ES_BRANCH_NAME STREQUAL "master") | ||
| 458 | + if (GE_ES_EXTRACT_HISTORY OR GE_ES_RELEASE_VERSION OR GE_ES_RELEASE_DATE) | ||
| 459 | + message(STATUS "[ES] Branch is master, ignoring GE_ES_EXTRACT_HISTORY/GE_ES_RELEASE_VERSION/GE_ES_RELEASE_DATE/GE_ES_BRANCH_NAME, using code-generation-only mode") | ||
| 460 | + endif () | ||
| 461 | + set(GE_ES_EXTRACT_HISTORY OFF) | ||
| 462 | + set(GE_ES_RELEASE_VERSION "") | ||
| 463 | + set(GE_ES_RELEASE_DATE "") | ||
| 464 | + set(GE_ES_BRANCH_NAME "") | ||
| 465 | + endif () | ||
| 466 | + | ||
| 467 | + set(EXTRACT_HISTORY_FLAG "") | ||
| 468 | + if (GE_ES_EXTRACT_HISTORY) | ||
| 469 | + set(EXTRACT_HISTORY_FLAG "--es_mode=extract_history") | ||
| 470 | + message(STATUS "[ES] Historical prototype library mode enabled (GE_ES_EXTRACT_HISTORY=ON), gen_esb will append --es_mode=extract_history") | ||
| 471 | + endif () | ||
| 472 | + set(RELEASE_VERSION_ARG "") | ||
| 473 | + if (GE_ES_RELEASE_VERSION) | ||
| 474 | + set(RELEASE_VERSION_ARG "--release_version=${GE_ES_RELEASE_VERSION}") | ||
| 475 | + endif () | ||
| 476 | + set(RELEASE_DATE_ARG "") | ||
| 477 | + if (GE_ES_RELEASE_DATE) | ||
| 478 | + set(RELEASE_DATE_ARG "--release_date=${GE_ES_RELEASE_DATE}") | ||
| 479 | + endif () | ||
| 480 | + set(BRANCH_NAME_ARG "") | ||
| 481 | + if (GE_ES_BRANCH_NAME) | ||
| 482 | + set(BRANCH_NAME_ARG "--branch_name=${GE_ES_BRANCH_NAME}") | ||
| 483 | + endif () | ||
| 484 | + | ||
| 313 | # 2.1. 检查 OPP_PROTO_TARGET 是否存在 | 485 | # 2.1. 检查 OPP_PROTO_TARGET 是否存在 |
| 314 | if (NOT TARGET ${ARG_OPP_PROTO_TARGET}) | 486 | if (NOT TARGET ${ARG_OPP_PROTO_TARGET}) |
| 315 | message(FATAL_ERROR "_add_es_library_impl: OPP_PROTO_TARGET '${ARG_OPP_PROTO_TARGET}' is not a valid CMake target") | 487 | message(FATAL_ERROR "_add_es_library_impl: OPP_PROTO_TARGET '${ARG_OPP_PROTO_TARGET}' is not a valid CMake target") |
| @@ -551,7 +723,72 @@ exit 1 | |||
| 551 | 723 | ||
| 552 | message(STATUS "add_es_package: Module name for gen_esb: ${MODULE_NAME}") | 724 | message(STATUS "add_es_package: Module name for gen_esb: ${MODULE_NAME}") |
| 553 | 725 | ||
| 554 | - # 2.7. 检测 eager_style_graph_builder_base 的来源 | 726 | + # 2.7. 自动推导历史原型库路径 |
| 727 | + # 从 cmake 文件路径推导安装根目录,查找 ${CANN_INSTALL_PATH}/cann/opp/history_registry/${MODULE_NAME}, | ||
| 728 | + # 路径存在且非空时自动传 --history_registry 给 gen_esb,无需用户显式设置。 | ||
| 729 | + set(HISTORY_REGISTRY_ARG "") | ||
| 730 | + set(_AUTO_HISTORY_REGISTRY "") | ||
| 731 | + if (USE_EXTERNAL_GEN_ESB) | ||
| 732 | + get_filename_component(_HIST_GE_DIR "${_ADD_ES_LIBRARY_CMAKE_DIR}" DIRECTORY) # 去掉 /cmake | ||
| 733 | + get_filename_component(_HIST_INCLUDE_DIR "${_HIST_GE_DIR}" DIRECTORY) # 去掉 /ge | ||
| 734 | + get_filename_component(_HIST_CANN_DIR "${_HIST_INCLUDE_DIR}" DIRECTORY) # 去掉 /include | ||
| 735 | + set(_CANDIDATE "${_HIST_CANN_DIR}/opp/history_registry/${MODULE_NAME}") | ||
| 736 | + if (IS_DIRECTORY "${_CANDIDATE}") | ||
| 737 | + file(GLOB _HIST_CONTENTS LIST_DIRECTORIES true "${_CANDIDATE}/*") | ||
| 738 | + if (_HIST_CONTENTS) | ||
| 739 | + set(_AUTO_HISTORY_REGISTRY "${_CANDIDATE}") | ||
| 740 | + set(HISTORY_REGISTRY_ARG "--history_registry=${_CANDIDATE}") | ||
| 741 | + message(STATUS "[add_es_library] Auto-detected history registry: ${_CANDIDATE}") | ||
| 742 | + else () | ||
| 743 | + message(STATUS "[add_es_library] History registry path exists but is empty, skipping: ${_CANDIDATE}") | ||
| 744 | + endif () | ||
| 745 | + else () | ||
| 746 | + message(STATUS "[add_es_library] No history registry found at ${_CANDIDATE}, skipping") | ||
| 747 | + endif () | ||
| 748 | + endif () | ||
| 749 | + | ||
| 750 | + # 版本去重:若历史原型库中已存在相同版本号 | ||
| 751 | + set(_DUPLICATE_VERSION_DETECTED FALSE) | ||
| 752 | + if (GE_ES_EXTRACT_HISTORY AND GE_ES_RELEASE_VERSION AND _AUTO_HISTORY_REGISTRY) | ||
| 753 | + set(_INDEX_JSON "${_AUTO_HISTORY_REGISTRY}/index.json") | ||
| 754 | + if (EXISTS "${_INDEX_JSON}") | ||
| 755 | + file(READ "${_INDEX_JSON}" _INDEX_CONTENT) | ||
| 756 | + string(FIND "${_INDEX_CONTENT}" "\"${GE_ES_RELEASE_VERSION}\"" _VER_POS) | ||
| 757 | + if (_VER_POS GREATER_EQUAL 0) | ||
| 758 | + message(STATUS "[ES] Version ${GE_ES_RELEASE_VERSION} already exists in historical prototype library, skipping archive, still using code generation mode") | ||
| 759 | + message(STATUS "[ES] Existing history registry will be copied to output: ${ARG_OUTPUT_PATH}") | ||
| 760 | + set(GE_ES_EXTRACT_HISTORY OFF) | ||
| 761 | + set(EXTRACT_HISTORY_FLAG "") | ||
| 762 | + set(_DUPLICATE_VERSION_DETECTED TRUE) | ||
| 763 | + endif () | ||
| 764 | + endif () | ||
| 765 | + endif () | ||
| 766 | + | ||
| 767 | + # 只要 GE_ES_EXTRACT_HISTORY=ON 就走双次调用路径 | ||
| 768 | + # 有已有历史原型库 → codegen(带重载)+ extract&merge | ||
| 769 | + # 无已有历史原型库(首次构建)→ codegen + extract 生成全新历史原型库,输出到 OUTPUT_PATH | ||
| 770 | + set(COMBINED_COMMERCIAL_MODE FALSE) | ||
| 771 | + if (GE_ES_EXTRACT_HISTORY) | ||
| 772 | + set(COMBINED_COMMERCIAL_MODE TRUE) | ||
| 773 | + if (_AUTO_HISTORY_REGISTRY) | ||
| 774 | + message(STATUS " - [add_es_library] Combined commercial mode: " | ||
| 775 | + "code gen with overload + extract & merge history registry (two gen_esb calls internally)") | ||
| 776 | + else () | ||
| 777 | + set(_AUTO_HISTORY_REGISTRY "${ARG_OUTPUT_PATH}") | ||
| 778 | + message(STATUS " - [add_es_library] Combined commercial mode (first build, no existing history registry): " | ||
| 779 | + "code gen + fresh history registry → ${ARG_OUTPUT_PATH}") | ||
| 780 | + endif () | ||
| 781 | + endif () | ||
| 782 | + | ||
| 783 | + # 代码生成步骤的 --es_mode 参数: | ||
| 784 | + # 完整商发模式下,代码生成步骤不传 --es_mode=extract_history(历史原型库生成模式由第二次 gen_esb 调用完成) | ||
| 785 | + if (COMBINED_COMMERCIAL_MODE) | ||
| 786 | + set(CODE_GEN_STEP_EXTRACT_FLAG "") | ||
| 787 | + else () | ||
| 788 | + set(CODE_GEN_STEP_EXTRACT_FLAG "${EXTRACT_HISTORY_FLAG}") | ||
| 789 | + endif () | ||
| 790 | + | ||
| 791 | + # 2.9. 检测 eager_style_graph_builder_base 的来源 | ||
| 555 | set(HAS_ES_BASE_TARGET FALSE) | 792 | set(HAS_ES_BASE_TARGET FALSE) |
| 556 | set(ES_BASE_LIB "") | 793 | set(ES_BASE_LIB "") |
| 557 | 794 | ||
| @@ -704,6 +941,7 @@ message(STATUS \"[ES Wrapper] Total operators included: \${NUM_OPS}\") | |||
| 704 | # 然后运行 generate_wrapper.cmake 生成包含所有 #include 的 wrapper 文件 | 941 | # 然后运行 generate_wrapper.cmake 生成包含所有 #include 的 wrapper 文件 |
| 705 | 942 | ||
| 706 | set(CODE_GEN_FLAG "${GEN_CODE_DIR}/generated_code.flag") | 943 | set(CODE_GEN_FLAG "${GEN_CODE_DIR}/generated_code.flag") |
| 944 | + set(GEN_ESB_OUTPUT_DIR "${GEN_CODE_DIR}") | ||
| 707 | 945 | ||
| 708 | # 8.1. 准备依赖列表 | 946 | # 8.1. 准备依赖列表 |
| 709 | # INTERFACE 库不需要构建,不添加到 DEPENDS 中 | 947 | # INTERFACE 库不需要构建,不添加到 DEPENDS 中 |
| @@ -716,59 +954,25 @@ message(STATUS \"[ES Wrapper] Total operators included: \${NUM_OPS}\") | |||
| 716 | endif () | 954 | endif () |
| 717 | endif () | 955 | endif () |
| 718 | 956 | ||
| 957 | + # INTERFACE 库不传 EXCLUDE_OPS(无算子需要排除) | ||
| 958 | + if (TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") | ||
| 959 | + set(_EXCL_OPS_ARG "") | ||
| 960 | + else () | ||
| 961 | + set(_EXCL_OPS_ARG "${ARG_EXCLUDE_OPS}") | ||
| 962 | + endif () | ||
| 963 | + | ||
| 719 | if (USE_EXTERNAL_GEN_ESB) | 964 | if (USE_EXTERNAL_GEN_ESB) |
| 720 | # 使用 run 包的 gen_esb | 965 | # 使用 run 包的 gen_esb |
| 721 | if (CODE_GEN_DEPENDS) | 966 | if (CODE_GEN_DEPENDS) |
| 722 | - add_custom_command( | 967 | + set(_COMBINED_MODE_DEPENDS "DEPENDS;${CODE_GEN_DEPENDS}") |
| 723 | - OUTPUT ${CODE_GEN_FLAG} | ||
| 724 | - COMMAND ${CMAKE_COMMAND} -E echo "Generating ES code for package: ${ARG_ES_LINKABLE_AND_ALL_TARGET}" | ||
| 725 | - # 清理旧的生成文件(删除整个目录) | ||
| 726 | - COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_CODE_DIR} | ||
| 727 | - COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_CODE_DIR} | ||
| 728 | - # 步骤1: 运行 gen_esb 生成各个算子的 .cpp 文件 | ||
| 729 | - COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 730 | - ${GEN_CODE_DIR}/.gen.lock | ||
| 731 | - ${GEN_ESB_EXE} | ||
| 732 | - ${OPP_PROTO_PATH} | ||
| 733 | - ${GEN_CODE_DIR} | ||
| 734 | - ${MODULE_NAME} | ||
| 735 | - ${ASCEND_LIB_DIR} | ||
| 736 | - ${ARG_EXCLUDE_OPS} | ||
| 737 | - # 步骤2: 代码生成完成后,动态生成 wrapper 文件的 include 内容 | ||
| 738 | - COMMAND ${CMAKE_COMMAND} -P ${GENERATE_WRAPPER_SCRIPT} | ||
| 739 | - # 标记完成 | ||
| 740 | - COMMAND ${CMAKE_COMMAND} -E touch ${CODE_GEN_FLAG} | ||
| 741 | - DEPENDS ${CODE_GEN_DEPENDS} | ||
| 742 | - COMMENT "Generating ES API code for package '${ARG_ES_LINKABLE_AND_ALL_TARGET}' using run package gen_esb..." | ||
| 743 | - JOB_POOL es_gen_esb_serial | ||
| 744 | - VERBATIM | ||
| 745 | - ) | ||
| 746 | else () | 968 | else () |
| 747 | # INTERFACE 库,无需依赖 | 969 | # INTERFACE 库,无需依赖 |
| 748 | - add_custom_command( | 970 | + unset(_COMBINED_MODE_DEPENDS) |
| 749 | - OUTPUT ${CODE_GEN_FLAG} | ||
| 750 | - COMMAND ${CMAKE_COMMAND} -E echo "Generating ES code for package: ${ARG_ES_LINKABLE_AND_ALL_TARGET}" | ||
| 751 | - # 清理旧的生成文件(删除整个目录) | ||
| 752 | - COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_CODE_DIR} | ||
| 753 | - COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_CODE_DIR} | ||
| 754 | - # 步骤1: 运行 gen_esb 生成各个算子的 .cpp 文件 | ||
| 755 | - COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 756 | - ${GEN_CODE_DIR}/.gen.lock | ||
| 757 | - ${GEN_ESB_EXE} | ||
| 758 | - ${OPP_PROTO_PATH} | ||
| 759 | - ${GEN_CODE_DIR} | ||
| 760 | - ${MODULE_NAME} | ||
| 761 | - ${ASCEND_LIB_DIR} | ||
| 762 | - ${ARG_EXCLUDE_OPS} | ||
| 763 | - # 步骤2: 代码生成完成后,动态生成 wrapper 文件的 include 内容 | ||
| 764 | - COMMAND ${CMAKE_COMMAND} -P ${GENERATE_WRAPPER_SCRIPT} | ||
| 765 | - # 标记完成 | ||
| 766 | - COMMAND ${CMAKE_COMMAND} -E touch ${CODE_GEN_FLAG} | ||
| 767 | - COMMENT "Generating ES API code for package '${ARG_ES_LINKABLE_AND_ALL_TARGET}' using run package gen_esb (no OPP build dependency)..." | ||
| 768 | - JOB_POOL es_gen_esb_serial | ||
| 769 | - VERBATIM | ||
| 770 | - ) | ||
| 771 | endif () | 971 | endif () |
| 972 | + _es_add_gen_esb_cmd( | ||
| 973 | + "${GEN_ESB_EXE}" "${ASCEND_LIB_DIR}" "${_EXCL_OPS_ARG}" | ||
| 974 | + "Generating ES API code for '${ARG_ES_LINKABLE_AND_ALL_TARGET}' using run package gen_esb..." | ||
| 975 | + ) | ||
| 772 | else () | 976 | else () |
| 773 | # 使用源码编译的 gen_esb target | 977 | # 使用源码编译的 gen_esb target |
| 774 | # 源码环境的 OPP_PROTO_TARGET 一定是实际的库 target,需要添加依赖 | 978 | # 源码环境的 OPP_PROTO_TARGET 一定是实际的库 target,需要添加依赖 |
| @@ -777,30 +981,10 @@ message(STATUS \"[ES Wrapper] Total operators included: \${NUM_OPS}\") | |||
| 777 | if (USE_STANDARD_PATH AND OPP_COPY_FLAG) | 981 | if (USE_STANDARD_PATH AND OPP_COPY_FLAG) |
| 778 | list(APPEND CODE_GEN_DEPENDS ${OPP_COPY_FLAG}) | 982 | list(APPEND CODE_GEN_DEPENDS ${OPP_COPY_FLAG}) |
| 779 | endif () | 983 | endif () |
| 780 | - | 984 | + set(_COMBINED_MODE_DEPENDS "DEPENDS;${CODE_GEN_DEPENDS}") |
| 781 | - add_custom_command( | 985 | + _es_add_gen_esb_cmd( |
| 782 | - OUTPUT ${CODE_GEN_FLAG} | 986 | + "$<TARGET_FILE:gen_esb>" "" "${_EXCL_OPS_ARG}" |
| 783 | - COMMAND ${CMAKE_COMMAND} -E echo "Generating ES code for package: ${ARG_ES_LINKABLE_AND_ALL_TARGET}" | 987 | + "Generating ES API code for '${ARG_ES_LINKABLE_AND_ALL_TARGET}' using source-built gen_esb..." |
| 784 | - # 清理旧的生成文件(删除整个目录) | ||
| 785 | - COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_CODE_DIR} | ||
| 786 | - COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_CODE_DIR} | ||
| 787 | - # 步骤1: 运行 gen_esb 生成各个算子的 .cpp 文件 | ||
| 788 | - # 使用包装脚本确保 gen_esb 可靠执行(带文件锁、重试机制和快速检查) | ||
| 789 | - COMMAND bash ${ES_LOCK_SCRIPT} | ||
| 790 | - ${GEN_CODE_DIR}/.gen.lock | ||
| 791 | - $<TARGET_FILE:gen_esb> | ||
| 792 | - ${OPP_PROTO_PATH} | ||
| 793 | - ${GEN_CODE_DIR} | ||
| 794 | - ${MODULE_NAME} | ||
| 795 | - ${ARG_EXCLUDE_OPS} | ||
| 796 | - # 步骤2: 代码生成完成后,动态生成 wrapper 文件的 include 内容 | ||
| 797 | - COMMAND ${CMAKE_COMMAND} -P ${GENERATE_WRAPPER_SCRIPT} | ||
| 798 | - # 标记完成 | ||
| 799 | - COMMAND ${CMAKE_COMMAND} -E touch ${CODE_GEN_FLAG} | ||
| 800 | - DEPENDS ${CODE_GEN_DEPENDS} | ||
| 801 | - COMMENT "Generating ES API code for package '${ARG_ES_LINKABLE_AND_ALL_TARGET}' using source-built gen_esb..." | ||
| 802 | - JOB_POOL es_gen_esb_serial | ||
| 803 | - VERBATIM | ||
| 804 | ) | 988 | ) |
| 805 | endif () | 989 | endif () |
| 806 | 990 | ||
| @@ -1,11 +1,12 @@ | |||
| 1 | -# This program is free software, you can redistribute it and/or modify. | 1 | +# ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This file is a part of the CANN Open Software. | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | -# Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | if (acl_rt_FOUND) | 11 | if (acl_rt_FOUND) |
| 11 | message(STATUS "Package acl_rt has been found.") | 12 | message(STATUS "Package acl_rt has been found.") |
| @@ -1,12 +1,13 @@ | |||
| 1 | # ----------------------------------------------------------------------------------------------------------- | 1 | # ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ----------------------------------------------------------------------------------------------------------- | 9 | # ----------------------------------------------------------------------------------------------------------- |
| 10 | + | ||
| 10 | set(BENCHMARK_DIR ${CMAKE_THIRD_PARTY_LIB_DIR}) | 11 | set(BENCHMARK_DIR ${CMAKE_THIRD_PARTY_LIB_DIR}) |
| 11 | if (TARGET benchmark_build) | 12 | if (TARGET benchmark_build) |
| 12 | return() | 13 | return() |
| @@ -0,0 +1,1670 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace ascir { | ||
| 20 | +namespace dumper { | ||
| 21 | +// ============================================================================= | ||
| 22 | +// 工具函数实现 | ||
| 23 | +// ============================================================================= | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * @brief 统一的 Dtype 映射表 | ||
| 27 | + */ | ||
| 28 | +static const std::map<ge::DataType, DtypeInfo> kDtypeInfoMap = { | ||
| 29 | + {ge::DT_FLOAT, {"float32", "f32", "32f"}}, | ||
| 30 | + {ge::DT_FLOAT16, {"float16", "f16", "16f"}}, | ||
| 31 | + {ge::DT_BF16, {"bfloat16", "bf16", "16f"}}, | ||
| 32 | + {ge::DT_INT8, {"int8_t", "i8", "8i"}}, | ||
| 33 | + {ge::DT_INT16, {"int16_t", "i16", "16i"}}, | ||
| 34 | + {ge::DT_INT32, {"int32_t", "i32", "32i"}}, | ||
| 35 | + {ge::DT_INT64, {"int64_t", "i64", "64i"}}, | ||
| 36 | + {ge::DT_UINT8, {"uint8_t", "u8", "8u"}}, | ||
| 37 | + {ge::DT_UINT16, {"uint16_t", "u16", "16u"}}, | ||
| 38 | + {ge::DT_UINT32, {"uint32_t", "u32", "32u"}}, | ||
| 39 | + {ge::DT_UINT64, {"uint64_t", "u64", "64u"}}, | ||
| 40 | + {ge::DT_BOOL, {"bool", "i1", "1i"}}, | ||
| 41 | + {ge::DT_DOUBLE, {"float64", "f64", "64f"}}, | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | +const DtypeInfo *GetDtypeInfo(ge::DataType dtype) { | ||
| 45 | + auto it = kDtypeInfoMap.find(dtype); | ||
| 46 | + if (it != kDtypeInfoMap.end()) { | ||
| 47 | + return &it->second; | ||
| 48 | + } | ||
| 49 | + return nullptr; | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | +int32_t GetAxisTypePriority(ge::Axis::Type type) { | ||
| 53 | + switch (type) { | ||
| 54 | + case ge::Axis::Type::kAxisTypeBlockOuter: return 1; | ||
| 55 | + case ge::Axis::Type::kAxisTypeBlockInner: return 2; | ||
| 56 | + case ge::Axis::Type::kAxisTypeTileOuter: return 3; | ||
| 57 | + case ge::Axis::Type::kAxisTypeTileInner: return 4; | ||
| 58 | + case ge::Axis::Type::kAxisTypeOriginal: return 5; | ||
| 59 | + case ge::Axis::Type::kAxisTypeMerged: return 6; | ||
| 60 | + default: return 999; | ||
| 61 | + } | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +std::string GetAxisTypeSuffix(ge::Axis::Type type) { | ||
| 65 | + switch (type) { | ||
| 66 | + case ge::Axis::Type::kAxisTypeTileOuter: return "TILE_OUT"; | ||
| 67 | + case ge::Axis::Type::kAxisTypeBlockOuter: return "BLOCK_OUT"; | ||
| 68 | + case ge::Axis::Type::kAxisTypeBlockInner: return "BLOCK_IN"; | ||
| 69 | + case ge::Axis::Type::kAxisTypeTileInner: return "TILE_IN"; | ||
| 70 | + default: return ""; | ||
| 71 | + } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +std::map<ge::AxisId, std::string> BuildAxisIdToNameMap(const std::vector<ge::AxisPtr> &axes) { | ||
| 75 | + std::map<ge::AxisId, std::string> id_to_name; | ||
| 76 | + for (const auto &axis: axes) { | ||
| 77 | + id_to_name[axis->id] = axis->name; | ||
| 78 | + } | ||
| 79 | + return id_to_name; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +std::map<int64_t, ge::Axis::Type> BuildAxisIdToTypeMap(const std::vector<ge::AxisPtr> &axes) { | ||
| 83 | + std::map<int64_t, ge::Axis::Type> id_to_type; | ||
| 84 | + for (const auto &axis: axes) { | ||
| 85 | + id_to_type[axis->id] = axis->type; | ||
| 86 | + } | ||
| 87 | + return id_to_type; | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +std::string ExtractDtypeFromTensorType(const std::string &tensor_type) { | ||
| 91 | + // tensor_type 格式: f32[...] 或 float32[...] | ||
| 92 | + size_t pos = tensor_type.find('['); | ||
| 93 | + if (pos != std::string::npos) { | ||
| 94 | + std::string dtype = tensor_type.substr(0, pos); | ||
| 95 | + // 转换简写为完整名称 | ||
| 96 | + if (dtype == "f32") return "float32"; | ||
| 97 | + if (dtype == "f16") return "float16"; | ||
| 98 | + if (dtype == "i32") return "int32"; | ||
| 99 | + if (dtype == "i8") return "int8"; | ||
| 100 | + if (dtype == "i16") return "int16"; | ||
| 101 | + if (dtype == "bf16") return "bfloat16"; | ||
| 102 | + return dtype; | ||
| 103 | + } | ||
| 104 | + return tensor_type; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +std::string ExtractAxisListFromTensorType(const std::string &tensor_type) { | ||
| 108 | + size_t pos = tensor_type.find('['); | ||
| 109 | + if (pos != std::string::npos) { | ||
| 110 | + return tensor_type.substr(pos); | ||
| 111 | + } | ||
| 112 | + return "[]"; | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +std::vector<std::string> CollectInputNames(const ascir::Graph &graph, const ge::AscNodePtr &node) { | ||
| 116 | + (void) graph; | ||
| 117 | + std::vector<std::string> input_names; | ||
| 118 | + | ||
| 119 | + for (uint32_t index = 0U; index < node->GetAllInDataAnchorsSize(); index++) { | ||
| 120 | + auto in_anchor = node->GetInDataAnchor(static_cast<int32_t>(index)); | ||
| 121 | + if (in_anchor == nullptr) { | ||
| 122 | + input_names.push_back("nil"); | ||
| 123 | + continue; | ||
| 124 | + } | ||
| 125 | + auto peer_out_anchor = in_anchor->GetPeerOutAnchor(); | ||
| 126 | + if (peer_out_anchor == nullptr) { | ||
| 127 | + input_names.push_back("nil"); | ||
| 128 | + } else { | ||
| 129 | + auto peer_name = peer_out_anchor->GetOwnerNode()->GetName(); | ||
| 130 | + int32_t out_idx = peer_out_anchor->GetIdx(); | ||
| 131 | + // 检查源节点是否有多个输出,如果有则显示索引 | ||
| 132 | + auto peer_node = peer_out_anchor->GetOwnerNode(); | ||
| 133 | + if (peer_node && peer_node->GetAllOutDataAnchorsSize() > 1) { | ||
| 134 | + input_names.push_back(peer_name + ".y[" + std::to_string(out_idx) + "]"); | ||
| 135 | + } else { | ||
| 136 | + input_names.push_back(peer_name + ".y"); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + return input_names; | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +SSAMappingInfo BuildSSAMapping(ge::AscNodeVisitor all_nodes) { | ||
| 144 | + SSAMappingInfo info; | ||
| 145 | + size_t topo_id = 0; | ||
| 146 | + | ||
| 147 | + for (auto node: all_nodes) { | ||
| 148 | + auto node_type = node->GetType(); | ||
| 149 | + if (node_type == NodeType::kData) { | ||
| 150 | + info.data_node_names.insert(node->GetName()); | ||
| 151 | + } else if (node_type != NodeType::kOutput && node_type != NodeType::kWorkspace) { | ||
| 152 | + info.node_name_to_ssa_id[node->GetName()] = topo_id + 1; | ||
| 153 | + info.node_name_to_topo_id[node->GetName()] = topo_id; | ||
| 154 | + topo_id++; | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + return info; | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +// ============================================================================= | ||
| 162 | +// VIEW 1: Loop Execution 内部辅助函数 | ||
| 163 | +// ============================================================================= | ||
| 164 | + | ||
| 165 | +namespace { | ||
| 166 | +/** | ||
| 167 | + * @brief 获取 DataType 的字符串表示(完整类型名) | ||
| 168 | + */ | ||
| 169 | +static std::string GetDtypeString(ge::DataType dtype) { | ||
| 170 | + const DtypeInfo *info = GetDtypeInfo(dtype); | ||
| 171 | + if (info != nullptr) { | ||
| 172 | + return info->full_name; | ||
| 173 | + } | ||
| 174 | + return ge::TypeUtils::DataTypeToSerialString(dtype); | ||
| 175 | +} | ||
| 176 | + | ||
| 177 | +// ============================================================================= | ||
| 178 | +// 向量化相关辅助函数实现 | ||
| 179 | +// ============================================================================= | ||
| 180 | + | ||
| 181 | +/** | ||
| 182 | + * @brief 检查向量化维度是否为广播维度 | ||
| 183 | + */ | ||
| 184 | +bool IsBroadcastDimension(const ge::Expression &stride) { | ||
| 185 | + if (stride.GetExprType() == ge::ExprType::kExprConstantRation) { | ||
| 186 | + int64_t val = 0; | ||
| 187 | + if (stride.GetConstValue(val) && val == 0) { | ||
| 188 | + return true; | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | + return false; | ||
| 192 | +} | ||
| 193 | + | ||
| 194 | +/** | ||
| 195 | + * @brief 获取向量化维度的大小字符串 | ||
| 196 | + */ | ||
| 197 | +std::string GetVectorizedDimSize(const ge::AscTensorAttr &attr, | ||
| 198 | + ge::AxisId axis_id, | ||
| 199 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 200 | + // 找到 axis_id 在 attr.axis 中的位置 | ||
| 201 | + size_t found_axis_idx = 0; | ||
| 202 | + for (; found_axis_idx < attr.axis.size(); ++found_axis_idx) { | ||
| 203 | + if (attr.axis[found_axis_idx] == axis_id) { | ||
| 204 | + break; | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + // 获取对应的 repeat 值 | ||
| 209 | + if (found_axis_idx < attr.repeats.size()) { | ||
| 210 | + auto repeat = attr.repeats[found_axis_idx]; | ||
| 211 | + if (repeat.GetExprType() == ge::ExprType::kExprConstantRation) { | ||
| 212 | + int64_t val = 0; | ||
| 213 | + if (repeat.GetConstValue(val)) { | ||
| 214 | + return std::to_string(val); | ||
| 215 | + } | ||
| 216 | + return "1"; | ||
| 217 | + } | ||
| 218 | + return ge::SymbolicUtils::ToString(repeat); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + // 找不到对应的 repeat,使用轴名 | ||
| 222 | + auto it = axis_id_to_name.find(axis_id); | ||
| 223 | + if (it != axis_id_to_name.end()) { | ||
| 224 | + return it->second + "_size"; | ||
| 225 | + } | ||
| 226 | + return "1"; | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +/** | ||
| 230 | + * @brief 获取 dtype 的简写后缀 | ||
| 231 | + */ | ||
| 232 | +std::string GetDtypeSuffix(ge::DataType dtype) { | ||
| 233 | + const DtypeInfo *info = GetDtypeInfo(dtype); | ||
| 234 | + if (info != nullptr) { | ||
| 235 | + return info->short_name; | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + // 未知类型,生成位宽表示 | ||
| 239 | + int32_t size_bytes = ge::GetSizeByDataType(dtype); | ||
| 240 | + std::string suffix = (size_bytes > 0) ? std::to_string(size_bytes * 8) : "32"; | ||
| 241 | + | ||
| 242 | + std::string type_name = ge::TypeUtils::DataTypeToSerialString(dtype); | ||
| 243 | + if (type_name.find("UINT") != std::string::npos || type_name.find("uint") != std::string::npos) { | ||
| 244 | + suffix += "u"; | ||
| 245 | + } else if (type_name.find("INT") != std::string::npos || type_name.find("int") != std::string::npos || | ||
| 246 | + type_name.find("BOOL") != std::string::npos) { | ||
| 247 | + suffix += "i"; | ||
| 248 | + } else { | ||
| 249 | + suffix += "f"; | ||
| 250 | + } | ||
| 251 | + return suffix; | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | +/** | ||
| 255 | + * @brief 获取向量化轴的字符串表示 | ||
| 256 | + */ | ||
| 257 | +static std::string GetVectorizedAxesStr(const ascir::Graph &graph, const ge::AscTensorAttr &attr, | ||
| 258 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 259 | + (void) graph; | ||
| 260 | + if (attr.vectorized_axis.empty()) { | ||
| 261 | + return ""; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + std::stringstream ss; | ||
| 265 | + ss << "vector<"; | ||
| 266 | + | ||
| 267 | + for (size_t i = 0; i < attr.vectorized_axis.size(); ++i) { | ||
| 268 | + if (i > 0) ss << "x"; | ||
| 269 | + | ||
| 270 | + auto axis_id = attr.vectorized_axis[i]; | ||
| 271 | + | ||
| 272 | + // 检查是否为广播维度 | ||
| 273 | + bool is_broadcast = false; | ||
| 274 | + if (i < attr.vectorized_strides.size()) { | ||
| 275 | + is_broadcast = IsBroadcastDimension(attr.vectorized_strides[i]); | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + if (is_broadcast) { | ||
| 279 | + ss << "1"; | ||
| 280 | + } else { | ||
| 281 | + ss << GetVectorizedDimSize(attr, axis_id, axis_id_to_name); | ||
| 282 | + } | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + ss << "x" << GetDtypeSuffix(attr.dtype) << ">"; | ||
| 286 | + | ||
| 287 | + return ss.str(); | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +/** | ||
| 291 | + * @brief 获取 tensor 类型字符串(用于函数签名) | ||
| 292 | + */ | ||
| 293 | +static std::string GetTensorTypeStr(const ascir::Graph &graph, const ge::AscTensorAttr &attr, | ||
| 294 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 295 | + (void) graph; | ||
| 296 | + std::stringstream ss; | ||
| 297 | + | ||
| 298 | + // 数据类型 - 使用简写类型名 | ||
| 299 | + auto dtype = attr.dtype; | ||
| 300 | + std::string dtype_str; | ||
| 301 | + const DtypeInfo *info = GetDtypeInfo(dtype); | ||
| 302 | + if (info != nullptr) { | ||
| 303 | + dtype_str = info->short_name; | ||
| 304 | + } else { | ||
| 305 | + // 使用完整类型名 | ||
| 306 | + dtype_str = GetDtypeString(dtype); | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + ss << dtype_str << "["; | ||
| 310 | + | ||
| 311 | + // 形状 | ||
| 312 | + for (size_t i = 0; i < attr.axis.size(); ++i) { | ||
| 313 | + if (i > 0) ss << ","; | ||
| 314 | + auto axis_id = attr.axis[i]; | ||
| 315 | + | ||
| 316 | + // 如果是 repeats,输出大小 | ||
| 317 | + if (i < attr.repeats.size()) { | ||
| 318 | + auto repeat = attr.repeats[i]; | ||
| 319 | + if (repeat.GetExprType() == ge::ExprType::kExprConstantRation) { | ||
| 320 | + int64_t val = 0; | ||
| 321 | + if (repeat.GetConstValue(val)) { | ||
| 322 | + ss << val; | ||
| 323 | + } else { | ||
| 324 | + auto it = axis_id_to_name.find(axis_id); | ||
| 325 | + ss << (it != axis_id_to_name.end() ? it->second : "axis") << "_size"; | ||
| 326 | + } | ||
| 327 | + } else { | ||
| 328 | + ss << ge::SymbolicUtils::ToString(repeat); | ||
| 329 | + } | ||
| 330 | + } else { | ||
| 331 | + auto it = axis_id_to_name.find(axis_id); | ||
| 332 | + ss << (it != axis_id_to_name.end() ? it->second : "axis") << "_size"; | ||
| 333 | + } | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + ss << "]"; | ||
| 337 | + return ss.str(); | ||
| 338 | +} | ||
| 339 | + | ||
| 340 | +/** | ||
| 341 | + * @brief 格式化输入参数列表 | ||
| 342 | + */ | ||
| 343 | +static std::string FormatInputParams(const std::vector<std::string> &input_names, | ||
| 344 | + const SSAMappingInfo &ssa_info) { | ||
| 345 | + std::stringstream ss; | ||
| 346 | + for (size_t i = 0; i < input_names.size(); ++i) { | ||
| 347 | + if (i > 0) ss << ", "; | ||
| 348 | + if (input_names[i] != "nil") { | ||
| 349 | + std::string input_name = input_names[i]; | ||
| 350 | + // 去掉 .y 或 .y[index] 后缀 | ||
| 351 | + size_t pos = input_name.find(".y"); | ||
| 352 | + if (pos != std::string::npos) { | ||
| 353 | + input_name = input_name.substr(0, pos); | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + // 判断是 Data 节点还是中间节点 | ||
| 357 | + if (ssa_info.IsDataNode(input_name)) { | ||
| 358 | + // Data 节点,使用节点名称 | ||
| 359 | + ss << "%" << input_name; | ||
| 360 | + } else { | ||
| 361 | + // 中间节点,使用 SSA 编号 | ||
| 362 | + size_t ssa_id = ssa_info.GetSsaId(input_name); | ||
| 363 | + if (ssa_id > 0) { | ||
| 364 | + ss << "%" << ssa_id; | ||
| 365 | + } else { | ||
| 366 | + ss << "%" << input_name; | ||
| 367 | + } | ||
| 368 | + } | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + return ss.str(); | ||
| 372 | +} | ||
| 373 | + | ||
| 374 | +/** | ||
| 375 | + * @brief 收集并排序子图的 loop_axis | ||
| 376 | + */ | ||
| 377 | +static std::vector<int64_t> CollectSubgraphLoopAxes(const ascir::Graph &graph, | ||
| 378 | + const std::map<int64_t, ge::Axis::Type> &axis_id_to_type) { | ||
| 379 | + auto all_nodes = graph.GetAllNodes(); | ||
| 380 | + | ||
| 381 | + // 收集所有节点的 loop_axis(去重) | ||
| 382 | + std::vector<int64_t> loop_axes_in_order; | ||
| 383 | + std::set<int64_t> seen_loop_axes; | ||
| 384 | + | ||
| 385 | + for (auto node: all_nodes) { | ||
| 386 | + auto node_type = node->GetType(); | ||
| 387 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput || node_type == NodeType::kWorkspace) { | ||
| 388 | + continue; | ||
| 389 | + } | ||
| 390 | + auto loop_axis = node->attr.sched.loop_axis; | ||
| 391 | + if (loop_axis != kInvalidLoopAxis && seen_loop_axes.find(loop_axis) == seen_loop_axes.end()) { | ||
| 392 | + seen_loop_axes.insert(loop_axis); | ||
| 393 | + loop_axes_in_order.push_back(loop_axis); | ||
| 394 | + } | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + // 按轴类型排序 | ||
| 398 | + std::sort(loop_axes_in_order.begin(), loop_axes_in_order.end(), | ||
| 399 | + [&axis_id_to_type](int64_t a, int64_t b) { | ||
| 400 | + int32_t priority_a = GetAxisTypePriority(axis_id_to_type.at(a)); | ||
| 401 | + int32_t priority_b = GetAxisTypePriority(axis_id_to_type.at(b)); | ||
| 402 | + if (priority_a != priority_b) { | ||
| 403 | + return priority_a < priority_b; | ||
| 404 | + } | ||
| 405 | + return a < b; | ||
| 406 | + }); | ||
| 407 | + | ||
| 408 | + return loop_axes_in_order; | ||
| 409 | +} | ||
| 410 | + | ||
| 411 | +/** | ||
| 412 | + * @brief 按 loop_axis 分组节点 | ||
| 413 | + */ | ||
| 414 | +static std::map<int64_t, std::vector<ge::AscNodePtr> > GroupNodesByLoopAxis(const ascir::Graph &graph) { | ||
| 415 | + std::map<int64_t, std::vector<ge::AscNodePtr> > nodes_by_loop_axis; | ||
| 416 | + auto all_nodes = graph.GetAllNodes(); | ||
| 417 | + | ||
| 418 | + for (auto node: all_nodes) { | ||
| 419 | + auto node_type = node->GetType(); | ||
| 420 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput || node_type == NodeType::kWorkspace) { | ||
| 421 | + continue; | ||
| 422 | + } | ||
| 423 | + auto loop_axis = node->attr.sched.loop_axis; | ||
| 424 | + nodes_by_loop_axis[loop_axis].push_back(node); | ||
| 425 | + } | ||
| 426 | + | ||
| 427 | + return nodes_by_loop_axis; | ||
| 428 | +} | ||
| 429 | + | ||
| 430 | +/** | ||
| 431 | + * @brief 输出子图中的单个节点 | ||
| 432 | + */ | ||
| 433 | +static void DumpSubgraphNode(std::stringstream &ss, | ||
| 434 | + const ascir::Graph &graph, | ||
| 435 | + const ge::AscNodePtr &node, | ||
| 436 | + const SSAMappingInfo &ssa_info, | ||
| 437 | + size_t indent) { | ||
| 438 | + std::string node_name = node->GetName(); | ||
| 439 | + size_t topo_id = ssa_info.GetTopoId(node_name); | ||
| 440 | + auto node_type = node->GetType(); | ||
| 441 | + | ||
| 442 | + ss << std::string(indent, ' ') << "%" << (topo_id + 1) | ||
| 443 | + << " = ascir.ops." << node_type << "("; | ||
| 444 | + | ||
| 445 | + // 输入参数 | ||
| 446 | + auto input_names = CollectInputNames(graph, node); | ||
| 447 | + ss << FormatInputParams(input_names, ssa_info); | ||
| 448 | + | ||
| 449 | + ss << ")"; | ||
| 450 | + | ||
| 451 | + // 子图显示标量类型 | ||
| 452 | + if (!node->outputs().empty()) { | ||
| 453 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 454 | + ss << " → " << GetDtypeString(output_attr.dtype); | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + ss << " # @" << node_name << " (topo_id=" << topo_id << ")" << std::endl; | ||
| 458 | +} | ||
| 459 | + | ||
| 460 | +/** | ||
| 461 | + * @brief 输出嵌套循环中的节点 | ||
| 462 | + */ | ||
| 463 | +static void DumpNodesInLoops(std::stringstream &ss, | ||
| 464 | + const ascir::Graph &graph, | ||
| 465 | + const std::vector<int64_t> &loop_axes_in_order, | ||
| 466 | + const std::map<int64_t, std::vector<ge::AscNodePtr> > &nodes_by_loop_axis, | ||
| 467 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 468 | + const SSAMappingInfo &ssa_info) { | ||
| 469 | + std::set<int64_t> opened_loops; | ||
| 470 | + size_t current_depth = 0; | ||
| 471 | + | ||
| 472 | + for (auto axis_id: loop_axes_in_order) { | ||
| 473 | + // 打开循环 | ||
| 474 | + ss << std::string(current_depth * kIndentSpaces, ' ') | ||
| 475 | + << "for %" << axis_id_to_name.at(axis_id) << " in " << axis_id_to_name.at(axis_id) << "_size {" << std::endl; | ||
| 476 | + opened_loops.insert(axis_id); | ||
| 477 | + current_depth++; | ||
| 478 | + | ||
| 479 | + // 输出 loop_axis = 当前轴的节点 | ||
| 480 | + if (nodes_by_loop_axis.count(axis_id) > 0) { | ||
| 481 | + for (auto node: nodes_by_loop_axis.at(axis_id)) { | ||
| 482 | + DumpSubgraphNode(ss, graph, node, ssa_info, current_depth * kIndentSpaces); | ||
| 483 | + } | ||
| 484 | + } | ||
| 485 | + } | ||
| 486 | + | ||
| 487 | + // 闭合所有循环 | ||
| 488 | + for (size_t i = 0; i < loop_axes_in_order.size(); ++i) { | ||
| 489 | + current_depth--; | ||
| 490 | + ss << std::string(current_depth * kIndentSpaces, ' ') << "}" << std::endl; | ||
| 491 | + } | ||
| 492 | +} | ||
| 493 | + | ||
| 494 | +/** | ||
| 495 | + * @brief 输出外层节点(loop_axis = kInvalidLoopAxis) | ||
| 496 | + */ | ||
| 497 | +static void DumpOuterNodes(std::stringstream &ss, | ||
| 498 | + const ascir::Graph &graph, | ||
| 499 | + const std::map<int64_t, std::vector<ge::AscNodePtr> > &nodes_by_loop_axis, | ||
| 500 | + const SSAMappingInfo &ssa_info) { | ||
| 501 | + if (nodes_by_loop_axis.count(kInvalidLoopAxis) == 0) { | ||
| 502 | + return; | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + for (auto node: nodes_by_loop_axis.at(kInvalidLoopAxis)) { | ||
| 506 | + DumpSubgraphNode(ss, graph, node, ssa_info, 2); // 2空格缩进 | ||
| 507 | + } | ||
| 508 | +} | ||
| 509 | + | ||
| 510 | +/** | ||
| 511 | + * @brief 生成子图模式的循环执行视图 | ||
| 512 | + */ | ||
| 513 | +static std::string DumpSubgraphLoopExecution(const ascir::Graph &graph, | ||
| 514 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 515 | + const std::map<int64_t, ge::Axis::Type> &axis_id_to_type) { | ||
| 516 | + std::stringstream ss; | ||
| 517 | + | ||
| 518 | + auto all_nodes = graph.GetAllNodes(); | ||
| 519 | + SSAMappingInfo ssa_info = BuildSSAMapping(all_nodes); | ||
| 520 | + | ||
| 521 | + // 收集并排序 loop_axis | ||
| 522 | + auto loop_axes_in_order = CollectSubgraphLoopAxes(graph, axis_id_to_type); | ||
| 523 | + | ||
| 524 | + // 按 loop_axis 分组节点 | ||
| 525 | + auto nodes_by_loop_axis = GroupNodesByLoopAxis(graph); | ||
| 526 | + | ||
| 527 | + // 生成嵌套循环并输出节点 | ||
| 528 | + DumpNodesInLoops(ss, graph, loop_axes_in_order, nodes_by_loop_axis, axis_id_to_name, ssa_info); | ||
| 529 | + | ||
| 530 | + // 输出外层节点 | ||
| 531 | + DumpOuterNodes(ss, graph, nodes_by_loop_axis, ssa_info); | ||
| 532 | + | ||
| 533 | + return ss.str(); | ||
| 534 | +} | ||
| 535 | +} // namespace | ||
| 536 | + | ||
| 537 | +// ============================================================================= | ||
| 538 | +// VIEW 1: Loop Execution 辅助函数实现 | ||
| 539 | +// ============================================================================= | ||
| 540 | + | ||
| 541 | +namespace { | ||
| 542 | +/** | ||
| 543 | + * @brief 检测图是否为子图 | ||
| 544 | + */ | ||
| 545 | +bool IsSubgraph(const std::string &graph_name) { | ||
| 546 | + return (graph_name.find("_VfSubgraph_") != std::string::npos || | ||
| 547 | + graph_name.find("_Subgraph_") != std::string::npos); | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +/** | ||
| 551 | + * @brief 收集所有 Data 和 Output 节点 | ||
| 552 | + */ | ||
| 553 | +void CollectDataAndOutputNodes(const ascir::Graph &graph, | ||
| 554 | + std::vector<ParamInfo> &inputs, | ||
| 555 | + std::vector<ParamInfo> &outputs, | ||
| 556 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 557 | + auto all_nodes = graph.GetAllNodes(); | ||
| 558 | + | ||
| 559 | + for (auto node: all_nodes) { | ||
| 560 | + auto node_type = node->GetType(); | ||
| 561 | + if (node_type == NodeType::kData || node_type == NodeType::kWorkspace) { | ||
| 562 | + if (!node->outputs().empty()) { | ||
| 563 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 564 | + inputs.push_back({node->GetName(), GetTensorTypeStr(graph, output_attr, axis_id_to_name)}); | ||
| 565 | + } | ||
| 566 | + } else if (node_type == NodeType::kOutput) { | ||
| 567 | + if (!node->outputs().empty()) { | ||
| 568 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 569 | + outputs.push_back({node->GetName(), GetTensorTypeStr(graph, output_attr, axis_id_to_name)}); | ||
| 570 | + } | ||
| 571 | + } | ||
| 572 | + } | ||
| 573 | +} | ||
| 574 | + | ||
| 575 | +/** | ||
| 576 | + * @brief 收集所有被向量化的轴 | ||
| 577 | + */ | ||
| 578 | +std::set<int64_t> CollectVectorizedAxes(const ascir::Graph &graph) { | ||
| 579 | + std::set<int64_t> vectorized_axes; | ||
| 580 | + auto all_nodes = graph.GetAllNodes(); | ||
| 581 | + | ||
| 582 | + for (auto node: all_nodes) { | ||
| 583 | + auto node_type = node->GetType(); | ||
| 584 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput) { | ||
| 585 | + continue; | ||
| 586 | + } | ||
| 587 | + if (!node->outputs().empty()) { | ||
| 588 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 589 | + for (auto axis_id: output_attr.vectorized_axis) { | ||
| 590 | + vectorized_axes.insert(axis_id); | ||
| 591 | + } | ||
| 592 | + } | ||
| 593 | + } | ||
| 594 | + | ||
| 595 | + return vectorized_axes; | ||
| 596 | +} | ||
| 597 | + | ||
| 598 | +/** | ||
| 599 | + * @brief 生成原始 tensor 形状的注释 | ||
| 600 | + */ | ||
| 601 | +std::string GenerateOriginalShapesComment(const std::vector<ParamInfo> &inputs, | ||
| 602 | + const std::vector<ParamInfo> &outputs) { | ||
| 603 | + std::stringstream ss; | ||
| 604 | + | ||
| 605 | + ss << "# Original tensor shapes:" << std::endl; | ||
| 606 | + | ||
| 607 | + if (!inputs.empty()) { | ||
| 608 | + // 按类型分组输入 | ||
| 609 | + std::map<std::string, std::vector<std::string> > inputs_by_type; | ||
| 610 | + for (auto &input: inputs) { | ||
| 611 | + auto dtype = ExtractDtypeFromTensorType(input.type); | ||
| 612 | + auto axes = ExtractAxisListFromTensorType(input.type); | ||
| 613 | + std::string full_type = dtype + axes; | ||
| 614 | + inputs_by_type[full_type].push_back(input.name); | ||
| 615 | + } | ||
| 616 | + | ||
| 617 | + for (auto &entry: inputs_by_type) { | ||
| 618 | + ss << "# "; | ||
| 619 | + for (size_t i = 0; i < entry.second.size(); ++i) { | ||
| 620 | + if (i > 0) ss << ", "; | ||
| 621 | + ss << entry.second[i]; | ||
| 622 | + } | ||
| 623 | + ss << ": " << ExtractDtypeFromTensorType(entry.first) | ||
| 624 | + << ExtractAxisListFromTensorType(entry.first) << std::endl; | ||
| 625 | + } | ||
| 626 | + } | ||
| 627 | + | ||
| 628 | + if (!outputs.empty()) { | ||
| 629 | + for (size_t i = 0; i < outputs.size(); ++i) { | ||
| 630 | + ss << "# output: " << outputs[i].name << ": " | ||
| 631 | + << ExtractDtypeFromTensorType(outputs[i].type) << "[]" << std::endl; | ||
| 632 | + } | ||
| 633 | + } | ||
| 634 | + | ||
| 635 | + ss << "#" << std::endl; | ||
| 636 | + | ||
| 637 | + return ss.str(); | ||
| 638 | +} | ||
| 639 | + | ||
| 640 | +/** | ||
| 641 | + * @brief 构建 Tile/Block 分解树 | ||
| 642 | + */ | ||
| 643 | +AxisTreeNode BuildAxisDecompositionTree(const ge::AxisPtr &axis, | ||
| 644 | + const std::vector<ge::AxisPtr> &all_axis, | ||
| 645 | + const std::set<int64_t> &merged_axes) { | ||
| 646 | + AxisTreeNode node; | ||
| 647 | + node.axis = axis; | ||
| 648 | + node.is_merge = (merged_axes.count(axis->id) > 0); | ||
| 649 | + | ||
| 650 | + // 找到所有直接从 axis 分解或合并出来的轴 | ||
| 651 | + std::vector<ge::AxisPtr> direct_derived; | ||
| 652 | + for (auto &target_axis: all_axis) { | ||
| 653 | + if (target_axis->id == axis->id) { | ||
| 654 | + continue; | ||
| 655 | + } | ||
| 656 | + if (!target_axis->from.empty()) { | ||
| 657 | + bool is_child = false; | ||
| 658 | + for (auto from_id: target_axis->from) { | ||
| 659 | + if (from_id == axis->id) { | ||
| 660 | + is_child = true; | ||
| 661 | + break; | ||
| 662 | + } | ||
| 663 | + } | ||
| 664 | + if (is_child) { | ||
| 665 | + direct_derived.push_back(target_axis); | ||
| 666 | + } | ||
| 667 | + } | ||
| 668 | + } | ||
| 669 | + | ||
| 670 | + // 按类型排序 | ||
| 671 | + std::sort(direct_derived.begin(), direct_derived.end(), | ||
| 672 | + [](const ge::AxisPtr &a, const ge::AxisPtr &b) { | ||
| 673 | + return GetAxisTypePriority(a->type) < GetAxisTypePriority(b->type); | ||
| 674 | + }); | ||
| 675 | + | ||
| 676 | + // 递归构建子树 | ||
| 677 | + for (auto &derived: direct_derived) { | ||
| 678 | + node.children.push_back(BuildAxisDecompositionTree(derived, all_axis, merged_axes)); | ||
| 679 | + } | ||
| 680 | + | ||
| 681 | + return node; | ||
| 682 | +} | ||
| 683 | + | ||
| 684 | +/** | ||
| 685 | + * @brief 输出 Tile/Block 分解树(递归) | ||
| 686 | + */ | ||
| 687 | +void PrintAxisDecompositionTree(std::stringstream &ss, | ||
| 688 | + const AxisTreeNode &node, | ||
| 689 | + const std::string &prefix, | ||
| 690 | + const std::string &child_prefix) { | ||
| 691 | + ss << "# " << prefix << node.axis->name; | ||
| 692 | + | ||
| 693 | + if (node.children.empty()) { | ||
| 694 | + if (node.is_merge) { | ||
| 695 | + ss << " ⋈"; | ||
| 696 | + } | ||
| 697 | + ss << std::endl; | ||
| 698 | + return; | ||
| 699 | + } | ||
| 700 | + | ||
| 701 | + // 判断是否是合并操作 | ||
| 702 | + if (node.is_merge) { | ||
| 703 | + ss << "-⋈" << std::endl; | ||
| 704 | + } else { | ||
| 705 | + ss << "-" << std::endl; | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + for (size_t i = 0; i < node.children.size(); ++i) { | ||
| 709 | + bool is_last = (i == node.children.size() - 1); | ||
| 710 | + std::string connector = is_last ? "└->" : "┬->"; | ||
| 711 | + std::string next_prefix = child_prefix + " " + connector; | ||
| 712 | + std::string next_child_prefix = child_prefix + (is_last ? " " : "│ "); | ||
| 713 | + PrintAxisDecompositionTree(ss, node.children[i], next_prefix, next_child_prefix); | ||
| 714 | + } | ||
| 715 | +} | ||
| 716 | + | ||
| 717 | +/** | ||
| 718 | + * @brief 生成 Tile/Block 分解的注释 | ||
| 719 | + */ | ||
| 720 | +std::string GenerateTileBlockDecompositionComment(const std::vector<ge::AxisPtr> &all_axis) { | ||
| 721 | + std::stringstream ss; | ||
| 722 | + ss << "# Tile/Block decomposition:" << std::endl; | ||
| 723 | + | ||
| 724 | + // 收集所有涉及合并的轴 | ||
| 725 | + std::set<int64_t> merged_axes; | ||
| 726 | + for (auto &axis: all_axis) { | ||
| 727 | + if (!axis->from.empty() && axis->from.size() > 1) { | ||
| 728 | + merged_axes.insert(axis->id); | ||
| 729 | + } | ||
| 730 | + } | ||
| 731 | + | ||
| 732 | + // 构建分解树并按树状图输出 | ||
| 733 | + for (auto &axis: all_axis) { | ||
| 734 | + if (axis->type == ge::Axis::Type::kAxisTypeOriginal) { | ||
| 735 | + AxisTreeNode root = BuildAxisDecompositionTree(axis, all_axis, merged_axes); | ||
| 736 | + if (root.children.empty()) { | ||
| 737 | + ss << "# " << axis->name << ": original (no tiling)" << std::endl; | ||
| 738 | + continue; | ||
| 739 | + } | ||
| 740 | + | ||
| 741 | + PrintAxisDecompositionTree(ss, root, "", ""); | ||
| 742 | + } | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | + ss << "#" << std::endl; | ||
| 746 | + | ||
| 747 | + return ss.str(); | ||
| 748 | +} | ||
| 749 | + | ||
| 750 | +/** | ||
| 751 | + * @brief 生成函数签名 | ||
| 752 | + */ | ||
| 753 | +std::string GenerateFunctionSignature(const std::string &graph_name, | ||
| 754 | + const std::vector<ParamInfo> &inputs, | ||
| 755 | + const std::vector<ParamInfo> &outputs) { | ||
| 756 | + std::stringstream ss; | ||
| 757 | + | ||
| 758 | + ss << "func @" << graph_name << "("; | ||
| 759 | + for (size_t i = 0; i < inputs.size(); ++i) { | ||
| 760 | + if (i > 0) ss << ", "; | ||
| 761 | + ss << "%" << inputs[i].name << ": " << inputs[i].type; | ||
| 762 | + } | ||
| 763 | + | ||
| 764 | + ss << ") -> "; | ||
| 765 | + if (!outputs.empty()) { | ||
| 766 | + if (outputs.size() > 1) { | ||
| 767 | + ss << "("; | ||
| 768 | + for (size_t i = 0; i < outputs.size(); ++i) { | ||
| 769 | + if (i > 0) ss << ", "; | ||
| 770 | + ss << ExtractDtypeFromTensorType(outputs[i].type) << "[]"; | ||
| 771 | + } | ||
| 772 | + ss << ")"; | ||
| 773 | + } else { | ||
| 774 | + ss << ExtractDtypeFromTensorType(outputs[0].type) << "[]"; | ||
| 775 | + } | ||
| 776 | + } else { | ||
| 777 | + ss << "()"; | ||
| 778 | + } | ||
| 779 | + | ||
| 780 | + ss << " {" << std::endl; | ||
| 781 | + | ||
| 782 | + return ss.str(); | ||
| 783 | +} | ||
| 784 | + | ||
| 785 | +/** | ||
| 786 | + * @brief 检查是否有节点设置了 loop_axis | ||
| 787 | + */ | ||
| 788 | +bool HasLoopAxis(const ascir::Graph &graph) { | ||
| 789 | + auto all_nodes = graph.GetAllNodes(); | ||
| 790 | + | ||
| 791 | + for (auto node: all_nodes) { | ||
| 792 | + auto node_type = node->GetType(); | ||
| 793 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput) { | ||
| 794 | + continue; | ||
| 795 | + } | ||
| 796 | + auto loop_axis = node->attr.sched.loop_axis; | ||
| 797 | + if (loop_axis != kInvalidLoopAxis) { | ||
| 798 | + return true; | ||
| 799 | + } | ||
| 800 | + } | ||
| 801 | + | ||
| 802 | + return false; | ||
| 803 | +} | ||
| 804 | + | ||
| 805 | +/** | ||
| 806 | + * @brief 收集所有需要循环的轴 | ||
| 807 | + */ | ||
| 808 | +/** | ||
| 809 | + * @brief 收集有 loop_axis 时的循环轴 | ||
| 810 | + */ | ||
| 811 | +static void CollectLoopAxesWithLoopAxis(const ascir::Graph &graph, | ||
| 812 | + const std::set<int64_t> &vectorized_axes, | ||
| 813 | + std::set<int64_t> &all_loop_axes) { | ||
| 814 | + auto all_nodes = graph.GetAllNodes(); | ||
| 815 | + | ||
| 816 | + for (auto node: all_nodes) { | ||
| 817 | + auto node_type = node->GetType(); | ||
| 818 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput) { | ||
| 819 | + continue; | ||
| 820 | + } | ||
| 821 | + | ||
| 822 | + auto loop_axis = node->attr.sched.loop_axis; | ||
| 823 | + if (loop_axis != kInvalidLoopAxis) { | ||
| 824 | + auto &axis_list = node->attr.sched.axis; | ||
| 825 | + for (auto axis_id: axis_list) { | ||
| 826 | + if (axis_id == loop_axis) { | ||
| 827 | + break; // 到 loop_axis 为止 | ||
| 828 | + } | ||
| 829 | + if (vectorized_axes.count(axis_id) == 0) { | ||
| 830 | + all_loop_axes.insert(axis_id); | ||
| 831 | + } | ||
| 832 | + } | ||
| 833 | + if (vectorized_axes.count(loop_axis) == 0) { | ||
| 834 | + all_loop_axes.insert(loop_axis); | ||
| 835 | + } | ||
| 836 | + } | ||
| 837 | + } | ||
| 838 | +} | ||
| 839 | + | ||
| 840 | +/** | ||
| 841 | + * @brief 收集无 loop_axis 时的循环轴 | ||
| 842 | + */ | ||
| 843 | +static void CollectLoopAxesWithoutLoopAxis(const ascir::Graph &graph, | ||
| 844 | + const std::set<int64_t> &vectorized_axes, | ||
| 845 | + std::set<int64_t> &all_loop_axes) { | ||
| 846 | + auto all_nodes = graph.GetAllNodes(); | ||
| 847 | + | ||
| 848 | + for (auto node: all_nodes) { | ||
| 849 | + auto node_type = node->GetType(); | ||
| 850 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput) { | ||
| 851 | + continue; | ||
| 852 | + } | ||
| 853 | + | ||
| 854 | + auto &axis_list = node->attr.sched.axis; | ||
| 855 | + for (auto axis_id: axis_list) { | ||
| 856 | + if (vectorized_axes.count(axis_id) == 0) { | ||
| 857 | + all_loop_axes.insert(axis_id); | ||
| 858 | + } | ||
| 859 | + } | ||
| 860 | + } | ||
| 861 | +} | ||
| 862 | + | ||
| 863 | +/** | ||
| 864 | + * @brief 按轴类型优先级排序循环轴 | ||
| 865 | + */ | ||
| 866 | +static std::vector<int64_t> SortLoopAxesByPriority(const std::set<int64_t> &all_loop_axes, | ||
| 867 | + const std::map<int64_t, ge::Axis::Type> &axis_id_to_type) { | ||
| 868 | + std::vector<int64_t> sorted_loop_axes(all_loop_axes.begin(), all_loop_axes.end()); | ||
| 869 | + std::sort(sorted_loop_axes.begin(), sorted_loop_axes.end(), | ||
| 870 | + [&axis_id_to_type](int64_t a, int64_t b) { | ||
| 871 | + int32_t priority_a = GetAxisTypePriority(axis_id_to_type.at(a)); | ||
| 872 | + int32_t priority_b = GetAxisTypePriority(axis_id_to_type.at(b)); | ||
| 873 | + if (priority_a != priority_b) { | ||
| 874 | + return priority_a < priority_b; | ||
| 875 | + } | ||
| 876 | + return a < b; | ||
| 877 | + }); | ||
| 878 | + return sorted_loop_axes; | ||
| 879 | +} | ||
| 880 | + | ||
| 881 | +/** | ||
| 882 | + * @brief 收集所有需要循环的轴 | ||
| 883 | + */ | ||
| 884 | +std::vector<int64_t> CollectLoopAxes(const ascir::Graph &graph, | ||
| 885 | + const std::set<int64_t> &vectorized_axes, | ||
| 886 | + const std::map<int64_t, ge::Axis::Type> &axis_id_to_type) { | ||
| 887 | + std::set<int64_t> all_loop_axes; | ||
| 888 | + bool has_loop_axis = HasLoopAxis(graph); | ||
| 889 | + if (has_loop_axis) { | ||
| 890 | + CollectLoopAxesWithLoopAxis(graph, vectorized_axes, all_loop_axes); | ||
| 891 | + } else { | ||
| 892 | + CollectLoopAxesWithoutLoopAxis(graph, vectorized_axes, all_loop_axes); | ||
| 893 | + } | ||
| 894 | + | ||
| 895 | + return SortLoopAxesByPriority(all_loop_axes, axis_id_to_type); | ||
| 896 | +} | ||
| 897 | + | ||
| 898 | +/** | ||
| 899 | + * @brief 输出 Scalar 节点 | ||
| 900 | + */ | ||
| 901 | +void DumpScalarNode(std::stringstream &ss, | ||
| 902 | + const ge::AscNodePtr &node, | ||
| 903 | + size_t indent_spaces, | ||
| 904 | + size_t topo_id) { | ||
| 905 | + ss << std::string(indent_spaces, ' ') << "%" << (topo_id + 1) << " = "; | ||
| 906 | + | ||
| 907 | + if (node->attr.ir_attr != nullptr) { | ||
| 908 | + std::string scalar_value; | ||
| 909 | + if (node->attr.ir_attr->GetAttrValue("value", scalar_value) == ge::GRAPH_SUCCESS) { | ||
| 910 | + ss << scalar_value << "f"; | ||
| 911 | + } else { | ||
| 912 | + ss << "0.0f"; | ||
| 913 | + } | ||
| 914 | + } else { | ||
| 915 | + ss << "0.0f"; | ||
| 916 | + } | ||
| 917 | + | ||
| 918 | + ss << " # @" << node->GetName() << " (topo_id=" << topo_id << ")" << std::endl; | ||
| 919 | +} | ||
| 920 | + | ||
| 921 | +/** | ||
| 922 | + * @brief 输出单个节点的执行语句 | ||
| 923 | + */ | ||
| 924 | +void DumpNodeExecution(std::stringstream &ss, | ||
| 925 | + const ascir::Graph &graph, | ||
| 926 | + const ge::AscNodePtr &node, | ||
| 927 | + const SSAMappingInfo &ssa_info, | ||
| 928 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 929 | + size_t indent_spaces) { | ||
| 930 | + std::string node_name = node->GetName(); | ||
| 931 | + auto node_type = node->GetType(); | ||
| 932 | + size_t topo_id = ssa_info.GetTopoId(node_name); | ||
| 933 | + | ||
| 934 | + // Scalar 节点特殊处理 | ||
| 935 | + if (node_type == NodeType::kScalar) { | ||
| 936 | + DumpScalarNode(ss, node, indent_spaces, topo_id); | ||
| 937 | + return; | ||
| 938 | + } | ||
| 939 | + | ||
| 940 | + // 非Scalar节点的通用处理 | ||
| 941 | + ss << std::string(indent_spaces, ' ') << "%" << (topo_id + 1) | ||
| 942 | + << " = ascir.ops." << node_type << "("; | ||
| 943 | + | ||
| 944 | + // 输入参数 | ||
| 945 | + auto input_names = CollectInputNames(graph, node); | ||
| 946 | + ss << FormatInputParams(input_names, ssa_info); | ||
| 947 | + | ||
| 948 | + ss << ")"; | ||
| 949 | + | ||
| 950 | + // 类型转换 | ||
| 951 | + if (!node->outputs().empty()) { | ||
| 952 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 953 | + auto vectorized_str = GetVectorizedAxesStr(graph, output_attr, axis_id_to_name); | ||
| 954 | + if (!vectorized_str.empty()) { | ||
| 955 | + ss << " → " << vectorized_str; | ||
| 956 | + } else { | ||
| 957 | + ss << " → " << GetDtypeString(output_attr.dtype); | ||
| 958 | + } | ||
| 959 | + } | ||
| 960 | + | ||
| 961 | + ss << " # @" << node_name << " (topo_id=" << topo_id << ")" << std::endl; | ||
| 962 | +} | ||
| 963 | + | ||
| 964 | +/** | ||
| 965 | + * @brief 确定节点应该放置的循环深度 | ||
| 966 | + * @param node 节点对象 | ||
| 967 | + * @param has_loop_axis 图是否有 loop_axis | ||
| 968 | + * @param loop_axis_to_depth loop_axis 到深度的映射 | ||
| 969 | + * @param sorted_loop_axes_size 排序后的 loop_axes 数量 | ||
| 970 | + * @param current_depth 当前深度 | ||
| 971 | + * @return 目标深度 | ||
| 972 | + */ | ||
| 973 | +static size_t DetermineNodeTargetDepth(const ge::AscNodePtr &node, | ||
| 974 | + bool has_loop_axis, | ||
| 975 | + const std::map<int64_t, size_t> &loop_axis_to_depth, | ||
| 976 | + size_t sorted_loop_axes_size, | ||
| 977 | + size_t current_depth) { | ||
| 978 | + auto node_type = node->GetType(); | ||
| 979 | + auto loop_axis = node->attr.sched.loop_axis; | ||
| 980 | + bool is_scalar = (node_type == NodeType::kScalar); | ||
| 981 | + | ||
| 982 | + if (is_scalar) { | ||
| 983 | + return current_depth; | ||
| 984 | + } else if (has_loop_axis && loop_axis != kInvalidLoopAxis && loop_axis_to_depth.count(loop_axis) > 0) { | ||
| 985 | + return loop_axis_to_depth.at(loop_axis); | ||
| 986 | + } else if (!has_loop_axis) { | ||
| 987 | + return sorted_loop_axes_size; | ||
| 988 | + } | ||
| 989 | + return 0; | ||
| 990 | +} | ||
| 991 | + | ||
| 992 | +/** | ||
| 993 | + * @brief 关闭不需要的循环 | ||
| 994 | + * @param ss 输出流 | ||
| 995 | + * @param current_depth 当前深度(会被修改) | ||
| 996 | + * @param target_depth 目标深度 | ||
| 997 | + * @param opened_loops 已打开的循环集合(会被修改) | ||
| 998 | + */ | ||
| 999 | +static void CloseUnneededLoops(std::stringstream &ss, | ||
| 1000 | + size_t ¤t_depth, | ||
| 1001 | + size_t target_depth, | ||
| 1002 | + std::set<int64_t> &opened_loops) { | ||
| 1003 | + while (current_depth > target_depth) { | ||
| 1004 | + current_depth--; | ||
| 1005 | + ss << std::string(current_depth * kIndentSpaces, ' ') << "}" << std::endl; | ||
| 1006 | + if (!opened_loops.empty()) { | ||
| 1007 | + auto it = opened_loops.end(); | ||
| 1008 | + it--; | ||
| 1009 | + opened_loops.erase(it); | ||
| 1010 | + } | ||
| 1011 | + } | ||
| 1012 | +} | ||
| 1013 | + | ||
| 1014 | +/** | ||
| 1015 | + * @brief 打开需要的循环 | ||
| 1016 | + * @param ss 输出流 | ||
| 1017 | + * @param sorted_loop_axes 排序后的 loop_axes | ||
| 1018 | + * @param target_depth 目标深度 | ||
| 1019 | + * @param axis_id_to_name axis_id 到 name 的映射 | ||
| 1020 | + * @param current_depth 当前深度(会被修改) | ||
| 1021 | + * @param opened_loops 已打开的循环集合(会被修改) | ||
| 1022 | + */ | ||
| 1023 | +static void OpenNeededLoops(std::stringstream &ss, | ||
| 1024 | + const std::vector<int64_t> &sorted_loop_axes, | ||
| 1025 | + size_t target_depth, | ||
| 1026 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 1027 | + size_t ¤t_depth, | ||
| 1028 | + std::set<int64_t> &opened_loops) { | ||
| 1029 | + for (auto axis_id: sorted_loop_axes) { | ||
| 1030 | + if (opened_loops.count(axis_id) == 0) { | ||
| 1031 | + auto depth_it = std::find(sorted_loop_axes.begin(), sorted_loop_axes.end(), axis_id); | ||
| 1032 | + if (depth_it != sorted_loop_axes.end()) { | ||
| 1033 | + size_t axis_depth = std::distance(sorted_loop_axes.begin(), depth_it) + 1; | ||
| 1034 | + if (axis_depth <= target_depth) { | ||
| 1035 | + ss << std::string(current_depth * kIndentSpaces, ' ') | ||
| 1036 | + << "for %" << axis_id_to_name.at(axis_id) << " in " | ||
| 1037 | + << axis_id_to_name.at(axis_id) << "_size {" << std::endl; | ||
| 1038 | + opened_loops.insert(axis_id); | ||
| 1039 | + current_depth++; | ||
| 1040 | + } | ||
| 1041 | + } | ||
| 1042 | + } | ||
| 1043 | + if (current_depth >= target_depth) { | ||
| 1044 | + break; | ||
| 1045 | + } | ||
| 1046 | + } | ||
| 1047 | +} | ||
| 1048 | + | ||
| 1049 | +/** | ||
| 1050 | + * @brief 输出常规图(非子图)的循环执行内容 | ||
| 1051 | + * @param graph 图对象 | ||
| 1052 | + * @param axis_id_to_name axis_id 到 name 的映射 | ||
| 1053 | + * @param axis_id_to_type axis_id 到 type 的映射 | ||
| 1054 | + * @param vectorized_axes 向量化轴集合 | ||
| 1055 | + * @param ssa_info SSA 映射信息 | ||
| 1056 | + * @return 循环执行内容的字符串 | ||
| 1057 | + */ | ||
| 1058 | +static std::string DumpRegularGraphLoopExecution( | ||
| 1059 | + const ascir::Graph &graph, | ||
| 1060 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 1061 | + const std::map<int64_t, ge::Axis::Type> &axis_id_to_type, | ||
| 1062 | + const std::set<int64_t> &vectorized_axes, | ||
| 1063 | + const SSAMappingInfo &ssa_info) { | ||
| 1064 | + std::stringstream ss; | ||
| 1065 | + | ||
| 1066 | + auto all_nodes = graph.GetAllNodes(); | ||
| 1067 | + auto sorted_loop_axes = CollectLoopAxes(graph, vectorized_axes, axis_id_to_type); | ||
| 1068 | + | ||
| 1069 | + // 建立 loop_axis 到深度的映射 | ||
| 1070 | + std::map<int64_t, size_t> loop_axis_to_depth; | ||
| 1071 | + for (size_t i = 0; i < sorted_loop_axes.size(); ++i) { | ||
| 1072 | + loop_axis_to_depth[sorted_loop_axes[i]] = i + 1; | ||
| 1073 | + } | ||
| 1074 | + | ||
| 1075 | + bool has_loop_axis = HasLoopAxis(graph); | ||
| 1076 | + | ||
| 1077 | + // 按拓扑序遍历节点,动态打开/关闭循环 | ||
| 1078 | + std::set<int64_t> opened_loops; | ||
| 1079 | + size_t current_depth = 0; | ||
| 1080 | + | ||
| 1081 | + for (auto node: all_nodes) { | ||
| 1082 | + auto node_type = node->GetType(); | ||
| 1083 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput || | ||
| 1084 | + node_type == NodeType::kWorkspace) { | ||
| 1085 | + continue; | ||
| 1086 | + } | ||
| 1087 | + | ||
| 1088 | + // 确定节点应该在哪个深度 | ||
| 1089 | + size_t target_depth = DetermineNodeTargetDepth(node, has_loop_axis, loop_axis_to_depth, | ||
| 1090 | + sorted_loop_axes.size(), current_depth); | ||
| 1091 | + | ||
| 1092 | + // 关闭不需要的循环 | ||
| 1093 | + CloseUnneededLoops(ss, current_depth, target_depth, opened_loops); | ||
| 1094 | + | ||
| 1095 | + // 打开需要的循环 | ||
| 1096 | + OpenNeededLoops(ss, sorted_loop_axes, target_depth, axis_id_to_name, current_depth, opened_loops); | ||
| 1097 | + | ||
| 1098 | + // 输出节点 | ||
| 1099 | + DumpNodeExecution(ss, graph, node, ssa_info, axis_id_to_name, current_depth * kIndentSpaces); | ||
| 1100 | + } | ||
| 1101 | + | ||
| 1102 | + // 闭合所有剩余循环 | ||
| 1103 | + while (current_depth > 0) { | ||
| 1104 | + current_depth--; | ||
| 1105 | + ss << std::string(current_depth * kIndentSpaces, ' ') << "}" << std::endl; | ||
| 1106 | + } | ||
| 1107 | + | ||
| 1108 | + return ss.str(); | ||
| 1109 | +} | ||
| 1110 | +} // namespace | ||
| 1111 | + | ||
| 1112 | +// ============================================================================= | ||
| 1113 | +// VIEW 1: Loop Execution | ||
| 1114 | +// ============================================================================= | ||
| 1115 | + | ||
| 1116 | +std::string DumpLoopExecutionView(const ascir::Graph &graph) { | ||
| 1117 | + std::stringstream ss; | ||
| 1118 | + | ||
| 1119 | + // 获取基本信息 | ||
| 1120 | + std::string graph_name = graph.GetName(); | ||
| 1121 | + bool is_subgraph = IsSubgraph(graph_name); | ||
| 1122 | + | ||
| 1123 | + auto all_axis = graph.GetAllAxis(); | ||
| 1124 | + auto axis_id_to_name = BuildAxisIdToNameMap(all_axis); | ||
| 1125 | + auto axis_id_to_type = BuildAxisIdToTypeMap(all_axis); | ||
| 1126 | + | ||
| 1127 | + // 收集输入输出 | ||
| 1128 | + std::vector<ParamInfo> inputs; | ||
| 1129 | + std::vector<ParamInfo> outputs; | ||
| 1130 | + CollectDataAndOutputNodes(graph, inputs, outputs, axis_id_to_name); | ||
| 1131 | + | ||
| 1132 | + // 收集向量化轴 | ||
| 1133 | + std::set<int64_t> vectorized_axes = CollectVectorizedAxes(graph); | ||
| 1134 | + | ||
| 1135 | + // 生成说明性注释 | ||
| 1136 | + ss << GenerateOriginalShapesComment(inputs, outputs); | ||
| 1137 | + | ||
| 1138 | + // 生成 Tile/Block 分解注释(仅非子图) | ||
| 1139 | + if (!is_subgraph) { | ||
| 1140 | + ss << GenerateTileBlockDecompositionComment(all_axis); | ||
| 1141 | + } | ||
| 1142 | + | ||
| 1143 | + // 生成函数签名 | ||
| 1144 | + ss << GenerateFunctionSignature(graph_name, inputs, outputs); | ||
| 1145 | + | ||
| 1146 | + // 生成函数体 | ||
| 1147 | + if (is_subgraph) { | ||
| 1148 | + // 子图模式 | ||
| 1149 | + ss << DumpSubgraphLoopExecution(graph, axis_id_to_name, axis_id_to_type); | ||
| 1150 | + } else { | ||
| 1151 | + // 非子图模式:按照 loop_axis 分层输出节点 | ||
| 1152 | + auto all_nodes = graph.GetAllNodes(); | ||
| 1153 | + SSAMappingInfo ssa_info = BuildSSAMapping(all_nodes); | ||
| 1154 | + ss << DumpRegularGraphLoopExecution(graph, axis_id_to_name, axis_id_to_type, | ||
| 1155 | + vectorized_axes, ssa_info); | ||
| 1156 | + } | ||
| 1157 | + | ||
| 1158 | + // 返回值 | ||
| 1159 | + if (!outputs.empty()) { | ||
| 1160 | + ss << " return %" << outputs[0].name << std::endl; | ||
| 1161 | + } | ||
| 1162 | + | ||
| 1163 | + ss << "}" << std::endl; | ||
| 1164 | + | ||
| 1165 | + return ss.str(); | ||
| 1166 | +} | ||
| 1167 | + | ||
| 1168 | +// ============================================================================= | ||
| 1169 | +// VIEW 2: Graph Structure 辅助函数 | ||
| 1170 | +// ============================================================================= | ||
| 1171 | + | ||
| 1172 | +/** | ||
| 1173 | + * @brief 获取 Position 的字符串表示 | ||
| 1174 | + */ | ||
| 1175 | +std::string PositionToString(ge::Position position) { | ||
| 1176 | + switch (position) { | ||
| 1177 | + case ge::Position::kPositionVecIn: return "VECIN"; | ||
| 1178 | + case ge::Position::kPositionVecCalc: return "VECCALC"; | ||
| 1179 | + case ge::Position::kPositionVecOut: return "VECOUT"; | ||
| 1180 | + case ge::Position::kPositionGM: return "GM"; | ||
| 1181 | + default: return "UNKNOWN"; | ||
| 1182 | + } | ||
| 1183 | +} | ||
| 1184 | + | ||
| 1185 | +/** | ||
| 1186 | + * @brief 获取 MemHardware 的字符串表示 | ||
| 1187 | + */ | ||
| 1188 | +std::string MemHardwareToString(ge::MemHardware hardware) { | ||
| 1189 | + switch (hardware) { | ||
| 1190 | + case ge::MemHardware::kMemHardwareGM: return "GM"; | ||
| 1191 | + case ge::MemHardware::kMemHardwareUB: return "UB"; | ||
| 1192 | + default: return "UNKNOWN"; | ||
| 1193 | + } | ||
| 1194 | +} | ||
| 1195 | + | ||
| 1196 | +// ============================================================================= | ||
| 1197 | +// VIEW 2: Graph Structure | ||
| 1198 | +// ============================================================================= | ||
| 1199 | + | ||
| 1200 | +namespace { | ||
| 1201 | +/** | ||
| 1202 | + * @brief 输出形状信息 (axis, repeats, strides) | ||
| 1203 | + */ | ||
| 1204 | +static std::stringstream &OutputShapeStr(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1205 | + const ge::AscTensorAttr &output_attr, | ||
| 1206 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 1207 | + (void) graph; | ||
| 1208 | + // 输出 axis 列表 | ||
| 1209 | + if (!output_attr.axis.empty()) { | ||
| 1210 | + ss << std::string(kPropertyIndent, ' ') << ".axis = {"; | ||
| 1211 | + for (size_t i = 0; i < output_attr.axis.size(); ++i) { | ||
| 1212 | + if (i > 0) ss << ", "; | ||
| 1213 | + auto it = axis_id_to_name.find(output_attr.axis[i]); | ||
| 1214 | + ss << (it != axis_id_to_name.end() ? it->second : "unknown"); | ||
| 1215 | + } | ||
| 1216 | + ss << "}" << std::endl; | ||
| 1217 | + } | ||
| 1218 | + | ||
| 1219 | + // 输出 repeats | ||
| 1220 | + if (!output_attr.repeats.empty()) { | ||
| 1221 | + ss << std::string(kPropertyIndent, ' ') << ".repeats = ("; | ||
| 1222 | + for (size_t i = 0; i < output_attr.repeats.size(); ++i) { | ||
| 1223 | + if (i > 0) ss << ", "; | ||
| 1224 | + ss << ge::SymbolicUtils::ToString(output_attr.repeats[i]); | ||
| 1225 | + } | ||
| 1226 | + ss << ")" << std::endl; | ||
| 1227 | + } | ||
| 1228 | + | ||
| 1229 | + // 输出 strides | ||
| 1230 | + if (!output_attr.strides.empty()) { | ||
| 1231 | + ss << std::string(kPropertyIndent, ' ') << ".strides = ("; | ||
| 1232 | + for (size_t i = 0; i < output_attr.strides.size(); ++i) { | ||
| 1233 | + if (i > 0) ss << ", "; | ||
| 1234 | + ss << ge::SymbolicUtils::ToString(output_attr.strides[i]); | ||
| 1235 | + } | ||
| 1236 | + ss << ")" << std::endl; | ||
| 1237 | + } | ||
| 1238 | + | ||
| 1239 | + return ss; | ||
| 1240 | +} | ||
| 1241 | + | ||
| 1242 | +/** | ||
| 1243 | + * @brief 输出 vectorized 信息 | ||
| 1244 | + */ | ||
| 1245 | +static std::stringstream &OutputVectorizedStr(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1246 | + const ge::AscTensorAttr &output_attr, | ||
| 1247 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 1248 | + (void) graph; | ||
| 1249 | + if (!output_attr.vectorized_axis.empty()) { | ||
| 1250 | + ss << std::string(kPropertyIndent, ' ') << ".vectorized = {"; | ||
| 1251 | + for (size_t i = 0; i < output_attr.vectorized_axis.size(); ++i) { | ||
| 1252 | + if (i > 0) ss << ", "; | ||
| 1253 | + auto it = axis_id_to_name.find(output_attr.vectorized_axis[i]); | ||
| 1254 | + std::string axis_name = (it != axis_id_to_name.end()) ? it->second : "unknown"; | ||
| 1255 | + ss << axis_name << ":"; | ||
| 1256 | + if (i < output_attr.vectorized_strides.size()) { | ||
| 1257 | + ss << ge::SymbolicUtils::ToString(output_attr.vectorized_strides[i]); | ||
| 1258 | + } | ||
| 1259 | + } | ||
| 1260 | + ss << "}" << std::endl; | ||
| 1261 | + } | ||
| 1262 | + return ss; | ||
| 1263 | +} | ||
| 1264 | + | ||
| 1265 | +/** | ||
| 1266 | + * @brief 输出内存信息 | ||
| 1267 | + */ | ||
| 1268 | +static std::stringstream &OutputMemStr(std::stringstream &ss, const ge::AscTensorAttr &output_attr, bool verbose) { | ||
| 1269 | + if (!verbose && (output_attr.mem.alloc_type != ge::AllocType::kAllocTypeQueue) && | ||
| 1270 | + (output_attr.mem.alloc_type != ge::AllocType::kAllocTypeBuffer)) { | ||
| 1271 | + return ss; | ||
| 1272 | + } | ||
| 1273 | + | ||
| 1274 | + std::string pos_str = PositionToString(output_attr.mem.position); | ||
| 1275 | + std::string hardware_str = MemHardwareToString(output_attr.mem.hardware); | ||
| 1276 | + | ||
| 1277 | + ss << std::string(kPropertyIndent, ' ') << ".mem = " << hardware_str << "["; | ||
| 1278 | + | ||
| 1279 | + // 输出 tensor_id(如果存在) | ||
| 1280 | + if (output_attr.mem.tensor_id != ge::kIdNone) { | ||
| 1281 | + ss << "tensor_id=" << output_attr.mem.tensor_id << ", "; | ||
| 1282 | + } | ||
| 1283 | + | ||
| 1284 | + if (output_attr.mem.alloc_type == ge::AllocType::kAllocTypeQueue) { | ||
| 1285 | + const auto &que = output_attr.que; | ||
| 1286 | + ss << "que_id=" << que.id; | ||
| 1287 | + if (output_attr.mem.reuse_id >= 0) { | ||
| 1288 | + ss << ", reuse_id=" << output_attr.mem.reuse_id; | ||
| 1289 | + } | ||
| 1290 | + ss << ", depth=" << que.depth << ", pos=" << pos_str; | ||
| 1291 | + } else if (output_attr.mem.alloc_type == ge::AllocType::kAllocTypeBuffer) { | ||
| 1292 | + ss << "buf_id=" << output_attr.buf.id; | ||
| 1293 | + if (output_attr.mem.reuse_id >= 0) { | ||
| 1294 | + ss << ", reuse_id=" << output_attr.mem.reuse_id; | ||
| 1295 | + } | ||
| 1296 | + ss << ", pos=" << pos_str; | ||
| 1297 | + } else { | ||
| 1298 | + ss << "pos=" << pos_str; | ||
| 1299 | + } | ||
| 1300 | + | ||
| 1301 | + ss << "]" << std::endl; | ||
| 1302 | + | ||
| 1303 | + return ss; | ||
| 1304 | +} | ||
| 1305 | +} // namespace | ||
| 1306 | + | ||
| 1307 | +// ============================================================================= | ||
| 1308 | +// VIEW 2: Graph Structure 辅助函数实现 | ||
| 1309 | +// ============================================================================= | ||
| 1310 | + | ||
| 1311 | +/** | ||
| 1312 | + * @brief 获取 ExecuteCondition 的字符串表示 | ||
| 1313 | + */ | ||
| 1314 | +std::string ExecuteConditionToString(ge::ExecuteCondition condition) { | ||
| 1315 | + switch (condition) { | ||
| 1316 | + case ge::ExecuteCondition::kNoCache: return "no_cache"; | ||
| 1317 | + case ge::ExecuteCondition::kCacheBlockSplitFusedBroadcastAxis: return "cache_block_split_fused_brc_axis"; | ||
| 1318 | + case ge::ExecuteCondition::kCacheBlockSplitOriginBroadcastAxis: return "cache_block_split_origin_brc_axis"; | ||
| 1319 | + case ge::ExecuteCondition::kConditionInvalid: return "invalid"; | ||
| 1320 | + default: return "unknown"; | ||
| 1321 | + } | ||
| 1322 | +} | ||
| 1323 | + | ||
| 1324 | +/** | ||
| 1325 | + * @brief 输出 Size 变量列表 | ||
| 1326 | + */ | ||
| 1327 | +void DumpSizeVars(std::stringstream &ss, const ascir::Graph &graph) { | ||
| 1328 | + ss << "Sizes:" << std::endl; | ||
| 1329 | + auto all_size_var = graph.GetAllSizeVar(); | ||
| 1330 | + | ||
| 1331 | + for (const auto &size_var: all_size_var) { | ||
| 1332 | + if (size_var->expr.GetExprType() == ge::ExprType::kExprVariable) { | ||
| 1333 | + ss << " " << size_var->expr.Str().get() << ": VAR" << std::endl; | ||
| 1334 | + } else { | ||
| 1335 | + ss << " " << size_var->name << ": " << ge::SymbolicUtils::ToString(size_var->expr) << std::endl; | ||
| 1336 | + } | ||
| 1337 | + } | ||
| 1338 | +} | ||
| 1339 | + | ||
| 1340 | +/** | ||
| 1341 | + * @brief 输出 Axis 列表 | ||
| 1342 | + */ | ||
| 1343 | +void DumpAxisList(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1344 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 1345 | + ss << std::endl << "Axis:" << std::endl; | ||
| 1346 | + auto all_axis = graph.GetAllAxis(); | ||
| 1347 | + | ||
| 1348 | + for (auto &axis: all_axis) { | ||
| 1349 | + ss << " " << axis->name << "(" << axis->id << ") : "; | ||
| 1350 | + ss << GetAxisTypeSuffix(axis->type); | ||
| 1351 | + ss << ", size:" << ge::SymbolicUtils::ToString(axis->size); | ||
| 1352 | + | ||
| 1353 | + if (!axis->from.empty()) { | ||
| 1354 | + ss << ", from: {"; | ||
| 1355 | + for (size_t i = 0; i < axis->from.size(); ++i) { | ||
| 1356 | + if (i > 0) ss << ", "; | ||
| 1357 | + auto it = axis_id_to_name.find(axis->from[i]); | ||
| 1358 | + ss << (it != axis_id_to_name.end() ? it->second : "unknown"); | ||
| 1359 | + } | ||
| 1360 | + ss << "}"; | ||
| 1361 | + } | ||
| 1362 | + | ||
| 1363 | + ss << std::endl; | ||
| 1364 | + } | ||
| 1365 | +} | ||
| 1366 | + | ||
| 1367 | +/** | ||
| 1368 | + * @brief 输出节点调度属性(axis, loop_axis) | ||
| 1369 | + */ | ||
| 1370 | +static void DumpNodeSchedProps(std::stringstream &ss, | ||
| 1371 | + const ge::AscNodePtr &node, | ||
| 1372 | + const std::map<ge::AxisId, std::string> &axis_id_to_name) { | ||
| 1373 | + // 输出 axis 列表 | ||
| 1374 | + if (!node->attr.sched.axis.empty()) { | ||
| 1375 | + ss << std::string(kPropertyIndent, ' ') << ".axis = {"; | ||
| 1376 | + for (size_t i = 0; i < node->attr.sched.axis.size(); ++i) { | ||
| 1377 | + if (i > 0) ss << ", "; | ||
| 1378 | + auto it = axis_id_to_name.find(node->attr.sched.axis[i]); | ||
| 1379 | + ss << (it != axis_id_to_name.end() ? it->second : "unknown"); | ||
| 1380 | + } | ||
| 1381 | + ss << "}" << std::endl; | ||
| 1382 | + } | ||
| 1383 | + | ||
| 1384 | + // 输出 loop_axis | ||
| 1385 | + if (node->attr.sched.loop_axis >= 0) { | ||
| 1386 | + auto it = axis_id_to_name.find(node->attr.sched.loop_axis); | ||
| 1387 | + ss << std::string(kPropertyIndent, ' ') << ".loop_axis = " | ||
| 1388 | + << (it != axis_id_to_name.end() ? it->second : "unknown") << std::endl; | ||
| 1389 | + } | ||
| 1390 | + | ||
| 1391 | + // 输出 exec_condition(只显示非默认值) | ||
| 1392 | + if (node->attr.sched.exec_condition != ge::ExecuteCondition::kNoCache) { | ||
| 1393 | + ss << std::string(kPropertyIndent, ' ') << ".exec_condition = " | ||
| 1394 | + << ExecuteConditionToString(node->attr.sched.exec_condition) << std::endl; | ||
| 1395 | + } | ||
| 1396 | +} | ||
| 1397 | + | ||
| 1398 | +/** | ||
| 1399 | + * @brief 输出节点输入 | ||
| 1400 | + */ | ||
| 1401 | +static void DumpNodeInputs(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1402 | + const ge::AscNodePtr &node) { | ||
| 1403 | + auto input_names = CollectInputNames(graph, node); | ||
| 1404 | + if (input_names.empty()) { | ||
| 1405 | + return; | ||
| 1406 | + } | ||
| 1407 | + | ||
| 1408 | + // 检查是否全部为 nil | ||
| 1409 | + bool all_nil = true; | ||
| 1410 | + for (const auto &name: input_names) { | ||
| 1411 | + if (name != "nil") { | ||
| 1412 | + all_nil = false; | ||
| 1413 | + break; | ||
| 1414 | + } | ||
| 1415 | + } | ||
| 1416 | + if (all_nil) { | ||
| 1417 | + return; | ||
| 1418 | + } | ||
| 1419 | + | ||
| 1420 | + ss << std::string(kPropertyIndent, ' ') << ".x = {"; | ||
| 1421 | + for (size_t i = 0; i < input_names.size(); ++i) { | ||
| 1422 | + if (i > 0) ss << ", "; | ||
| 1423 | + if (input_names[i] != "nil") { | ||
| 1424 | + ss << input_names[i]; | ||
| 1425 | + } | ||
| 1426 | + } | ||
| 1427 | + ss << "}" << std::endl; | ||
| 1428 | +} | ||
| 1429 | + | ||
| 1430 | +/** | ||
| 1431 | + * @brief 输出节点输出 | ||
| 1432 | + */ | ||
| 1433 | +static void DumpNodeOutputs(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1434 | + const ge::AscNodePtr &node, | ||
| 1435 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 1436 | + bool verbose, bool is_subgraph) { | ||
| 1437 | + auto node_type = node->GetType(); | ||
| 1438 | + // 子图模式下,只输出 Data 和 Output 节点的输出信息 | ||
| 1439 | + if (is_subgraph && node_type != "Data" && node_type != "Output") { | ||
| 1440 | + return; | ||
| 1441 | + } | ||
| 1442 | + | ||
| 1443 | + for (size_t i = 0; i < node->outputs().size(); ++i) { | ||
| 1444 | + auto &output_attr = node->outputs()[i]->attr; | ||
| 1445 | + | ||
| 1446 | + // 输出 tensor 类型 | ||
| 1447 | + ss << std::string(kPropertyIndent, ' ') << ".y: " << GetDtypeString(output_attr.dtype) << std::endl; | ||
| 1448 | + | ||
| 1449 | + // 输出形状、向量化信息 | ||
| 1450 | + OutputShapeStr(ss, graph, output_attr, axis_id_to_name); | ||
| 1451 | + OutputVectorizedStr(ss, graph, output_attr, axis_id_to_name); | ||
| 1452 | + | ||
| 1453 | + // mem 信息 - 仅非子图显示 | ||
| 1454 | + if (!is_subgraph) { | ||
| 1455 | + OutputMemStr(ss, output_attr, verbose); | ||
| 1456 | + } | ||
| 1457 | + } | ||
| 1458 | +} | ||
| 1459 | + | ||
| 1460 | +/** | ||
| 1461 | + * @brief 输出单个节点的详细信息 | ||
| 1462 | + */ | ||
| 1463 | +void DumpNodeDetails(std::stringstream &ss, const ascir::Graph &graph, | ||
| 1464 | + const ge::AscNodePtr &node, size_t idx, | ||
| 1465 | + const std::map<ge::AxisId, std::string> &axis_id_to_name, | ||
| 1466 | + bool verbose, bool is_subgraph) { | ||
| 1467 | + // 节点名和类型 | ||
| 1468 | + ss << " [" << idx << "] " << node->GetName() << " : ascir.ops." << node->GetType() << std::endl; | ||
| 1469 | + | ||
| 1470 | + // 输出调度属性 | ||
| 1471 | + DumpNodeSchedProps(ss, node, axis_id_to_name); | ||
| 1472 | + | ||
| 1473 | + // 输出输入 | ||
| 1474 | + DumpNodeInputs(ss, graph, node); | ||
| 1475 | + | ||
| 1476 | + // 输出输出 | ||
| 1477 | + DumpNodeOutputs(ss, graph, node, axis_id_to_name, verbose, is_subgraph); | ||
| 1478 | +} | ||
| 1479 | + | ||
| 1480 | +std::string DumpGraphStructureView(const ascir::Graph &graph, bool verbose, bool is_subgraph) { | ||
| 1481 | + std::stringstream ss; | ||
| 1482 | + | ||
| 1483 | + // Header | ||
| 1484 | + ss << "Graph: " << graph.GetName() << std::endl; | ||
| 1485 | + | ||
| 1486 | + // 获取轴映射 | ||
| 1487 | + auto all_axis = graph.GetAllAxis(); | ||
| 1488 | + auto axis_id_to_name = BuildAxisIdToNameMap(all_axis); | ||
| 1489 | + | ||
| 1490 | + // Sizes | ||
| 1491 | + DumpSizeVars(ss, graph); | ||
| 1492 | + | ||
| 1493 | + // Axis | ||
| 1494 | + DumpAxisList(ss, graph, axis_id_to_name); | ||
| 1495 | + | ||
| 1496 | + // Nodes | ||
| 1497 | + ss << std::endl << "Nodes:" << std::endl; | ||
| 1498 | + auto all_nodes = graph.GetAllNodes(); | ||
| 1499 | + size_t idx = 0UL; | ||
| 1500 | + | ||
| 1501 | + for (auto node: all_nodes) { | ||
| 1502 | + DumpNodeDetails(ss, graph, node, idx++, axis_id_to_name, verbose, is_subgraph); | ||
| 1503 | + } | ||
| 1504 | + | ||
| 1505 | + return ss.str(); | ||
| 1506 | +} | ||
| 1507 | + | ||
| 1508 | +namespace { | ||
| 1509 | +/** | ||
| 1510 | + * @brief 收集 Queue 和 Buffer 信息 | ||
| 1511 | + */ | ||
| 1512 | +void CollectMemoryInfo(const ascir::Graph &graph, | ||
| 1513 | + std::map<int32_t, dumper::QueueInfo> &queues, | ||
| 1514 | + std::map<int32_t, dumper::BufferInfo> &buffers) { | ||
| 1515 | + auto all_nodes = graph.GetAllNodes(); | ||
| 1516 | + size_t topo_id = 0; | ||
| 1517 | + | ||
| 1518 | + for (auto node: all_nodes) { | ||
| 1519 | + auto node_type = node->GetType(); | ||
| 1520 | + if (node_type == NodeType::kData || node_type == NodeType::kOutput || node_type == NodeType::kWorkspace) { | ||
| 1521 | + continue; | ||
| 1522 | + } | ||
| 1523 | + | ||
| 1524 | + if (!node->outputs().empty()) { | ||
| 1525 | + auto &output_attr = node->outputs()[0]->attr; | ||
| 1526 | + auto &mem = output_attr.mem; | ||
| 1527 | + | ||
| 1528 | + if (mem.alloc_type == ge::AllocType::kAllocTypeQueue) { | ||
| 1529 | + int32_t que_id = output_attr.que.id; | ||
| 1530 | + if (queues.find(que_id) == queues.end()) { | ||
| 1531 | + dumper::QueueInfo info; | ||
| 1532 | + info.que_id = que_id; | ||
| 1533 | + info.depth = output_attr.que.depth; | ||
| 1534 | + info.position = "TPosition::" + PositionToString(mem.position); | ||
| 1535 | + queues[que_id] = info; | ||
| 1536 | + } | ||
| 1537 | + queues[que_id].nodes.push_back({topo_id, node->GetName(), static_cast<int32_t>(mem.reuse_id)}); | ||
| 1538 | + } else if (mem.alloc_type == ge::AllocType::kAllocTypeBuffer) { | ||
| 1539 | + int32_t buf_id = output_attr.buf.id; | ||
| 1540 | + if (buffers.find(buf_id) == buffers.end()) { | ||
| 1541 | + dumper::BufferInfo info; | ||
| 1542 | + info.buf_id = buf_id; | ||
| 1543 | + buffers[buf_id] = info; | ||
| 1544 | + } | ||
| 1545 | + buffers[buf_id].nodes.push_back({topo_id, node->GetName()}); | ||
| 1546 | + } | ||
| 1547 | + } | ||
| 1548 | + topo_id++; | ||
| 1549 | + } | ||
| 1550 | +} | ||
| 1551 | + | ||
| 1552 | +/** | ||
| 1553 | + * @brief 输出 Queues 部分 | ||
| 1554 | + */ | ||
| 1555 | +void DumpQueues(std::stringstream &ss, const std::map<int32_t, dumper::QueueInfo> &queues) { | ||
| 1556 | + ss << "# Queues (" << queues.size() << " queues)" << std::endl; | ||
| 1557 | + ss << std::endl; | ||
| 1558 | + | ||
| 1559 | + for (auto &entry: queues) { | ||
| 1560 | + auto &info = entry.second; | ||
| 1561 | + ss << "Queue " << info.que_id << " [" << info.position << ", depth=" << info.depth << "]:" << std::endl; | ||
| 1562 | + | ||
| 1563 | + // 按 reuse_id 分组 | ||
| 1564 | + std::map<int32_t, std::vector<dumper::QueueNodeInfo> > reuse_groups; | ||
| 1565 | + for (auto &node_info: info.nodes) { | ||
| 1566 | + reuse_groups[node_info.reuse_id].push_back(node_info); | ||
| 1567 | + } | ||
| 1568 | + | ||
| 1569 | + // 输出每个 reuse 组 | ||
| 1570 | + for (auto &reuse_entry: reuse_groups) { | ||
| 1571 | + auto &nodes = reuse_entry.second; | ||
| 1572 | + ss << " "; | ||
| 1573 | + for (size_t i = 0; i < nodes.size(); ++i) { | ||
| 1574 | + if (i > 0) ss << ", "; | ||
| 1575 | + ss << "[" << nodes[i].topo_id << "] " << nodes[i].node_name << ".y"; | ||
| 1576 | + } | ||
| 1577 | + ss << std::endl; | ||
| 1578 | + } | ||
| 1579 | + ss << std::endl; | ||
| 1580 | + } | ||
| 1581 | +} | ||
| 1582 | + | ||
| 1583 | +/** | ||
| 1584 | + * @brief 输出 Buffers 部分 | ||
| 1585 | + */ | ||
| 1586 | +void DumpBuffers(std::stringstream &ss, const std::map<int32_t, dumper::BufferInfo> &buffers) { | ||
| 1587 | + ss << "# Buffers (" << buffers.size() << " buffers)" << std::endl; | ||
| 1588 | + ss << std::endl; | ||
| 1589 | + | ||
| 1590 | + for (auto &entry: buffers) { | ||
| 1591 | + auto &info = entry.second; | ||
| 1592 | + ss << "Buffer " << info.buf_id << ":" << std::endl; | ||
| 1593 | + | ||
| 1594 | + // 按 topo_id 排序 | ||
| 1595 | + auto sorted_nodes = info.nodes; | ||
| 1596 | + std::sort(sorted_nodes.begin(), sorted_nodes.end(), | ||
| 1597 | + [](const dumper::BufferNodeInfo &a, const dumper::BufferNodeInfo &b) { | ||
| 1598 | + return a.topo_id < b.topo_id; | ||
| 1599 | + }); | ||
| 1600 | + | ||
| 1601 | + for (auto &node_info: sorted_nodes) { | ||
| 1602 | + ss << " [" << node_info.topo_id << "] " << node_info.node_name << ".y" << std::endl; | ||
| 1603 | + } | ||
| 1604 | + ss << std::endl; | ||
| 1605 | + } | ||
| 1606 | +} | ||
| 1607 | +} // namespace | ||
| 1608 | + | ||
| 1609 | +std::string DumpMemoryLayoutView(const ascir::Graph &graph, bool verbose) { | ||
| 1610 | + if (!verbose) { | ||
| 1611 | + return ""; | ||
| 1612 | + } | ||
| 1613 | + | ||
| 1614 | + std::stringstream ss; | ||
| 1615 | + | ||
| 1616 | + // 收集内存信息 | ||
| 1617 | + std::map<int32_t, QueueInfo> queues; | ||
| 1618 | + std::map<int32_t, BufferInfo> buffers; | ||
| 1619 | + CollectMemoryInfo(graph, queues, buffers); | ||
| 1620 | + | ||
| 1621 | + // 输出 Queues 和 Buffers | ||
| 1622 | + DumpQueues(ss, queues); | ||
| 1623 | + DumpBuffers(ss, buffers); | ||
| 1624 | + | ||
| 1625 | + return ss.str(); | ||
| 1626 | +} | ||
| 1627 | + | ||
| 1628 | +std::string DumpGraphText(const ascir::Graph &graph, bool verbose, bool is_subgraph) { | ||
| 1629 | + std::stringstream ss; | ||
| 1630 | + | ||
| 1631 | + // Header | ||
| 1632 | + ss << "================================================================================" << std::endl; | ||
| 1633 | + ss << "Graph: " << graph.GetName() << std::endl; | ||
| 1634 | + ss << "================================================================================" << std::endl; | ||
| 1635 | + ss << std::endl; | ||
| 1636 | + | ||
| 1637 | + // VIEW 1: Loop Execution | ||
| 1638 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1639 | + ss << "VIEW 1: Loop Execution" << std::endl; | ||
| 1640 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1641 | + ss << DumpLoopExecutionView(graph); | ||
| 1642 | + ss << std::endl; | ||
| 1643 | + | ||
| 1644 | + // VIEW 2: Graph Structure | ||
| 1645 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1646 | + ss << "VIEW 2: Graph Structure" << std::endl; | ||
| 1647 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1648 | + ss << DumpGraphStructureView(graph, verbose, is_subgraph); | ||
| 1649 | + ss << std::endl; | ||
| 1650 | + | ||
| 1651 | + // VIEW 3: Memory Layout (子图不显示,非子图仅在 verbose=true 时显示) | ||
| 1652 | + if (!is_subgraph) { | ||
| 1653 | + auto memory_layout = DumpMemoryLayoutView(graph, verbose); | ||
| 1654 | + if (!memory_layout.empty()) { | ||
| 1655 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1656 | + ss << "VIEW 3: Memory Layout" << std::endl; | ||
| 1657 | + ss << "--------------------------------------------------------------------------------" << std::endl; | ||
| 1658 | + ss << memory_layout; | ||
| 1659 | + ss << std::endl; | ||
| 1660 | + } | ||
| 1661 | + } | ||
| 1662 | + | ||
| 1663 | + ss << "================================================================================" << std::endl; | ||
| 1664 | + ss << "End of Dump" << std::endl; | ||
| 1665 | + ss << "================================================================================" << std::endl; | ||
| 1666 | + | ||
| 1667 | + return ss.str(); | ||
| 1668 | +} | ||
| 1669 | +} // namespace dumper | ||
| 1670 | +} // namespace ascir | ||
| @@ -0,0 +1,234 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace ascir { | ||
| 21 | +namespace dumper { | ||
| 22 | +namespace NodeType { | ||
| 23 | +constexpr const char *kData = "Data"; | ||
| 24 | +constexpr const char *kOutput = "Output"; | ||
| 25 | +constexpr const char *kWorkspace = "Workspace"; | ||
| 26 | +constexpr const char *kScalar = "Scalar"; | ||
| 27 | +} // namespace NodeType | ||
| 28 | + | ||
| 29 | +// 魔法数字常量 | ||
| 30 | +constexpr int64_t kInvalidLoopAxis = -1; | ||
| 31 | +constexpr int64_t kInvalidAxisId = -1; | ||
| 32 | +constexpr size_t kIndentSpaces = 2; // 循环缩进空格数 | ||
| 33 | +constexpr size_t kPropertyIndent = 8; // 属性缩进空格数 (VIEW 2) | ||
| 34 | +constexpr size_t kNodeIndent = 4; // 节点缩进空格数 | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * @brief Dtype 信息结构体 | ||
| 38 | + */ | ||
| 39 | +struct DtypeInfo { | ||
| 40 | + const char *full_name; // 完整类型名 (如 "float32") | ||
| 41 | + const char *short_name; // 简写类型名 (如 "f32") | ||
| 42 | + const char *suffix; // 后缀 (如 "32f") | ||
| 43 | +}; | ||
| 44 | + | ||
| 45 | +/** | ||
| 46 | + * @brief 获取 Dtype 信息 | ||
| 47 | + * @param dtype 数据类型 | ||
| 48 | + * @return Dtype 信息指针,如果找不到返回 nullptr | ||
| 49 | + */ | ||
| 50 | +const DtypeInfo *GetDtypeInfo(ge::DataType dtype); | ||
| 51 | + | ||
| 52 | +/** | ||
| 53 | + * @brief 获取轴类型的优先级(用于排序) | ||
| 54 | + * @param type 轴类型 | ||
| 55 | + * @return 优先级值,越小越外层 | ||
| 56 | + */ | ||
| 57 | +int32_t GetAxisTypePriority(ge::Axis::Type type); | ||
| 58 | + | ||
| 59 | +/** | ||
| 60 | + * @brief 获取轴类型对应的字符串后缀 | ||
| 61 | + * @param type 轴类型 | ||
| 62 | + * @return 类型字符串 (如 "TILE_OUT", "BLOCK_IN") | ||
| 63 | + */ | ||
| 64 | +std::string GetAxisTypeSuffix(ge::Axis::Type type); | ||
| 65 | + | ||
| 66 | +/** | ||
| 67 | + * @brief 构建 axis_id 到 axis_name 的映射 | ||
| 68 | + * @param axes 所有轴列表 | ||
| 69 | + * @return axis_id -> axis_name 的映射表 | ||
| 70 | + */ | ||
| 71 | +std::map<ge::AxisId, std::string> BuildAxisIdToNameMap(const std::vector<ge::AxisPtr> &axes); | ||
| 72 | + | ||
| 73 | +/** | ||
| 74 | + * @brief 构建 axis_id 到 axis_type 的映射 | ||
| 75 | + * @param axes 所有轴列表 | ||
| 76 | + * @return axis_id -> axis_type 的映射表 | ||
| 77 | + */ | ||
| 78 | +std::map<int64_t, ge::Axis::Type> BuildAxisIdToTypeMap(const std::vector<ge::AxisPtr> &axes); | ||
| 79 | + | ||
| 80 | +/** | ||
| 81 | + * @brief 从 tensor 类型字符串中提取 dtype | ||
| 82 | + * @param tensor_type tensor 类型字符串 (如 "f32[...]") | ||
| 83 | + * @return 完整的 dtype 名称 (如 "float32") | ||
| 84 | + */ | ||
| 85 | +std::string ExtractDtypeFromTensorType(const std::string &tensor_type); | ||
| 86 | + | ||
| 87 | +/** | ||
| 88 | + * @brief 从 tensor 类型字符串中提取 axis 列表 | ||
| 89 | + * @param tensor_type tensor 类型字符串 (如 "f32[...]") | ||
| 90 | + * @return axis 列表部分 (如 "[...]") | ||
| 91 | + */ | ||
| 92 | +std::string ExtractAxisListFromTensorType(const std::string &tensor_type); | ||
| 93 | + | ||
| 94 | +/** | ||
| 95 | + * @brief 收集节点的输入名称列表 | ||
| 96 | + * @param graph 图对象 | ||
| 97 | + * @param node 节点对象 | ||
| 98 | + * @return 输入名称列表 | ||
| 99 | + */ | ||
| 100 | +std::vector<std::string> CollectInputNames(const ascir::Graph &graph, const ge::AscNodePtr &node); | ||
| 101 | + | ||
| 102 | +/** | ||
| 103 | + * @brief SSA 编号映射信息 | ||
| 104 | + */ | ||
| 105 | +struct SSAMappingInfo { | ||
| 106 | + std::map<std::string, size_t> node_name_to_ssa_id; // 节点名 -> SSA 编号 | ||
| 107 | + std::set<std::string> data_node_names; // Data 节点名称集合 | ||
| 108 | + std::map<std::string, size_t> node_name_to_topo_id; // 节点名 -> topo_id | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * @brief 获取节点的 SSA 编号 | ||
| 112 | + * @param node_name 节点名称 | ||
| 113 | + * @return SSA 编号,如果找不到返回 0 | ||
| 114 | + */ | ||
| 115 | + size_t GetSsaId(const std::string &node_name) const { | ||
| 116 | + auto it = node_name_to_ssa_id.find(node_name); | ||
| 117 | + return (it != node_name_to_ssa_id.end()) ? it->second : 0; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + /** | ||
| 121 | + * @brief 获取节点的 topo_id | ||
| 122 | + * @param node_name 节点名称 | ||
| 123 | + * @return topo_id,如果找不到返回 0 | ||
| 124 | + */ | ||
| 125 | + size_t GetTopoId(const std::string &node_name) const { | ||
| 126 | + auto it = node_name_to_topo_id.find(node_name); | ||
| 127 | + return (it != node_name_to_topo_id.end()) ? it->second : 0; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * @brief 判断是否为 Data 节点 | ||
| 132 | + * @param node_name 节点名称 | ||
| 133 | + * @return 如果是 Data 节点返回 true | ||
| 134 | + */ | ||
| 135 | + bool IsDataNode(const std::string &node_name) const { | ||
| 136 | + return data_node_names.count(node_name) > 0; | ||
| 137 | + } | ||
| 138 | +}; | ||
| 139 | + | ||
| 140 | +/** | ||
| 141 | + * @brief 构建 SSA 映射信息 | ||
| 142 | + * @param all_nodes 所有节点列表 | ||
| 143 | + * @return SSA 映射信息 | ||
| 144 | + */ | ||
| 145 | +SSAMappingInfo BuildSSAMapping(ge::AscNodeVisitor all_nodes); | ||
| 146 | + | ||
| 147 | +/** | ||
| 148 | + * @brief 参数信息(用于输入/输出) | ||
| 149 | + */ | ||
| 150 | +struct ParamInfo { | ||
| 151 | + std::string name; | ||
| 152 | + std::string type; | ||
| 153 | +}; | ||
| 154 | + | ||
| 155 | +/** | ||
| 156 | + * @brief Tile/Block 分解树的节点 | ||
| 157 | + */ | ||
| 158 | +struct AxisTreeNode { | ||
| 159 | + ge::AxisPtr axis; | ||
| 160 | + bool is_merge; | ||
| 161 | + std::vector<AxisTreeNode> children; | ||
| 162 | +}; | ||
| 163 | + | ||
| 164 | +/** | ||
| 165 | + * @brief Queue 节点信息 | ||
| 166 | + */ | ||
| 167 | +struct QueueNodeInfo { | ||
| 168 | + size_t topo_id; | ||
| 169 | + std::string node_name; | ||
| 170 | + int32_t reuse_id; | ||
| 171 | +}; | ||
| 172 | + | ||
| 173 | +/** | ||
| 174 | + * @brief Queue 信息 | ||
| 175 | + */ | ||
| 176 | +struct QueueInfo { | ||
| 177 | + int32_t que_id; | ||
| 178 | + int32_t depth; | ||
| 179 | + std::string position; | ||
| 180 | + std::vector<QueueNodeInfo> nodes; | ||
| 181 | +}; | ||
| 182 | + | ||
| 183 | +/** | ||
| 184 | + * @brief Buffer 节点信息 | ||
| 185 | + */ | ||
| 186 | +struct BufferNodeInfo { | ||
| 187 | + size_t topo_id; | ||
| 188 | + std::string node_name; | ||
| 189 | +}; | ||
| 190 | + | ||
| 191 | +/** | ||
| 192 | + * @brief Buffer 信息 | ||
| 193 | + */ | ||
| 194 | +struct BufferInfo { | ||
| 195 | + int32_t buf_id; | ||
| 196 | + std::vector<BufferNodeInfo> nodes; | ||
| 197 | +}; | ||
| 198 | + | ||
| 199 | +/** | ||
| 200 | + * @brief 生成 VIEW 1: Loop Execution 的文本 | ||
| 201 | + * @param graph 图对象 | ||
| 202 | + * @return VIEW 1 的文本内容 | ||
| 203 | + */ | ||
| 204 | +std::string DumpLoopExecutionView(const ascir::Graph &graph); | ||
| 205 | + | ||
| 206 | +/** | ||
| 207 | + * @brief 生成 VIEW 2: Graph Structure 的文本 | ||
| 208 | + * @param graph 图对象 | ||
| 209 | + * @param verbose 是否显示详细信息 | ||
| 210 | + * @param is_subgraph 是否为子图 | ||
| 211 | + * @return VIEW 2 的文本内容 | ||
| 212 | + */ | ||
| 213 | +std::string DumpGraphStructureView(const ascir::Graph &graph, bool verbose, bool is_subgraph); | ||
| 214 | + | ||
| 215 | +/** | ||
| 216 | + * @brief 生成 VIEW 3: Memory Layout 的文本 | ||
| 217 | + * @param graph 图对象 | ||
| 218 | + * @param verbose 是否显示详细信息 | ||
| 219 | + * @return VIEW 3 的文本内容 | ||
| 220 | + */ | ||
| 221 | +std::string DumpMemoryLayoutView(const ascir::Graph &graph, bool verbose); | ||
| 222 | + | ||
| 223 | +/** | ||
| 224 | + * @brief 生成完整的图转储文本(包含三个 VIEW) | ||
| 225 | + * @param graph 图对象 | ||
| 226 | + * @param verbose 是否显示详细信息 | ||
| 227 | + * @param is_subgraph 是否为子图 | ||
| 228 | + * @return 完整的转储文本 | ||
| 229 | + */ | ||
| 230 | +std::string DumpGraphText(const ascir::Graph &graph, bool verbose = false, bool is_subgraph = false); | ||
| 231 | +} // namespace dumper | ||
| 232 | +} // namespace ascir | ||
| 233 | + | ||
| 234 | + | ||
| @@ -13,6 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | + | ||
| 17 | + | ||
| 16 | 18 | ||
| 17 | 19 | ||
| 18 | 20 | ||
| @@ -21,9 +23,11 @@ | |||
| 21 | 23 | ||
| 22 | 24 | ||
| 23 | 25 | ||
| 26 | + | ||
| 24 | 27 | ||
| 25 | 28 | ||
| 26 | 29 | ||
| 30 | + | ||
| 27 | 31 | ||
| 28 | namespace { | 32 | namespace { |
| 29 | constexpr int32_t DUMP_ID_WIDTH = 8; | 33 | constexpr int32_t DUMP_ID_WIDTH = 8; |
| @@ -181,18 +185,29 @@ bool CheckNeedDumpGraphBySuffix(const std::string &suffix) { | |||
| 181 | namespace ascir::utils { | 185 | namespace ascir::utils { |
| 182 | static uint64_t kDumpGraphIndex = 0UL; | 186 | static uint64_t kDumpGraphIndex = 0UL; |
| 183 | static std::string DtypeToStr(ge::DataType dtype) { | 187 | static std::string DtypeToStr(ge::DataType dtype) { |
| 184 | - const char *kTypeName[] = { | 188 | + switch (dtype) { |
| 185 | - [ge::DT_FLOAT] = "float32", [ge::DT_FLOAT16] = "float16", [ge::DT_INT8] = "int8_t", | 189 | + case ge::DT_FLOAT: return "float32"; |
| 186 | - [ge::DT_INT32] = "int32_t", [ge::DT_UINT8] = "uint8_t", "", | 190 | + case ge::DT_FLOAT16: return "float16"; |
| 187 | - [ge::DT_INT16] = "int16_t", [ge::DT_UINT16] = "uint16_t", [ge::DT_UINT32] = "uint32_t", | 191 | + case ge::DT_INT8: return "int8_t"; |
| 188 | - [ge::DT_INT64] = "int64_t", [ge::DT_UINT64] = "uint64_t", | 192 | + case ge::DT_INT32: return "int32_t"; |
| 189 | - }; | 193 | + case ge::DT_UINT8: return "uint8_t"; |
| 190 | - | 194 | + case ge::DT_INT16: return "int16_t"; |
| 191 | - if (dtype >= sizeof(kTypeName) / sizeof(kTypeName[0])) { | 195 | + case ge::DT_UINT16: return "uint16_t"; |
| 192 | - return ge::TypeUtils::DataTypeToSerialString(dtype); | 196 | + case ge::DT_UINT32: return "uint32_t"; |
| 197 | + case ge::DT_INT64: return "int64_t"; | ||
| 198 | + case ge::DT_UINT64: return "uint64_t"; | ||
| 199 | + default: return ge::TypeUtils::DataTypeToSerialString(dtype); | ||
| 193 | } | 200 | } |
| 194 | - return kTypeName[dtype]; | 201 | +} |
| 195 | -}; | 202 | + |
| 203 | +// 构建 axis_id 到 axis_name 的映射(供 ascir_utils.cpp 内部使用) | ||
| 204 | +static std::map<ge::AxisId, std::string> GetAxisIdToName(const std::vector<ge::AxisPtr> &axes) { | ||
| 205 | + std::map<ge::AxisId, std::string> axis_id_to_name; | ||
| 206 | + for (auto &axis : axes) { | ||
| 207 | + axis_id_to_name[axis->id] = axis->name; | ||
| 208 | + } | ||
| 209 | + return axis_id_to_name; | ||
| 210 | +} | ||
| 196 | 211 | ||
| 197 | std::stringstream GetDumpGraphPrefixAndCreateDir() { | 212 | std::stringstream GetDumpGraphPrefixAndCreateDir() { |
| 198 | std::stringstream stream_file_name; | 213 | std::stringstream stream_file_name; |
| @@ -278,14 +293,6 @@ static std::string PositionToStr(ge::Position position) { | |||
| 278 | return "unknown"; | 293 | return "unknown"; |
| 279 | } | 294 | } |
| 280 | 295 | ||
| 281 | -static std::map<ge::AxisId, std::string> GetAxisIdToName(const std::vector<ge::AxisPtr> &axes) { | ||
| 282 | - std::map<ge::AxisId, std::string> id_to_name; | ||
| 283 | - for (const auto &iter : axes) { | ||
| 284 | - id_to_name[iter->id] = iter->name; | ||
| 285 | - } | ||
| 286 | - return id_to_name; | ||
| 287 | -} | ||
| 288 | - | ||
| 289 | static std::stringstream &GraphNameStr(std::stringstream &ss, const ascir::Graph &graph) { | 296 | static std::stringstream &GraphNameStr(std::stringstream &ss, const ascir::Graph &graph) { |
| 290 | ss << "Graph: " << graph.GetName() << std::endl; | 297 | ss << "Graph: " << graph.GetName() << std::endl; |
| 291 | return ss; | 298 | return ss; |
| @@ -401,27 +408,6 @@ static std::stringstream &NodeAttrStr(std::stringstream &ss, const ascir::Graph | |||
| 401 | return ss; | 408 | return ss; |
| 402 | } | 409 | } |
| 403 | 410 | ||
| 404 | -static std::vector<std::string> CollectInputNames(const ascir::Graph &graph, const ge::AscNodePtr &node) { | ||
| 405 | - (void)graph; | ||
| 406 | - std::vector<std::string> input_names; | ||
| 407 | - | ||
| 408 | - for (uint32_t index = 0U; index < node->GetAllInDataAnchorsSize(); index++) { | ||
| 409 | - auto in_anchor = node->GetInDataAnchor(static_cast<int32_t>(index)); | ||
| 410 | - if (in_anchor == nullptr) { | ||
| 411 | - input_names.push_back("nil"); | ||
| 412 | - continue; | ||
| 413 | - } | ||
| 414 | - auto peer_out_anchor = in_anchor->GetPeerOutAnchor(); | ||
| 415 | - if (peer_out_anchor == nullptr) { | ||
| 416 | - input_names.push_back("nil"); | ||
| 417 | - } else { | ||
| 418 | - auto peer_name = peer_out_anchor->GetOwnerNode()->GetName(); | ||
| 419 | - input_names.push_back(peer_name + ".y"); | ||
| 420 | - } | ||
| 421 | - } | ||
| 422 | - return input_names; | ||
| 423 | -} | ||
| 424 | - | ||
| 425 | static std::stringstream &NodeInputStr(std::stringstream &ss, const std::vector<std::string> &input_names) { | 411 | static std::stringstream &NodeInputStr(std::stringstream &ss, const std::vector<std::string> &input_names) { |
| 426 | bool all_nil = true; | 412 | bool all_nil = true; |
| 427 | for (const auto &name : input_names) { | 413 | for (const auto &name : input_names) { |
| @@ -610,7 +596,13 @@ static void DumpGraphText(const Graph &graph, const string &suffix, const uint32 | |||
| 610 | static std::stringstream prefix = GetDumpGraphPrefixAndCreateDir(); | 596 | static std::stringstream prefix = GetDumpGraphPrefixAndCreateDir(); |
| 611 | std::stringstream ss; | 597 | std::stringstream ss; |
| 612 | ss << prefix.str(); | 598 | ss << prefix.str(); |
| 613 | - auto dump_asc_graph = DebugStr(graph, verbose); | 599 | + |
| 600 | + // 判断是否是子图 | ||
| 601 | + bool is_subgraph = (suffix.find("_Subgraph_") != std::string::npos); | ||
| 602 | + | ||
| 603 | + // 使用新的 MLIR 风格格式 | ||
| 604 | + auto dump_asc_graph = DebugStrNew(graph, verbose, is_subgraph); | ||
| 605 | + | ||
| 614 | ss << "ascgraph_" << std::setw(DUMP_ID_WIDTH) << std::setfill('0') << kDumpGraphIndex; | 606 | ss << "ascgraph_" << std::setw(DUMP_ID_WIDTH) << std::setfill('0') << kDumpGraphIndex; |
| 615 | ss << "_" << graph.GetName() << "_" << suffix << "_" << graph_id << ".txt"; | 607 | ss << "_" << graph.GetName() << "_" << suffix << "_" << graph_id << ".txt"; |
| 616 | std::ofstream f_stream(ss.str()); | 608 | std::ofstream f_stream(ss.str()); |
| @@ -645,9 +637,6 @@ void DumpGraph(const ascir::Graph &graph, const std::string &suffix, const uint3 | |||
| 645 | DumpGraphText(subgraph, "_Subgraph_", graph_id, verbose); | 637 | DumpGraphText(subgraph, "_Subgraph_", graph_id, verbose); |
| 646 | } | 638 | } |
| 647 | 639 | ||
| 648 | - // dump onnx | ||
| 649 | - const auto compute_graph = ge::AscGraphUtils::GetComputeGraph(graph); | ||
| 650 | - DumpComputeGraph(compute_graph, suffix); | ||
| 651 | ++kDumpGraphIndex; | 640 | ++kDumpGraphIndex; |
| 652 | } | 641 | } |
| 653 | 642 | ||
| @@ -660,9 +649,6 @@ void AlwaysDumpGraph(const Graph &graph, const string &suffix, const uint32_t gr | |||
| 660 | DumpGraphText(subgraph, "_Subgraph_", graph_id, verbose); | 649 | DumpGraphText(subgraph, "_Subgraph_", graph_id, verbose); |
| 661 | } | 650 | } |
| 662 | 651 | ||
| 663 | - // dump onnx | ||
| 664 | - const auto compute_graph = ge::AscGraphUtils::GetComputeGraph(graph); | ||
| 665 | - DumpComputeGraph(compute_graph, suffix, true); | ||
| 666 | ++kDumpGraphIndex; | 652 | ++kDumpGraphIndex; |
| 667 | } | 653 | } |
| 668 | 654 | ||
| @@ -711,7 +697,7 @@ std::string DebugStr(const ascir::Graph &graph, bool verbose) { | |||
| 711 | NodeAttrStr(ss, graph, node, verbose); | 697 | NodeAttrStr(ss, graph, node, verbose); |
| 712 | 698 | ||
| 713 | // Node inputs | 699 | // Node inputs |
| 714 | - auto input_names = CollectInputNames(graph, node); | 700 | + auto input_names = dumper::CollectInputNames(graph, node); |
| 715 | NodeInputStr(ss, input_names); | 701 | NodeInputStr(ss, input_names); |
| 716 | 702 | ||
| 717 | // Node outputs | 703 | // Node outputs |
| @@ -731,6 +717,10 @@ std::string DebugImplGraphStr(const ascir::ImplGraph &graph) { | |||
| 731 | return DebugStr(graph, true); | 717 | return DebugStr(graph, true); |
| 732 | } | 718 | } |
| 733 | 719 | ||
| 720 | +std::string DebugStrNew(const ascir::Graph &graph, bool verbose, bool is_subgraph) { | ||
| 721 | + return ascir::dumper::DumpGraphText(graph, verbose, is_subgraph); | ||
| 722 | +} | ||
| 723 | + | ||
| 734 | void DumpScheduleResult(const ascir::FusedScheduledResult &fused_scheduled_result, const std::string &suffix, | 724 | void DumpScheduleResult(const ascir::FusedScheduledResult &fused_scheduled_result, const std::string &suffix, |
| 735 | uint32_t graph_id, bool verbose) { | 725 | uint32_t graph_id, bool verbose) { |
| 736 | for (const auto &results : fused_scheduled_result.node_idx_to_scheduled_results) { | 726 | for (const auto &results : fused_scheduled_result.node_idx_to_scheduled_results) { |
| @@ -44,6 +44,10 @@ std::string DebugStr(const ascir::Graph &graph, bool verbose = false); | |||
| 44 | std::string DebugHintGraphStr(const ascir::HintGraph &graph); | 44 | std::string DebugHintGraphStr(const ascir::HintGraph &graph); |
| 45 | std::string DebugImplGraphStr(const ascir::ImplGraph &graph); | 45 | std::string DebugImplGraphStr(const ascir::ImplGraph &graph); |
| 46 | 46 | ||
| 47 | +// New MLIR-style dump format | ||
| 48 | +// is_subgraph: true for subgraph (simplified mode, VIEW3/.api.unit/.mem are not displayed) | ||
| 49 | +std::string DebugStrNew(const ascir::Graph &graph, bool verbose = false, bool is_subgraph = false); | ||
| 50 | + | ||
| 47 | void DumpScheduleResult(const ascir::FusedScheduledResult &fused_scheduled_result, const std::string &suffix, | 51 | void DumpScheduleResult(const ascir::FusedScheduledResult &fused_scheduled_result, const std::string &suffix, |
| 48 | uint32_t graph_id = 0U, bool verbose = true); | 52 | uint32_t graph_id = 0U, bool verbose = true); |
| 49 | 53 | ||
| @@ -56,6 +60,7 @@ bool IsConcatAllInputsAligned(const ge::AscNode &node); | |||
| 56 | ge::TriBool AreConcatInputShapesEqual(const ge::AscNodePtr &node); | 60 | ge::TriBool AreConcatInputShapesEqual(const ge::AscNodePtr &node); |
| 57 | 61 | ||
| 58 | bool AreAllInputsLoad(const ge::NodePtr &node); | 62 | bool AreAllInputsLoad(const ge::NodePtr &node); |
| 63 | + | ||
| 59 | } // namespace ascir::utils | 64 | } // namespace ascir::utils |
| 60 | 65 | ||
| 61 | 66 | ||
| @@ -199,6 +199,11 @@ bool IsSplitComplete(const NodePtr &node) { | |||
| 199 | if (ascir_node->GetType() == kSplitType) { | 199 | if (ascir_node->GetType() == kSplitType) { |
| 200 | fused_split_num++; | 200 | fused_split_num++; |
| 201 | } | 201 | } |
| 202 | + if (kPureSplitIncludedAscirNodeTypes.count(ascir_node->GetType()) == 0U) { | ||
| 203 | + GELOGD("split AscBackend node %s has ascir node %s(%s), has fused with other types of AscBackend", | ||
| 204 | + node->GetName().c_str(), ascir_node->GetType().c_str(), ascir_node->GetName().c_str()); | ||
| 205 | + return false; | ||
| 206 | + } | ||
| 202 | } | 207 | } |
| 203 | GELOGD("split node %s, original node %s, original output num %zu, fused split node %zu", node->GetName().c_str(), | 208 | GELOGD("split node %s, original node %s, original output num %zu, fused split node %zu", node->GetName().c_str(), |
| 204 | origin_node->GetName().c_str(), origin_output_num, fused_split_num); | 209 | origin_node->GetName().c_str(), origin_output_num, fused_split_num); |
| @@ -41,6 +41,7 @@ const std::string kSqueezeType = "Squeeze"; | |||
| 41 | const std::string kUnsqueezeType = "Unsqueeze"; | 41 | const std::string kUnsqueezeType = "Unsqueeze"; |
| 42 | const ge::Expression kSymbolZero = ge::Symbol(0); | 42 | const ge::Expression kSymbolZero = ge::Symbol(0); |
| 43 | const ge::Expression kSymbolOne = ge::Symbol(1); | 43 | const ge::Expression kSymbolOne = ge::Symbol(1); |
| 44 | +const std::set kPureSplitIncludedAscirNodeTypes({kSplitType, kDataType, kLoadType, kStoreType, kOutputType}); | ||
| 44 | 45 | ||
| 45 | struct NodeFuseInfo; | 46 | struct NodeFuseInfo; |
| 46 | struct ComparePairs; | 47 | struct ComparePairs; |
| @@ -63,7 +63,7 @@ bool SplitFusionStrategy::CanFuse(const NodePtr &node1, const NodePtr &node2) { | |||
| 63 | return false; | 63 | return false; |
| 64 | } | 64 | } |
| 65 | // split不做水平融合 | 65 | // split不做水平融合 |
| 66 | - if (BackendUtils::IsHorizontal(node1, node2)) { | 66 | + if (!BackendUtils::IsVertical(node1, node2)) { |
| 67 | GELOGI("node1 %s(%s) and node2 %s(%s) can not fuse, the reason is [%s][split cannot fuse other node horizontal.]", | 67 | GELOGI("node1 %s(%s) and node2 %s(%s) can not fuse, the reason is [%s][split cannot fuse other node horizontal.]", |
| 68 | node1->GetName().c_str(), node1->GetType().c_str(), node2->GetName().c_str(), node2->GetType().c_str(), | 68 | node1->GetName().c_str(), node1->GetType().c_str(), node2->GetName().c_str(), node2->GetType().c_str(), |
| 69 | ge::NotFuseReasonCode(ge::NotFuseReason::kSplitCanNotFuseHorizontal)); | 69 | ge::NotFuseReasonCode(ge::NotFuseReason::kSplitCanNotFuseHorizontal)); |
| @@ -491,13 +491,13 @@ graphStatus ParseSplitNodeAndValidate(const NodePtr &split_node, InDataAnchorPtr | |||
| 491 | 491 | ||
| 492 | graphStatus ComputeSplitSplits(const NodePtr &node, const Expression &x_dim, vector<Expression> &size_splits) { | 492 | graphStatus ComputeSplitSplits(const NodePtr &node, const Expression &x_dim, vector<Expression> &size_splits) { |
| 493 | vector<int64_t> num_split_list = {}; | 493 | vector<int64_t> num_split_list = {}; |
| 494 | - GE_ASSERT_GRAPH_SUCCESS(AutofuseUtils::GetListIntByInputOrAttr(node, num_split_list, "num_split", "num_split"), | 494 | + GE_WARN_ASSERT(AutofuseUtils::GetListIntByInputOrAttr(node, num_split_list, "num_split", "num_split"), |
| 495 | "Skip lowering node %s, as: Failed to get num_split.", node->GetNamePtr()); | 495 | "Skip lowering node %s, as: Failed to get num_split.", node->GetNamePtr()); |
| 496 | GE_ASSERT(!num_split_list.empty()); | 496 | GE_ASSERT(!num_split_list.empty()); |
| 497 | 497 | ||
| 498 | vector<int64_t> size_splits_list = {}; | 498 | vector<int64_t> size_splits_list = {}; |
| 499 | if (node->GetType() == AF_SPLITVD || node->GetType() == AF_SPLITV) { | 499 | if (node->GetType() == AF_SPLITVD || node->GetType() == AF_SPLITV) { |
| 500 | - GE_ASSERT_GRAPH_SUCCESS(AutofuseUtils::GetListIntByInputOrAttr(node, size_splits_list, "size_splits", "size_splits"), | 500 | + GE_WARN_ASSERT(AutofuseUtils::GetListIntByInputOrAttr(node, size_splits_list, "size_splits", "size_splits"), |
| 501 | "Skip lowering node %s, as: Failed to get size_splits .", node->GetNamePtr()); | 501 | "Skip lowering node %s, as: Failed to get size_splits .", node->GetNamePtr()); |
| 502 | GE_ASSERT(!size_splits_list.empty()); | 502 | GE_ASSERT(!size_splits_list.empty()); |
| 503 | for (size_t i = 0U; i < size_splits_list.size(); ++i) { | 503 | for (size_t i = 0U; i < size_splits_list.size(); ++i) { |
| @@ -81,8 +81,8 @@ docs/es/ | |||
| 81 | ### API 集成 | 81 | ### API 集成 |
| 82 | 82 | ||
| 83 | - [x] [***December 2025***]math 分包已完成ES API集成。 | 83 | - [x] [***December 2025***]math 分包已完成ES API集成。 |
| 84 | -- [ ] [***February 2026***]nn、cv、transformer、hcom分包完成ES API集成。 | 84 | +- [x] [***February 2026***]nn、cv、transformer完成ES API集成。 |
| 85 | -- [ ] [***March 2026***]hcom分包完成ES API集成。 | 85 | +- [ ] [***April 2026***]hcom分包完成ES API集成。 |
| 86 | 86 | ||
| 87 | 注:在全量原型的ES API打包到各个算子分包之前,如需使用 ES API,可以参考工具文档中的 [generate_es_package.cmake](tools/generate_es_package_cmake_readme.md) 进行代码生成和集成。 | 87 | 注:在全量原型的ES API打包到各个算子分包之前,如需使用 ES API,可以参考工具文档中的 [generate_es_package.cmake](tools/generate_es_package_cmake_readme.md) 进行代码生成和集成。 |
| 88 | 88 | ||
| @@ -95,7 +95,7 @@ docs/es/ | |||
| 95 | ### 后向兼容 | 95 | ### 后向兼容 |
| 96 | - [x] [***December 2025***]Python API后向兼容完成设计并落地。 | 96 | - [x] [***December 2025***]Python API后向兼容完成设计并落地。 |
| 97 | - [x] [***January 2026***]C++ API后向兼容性设计完成;C++ API的后向兼容依赖完成`历史原型库`的设计方案。 | 97 | - [x] [***January 2026***]C++ API后向兼容性设计完成;C++ API的后向兼容依赖完成`历史原型库`的设计方案。 |
| 98 | -- [ ] [***March 2026***]C++ API后向兼容性代码开发完成;实现C++构图场景的完整向后兼容能力。 | 98 | +- [x] [***March 2026***]C++ API后向兼容性代码开发完成;实现C++构图场景的完整向后兼容能力。 |
| 99 | 99 | ||
| 100 | ### 自定义算子工程集成 | 100 | ### 自定义算子工程集成 |
| 101 | 101 | ||
| @@ -74,6 +74,8 @@ make my_app | |||
| 74 | 74 | ||
| 75 | ## 参数说明 | 75 | ## 参数说明 |
| 76 | 76 | ||
| 77 | +### 函数参数 | ||
| 78 | + | ||
| 77 | 两个函数参数完全相同: | 79 | 两个函数参数完全相同: |
| 78 | 80 | ||
| 79 | | 参数 | 必需性 | 说明 | 示例 | | 81 | | 参数 | 必需性 | 说明 | 示例 | |
| @@ -92,6 +94,21 @@ make my_app | |||
| 92 | 类型的 `ES_LINKABLE_AND_ALL_TARGET` 的原因 | 94 | 类型的 `ES_LINKABLE_AND_ALL_TARGET` 的原因 |
| 93 | - 函数会自动从 `OPP_PROTO_TARGET` 的 `LIBRARY_OUTPUT_DIRECTORY` 推导原型库路径,这是生成原型库对应的 ES 产物的基本条件 | 95 | - 函数会自动从 `OPP_PROTO_TARGET` 的 `LIBRARY_OUTPUT_DIRECTORY` 推导原型库路径,这是生成原型库对应的 ES 产物的基本条件 |
| 94 | 96 | ||
| 97 | +### 历史原型库相关 CMake 变量 | ||
| 98 | + | ||
| 99 | +以下变量在调用函数前通过 `set()` 设置,用于控制历史原型库功能: | ||
| 100 | + | ||
| 101 | +| 变量 | 类型 | 说明 | 示例 | | ||
| 102 | +|------|------|------|------| | ||
| 103 | +| `GE_ES_EXTRACT_HISTORY` | bool(可选) | ON 时向 gen_esb 传入 `--es_mode=extract_history`,启用**历史原型库生成模式**(归档当前原型为 JSON,供后续版本代码生成时使用);不设置或 OFF 则 gen_esb 默认 `codegen`(仅生成 C++ API) | `set(GE_ES_EXTRACT_HISTORY ON)` | | ||
| 104 | +| `GE_ES_RELEASE_VERSION` | 可选 | **当前新版本号**,归档步骤将当前原型归档为此版本;历史原型库生成模式下必须设置 | `set(GE_ES_RELEASE_VERSION "8.0.RC1")` | | ||
| 105 | +| `GE_ES_RELEASE_DATE` | 可选 | 历史原型库生成模式下指定发布日期(格式 `YYYY-MM-DD`),不设置则由 gen_esb 使用当前日期 | `set(GE_ES_RELEASE_DATE "2026-02-28")` | | ||
| 106 | +| `GE_ES_BRANCH_NAME` | 可选 | 历史原型库生成模式下指定发布分支名。**注意**:当设为 `master` 时,函数会忽略所有归档相关变量(`GE_ES_EXTRACT_HISTORY`/`GE_ES_RELEASE_VERSION`/`GE_ES_RELEASE_DATE`),仅走纯代码生成模式 | `set(GE_ES_BRANCH_NAME "release/8.0")` | | ||
| 107 | + | ||
| 108 | +> **历史原型库路径自动推导**:函数内部根据 cmake 文件安装位置自动推导 `${CANN_INSTALL_PATH}/cann/opp/history_registry/<module>` 路径,路径存在且非空时自动向 gen_esb 传入 `--history_registry`,**调用方无需显式设置历史原型库路径**。 | ||
| 109 | +> | ||
| 110 | +> **完整商发模式**:`GE_ES_EXTRACT_HISTORY=ON` 且 ops 包中存在历史原型库时,`add_es_library` 内部自动串行执行两次 gen_esb(代码生成 + 历史原型库归档&合并),**调用方无需额外处理**,一次 `add_es_library` 调用即可完成完整商发所需的全部操作(参见示例 9)。 | ||
| 111 | + | ||
| 95 | ## 输出产物 | 112 | ## 输出产物 |
| 96 | 113 | ||
| 97 | ### add_es_library_and_whl 生成的产物 | 114 | ### add_es_library_and_whl 生成的产物 |
| @@ -104,7 +121,8 @@ OUTPUT_PATH/ | |||
| 104 | │ ├── es_math_ops_c.h # C 接口聚合头文件 | 121 | │ ├── es_math_ops_c.h # C 接口聚合头文件 |
| 105 | │ └── es_add.h ... # 单个算子头文件(一般是有多个文件) | 122 | │ └── es_add.h ... # 单个算子头文件(一般是有多个文件) |
| 106 | ├── lib64/ | 123 | ├── lib64/ |
| 107 | -│ └── libes_math.so # 动态库 | 124 | +│ ├── libes_math.so # 动态库 |
| 125 | +│ └── libes_math.a # 静态库 | ||
| 108 | └── whl/ | 126 | └── whl/ |
| 109 | └── es_math-1.0.0-py3-none-any.whl # Python 包 | 127 | └── es_math-1.0.0-py3-none-any.whl # Python 包 |
| 110 | ``` | 128 | ``` |
| @@ -119,9 +137,32 @@ OUTPUT_PATH/ | |||
| 119 | │ ├── es_math_ops_c.h # C 接口聚合头文件 | 137 | │ ├── es_math_ops_c.h # C 接口聚合头文件 |
| 120 | │ └── es_add.h ... # 单个算子头文件(一般是有多个文件) | 138 | │ └── es_add.h ... # 单个算子头文件(一般是有多个文件) |
| 121 | └── lib64/ | 139 | └── lib64/ |
| 122 | - └── libes_math.so # 动态库 | 140 | + ├── libes_math.so # 动态库 |
| 141 | + └── libes_math.a # 静态库 | ||
| 123 | ``` | 142 | ``` |
| 124 | -**聚合的含义**:包含 es_math 下所有算子的构图 API | 143 | + |
| 144 | +**说明**: | ||
| 145 | +- **聚合的含义**:包含 es_math 下所有算子的构图 API | ||
| 146 | +- **动态库与静态库**:每次生成会同时产出 `lib<name>.so` 与 `lib<name>.a`。对外接口 target(如 `es_math`)默认链接动态库;若需静态链接,可手动指定 `lib64/lib<name>.a` 或通过 `target_link_libraries(your_target PRIVATE ${OUTPUT_PATH}/lib64/libes_math.a)` 等方式链接静态库。 | ||
| 147 | + | ||
| 148 | +### 启用历史原型库相关模式后的额外产物 | ||
| 149 | + | ||
| 150 | +#### 历史原型库生成模式(`GE_ES_EXTRACT_HISTORY=ON`) | ||
| 151 | + | ||
| 152 | +gen_esb 直接输出到 `OUTPUT_PATH`,生成以下 JSON 结构: | ||
| 153 | + | ||
| 154 | +``` | ||
| 155 | +OUTPUT_PATH/ | ||
| 156 | +├── index.json # 版本索引(所有已归档版本的列表) | ||
| 157 | +└── registry/ | ||
| 158 | + └── <GE_ES_RELEASE_VERSION>/ | ||
| 159 | + ├── metadata.json # 版本元信息(版本号、发布日期、分支名等) | ||
| 160 | + └── operators.json # 算子原型数据(IR 结构化描述) | ||
| 161 | +``` | ||
| 162 | + | ||
| 163 | +#### 代码生成模式含历史兼容(自动检测到历史原型库时) | ||
| 164 | + | ||
| 165 | +C++ 头文件中同一算子会出现多版本重载签名(历史版本签名 + 当前版本签名),`.so` 同时包含所有版本的实现,向前兼容旧版本调用方式。产物目录结构与标准模式相同,仅头文件内容有差异。 | ||
| 125 | 166 | ||
| 126 | ## 生成的 Target | 167 | ## 生成的 Target |
| 127 | 168 | ||
| @@ -129,7 +170,7 @@ OUTPUT_PATH/ | |||
| 129 | 170 | ||
| 130 | | Target 名称 | 用途 | 说明 | | 171 | | Target 名称 | 用途 | 说明 | |
| 131 | |------------|------|------| | 172 | |------------|------|------| |
| 132 | -| `es_math` | **链接依赖** | **使用方通过此 target 链接,自动触发构建** | | 173 | +| `es_math` | **链接依赖** | **使用方通过此 target 链接,自动触发构建**;默认链接动态库(.so),静态库(.a)同时生成在 `lib64/` 下,需静态链接时请直接指定静态库文件。 | |
| 133 | 174 | ||
| 134 | ## 使用示例 | 175 | ## 使用示例 |
| 135 | 176 | ||
| @@ -267,6 +308,57 @@ graph = builder.build_and_reset() | |||
| 267 | - 可以使用 `ge.es.list_plugins()` 查看所有已加载的插件名称 | 308 | - 可以使用 `ge.es.list_plugins()` 查看所有已加载的插件名称 |
| 268 | - 可以使用 `ge.es.get_plugin('math')` 检查插件是否存在(返回模块对象或 None)。 | 309 | - 可以使用 `ge.es.get_plugin('math')` 检查插件是否存在(返回模块对象或 None)。 |
| 269 | 310 | ||
| 311 | +### 示例 7:历史原型库生成模式(商发首次构建,归档当前版本原型) | ||
| 312 | + | ||
| 313 | +```cmake | ||
| 314 | +# 从已安装的算子原型 .so 中提取 IR 原型,归档为 JSON 供下次商发使用 | ||
| 315 | +set(GE_ES_EXTRACT_HISTORY ON) | ||
| 316 | +set(GE_ES_RELEASE_VERSION "8.0.RC1") | ||
| 317 | +set(GE_ES_RELEASE_DATE "2026-02-28") # 可选,不设置则使用当前日期 | ||
| 318 | +set(GE_ES_BRANCH_NAME "release/8.0") # 可选;若设为 master 则不会执行归档,仅走代码生成 | ||
| 319 | + | ||
| 320 | +add_es_library( | ||
| 321 | + ES_LINKABLE_AND_ALL_TARGET es_math | ||
| 322 | + OPP_PROTO_TARGET opgraph_math | ||
| 323 | + OUTPUT_PATH ${CMAKE_BINARY_DIR}/output | ||
| 324 | +) | ||
| 325 | +# 产物:output/index.json, output/registry/8.0.RC1/metadata.json, output/registry/8.0.RC1/operators.json | ||
| 326 | +``` | ||
| 327 | + | ||
| 328 | +### 示例 8:代码生成模式含历史兼容(自动消费已有历史数据,生成带重载的 C++ API) | ||
| 329 | + | ||
| 330 | +```cmake | ||
| 331 | +# 函数内部自动检测 ${CANN_INSTALL_PATH}/cann/opp/history_registry/math, | ||
| 332 | +# 路径存在且非空时自动生成带历史兼容重载签名的 C++ 接口,无需手动设置路径 | ||
| 333 | +set(GE_ES_RELEASE_VERSION "8.0.RC2") | ||
| 334 | + | ||
| 335 | +add_es_library( | ||
| 336 | + ES_LINKABLE_AND_ALL_TARGET es_math | ||
| 337 | + OPP_PROTO_TARGET opgraph_math | ||
| 338 | + OUTPUT_PATH ${CMAKE_BINARY_DIR}/output | ||
| 339 | +) | ||
| 340 | +# 产物头文件中同一算子出现多版本重载(旧签名 + 新签名),向前兼容旧版本调用 | ||
| 341 | +``` | ||
| 342 | + | ||
| 343 | +### 示例 9:完整商发模式(单次调用,函数内部自动完成代码生成 + 历史原型库归档&合并) | ||
| 344 | + | ||
| 345 | +```cmake | ||
| 346 | +# GE_ES_EXTRACT_HISTORY=ON + ops 包中存在历史原型库(自动检测)= 完整商发模式 | ||
| 347 | +# add_es_library 内部自动串行执行两次 gen_esb,调用方无需额外处理: | ||
| 348 | +# gen_esb 调用1:默认 codegen 模式,以当前日期为锚点自动选取窗口内历史版本 → 对比当前原型 → 生成带重载 C++ API | ||
| 349 | +# gen_esb 调用2:--es_mode=extract_history,将已有历史库从 _AUTO_HISTORY_REGISTRY 复制至 OUTPUT_PATH,在 OUTPUT_PATH 追加当前版本原型 → OUTPUT_PATH 包含完整历史原型库 | ||
| 350 | +set(GE_ES_EXTRACT_HISTORY ON) | ||
| 351 | +set(GE_ES_RELEASE_VERSION "8.0.RC2") # 当前新版本号,用于归档步骤 | ||
| 352 | +set(GE_ES_RELEASE_DATE "2026-02-28") # 可选 | ||
| 353 | +set(GE_ES_BRANCH_NAME "develop") # 可选;若设为 master 则不会归档,仅走代码生成 | ||
| 354 | + | ||
| 355 | +add_es_library( | ||
| 356 | + ES_LINKABLE_AND_ALL_TARGET es_math | ||
| 357 | + OPP_PROTO_TARGET opgraph_math | ||
| 358 | + OUTPUT_PATH ${CMAKE_BINARY_DIR}/output | ||
| 359 | +) | ||
| 360 | +``` | ||
| 361 | + | ||
| 270 | ## 命名规则 | 362 | ## 命名规则 |
| 271 | 363 | ||
| 272 | ### 产物命名 | 364 | ### 产物命名 |
| @@ -274,6 +366,7 @@ graph = builder.build_and_reset() | |||
| 274 | | 产物类型 | 命名规则 | 示例 (ES_LINKABLE_AND_ALL_TARGET=es_math) | | 366 | | 产物类型 | 命名规则 | 示例 (ES_LINKABLE_AND_ALL_TARGET=es_math) | |
| 275 | |---------|---------|--------------------------------| | 367 | |---------|---------|--------------------------------| |
| 276 | | 动态库 | `lib<ES_LINKABLE_AND_ALL_TARGET>.so` | `libes_math.so` | | 368 | | 动态库 | `lib<ES_LINKABLE_AND_ALL_TARGET>.so` | `libes_math.so` | |
| 369 | +| 静态库 | `lib<ES_LINKABLE_AND_ALL_TARGET>.a` | `libes_math.a` | | ||
| 277 | | Python 包 | `<ES_LINKABLE_AND_ALL_TARGET>-1.0.0-py3-none-any.whl` | `es_math-1.0.0-py3-none-any.whl` | | 370 | | Python 包 | `<ES_LINKABLE_AND_ALL_TARGET>-1.0.0-py3-none-any.whl` | `es_math-1.0.0-py3-none-any.whl` | |
| 278 | | 聚合头文件 | `es_<name>_ops.h` | `es_math_ops.h` | | 371 | | 聚合头文件 | `es_<name>_ops.h` | `es_math_ops.h` | |
| 279 | 372 | ||
| @@ -291,6 +384,17 @@ graph = builder.build_and_reset() | |||
| 291 | - 使用小写字母和下划线 | 384 | - 使用小写字母和下划线 |
| 292 | - 避免使用特殊字符和 C++ 关键字 | 385 | - 避免使用特殊字符和 C++ 关键字 |
| 293 | 386 | ||
| 387 | +2. **历史原型库相关变量**: | ||
| 388 | + - 历史原型库路径由函数**自动推导**(`${CANN_INSTALL_PATH}/cann/opp/history_registry/<module>`),路径存在且非空时自动启用,调用方无需传参 | ||
| 389 | + - **master 分支**:当 `GE_ES_BRANCH_NAME` 为 `master` 时,会忽略 `GE_ES_EXTRACT_HISTORY`/`GE_ES_RELEASE_VERSION`/`GE_ES_RELEASE_DATE`,仅走纯代码生成模式(历史原型库路径仍会传递,用于生成带重载的 C++ API) | ||
| 390 | + - `GE_ES_EXTRACT_HISTORY=ON` 且 ops 包中存在历史原型库(自动检测到)即为**完整商发模式**,函数内部自动执行两次 gen_esb(代码生成 + 历史原型库归档&合并),调用方无需任何额外处理(参见示例 9) | ||
| 391 | + - **版本去重**:若历史原型库的 `index.json` 中已存在与 `GE_ES_RELEASE_VERSION` 相同的版本号,则跳过归档步骤,仅执行代码生成(避免重复归档);同时将 CANN 安装路径中的历史原型库完整复制到 `OUTPUT_PATH`,方便后续换路径安装 | ||
| 392 | + - 纯历史归档模式(仅设置 `GE_ES_EXTRACT_HISTORY=ON`,ops 包中无历史原型库):gen_esb 输出到 `OUTPUT_PATH`,只生成 JSON,不生成 C++ API | ||
| 393 | + - 完整商发模式下,代码生成步骤 gen_esb 不传 `--release_version`,以当前日期为锚点自动选取窗口内历史版本对比;归档步骤使用 `GE_ES_RELEASE_VERSION` 作为新版本号写入历史库 | ||
| 394 | + - 完整商发模式下,归档步骤将已有历史库从 `_AUTO_HISTORY_REGISTRY`(CANN 安装路径,只读)复制到 `OUTPUT_PATH`(构建目录,可写),gen_esb 在 `OUTPUT_PATH` 追加当前版本条目;首次构建(CANN 路径中无已有历史库)时直接输出至 `OUTPUT_PATH`;最终 `OUTPUT_PATH` 包含所有历史版本 + 当前版本的完整合并结果 | ||
| 395 | + - `GE_ES_RELEASE_VERSION` 归档时必须设置,否则归档版本无法识别 | ||
| 396 | + - 历史原型库数据(JSON 文件)通常随 ops 包安装,默认位于 `${CANN_INSTALL_PATH}/cann/opp/history_registry/<package_name>/` | ||
| 397 | + | ||
| 294 | 398 | ||
| 295 | ## 依赖要求 | 399 | ## 依赖要求 |
| 296 | 400 | ||
| @@ -327,8 +431,8 @@ add_es_library_and_whl( | |||
| 327 | # │ ├── es_math/ | 431 | # │ ├── es_math/ |
| 328 | # │ └── es_nn/ | 432 | # │ └── es_nn/ |
| 329 | # ├── lib64/ | 433 | # ├── lib64/ |
| 330 | -# │ ├── libes_math.so | 434 | +# │ ├── libes_math.so, libes_math.a |
| 331 | -# │ └── libes_nn.so | 435 | +# │ └── libes_nn.so, libes_nn.a |
| 332 | # └── whl/ | 436 | # └── whl/ |
| 333 | # ├── es_math-1.0.0-py3-none-any.whl | 437 | # ├── es_math-1.0.0-py3-none-any.whl |
| 334 | # └── es_nn-1.0.0-py3-none-any.whl | 438 | # └── es_nn-1.0.0-py3-none-any.whl |
| @@ -57,7 +57,8 @@ GE-PY 模块包含以下核心组件: | |||
| 57 | ### API 集成 | 57 | ### API 集成 |
| 58 | 58 | ||
| 59 | - [x] [***December 2025***]基础接口已经完成设计和落地。 | 59 | - [x] [***December 2025***]基础接口已经完成设计和落地。 |
| 60 | -- [ ] [***February 2026***] es 的 python 算子 api 支持,详见[es api集成路标](../es/README.md#api-集成)。 | 60 | +- [x] [***February 2026***] es 的 python 算子 api 支持,详见[es api集成路标](../es/README.md#api-集成)。 |
| 61 | +- [ ] [***March 2026***] 图异步执行的python接口提供 | ||
| 61 | 62 | ||
| 62 | ### sample和相关文档 | 63 | ### sample和相关文档 |
| 63 | 64 | ||
| @@ -33,9 +33,12 @@ | |||
| 33 | ├── CMakeLists.txt //编译脚本,调用src目录下的CMakeLists文件 | 33 | ├── CMakeLists.txt //编译脚本,调用src目录下的CMakeLists文件 |
| 34 | ``` | 34 | ``` |
| 35 | 35 | ||
| 36 | -## 环境要求 | 36 | +## 环境准备 |
| 37 | - | 37 | +- 通过安装指导 [环境准备](../../../docs/build.md#2-安装软件包)正确安装`toolkit`和`ops`包 |
| 38 | -- 已完成[昇腾AI软件栈在开发环境上的部署](https://www.hiascend.com/document/redirect/CannCommunityInstSoftware) | 38 | +- 设置环境变量 (假设包安装在/usr/local/Ascend/) |
| 39 | +``` | ||
| 40 | +source /usr/local/Ascend/cann/set_env.sh | ||
| 41 | +``` | ||
| 39 | 42 | ||
| 40 | ## 实现步骤 | 43 | ## 实现步骤 |
| 41 | 44 | ||
| @@ -43,7 +46,7 @@ | |||
| 43 | 46 | ||
| 44 | 2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/1_sample_resnet50_imagenet_classification"样例目录。 | 47 | 2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/1_sample_resnet50_imagenet_classification"样例目录。 |
| 45 | 48 | ||
| 46 | - 请注意,下文中的样例目录均指“examples/acl/1_sample_resnet50_imagenet_classification”目录。 | 49 | + 请注意,下文中的样例目录均指"examples/acl/1_sample_resnet50_imagenet_classification"目录。 |
| 47 | 50 | ||
| 48 | 3. 准备ResNet-50模型。 | 51 | 3. 准备ResNet-50模型。 |
| 49 | 1. 获取ResNet-50原始模型。 | 52 | 1. 获取ResNet-50原始模型。 |
| @@ -57,6 +60,7 @@ | |||
| 57 | 切换到样例目录,执行如下命令(以Atlas A2系列产品为例): | 60 | 切换到样例目录,执行如下命令(以Atlas A2系列产品为例): |
| 58 | 61 | ||
| 59 | ``` | 62 | ``` |
| 63 | + cd "样例目录/model" | ||
| 60 | atc --model=resnet50_Opset16.onnx --framework=5 --output=resnet50 --soc_version=Ascend910B1 --input_format=NCHW --output_type=FP32 | 64 | atc --model=resnet50_Opset16.onnx --framework=5 --output=resnet50 --soc_version=Ascend910B1 --input_format=NCHW --output_type=FP32 |
| 61 | ``` | 65 | ``` |
| 62 | 66 | ||
| @@ -64,26 +68,27 @@ | |||
| 64 | - --framework:原始框架类型。0:表示Caffe;1:表示MindSpore;3:表示TensorFlow;5:表示ONNX。 | 68 | - --framework:原始框架类型。0:表示Caffe;1:表示MindSpore;3:表示TensorFlow;5:表示ONNX。 |
| 65 | - --soc\_version:昇腾AI处理器的版本。版本获取可参考[Link](https://hiascend.com/document/redirect/CannCommunityAtcSocVersion)。 | 69 | - --soc\_version:昇腾AI处理器的版本。版本获取可参考[Link](https://hiascend.com/document/redirect/CannCommunityAtcSocVersion)。 |
| 66 | - --output\_type:指定输出的数据类型为float32。 | 70 | - --output\_type:指定输出的数据类型为float32。 |
| 67 | - - --output:生成的resnet50.om文件存放在“样例目录/model“目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_resnet50\_imagenet\_classification.cpp 中的omModelPath参数值。 | 71 | + - --output:生成的resnet50.om文件存放在"样例目录/model"目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_resnet50\_imagenet\_classification.cpp 中的omModelPath参数值。 |
| 68 | 72 | ||
| 69 | ``` | 73 | ``` |
| 70 | const char* omModelPath = "../model/resnet50.om"; | 74 | const char* omModelPath = "../model/resnet50.om"; |
| 71 | ``` | 75 | ``` |
| 72 | 76 | ||
| 73 | 4. 准备测试图片。 | 77 | 4. 准备测试图片。 |
| 74 | - 1. 请从以下链接获取该样例的输入图片,并以运行用户将获取的文件上传至开发环境的"样例目录/data"目录下。如果目录不存在,需自行创建。 | 78 | + 1. 可以按照以下命令获取样例的输入图片,输入图片需要放置到"样例目录/data"目录下。如果目录不存在,需自行创建。如果wget失败,您也可以直接在浏览器中输入以下链接下载后上传至"样例目录/data"目录。 |
| 79 | + ``` | ||
| 80 | + cd "样例目录/data" | ||
| 81 | + wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog1_1024_683.jpg | ||
| 82 | + wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog2_1024_683.jpg | ||
| 83 | + ``` | ||
| 75 | 84 | ||
| 76 | - [https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog1\_1024\_683.jpg](https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog1_1024_683.jpg) | 85 | + 2. 切换到"样例目录/data"目录下,执行transferPic.py脚本,将\*.jpg转换为\*.bin,同时将图片从1024\*683的分辨率缩放为224\*224。在"样例目录/data"目录下生成2个\*.bin文件。 |
| 77 | - | ||
| 78 | - [https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog2\_1024\_683.jpg](https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog2_1024_683.jpg) | ||
| 79 | - | ||
| 80 | - 2. 切换到“样例目录/data“目录下,执行transferPic.py脚本,将\*.jpg转换为\*.bin,同时将图片从1024\*683的分辨率缩放为224\*224。在“样例目录/data“目录下生成2个\*.bin文件。 | ||
| 81 | 86 | ||
| 82 | ``` | 87 | ``` |
| 83 | python3 ../scripts/transferPic.py | 88 | python3 ../scripts/transferPic.py |
| 84 | ``` | 89 | ``` |
| 85 | 90 | ||
| 86 | - 如果执行脚本报错“ModuleNotFoundError: No module named 'PIL'”,则表示缺少Pillow库,请使用**pip3 install Pillow --user**命令安装Pillow库。 | 91 | + 如果执行脚本报错"ModuleNotFoundError: No module named 'PIL'",则表示缺少Pillow库,请使用**pip3 install Pillow --user**命令安装Pillow库。 |
| 87 | 92 | ||
| 88 | ## 构建验证 | 93 | ## 构建验证 |
| 89 | 94 | ||
| @@ -97,7 +102,7 @@ | |||
| 97 | 102 | ||
| 98 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 | 103 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 |
| 99 | 104 | ||
| 100 | - **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找“Ascend-cann-toolkit安装目录/lib64”目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 | 105 | + **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找"Ascend-cann-toolkit安装目录/lib64"目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 |
| 101 | 106 | ||
| 102 | - 配置示例如下所示: | 107 | - 配置示例如下所示: |
| 103 | 108 | ||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | ## 功能描述 | 3 | ## 功能描述 |
| 4 | 4 | ||
| 5 | -该样例主要是基于Onnx ResNet-50网络(单输入、动态多Batch)实现图片分类的功能。 | 5 | +该样例主要是基于Onnx ResNet-50网络(单输入、单Batch)实现多batch场景下图片分类的功能。 |
| 6 | 6 | ||
| 7 | 在该样例中: | 7 | 在该样例中: |
| 8 | 1. 先使用样例提供的脚本transferPic.py,将2张\*.jpg图片都转换为\*.bin格式,同时将图片从1024\*683的分辨率缩放为224\*224。 | 8 | 1. 先使用样例提供的脚本transferPic.py,将2张\*.jpg图片都转换为\*.bin格式,同时将图片从1024\*683的分辨率缩放为224\*224。 |
| @@ -35,7 +35,11 @@ | |||
| 35 | 35 | ||
| 36 | ## 环境要求 | 36 | ## 环境要求 |
| 37 | 37 | ||
| 38 | -- 已完成[昇腾AI软件栈在开发环境上的部署](https://www.hiascend.com/document/redirect/CannCommunityInstSoftware) | 38 | +- 通过安装指导 [环境准备](https://gitcode.com/cann/ge/blob/master/docs/build.md#2-%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%8C%85) 正确安装 `toolkit` 和 `ops` 包 |
| 39 | +- 设置环境变量(假设包安装在/usr/local/Ascend/) | ||
| 40 | + ``` | ||
| 41 | + source /usr/local/Ascend/cann/set_env.sh | ||
| 42 | + ``` | ||
| 39 | 43 | ||
| 40 | ## 实现步骤 | 44 | ## 实现步骤 |
| 41 | 45 | ||
| @@ -43,7 +47,7 @@ | |||
| 43 | 47 | ||
| 44 | 2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/2_sample_resnet50_imagenet_classification_dynamic_batch"样例目录。 | 48 | 2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/2_sample_resnet50_imagenet_classification_dynamic_batch"样例目录。 |
| 45 | 49 | ||
| 46 | - 请注意,下文中的样例目录均指“examples/acl/2_sample_resnet50_imagenet_classification_dynamic_batch”目录。 | 50 | + 请注意,下文中的样例目录均指"examples/acl/2_sample_resnet50_imagenet_classification_dynamic_batch"目录。 |
| 47 | 51 | ||
| 48 | 3. 准备ResNet-50模型。 | 52 | 3. 准备ResNet-50模型。 |
| 49 | 1. 获取ResNet-50原始模型。 | 53 | 1. 获取ResNet-50原始模型。 |
| @@ -63,10 +67,10 @@ | |||
| 63 | - --model:原始模型文件路径。 | 67 | - --model:原始模型文件路径。 |
| 64 | - --framework:原始框架类型。0:表示Caffe;1:表示MindSpore;3:表示TensorFlow;5:表示ONNX。 | 68 | - --framework:原始框架类型。0:表示Caffe;1:表示MindSpore;3:表示TensorFlow;5:表示ONNX。 |
| 65 | - --soc\_version:昇腾AI处理器的版本。版本获取可参考[Link](https://hiascend.com/document/redirect/CannCommunityAtcSocVersion)。 | 69 | - --soc\_version:昇腾AI处理器的版本。版本获取可参考[Link](https://hiascend.com/document/redirect/CannCommunityAtcSocVersion)。 |
| 66 | - - --output\_type:指定输出的数据类型为float32。 | ||
| 67 | - - --output:生成的resnet50.om文件存放在“样例目录/model“目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_resnet50\_imagenet\_classification.cpp 中的omModelPath参数值。 | ||
| 68 | - --input\_shape: 指定输入数据的shape值,其中不想指定的维度可以将其设置为-1。 | 70 | - --input\_shape: 指定输入数据的shape值,其中不想指定的维度可以将其设置为-1。 |
| 69 | - --dynamic\_batch\_size: 设置动态batch_size参数。 | 71 | - --dynamic\_batch\_size: 设置动态batch_size参数。 |
| 72 | + - --output\_type:指定输出的数据类型为float32。 | ||
| 73 | + - --output:生成的resnet50.om文件存放在“样例目录/model“目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_resnet50\_imagenet\_classification.cpp 中的omModelPath参数值。 | ||
| 70 | 74 | ||
| 71 | ``` | 75 | ``` |
| 72 | const char* omModelPath = "../model/resnet50_dynamic_batch.om"; | 76 | const char* omModelPath = "../model/resnet50_dynamic_batch.om"; |
| @@ -85,7 +89,7 @@ | |||
| 85 | python3 ../scripts/transferPic.py | 89 | python3 ../scripts/transferPic.py |
| 86 | ``` | 90 | ``` |
| 87 | 91 | ||
| 88 | - 如果执行脚本报错“ModuleNotFoundError: No module named 'PIL'”,则表示缺少Pillow库,请使用**pip3 install Pillow --user**命令安装Pillow库。 | 92 | + 如果执行脚本报错"ModuleNotFoundError: No module named 'PIL'",则表示缺少Pillow库,请使用**pip3 install Pillow --user**命令安装Pillow库。 |
| 89 | 93 | ||
| 90 | ## 构建验证 | 94 | ## 构建验证 |
| 91 | 95 | ||
| @@ -99,7 +103,7 @@ | |||
| 99 | 103 | ||
| 100 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 | 104 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 |
| 101 | 105 | ||
| 102 | - **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找“Ascend-cann-toolkit安装目录/lib64”目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 | 106 | + **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找"Ascend-cann-toolkit安装目录/lib64"目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 |
| 103 | 107 | ||
| 104 | - 配置示例如下所示: | 108 | - 配置示例如下所示: |
| 105 | 109 | ||
Mexamples/acl/2_sample_resnet50_imagenet_classification_dynmaic_batch/src/sample_resnet50_imagenet_classification_dynamic_batch.cpp+2-1
| @@ -95,7 +95,8 @@ Result SampleRes50ImagenetClassification::PrepareModel(const char *modelPath) | |||
| 95 | return SUCCESS; | 95 | return SUCCESS; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | -void SampleRes50ImagenetClassification::OutputModelResult(uint64_t batchSize) const { | 98 | +void SampleRes50ImagenetClassification::OutputModelResult(uint64_t batchSize) const |
| 99 | +{ | ||
| 99 | for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(modelOutput_->GetDataSet()); ++i) { | 100 | for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(modelOutput_->GetDataSet()); ++i) { |
| 100 | // Get model output data | 101 | // Get model output data |
| 101 | aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(modelOutput_->GetDataSet(), i); | 102 | aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(modelOutput_->GetDataSet(), i); |
文件重命名但无更改。
| @@ -27,25 +27,29 @@ | |||
| 27 | ├── CMakeLists.txt // 编译脚本,调用src目录下的CMakeLists文件 | 27 | ├── CMakeLists.txt // 编译脚本,调用src目录下的CMakeLists文件 |
| 28 | ``` | 28 | ``` |
| 29 | 29 | ||
| 30 | -## 环境要求 | 30 | +## 环境准备 |
| 31 | - | 31 | +- 通过安装指导 [环境准备](../../../docs/build.md#2-安装软件包)正确安装`toolkit`和`ops`包 |
| 32 | -- 已完成[昇腾AI软件栈在开发环境上的部署](https://www.hiascend.com/document/redirect/CannCommunityInstSoftware) | 32 | +- 设置环境变量 (假设包安装在/usr/local/Ascend/) |
| 33 | +``` | ||
| 34 | +source /usr/local/Ascend/cann/set_env.sh | ||
| 35 | +``` | ||
| 33 | 36 | ||
| 34 | ## 实现步骤 | 37 | ## 实现步骤 |
| 35 | 38 | ||
| 36 | 1. 以运行用户登录开发环境。 | 39 | 1. 以运行用户登录开发环境。 |
| 37 | 40 | ||
| 38 | -2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/2_sample_qwen_llm"样例目录。 | 41 | +2. 下载代码并上传至环境后,请先进入根目录下"examples/acl/3_sample_qwen_llm"样例目录。 |
| 39 | 42 | ||
| 40 | - 请注意,下文中的样例目录均指"examples/acl/2_sample_qwen_llm"目录。 | 43 | + 请注意,下文中的样例目录均指"examples/acl/3_sample_qwen_llm"目录。 |
| 41 | 44 | ||
| 42 | 3. 准备Qwen模型。 | 45 | 3. 准备Qwen模型。 |
| 43 | - 1. 获取Qwen AIR格式模型。 | 46 | + 1. 获取Qwen ONNX格式模型。 |
| 44 | - | ||
| 45 | - 您可以从以下链接中获取Qwen网络的模型文件,并以运行用户将获取的文件上传至开发环境的"样例目录/model"目录下。如果目录不存在,需要自行创建。 | ||
| 46 | - | ||
| 47 | - - Qwen网络的模型文件(qwen.onnx):单击[Link](https://ascend-cann.obs.cn-north-4.myhuaweicloud.com/cann_test/qwen.onnx)下载该文件。 | ||
| 48 | 47 | ||
| 48 | + 您可以按照以下命令获取Qwen网络的模型文件,模型文件需要放置到"样例目录/model"目录下。如果目录不存在,需要自行创建。如果wget失败,您也可以直接在浏览器中输入以下链接下载后上传至"样例目录/model"目录。 | ||
| 49 | + ``` | ||
| 50 | + cd "样例目录/model" | ||
| 51 | + wget https://ascend-cann.obs.cn-north-4.myhuaweicloud.com/cann_test/qwen.onnx | ||
| 52 | + ``` | ||
| 49 | 2. 将Qwen原始模型转换为适配昇腾AI处理器的离线模型(\*.om文件)。注意如果生成的om文件带有架构后缀(如qwen_linux_aarch64.om),请将文件重命名为qwen.om。 | 53 | 2. 将Qwen原始模型转换为适配昇腾AI处理器的离线模型(\*.om文件)。注意如果生成的om文件带有架构后缀(如qwen_linux_aarch64.om),请将文件重命名为qwen.om。 |
| 50 | 54 | ||
| 51 | 切换到"样例目录/model", 执行模型转换脚本: | 55 | 切换到"样例目录/model", 执行模型转换脚本: |
| @@ -67,7 +71,7 @@ | |||
| 67 | 71 | ||
| 68 | - --model:原始模型文件路径。 | 72 | - --model:原始模型文件路径。 |
| 69 | - --input_shape:指定模型输入的shape。 | 73 | - --input_shape:指定模型输入的shape。 |
| 70 | - - --output:生成的qwen_*.om文件重命名为qwen.om并存放在“样例目录/model“目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_qwen\_llm.cpp 中的omModelPath参数值。 | 74 | + - --output:生成的qwen_*.om文件重命名为qwen.om并存放在"样例目录/model"目录下。建议使用命令中的默认设置,否则在编译代码前,您还需要修改sample\_qwen\_llm.cpp 中的omModelPath参数值。 |
| 71 | 75 | ||
| 72 | ``` | 76 | ``` |
| 73 | ret = sampleQwen.PrepareModel("../model/qwen.om"); | 77 | ret = sampleQwen.PrepareModel("../model/qwen.om"); |
| @@ -83,15 +87,15 @@ | |||
| 83 | 87 | ||
| 84 | 1. 以运行用户登录开发环境。 | 88 | 1. 以运行用户登录开发环境。 |
| 85 | 89 | ||
| 86 | -2. 请先进入根目录下"examples/acl/2_sample_qwen_llm"样例目录。 | 90 | +2. 请先进入根目录下"examples/acl/3_sample_qwen_llm"样例目录。 |
| 87 | 91 | ||
| 88 | - 请注意,下文中的样例目录均指"examples/acl/2_sample_qwen_llm"目录。 | 92 | + 请注意,下文中的样例目录均指"examples/acl/3_sample_qwen_llm"目录。 |
| 89 | 93 | ||
| 90 | 3. 设置环境变量,配置程序编译依赖的头文件与库文件路径。 | 94 | 3. 设置环境变量,配置程序编译依赖的头文件与库文件路径。 |
| 91 | 95 | ||
| 92 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 | 96 | 设置以下环境变量后,编译脚本会根据"{DDK_PATH}环境变量值/include/"目录查找编译依赖的头文件,根据{NPU_HOST_LIB}环境变量指向的目录查找编译依赖的库文件。 |
| 93 | 97 | ||
| 94 | - **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找“Ascend-cann-toolkit安装目录/lib64”目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 | 98 | + **注意**,在配置{NPU_HOST_LIB}环境变量时,需使用的"devlib"目录下*.so库,确保在编译基于AscendCL接口的应用程序时,不依赖其它组件(例如Driver)的*.so库,编译成功后,运行应用程序时,系统会根据LD_LIBRARY_PATH环境变量查找"Ascend-cann-toolkit安装目录/lib64"目录下的*.so库,同时会自动链接到所依赖的其它组件的*.so库。 |
| 95 | 99 | ||
| 96 | - 配置示例如下所示: | 100 | - 配置示例如下所示: |
| 97 | 101 | ||
Rexamples/acl/2_sample_qwen_llm/scripts/build.sh→examples/acl/3_sample_qwen_llm/scripts/build.sh+0-0
文件重命名但无更改。
文件重命名但无更改。
Rexamples/acl/2_sample_qwen_llm/src/CMakeLists.txt→examples/acl/3_sample_qwen_llm/src/CMakeLists.txt+0-0
文件重命名但无更改。
文件重命名但无更改。
Rexamples/acl/2_sample_qwen_llm/src/sample_qwen_llm.cpp→examples/acl/3_sample_qwen_llm/src/sample_qwen_llm.cpp+0-0
文件重命名但无更改。
| @@ -0,0 +1,9 @@ | |||
| 1 | +## ES构图样例 | ||
| 2 | + | ||
| 3 | +本目录提供了ACL接口相关的各种样例,包括: | ||
| 4 | + | ||
| 5 | +| 样例 | 样例链接 | | ||
| 6 | +| --------------------------------------------------------- | ------------------------------------------------------------ | | ||
| 7 | +| Resnet50图像识别样例 | [Resnet50](1_sample_resnet50_imagenet_classification/README.md) | | ||
| 8 | +| Resnet50图像识别dynmaic batch样例 | [Resnet50 dynmaic batch](2_sample_resnet50_imagenet_classification_dynmaic_batch/README.md) | | ||
| 9 | +| Qwen LLM样例 | [Qwen LLM](3_sample_qwen_llm/README.md) | | ||
| @@ -1,11 +1,12 @@ | |||
| 1 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | -# This file is a part of the CANN Open Software. | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | cmake_minimum_required(VERSION 3.14) | 11 | cmake_minimum_required(VERSION 3.14) |
| 11 | 12 | ||
| @@ -1,11 +1,12 @@ | |||
| 1 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | -# This file is a part of the CANN Open Software. | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | cmake_minimum_required(VERSION 3.14) | 11 | cmake_minimum_required(VERSION 3.14) |
| 11 | PROJECT(UDF) | 12 | PROJECT(UDF) |
| @@ -1,11 +1,12 @@ | |||
| 1 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | -# This file is a part of the CANN Open Software. | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | cmake_minimum_required(VERSION 3.14) | 11 | cmake_minimum_required(VERSION 3.14) |
| 11 | PROJECT(UDF) | 12 | PROJECT(UDF) |
| @@ -2,17 +2,18 @@ | |||
| 2 | 2 | ||
| 3 | 本目录提供了ES构图相关的各种样例,包括C++和Python两种实现方式: | 3 | 本目录提供了ES构图相关的各种样例,包括C++和Python两种实现方式: |
| 4 | 4 | ||
| 5 | -| 样例 | 样例链接 | | 5 | +| 样例 | 样例链接 | |
| 6 | -| --------------------------------------------------------- | ------------------------------------------------------------ | | 6 | +|-------------------|--------------------------------------------------------------------------------------------------------| |
| 7 | -| es构图控制边样例 | [C++样例](control_edge/cpp/README.md)<br>[Python样例](control_edge/python/README.md) | | 7 | +| es构图控制边样例 | [C++样例](control_edge/cpp/README.md)<br>[Python样例](control_edge/python/README.md) | |
| 8 | -| es构图控制算子样例 | [C++样例](control_op/cpp/README.md)<br>[Python样例](control_op/python/README.md) | | 8 | +| es构图控制算子样例 | [C++样例](control_op/cpp/README.md)<br>[Python样例](control_op/python/README.md) | |
| 9 | -| es构图动态输入样例 | [C++样例](dynamic_input/cpp/README.md)<br>[Python样例](dynamic_input/python/README.md) | | 9 | +| es构图动态输入样例 | [C++样例](dynamic_input/cpp/README.md)<br>[Python样例](dynamic_input/python/README.md) | |
| 10 | -| es构图动态输出样例 | [C++样例](dynamic_output/cpp/README.md)<br>[Python样例](dynamic_output/python/README.md) | | 10 | +| es构图动态输出样例 | [C++样例](dynamic_output/cpp/README.md)<br>[Python样例](dynamic_output/python/README.md) | |
| 11 | -| es构图普通属性样例 | [C++样例](normal_attributes/cpp/README.md)<br>[Python样例](normal_attributes/python/README.md) | | 11 | +| es构图普通属性样例 | [C++样例](normal_attributes/cpp/README.md)<br>[Python样例](normal_attributes/python/README.md) | |
| 12 | -| es构图普通输入样例 | [C++样例](normal_input/cpp/README.md)<br>[Python样例](normal_input/python/README.md) | | 12 | +| es构图普通输入样例 | [C++样例](normal_input/cpp/README.md)<br>[Python样例](normal_input/python/README.md) | |
| 13 | -| es构图操作符重载样例 | [C++样例](operator_overload/cpp/README.md)<br>[Python样例](operator_overload/python/README.md) | | 13 | +| es构图操作符重载样例 | [C++样例](operator_overload/cpp/README.md)<br>[Python样例](operator_overload/python/README.md) | |
| 14 | -| es构图可选输入样例 | [C++样例](optional_input/cpp/README.md)<br>[Python样例](optional_input/python/README.md) | | 14 | +| es构图可选输入样例 | [C++样例](optional_input/cpp/README.md)<br>[Python样例](optional_input/python/README.md) | |
| 15 | -| es构图私有属性样例 | [C++样例](private_attributes/cpp/README.md)<br>[Python样例](private_attributes/python/README.md) | | 15 | +| es构图私有属性样例 | [C++样例](private_attributes/cpp/README.md)<br>[Python样例](private_attributes/python/README.md) | |
| 16 | -| es构图transformer样例 | [C++样例](transformer/cpp/README.md)<br>[Python样例](transformer/python/README.md) | | 16 | +| es构图transformer样例 | [C++样例](transformer/cpp/README.md)<br>[Python样例](transformer/python/README.md) | |
| 17 | -| es构图集合通信hccl_tp样例 | [C++样例](hccl_tp/cpp/README.md)<br>[Python样例](hccl_tp/python/README.md) | | 17 | +| es构图集合通信hccl_tp样例 | [C++样例](hccl_tp/cpp/README.md)<br>[Python样例](hccl_tp/python/README.md) | |
| 18 | -| es构图集合通信hccl_ep样例 | [C++样例](hccl_ep/cpp/README.md)<br>[Python样例](hccl_ep/python/README.md) | | 18 | +| es构图集合通信hccl_ep样例 | [C++样例](hccl_ep/cpp/README.md)<br>[Python样例](hccl_ep/python/README.md) | |
| 19 | +| es构图异步执行的样例 | [C++样例](operator_overload_async/cpp/README.md)<br>[Python样例](operator_overload_async/python/README.md) | | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | # 样例使用指导 | 1 | # 样例使用指导 |
| 2 | 2 | ||
| 3 | ## 1、功能描述 | 3 | ## 1、功能描述 |
| 4 | -本样例使用操作符重载进行构图,旨在帮助构图开发者快速理解操作符重载的定义,因为python接口暂时**未支持异步执行**,所以本样例仅展示同步执行的构图过程。 | 4 | +本样例使用操作符重载进行构图,旨在帮助构图开发者快速理解操作符重载的定义,因为python接口暂时**未支持异步执行**,所以本样例**仅展示同步执行**的构图过程。 |
| 5 | ## 2、目录结构 | 5 | ## 2、目录结构 |
| 6 | ```angular2html | 6 | ```angular2html |
| 7 | python/ | 7 | python/ |
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | +extern "C" __attribute__((weak)) void SetMetadefPluginCustomOpLibPathForC(const char* custom_op_Lib_path); | ||
| 21 | namespace { | 22 | namespace { |
| 22 | const std::string custom_so_name = "libcust_opapi.so"; | 23 | const std::string custom_so_name = "libcust_opapi.so"; |
| 23 | } | 24 | } |
| @@ -168,6 +169,9 @@ graphStatus OpLibRegistry::CallInitFunc(const std::string &custom_opp_path, | |||
| 168 | op_lib_paths_ += custom_opp_path; // add origin env path to ensure priority(so mode first, runbag mode second) | 169 | op_lib_paths_ += custom_opp_path; // add origin env path to ensure priority(so mode first, runbag mode second) |
| 169 | } | 170 | } |
| 170 | PluginManager::SetCustomOpLibPath(op_lib_paths_); | 171 | PluginManager::SetCustomOpLibPath(op_lib_paths_); |
| 172 | + if (SetMetadefPluginCustomOpLibPathForC != nullptr) { | ||
| 173 | + SetMetadefPluginCustomOpLibPathForC(op_lib_paths_.c_str()); | ||
| 174 | + } | ||
| 171 | GELOGI("CallInitFunc %zu successfully, op_lib_paths_ is %s", vendor_funcs_.size(), op_lib_paths_.c_str()); | 175 | GELOGI("CallInitFunc %zu successfully, op_lib_paths_ is %s", vendor_funcs_.size(), op_lib_paths_.c_str()); |
| 172 | return GRAPH_SUCCESS; | 176 | return GRAPH_SUCCESS; |
| 173 | } | 177 | } |
| @@ -312,6 +312,7 @@ target_link_libraries(ge_executor_shared | |||
| 312 | hccl_headers | 312 | hccl_headers |
| 313 | $<$<TARGET_EXISTS:datagw_headers>:datagw_headers> | 313 | $<$<TARGET_EXISTS:datagw_headers>:datagw_headers> |
| 314 | -Wl,--no-as-needed | 314 | -Wl,--no-as-needed |
| 315 | + graph | ||
| 315 | ge_common | 316 | ge_common |
| 316 | ge_common_base | 317 | ge_common_base |
| 317 | runtime | 318 | runtime |
| @@ -2701,12 +2701,30 @@ void DavinciModel::InitModelInputsMergeCopyHostMem() { | |||
| 2701 | 2701 | ||
| 2702 | // init host buff for merge copy, if fail just return and run with no merge copy | 2702 | // init host buff for merge copy, if fail just return and run with no merge copy |
| 2703 | input_merge_copy_mem_size_ = last_input.second + last_input_size - first_input.second; | 2703 | input_merge_copy_mem_size_ = last_input.second + last_input_size - first_input.second; |
| 2704 | - input_merge_copy_mem_base_.reset(new (std::nothrow) uint8_t[input_merge_copy_mem_size_], | 2704 | + void *host_mem = nullptr; |
| 2705 | - std::default_delete<uint8_t[]>()); | 2705 | + const rtError_t rt_ret = rtMallocHost(&host_mem, input_merge_copy_mem_size_, GE_MODULE_NAME_U16); |
| 2706 | - if (input_merge_copy_mem_base_ == nullptr) { | 2706 | + if (rt_ret != RT_ERROR_NONE) { |
| 2707 | - GELOGW("[InputMergeCopy][New] host buffer failed, size:%" PRIu64, input_merge_copy_mem_size_); | 2707 | + input_merge_copy_mem_base_.reset(); |
| 2708 | + GELOGW("[InputMergeCopy][rtMallocHost] host buffer alloc failed, size:%" PRIu64 ", ret:%d", | ||
| 2709 | + input_merge_copy_mem_size_, static_cast<int32_t>(rt_ret)); | ||
| 2708 | return; | 2710 | return; |
| 2709 | } | 2711 | } |
| 2712 | + if (host_mem == nullptr) { | ||
| 2713 | + input_merge_copy_mem_base_.reset(); | ||
| 2714 | + GELOGW("[InputMergeCopy][rtMallocHost] host buffer is nullptr, size:%" PRIu64 ", ret:%d", | ||
| 2715 | + input_merge_copy_mem_size_, static_cast<int32_t>(rt_ret)); | ||
| 2716 | + return; | ||
| 2717 | + } | ||
| 2718 | + input_merge_copy_mem_base_.reset(static_cast<uint8_t *>(host_mem), [](uint8_t *ptr) { | ||
| 2719 | + if (ptr == nullptr) { | ||
| 2720 | + return; | ||
| 2721 | + } | ||
| 2722 | + const rtError_t free_ret = rtFreeHost(ptr); | ||
| 2723 | + if (free_ret != RT_ERROR_NONE) { | ||
| 2724 | + GELOGW("[InputMergeCopy][rtFreeHost] host buffer free failed, ptr:%p, ret:%d", ptr, | ||
| 2725 | + static_cast<int32_t>(free_ret)); | ||
| 2726 | + } | ||
| 2727 | + }); | ||
| 2710 | (void)memset_s(input_merge_copy_mem_base_.get(), input_merge_copy_mem_size_, 0U, input_merge_copy_mem_size_); | 2728 | (void)memset_s(input_merge_copy_mem_base_.get(), input_merge_copy_mem_size_, 0U, input_merge_copy_mem_size_); |
| 2711 | 2729 | ||
| 2712 | // record offset for fusion copy input | 2730 | // record offset for fusion copy input |
| @@ -102,6 +102,10 @@ dflow_executor_install_package() { | |||
| 102 | local _package="$1" | 102 | local _package="$1" |
| 103 | local _pythonlocalpath="$2" | 103 | local _pythonlocalpath="$2" |
| 104 | log "INFO" "install python module package in ${_package}" | 104 | log "INFO" "install python module package in ${_package}" |
| 105 | + if ! command -v pip3 >/dev/null 2>&1; then | ||
| 106 | + log "ERROR" "install ${_package} failed, pip3 is not installed." | ||
| 107 | + exit 1 | ||
| 108 | + fi | ||
| 105 | if [ -f "$_package" ]; then | 109 | if [ -f "$_package" ]; then |
| 106 | if [ "$pylocal" = "y" ]; then | 110 | if [ "$pylocal" = "y" ]; then |
| 107 | pip3 install --disable-pip-version-check --upgrade --no-deps --force-reinstall "${_package}" -t "${_pythonlocalpath}" 1> /dev/null | 111 | pip3 install --disable-pip-version-check --upgrade --no-deps --force-reinstall "${_package}" -t "${_pythonlocalpath}" 1> /dev/null |
| @@ -1,10 +1,10 @@ | |||
| 1 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | # ----------------------------------------------------------------------------------------------------------- | 2 | # ----------------------------------------------------------------------------------------------------------- |
| 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 4 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | 9 | # See LICENSE in the root of the software repository for the full text of the License. |
| 10 | # ----------------------------------------------------------------------------------------------------------- | 10 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -83,6 +83,10 @@ ge_compiler_install_package() { | |||
| 83 | local _package="$1" | 83 | local _package="$1" |
| 84 | local _pythonlocalpath="$2" | 84 | local _pythonlocalpath="$2" |
| 85 | log "INFO" "install python module package in ${_package}" | 85 | log "INFO" "install python module package in ${_package}" |
| 86 | + if ! command -v pip3 >/dev/null 2>&1; then | ||
| 87 | + log "ERROR" "install ${_package} failed, pip3 is not installed." | ||
| 88 | + exit 1 | ||
| 89 | + fi | ||
| 86 | if [ -f "$_package" ]; then | 90 | if [ -f "$_package" ]; then |
| 87 | if [ "$pylocal" = "y" ]; then | 91 | if [ "$pylocal" = "y" ]; then |
| 88 | pip3 install --disable-pip-version-check --upgrade --no-deps --force-reinstall "${_package}" -t "${_pythonlocalpath}" 1> /dev/null | 92 | pip3 install --disable-pip-version-check --upgrade --no-deps --force-reinstall "${_package}" -t "${_pythonlocalpath}" 1> /dev/null |
| @@ -1,10 +1,10 @@ | |||
| 1 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | # ----------------------------------------------------------------------------------------------------------- | 2 | # ----------------------------------------------------------------------------------------------------------- |
| 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 4 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | 9 | # See LICENSE in the root of the software repository for the full text of the License. |
| 10 | # ----------------------------------------------------------------------------------------------------------- | 10 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -1,10 +1,10 @@ | |||
| 1 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | # ----------------------------------------------------------------------------------------------------------- | 2 | # ----------------------------------------------------------------------------------------------------------- |
| 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 4 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | 9 | # See LICENSE in the root of the software repository for the full text of the License. |
| 10 | # ----------------------------------------------------------------------------------------------------------- | 10 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -86,7 +86,7 @@ set(OP_EXEC_SRC_FILES | |||
| 86 | "${BASE_DIR}/api/acl/acl_op_executor/single_op/executor/op_task.cpp" | 86 | "${BASE_DIR}/api/acl/acl_op_executor/single_op/executor/op_task.cpp" |
| 87 | "${BASE_DIR}/api/acl/acl_op_executor/types/op_attr.cpp" | 87 | "${BASE_DIR}/api/acl/acl_op_executor/types/op_attr.cpp" |
| 88 | "${BASE_DIR}/api/acl/acl_op_executor/types/op_model.cpp" | 88 | "${BASE_DIR}/api/acl/acl_op_executor/types/op_model.cpp" |
| 89 | - "${BASE_DIR}/api/acl/acl_op_executor/types/acl_op.cpp" | 89 | + "${BASE_DIR}/api/acl/acl_op_executor/types/acl_op_inner.cpp" |
| 90 | "${BASE_DIR}/api/acl/common/common_inner.cpp" | 90 | "${BASE_DIR}/api/acl/common/common_inner.cpp" |
| 91 | "${BASE_DIR}/api/acl/common/log_inner.cpp" | 91 | "${BASE_DIR}/api/acl/common/log_inner.cpp" |
| 92 | "${BASE_DIR}/api/acl/common/json_parser.cpp" | 92 | "${BASE_DIR}/api/acl/common/json_parser.cpp" |
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | -#include "types/acl_op.h" | 8 | +#include "types/acl_op_inner.h" |
| 9 | 9 | ||
| 10 | using namespace testing; | 10 | using namespace testing; |
| 11 | using namespace std; | 11 | using namespace std; |
| @@ -1,9 +1,9 @@ | |||
| 1 | # ----------------------------------------------------------------------------------------------------------- | 1 | # ----------------------------------------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ----------------------------------------------------------------------------------------------------------- | 9 | # ----------------------------------------------------------------------------------------------------------- |
| @@ -651,6 +651,8 @@ void rtStubTearDown() { | |||
| 651 | DEL_STUB_RETURN_VALUE(rtQueryFunctionRegistered, rtError_t); | 651 | DEL_STUB_RETURN_VALUE(rtQueryFunctionRegistered, rtError_t); |
| 652 | 652 | ||
| 653 | DEL_STUB_RETURN_VALUE(rtMalloc, rtError_t); | 653 | DEL_STUB_RETURN_VALUE(rtMalloc, rtError_t); |
| 654 | + DEL_STUB_RETURN_VALUE(rtMallocHost, rtError_t); | ||
| 655 | + DEL_STUB_RETURN_VALUE(rtFreeHost, rtError_t); | ||
| 654 | DEL_STUB_RETURN_VALUE(rtMemcpy, rtError_t); | 656 | DEL_STUB_RETURN_VALUE(rtMemcpy, rtError_t); |
| 655 | DEL_STUB_RETURN_VALUE(rtsMemcpyBatch, rtError_t); | 657 | DEL_STUB_RETURN_VALUE(rtsMemcpyBatch, rtError_t); |
| 656 | DEL_STUB_RETURN_VALUE(rtDatadumpInfoLoad, rtError_t); | 658 | DEL_STUB_RETURN_VALUE(rtDatadumpInfoLoad, rtError_t); |
| @@ -853,14 +855,22 @@ rtError_t rtFree(void *dev_ptr) { | |||
| 853 | return ge::RuntimeStub::GetInstance()->rtFree(dev_ptr); | 855 | return ge::RuntimeStub::GetInstance()->rtFree(dev_ptr); |
| 854 | } | 856 | } |
| 855 | 857 | ||
| 858 | +ADD_STUB_RETURN_VALUE(rtMallocHost, rtError_t); | ||
| 856 | rtError_t rtMallocHost(void **host_ptr, uint64_t size, uint16_t moduleId) { | 859 | rtError_t rtMallocHost(void **host_ptr, uint64_t size, uint16_t moduleId) { |
| 860 | + const rtError_t ret = GET_STUB_RETURN_VALUE(rtMallocHost, rtError_t, RT_ERROR_NONE); | ||
| 861 | + if (ret != RT_ERROR_NONE) { | ||
| 862 | + *host_ptr = nullptr; | ||
| 863 | + return ret; | ||
| 864 | + } | ||
| 857 | *host_ptr = new uint8_t[size]; | 865 | *host_ptr = new uint8_t[size]; |
| 858 | return RT_ERROR_NONE; | 866 | return RT_ERROR_NONE; |
| 859 | } | 867 | } |
| 860 | 868 | ||
| 869 | +ADD_STUB_RETURN_VALUE(rtFreeHost, rtError_t); | ||
| 861 | rtError_t rtFreeHost(void *host_ptr) { | 870 | rtError_t rtFreeHost(void *host_ptr) { |
| 871 | + const rtError_t ret = GET_STUB_RETURN_VALUE(rtFreeHost, rtError_t, RT_ERROR_NONE); | ||
| 862 | delete[](uint8_t *) host_ptr; | 872 | delete[](uint8_t *) host_ptr; |
| 863 | - return RT_ERROR_NONE; | 873 | + return ret; |
| 864 | } | 874 | } |
| 865 | 875 | ||
| 866 | rtError_t rtStreamCreate(rtStream_t *stream, int32_t priority) { | 876 | rtError_t rtStreamCreate(rtStream_t *stream, int32_t priority) { |
| @@ -468,6 +468,8 @@ RTS_STUB_RETURN_EXTERN(rtNpuGetFloatStatus, rtError_t); | |||
| 468 | RTS_STUB_RETURN_EXTERN(rtNpuClearFloatStatus, rtError_t); | 468 | RTS_STUB_RETURN_EXTERN(rtNpuClearFloatStatus, rtError_t); |
| 469 | 469 | ||
| 470 | RTS_STUB_RETURN_EXTERN(rtMalloc, rtError_t); | 470 | RTS_STUB_RETURN_EXTERN(rtMalloc, rtError_t); |
| 471 | +RTS_STUB_RETURN_EXTERN(rtMallocHost, rtError_t); | ||
| 472 | +RTS_STUB_RETURN_EXTERN(rtFreeHost, rtError_t); | ||
| 471 | RTS_STUB_RETURN_EXTERN(rtMemcpy, rtError_t); | 473 | RTS_STUB_RETURN_EXTERN(rtMemcpy, rtError_t); |
| 472 | RTS_STUB_RETURN_EXTERN(rtsMemcpyBatch, rtError_t); | 474 | RTS_STUB_RETURN_EXTERN(rtsMemcpyBatch, rtError_t); |
| 473 | RTS_STUB_RETURN_EXTERN(rtDatadumpInfoLoad, rtError_t); | 475 | RTS_STUB_RETURN_EXTERN(rtDatadumpInfoLoad, rtError_t); |
| @@ -1,9 +1,11 @@ | |||
| 1 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 1 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 2 | -# This file is a part of the CANN Open Software. | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). |
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 10 | + | ||
| 9 | add_subdirectory(ut) | 11 | add_subdirectory(ut) |
| @@ -1,11 +1,12 @@ | |||
| 1 | -# Copyright (c) 2024 Huawei Technologies Co., Ltd. | 1 | +# ----------------------------------------------------------------------------------------------------------- |
| 2 | -# This file is a part of the CANN Open Software. | 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | if (ENABLE_GE_COV) | 11 | if (ENABLE_GE_COV) |
| 11 | set(COVERAGE_COMPILER_FLAGS ${AIR_COMMON_COMPILE_OPTION}) | 12 | set(COVERAGE_COMPILER_FLAGS ${AIR_COMMON_COMPILE_OPTION}) |
| @@ -1,11 +1,12 @@ | |||
| 1 | -# Copyright (c) 2024 Huawei Technologies Co., Ltd. | 1 | +# ----------------------------------------------------------------------------------------------------------- |
| 2 | -# This file is a part of the CANN Open Software. | 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | if (ENABLE_LLT_COV) | 11 | if (ENABLE_LLT_COV) |
| 11 | set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-arcs -fPIC -O0 -ftest-coverage") | 12 | set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-arcs -fPIC -O0 -ftest-coverage") |
| @@ -1,11 +1,12 @@ | |||
| 1 | -# Copyright (c) 2024 Huawei Technologies Co., Ltd. | 1 | +# ----------------------------------------------------------------------------------------------------------- |
| 2 | -# This file is a part of the CANN Open Software. | 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | -# Licensed under CANN Open Software License Agreement Version 1.0 (the "License"). | 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 4 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 5 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 6 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 7 | # See LICENSE in the root of the software repository for the full text of the License. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 8 | -# ====================================================================================================================== | 9 | +# ----------------------------------------------------------------------------------------------------------- |
| 9 | 10 | ||
| 10 | set(proto_src_files | 11 | set(proto_src_files |
| 11 | ${METADEF_PROTO_DIR}/task.proto | 12 | ${METADEF_PROTO_DIR}/task.proto |
| @@ -1,9 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| @@ -1,9 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| @@ -7505,6 +7505,81 @@ TEST_F(UtestDavinciModel, InputMergeCopy) { | |||
| 7505 | ge::GetThreadLocalContext().SetGraphOption({}); // restore option | 7505 | ge::GetThreadLocalContext().SetGraphOption({}); // restore option |
| 7506 | } | 7506 | } |
| 7507 | 7507 | ||
| 7508 | +TEST_F(UtestDavinciModel, InitModelInputsMergeCopyHostMem_rtMallocHost_fail) { | ||
| 7509 | + RTS_STUB_RETURN_VALUE(rtMallocHost, rtError_t, ACL_ERROR_RT_PARAM_INVALID); | ||
| 7510 | + const uint64_t input_fusion_size = 25600U; | ||
| 7511 | + const uint64_t start_logic_addr = 30902000U; // random value for test | ||
| 7512 | + std::map<std::string, std::string> options_map; | ||
| 7513 | + options_map[OPTION_EXEC_INPUT_FUSION_SIZE] = std::to_string(input_fusion_size); | ||
| 7514 | + ge::GetThreadLocalContext().SetGraphOption(options_map); | ||
| 7515 | + | ||
| 7516 | + const uint64_t input0_size = input_fusion_size - 1U; | ||
| 7517 | + const uint64_t input1_size = input_fusion_size; | ||
| 7518 | + | ||
| 7519 | + DavinciModel davinci_model(0, nullptr); | ||
| 7520 | + davinci_model.zero_copy_input_indexes_.emplace_back(0); | ||
| 7521 | + davinci_model.zero_copy_input_indexes_.emplace_back(1); | ||
| 7522 | + davinci_model.input_index_to_allocation_ids_.emplace_back(0); | ||
| 7523 | + davinci_model.input_index_to_allocation_ids_.emplace_back(1); | ||
| 7524 | + | ||
| 7525 | + MemAllocation mem_allocation0 = {}; | ||
| 7526 | + mem_allocation0.data_size = input0_size + 32U; | ||
| 7527 | + mem_allocation0.tensor_size = input0_size; | ||
| 7528 | + mem_allocation0.logical_addr = start_logic_addr; | ||
| 7529 | + | ||
| 7530 | + MemAllocation mem_allocation1; | ||
| 7531 | + mem_allocation1.data_size = input1_size + 32U; | ||
| 7532 | + mem_allocation1.tensor_size = input1_size; | ||
| 7533 | + mem_allocation1.logical_addr = start_logic_addr - mem_allocation1.data_size; | ||
| 7534 | + | ||
| 7535 | + davinci_model.logical_mem_allocations_.emplace_back(mem_allocation0); | ||
| 7536 | + davinci_model.logical_mem_allocations_.emplace_back(mem_allocation1); | ||
| 7537 | + | ||
| 7538 | + davinci_model.InitModelInputsMergeCopyHostMem(); | ||
| 7539 | + EXPECT_EQ(davinci_model.input_merge_copy_mem_base_, nullptr); | ||
| 7540 | + EXPECT_TRUE(davinci_model.input_index_to_merge_copy_offset_.empty()); | ||
| 7541 | + ge::GetThreadLocalContext().SetGraphOption({}); | ||
| 7542 | +} | ||
| 7543 | + | ||
| 7544 | +TEST_F(UtestDavinciModel, InitModelInputsMergeCopyHostMem_rtFreeHost_fail) { | ||
| 7545 | + const uint64_t input_fusion_size = 25600U; | ||
| 7546 | + const uint64_t start_logic_addr = 30902000U; // random value for test | ||
| 7547 | + std::map<std::string, std::string> options_map; | ||
| 7548 | + options_map[OPTION_EXEC_INPUT_FUSION_SIZE] = std::to_string(input_fusion_size); | ||
| 7549 | + ge::GetThreadLocalContext().SetGraphOption(options_map); | ||
| 7550 | + | ||
| 7551 | + const uint64_t input0_size = input_fusion_size - 1U; | ||
| 7552 | + const uint64_t input1_size = input_fusion_size; | ||
| 7553 | + | ||
| 7554 | + DavinciModel davinci_model(0, nullptr); | ||
| 7555 | + davinci_model.zero_copy_input_indexes_.emplace_back(0); | ||
| 7556 | + davinci_model.zero_copy_input_indexes_.emplace_back(1); | ||
| 7557 | + davinci_model.input_index_to_allocation_ids_.emplace_back(0); | ||
| 7558 | + davinci_model.input_index_to_allocation_ids_.emplace_back(1); | ||
| 7559 | + | ||
| 7560 | + MemAllocation mem_allocation0 = {}; | ||
| 7561 | + mem_allocation0.data_size = input0_size + 32U; | ||
| 7562 | + mem_allocation0.tensor_size = input0_size; | ||
| 7563 | + mem_allocation0.logical_addr = start_logic_addr; | ||
| 7564 | + | ||
| 7565 | + MemAllocation mem_allocation1; | ||
| 7566 | + mem_allocation1.data_size = input1_size + 32U; | ||
| 7567 | + mem_allocation1.tensor_size = input1_size; | ||
| 7568 | + mem_allocation1.logical_addr = start_logic_addr - mem_allocation1.data_size; | ||
| 7569 | + | ||
| 7570 | + davinci_model.logical_mem_allocations_.emplace_back(mem_allocation0); | ||
| 7571 | + davinci_model.logical_mem_allocations_.emplace_back(mem_allocation1); | ||
| 7572 | + | ||
| 7573 | + davinci_model.InitModelInputsMergeCopyHostMem(); | ||
| 7574 | + EXPECT_NE(davinci_model.input_merge_copy_mem_base_, nullptr); | ||
| 7575 | + EXPECT_EQ(davinci_model.input_index_to_merge_copy_offset_.size(), 2U); | ||
| 7576 | + | ||
| 7577 | + RTS_STUB_RETURN_VALUE(rtFreeHost, rtError_t, ACL_ERROR_RT_PARAM_INVALID); | ||
| 7578 | + davinci_model.input_merge_copy_mem_base_.reset(); | ||
| 7579 | + EXPECT_EQ(davinci_model.input_merge_copy_mem_base_, nullptr); | ||
| 7580 | + ge::GetThreadLocalContext().SetGraphOption({}); | ||
| 7581 | +} | ||
| 7582 | + | ||
| 7508 | TEST_F(UtestDavinciModel, GenInputMemAllocations_InValid) { | 7583 | TEST_F(UtestDavinciModel, GenInputMemAllocations_InValid) { |
| 7509 | DavinciModel davinci_model(0, nullptr); | 7584 | DavinciModel davinci_model(0, nullptr); |
| 7510 | std::map<uint32_t, OpDescPtr> index_to_data; | 7585 | std::map<uint32_t, OpDescPtr> index_to_data; |
scripts/package/ge-compiler/scripts/run_ge-compiler_upgrade.sh此评论由代码审查工具自动生成