| @@ -127,12 +127,13 @@ void *EagerOpExecutionContext::MallocWorkSpace(size_t size) { | |||
| 127 | return mem_block->GetAddr(); | 127 | return mem_block->GetAddr(); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | -const KernelArgs *EagerOpExecutionContext::MallocReadOnlyDevArgs(void *host_args, size_t args_size) const { | 130 | +const KernelArgs* EagerOpExecutionContext::MallocReadOnlyDevArgs(void *host_args, size_t args_size) const { |
| 131 | - auto additional_start_index = GetAdditionalInputStartIndex(); | 131 | + auto additional_output_start = GetAdditionalOutputStartIndex(); |
| 132 | - GE_ASSERT_TRUE(additional_start_index >= 0); | 132 | + GE_ASSERT_TRUE(additional_output_start >= 0); |
| 133 | 133 | ||
| 134 | - auto *handler = | 134 | + auto *chain = GetOutput(static_cast<size_t>(additional_output_start) + static_cast<size_t>(AdditionalOutputIndex::kArgsHandler)); |
| 135 | - GetInputValue<ArgsHandler *>(additional_start_index + static_cast<int64_t>(AdditionalInputIndex::kArgsHandler)); | 135 | + GE_ASSERT_NOTNULL(chain); |
| 136 | + auto *handler = chain->GetValue<ArgsHandler *>(); | ||
| 136 | GE_ASSERT_NOTNULL(handler); | 137 | GE_ASSERT_NOTNULL(handler); |
| 137 | 138 | ||
| 138 | return handler->MallocReadOnlyDevArgs(host_args, args_size); | 139 | return handler->MallocReadOnlyDevArgs(host_args, args_size); |
| @@ -15,12 +15,14 @@ | |||
| 15 | 15 | ||
| 16 | namespace gert { | 16 | namespace gert { |
| 17 | 17 | ||
| 18 | -const KernelArgs *UpdateArgsContext::GetKernelArgs(Placement placement, size_t index) const { | 18 | +const KernelArgs* UpdateArgsContext::GetKernelArgs(Placement placement, size_t index) const { |
| 19 | - auto additional_start_index = GetAdditionalInputStartIndex(); | 19 | + auto additional_output_start = GetAdditionalOutputStartIndex(); |
| 20 | - GE_ASSERT_TRUE(additional_start_index >= 0); | 20 | + GE_ASSERT_TRUE(additional_output_start >= 0); |
| 21 | 21 | ||
| 22 | - auto *handler = GetInputValue<ArgsHandler *>( | 22 | + auto *chain = GetOutput(static_cast<size_t>(additional_output_start) + |
| 23 | - additional_start_index + static_cast<int64_t>(EagerOpExecutionContext::AdditionalInputIndex::kArgsHandler)); | 23 | + static_cast<size_t>(EagerOpExecutionContext::AdditionalOutputIndex::kArgsHandler)); |
| 24 | + GE_ASSERT_NOTNULL(chain); | ||
| 25 | + auto *handler = chain->GetValue<ArgsHandler *>(); | ||
| 24 | GE_ASSERT_NOTNULL(handler); | 26 | GE_ASSERT_NOTNULL(handler); |
| 25 | 27 | ||
| 26 | const auto &args_deque = handler->GetKernelArgs(placement); | 28 | const auto &args_deque = handler->GetKernelArgs(placement); |
| @@ -125,10 +125,14 @@ class EagerOpExecutionContext : public ExtendedKernelContext { | |||
| 125 | enum class AdditionalInputIndex : uint32_t { | 125 | enum class AdditionalInputIndex : uint32_t { |
| 126 | kDeviceAllocator = 0, | 126 | kDeviceAllocator = 0, |
| 127 | kStream, | 127 | kStream, |
| 128 | - kArgsHandler // Args handler base class pointer | 128 | + kNum |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | - enum class AdditionalOutputIndex : uint32_t { kWorkSpace = 0, kNum }; | 131 | + enum class AdditionalOutputIndex : uint32_t { |
| 132 | + kWorkSpace = 0, | ||
| 133 | + kArgsHandler, | ||
| 134 | + kNum | ||
| 135 | + }; | ||
| 132 | 136 | ||
| 133 | protected: | 137 | protected: |
| 134 | int64_t GetAdditionalInputStartIndex() const { | 138 | int64_t GetAdditionalInputStartIndex() const { |
| @@ -308,10 +308,8 @@ Status CustomTaskInfo::Distribute() { | |||
| 308 | 308 | ||
| 309 | args_handler_ = ge::ComGraphMakeUnique<SinkOpArgsHandler>(this); | 309 | args_handler_ = ge::ComGraphMakeUnique<SinkOpArgsHandler>(this); |
| 310 | GE_ASSERT_NOTNULL(args_handler_); | 310 | GE_ASSERT_NOTNULL(args_handler_); |
| 311 | - std::vector<void *> additional_inputs = {sink_only_allocator_.get(), stream_, args_handler_.get()}; | 311 | + std::vector<void*> additional_inputs = {sink_only_allocator_.get(), stream_}; |
| 312 | - | 312 | + std::vector<void*> additional_outputs = {&ws_vec_, args_handler_.get()}; |
| 313 | - std::vector<void *> additional_outputs; | ||
| 314 | - additional_outputs.push_back(&ws_vec_); | ||
| 315 | 313 | ||
| 316 | eager_context_holder_ = gert::KernelRunContextBuilder() | 314 | eager_context_holder_ = gert::KernelRunContextBuilder() |
| 317 | .Inputs(GetHoldersRawPtr(inputs_holder_)) | 315 | .Inputs(GetHoldersRawPtr(inputs_holder_)) |
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | + | ||
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | 24 | ||
| @@ -106,9 +107,11 @@ LowerResult LoweringCustomNode(const ge::NodePtr &node, const LowerInput &lower_ | |||
| 106 | infer_output_shapes = bg::InferCustomOpShape(node, lower_input.input_shapes, *lower_input.global_data); | 107 | infer_output_shapes = bg::InferCustomOpShape(node, lower_input.input_shapes, *lower_input.global_data); |
| 107 | input_holders.insert(input_holders.end(), infer_output_shapes.begin(), infer_output_shapes.end()); | 108 | input_holders.insert(input_holders.end(), infer_output_shapes.begin(), infer_output_shapes.end()); |
| 108 | } | 109 | } |
| 109 | - // 最后需要一个workspace地址 | 110 | + // 最后需要workspace地址和args_handler地址 |
| 110 | std::vector<bg::ValueHolderPtr> output_tensor_holders = | 111 | std::vector<bg::ValueHolderPtr> output_tensor_holders = |
| 111 | - bg::ValueHolder::CreateDataOutput(kernel_type.c_str(), input_holders, node->GetAllOutDataAnchorsSize() + 1); | 112 | + bg::ValueHolder::CreateDataOutput(kernel_type.c_str(), |
| 113 | + input_holders, node->GetAllOutDataAnchorsSize() + | ||
| 114 | + static_cast<size_t>(gert::EagerOpExecutionContext::AdditionalOutputIndex::kNum)); | ||
| 112 | std::vector<bg::ValueHolderPtr> output_shapes; | 115 | std::vector<bg::ValueHolderPtr> output_shapes; |
| 113 | std::vector<bg::DevMemValueHolderPtr> output_addrs; | 116 | std::vector<bg::DevMemValueHolderPtr> output_addrs; |
| 114 | for (size_t i = 0UL; i < node->GetAllOutDataAnchorsSize(); i++) { | 117 | for (size_t i = 0UL; i < node->GetAllOutDataAnchorsSize(); i++) { |
| @@ -121,8 +124,11 @@ LowerResult LoweringCustomNode(const ge::NodePtr &node, const LowerInput &lower_ | |||
| 121 | output_shapes.emplace_back(split_outputs[static_cast<size_t>(kernel::SplitTensorOutputs::kShape)]); | 124 | output_shapes.emplace_back(split_outputs[static_cast<size_t>(kernel::SplitTensorOutputs::kShape)]); |
| 122 | output_addrs.emplace_back(split_outputs[static_cast<size_t>(kernel::SplitTensorOutputs::kTensorData)]); | 125 | output_addrs.emplace_back(split_outputs[static_cast<size_t>(kernel::SplitTensorOutputs::kTensorData)]); |
| 123 | } | 126 | } |
| 124 | - LOWER_REQUIRE_NOTNULL( | 127 | + LOWER_REQUIRE_NOTNULL(bg::ValueHolder::CreateVoidGuarder("FreeCustomOpWorkspaces", |
| 125 | - bg::ValueHolder::CreateVoidGuarder("FreeCustomOpWorkspaces", output_tensor_holders.back(), {allocator_holder})); | 128 | + output_tensor_holders[node->GetAllOutDataAnchorsSize()], {allocator_holder})); |
| 129 | + LOWER_REQUIRE_NOTNULL(bg::ValueHolder::CreateVoidGuarder("FreeArgsGuarder", | ||
| 130 | + output_tensor_holders[node->GetAllOutDataAnchorsSize() + | ||
| 131 | + static_cast<size_t>(gert::EagerOpExecutionContext::AdditionalOutputIndex::kArgsHandler)], {})); | ||
| 126 | // 输入tensor需要添加对地址guard的依赖边,否则会出现提前释放 | 132 | // 输入tensor需要添加对地址guard的依赖边,否则会出现提前释放 |
| 127 | for (auto &addr : input_addr_holders) { | 133 | for (auto &addr : input_addr_holders) { |
| 128 | auto guarder = addr->GetGuarder(); | 134 | auto guarder = addr->GetGuarder(); |
| @@ -19,11 +19,17 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | + | ||
| 23 | + | ||
| 22 | 24 | ||
| 23 | namespace gert { | 25 | namespace gert { |
| 24 | namespace kernel { | 26 | namespace kernel { |
| 25 | namespace { | 27 | namespace { |
| 26 | -enum class CustomOpInput { kAllocator = 0, kStream, kFunc, kEnd }; | 28 | +// 自定义算子特有的输入,从 AdditionalInputIndex::kNum 开始 |
| 29 | +enum class CustomOpInput { | ||
| 30 | + kFunc = static_cast<uint32_t>(EagerOpExecutionContext::AdditionalInputIndex::kNum), | ||
| 31 | + kEnd | ||
| 32 | +}; | ||
| 27 | 33 | ||
| 28 | std::string PrintNodeType(const KernelContext *context) { | 34 | std::string PrintNodeType(const KernelContext *context) { |
| 29 | std::stringstream ss; | 35 | std::stringstream ss; |
| @@ -110,13 +116,23 @@ static ge::graphStatus CreateWorkspaceHolder(KernelContext *context, size_t node | |||
| 110 | return ge::GRAPH_SUCCESS; | 116 | return ge::GRAPH_SUCCESS; |
| 111 | } | 117 | } |
| 112 | 118 | ||
| 113 | -static ge::graphStatus CreateWorkspacesMemory(const ge::FastNode *node, KernelContext *context) { | 119 | +static ge::graphStatus CreateCustomOpOutputs(const ge::FastNode *node, KernelContext *context) { |
| 114 | (void)node; | 120 | (void)node; |
| 115 | auto *extended_kernel_context = reinterpret_cast<ExtendedKernelContext *>(context); | 121 | auto *extended_kernel_context = reinterpret_cast<ExtendedKernelContext *>(context); |
| 116 | GE_ASSERT_NOTNULL(extended_kernel_context); | 122 | GE_ASSERT_NOTNULL(extended_kernel_context); |
| 117 | const size_t node_output_num = extended_kernel_context->GetComputeNodeOutputNum(); | 123 | const size_t node_output_num = extended_kernel_context->GetComputeNodeOutputNum(); |
| 118 | GE_ASSERT_SUCCESS(CreateOutputTensors(extended_kernel_context, context)); | 124 | GE_ASSERT_SUCCESS(CreateOutputTensors(extended_kernel_context, context)); |
| 119 | GE_ASSERT_SUCCESS(CreateWorkspaceHolder(context, node_output_num)); | 125 | GE_ASSERT_SUCCESS(CreateWorkspaceHolder(context, node_output_num)); |
| 126 | + | ||
| 127 | + // allocator 在 Create 阶段尚未就绪(Init 图未执行),创建空 EagerArgsHandler,在 RunFunc 阶段初始化 | ||
| 128 | + auto *args_handler = new (std::nothrow) EagerArgsHandler(); | ||
| 129 | + GE_ASSERT_NOTNULL(args_handler); | ||
| 130 | + | ||
| 131 | + auto *args_output = context->GetOutput(node_output_num + | ||
| 132 | + static_cast<size_t>(EagerOpExecutionContext::AdditionalOutputIndex::kArgsHandler)); | ||
| 133 | + GE_ASSERT_NOTNULL(args_output); | ||
| 134 | + args_output->SetWithDefaultDeleter(static_cast<ArgsHandler *>(args_handler)); | ||
| 135 | + | ||
| 120 | return ge::GRAPH_SUCCESS; | 136 | return ge::GRAPH_SUCCESS; |
| 121 | } | 137 | } |
| 122 | 138 | ||
| @@ -138,6 +154,21 @@ static ge::graphStatus ExecuteCustomOpImpl(KernelContext *context) { | |||
| 138 | auto *eager_context = reinterpret_cast<EagerOpExecutionContext *>(context); | 154 | auto *eager_context = reinterpret_cast<EagerOpExecutionContext *>(context); |
| 139 | GE_ASSERT_NOTNULL(eager_context); | 155 | GE_ASSERT_NOTNULL(eager_context); |
| 140 | const size_t node_input_num = eager_context->GetComputeNodeInputNum(); | 156 | const size_t node_input_num = eager_context->GetComputeNodeInputNum(); |
| 157 | + const size_t node_output_num = eager_context->GetComputeNodeOutputNum(); | ||
| 158 | + auto *chain = context->GetOutput(node_output_num + | ||
| 159 | + static_cast<size_t>(EagerOpExecutionContext::AdditionalOutputIndex::kArgsHandler)); | ||
| 160 | + GE_ASSERT_NOTNULL(chain); | ||
| 161 | + auto *args_handler = static_cast<EagerArgsHandler *>(chain->GetValue<ArgsHandler *>()); | ||
| 162 | + GE_ASSERT_NOTNULL(args_handler); | ||
| 163 | + if (!args_handler->IsInitialized()) { | ||
| 164 | + auto *allocator = context->GetInputValue<GertAllocator *>( | ||
| 165 | + node_input_num + static_cast<size_t>(EagerOpExecutionContext::AdditionalInputIndex::kDeviceAllocator)); | ||
| 166 | + GE_ASSERT_NOTNULL(allocator); | ||
| 167 | + auto stream_id = allocator->GetStreamId(); | ||
| 168 | + args_handler->Initialize(allocator, stream_id); | ||
| 169 | + GELOGD("EagerArgsHandler initialized in RunFunc with allocator %p", allocator); | ||
| 170 | + } | ||
| 171 | + | ||
| 141 | auto custom_op_ptr = | 172 | auto custom_op_ptr = |
| 142 | context->GetInputValue<ge::BaseCustomOp *>(node_input_num + static_cast<size_t>(CustomOpInput::kFunc)); | 173 | context->GetInputValue<ge::BaseCustomOp *>(node_input_num + static_cast<size_t>(CustomOpInput::kFunc)); |
| 143 | GE_ASSERT_NOTNULL(custom_op_ptr); | 174 | GE_ASSERT_NOTNULL(custom_op_ptr); |
| @@ -177,6 +208,14 @@ ge::graphStatus FreeCustomOpWorkspacesFunc(KernelContext *context) { | |||
| 177 | return ge::GRAPH_SUCCESS; | 208 | return ge::GRAPH_SUCCESS; |
| 178 | } | 209 | } |
| 179 | 210 | ||
| 211 | +ge::graphStatus FreeArgsGuarderFunc(KernelContext *context) { | ||
| 212 | + auto *handler_base = context->GetInputValue<ArgsHandler *>(0); | ||
| 213 | + if (handler_base != nullptr) { | ||
| 214 | + static_cast<EagerArgsHandler *>(handler_base)->Release(); | ||
| 215 | + } | ||
| 216 | + return ge::GRAPH_SUCCESS; | ||
| 217 | +} | ||
| 218 | + | ||
| 180 | static std::vector<std::string> CustomOpExecuteKernelTrace(const KernelContext *context) { | 219 | static std::vector<std::string> CustomOpExecuteKernelTrace(const KernelContext *context) { |
| 181 | auto extend_context = reinterpret_cast<const ExtendedKernelContext *>(context); | 220 | auto extend_context = reinterpret_cast<const ExtendedKernelContext *>(context); |
| 182 | auto compute_node_info = extend_context->GetComputeNodeInfo(); | 221 | auto compute_node_info = extend_context->GetComputeNodeInfo(); |
| @@ -251,16 +290,13 @@ ge::graphStatus CustomOpProfilingDataFill(const KernelContext *context, Profilin | |||
| 251 | } | 290 | } |
| 252 | 291 | ||
| 253 | REGISTER_KERNEL(FindCustomOp).RunFunc(FindCustomOpFunc); | 292 | REGISTER_KERNEL(FindCustomOp).RunFunc(FindCustomOpFunc); |
| 254 | -REGISTER_KERNEL(ExecuteCustomOp) | 293 | +REGISTER_KERNEL(ExecuteCustomOp).OutputsCreator(CreateCustomOpOutputs) |
| 255 | - .OutputsCreator(CreateWorkspacesMemory) | 294 | + .RunFunc(ExecuteCustomOpFunc).TracePrinter(CustomOpExecuteKernelTrace) |
| 256 | - .RunFunc(ExecuteCustomOpFunc) | ||
| 257 | - .TracePrinter(CustomOpExecuteKernelTrace) | ||
| 258 | .ProfilingInfoFiller(CustomOpProfilingDataFill); | 295 | .ProfilingInfoFiller(CustomOpProfilingDataFill); |
| 259 | -REGISTER_KERNEL(ExecuteCustomOpWithInferShape) | 296 | +REGISTER_KERNEL(ExecuteCustomOpWithInferShape).OutputsCreator(CreateCustomOpOutputs) |
| 260 | - .OutputsCreator(CreateWorkspacesMemory) | 297 | + .RunFunc(ExecuteCustomOpWithInferShapeFunc).TracePrinter(CustomOpExecuteKernelTrace) |
| 261 | - .RunFunc(ExecuteCustomOpWithInferShapeFunc) | ||
| 262 | - .TracePrinter(CustomOpExecuteKernelTrace) | ||
| 263 | .ProfilingInfoFiller(CustomOpProfilingDataFill); | 298 | .ProfilingInfoFiller(CustomOpProfilingDataFill); |
| 264 | REGISTER_KERNEL(FreeCustomOpWorkspaces).RunFunc(FreeCustomOpWorkspacesFunc); | 299 | REGISTER_KERNEL(FreeCustomOpWorkspaces).RunFunc(FreeCustomOpWorkspacesFunc); |
| 265 | -} // namespace kernel | 300 | +REGISTER_KERNEL(FreeArgsGuarder).RunFunc(FreeArgsGuarderFunc); |
| 266 | -} // namespace gert | 301 | +} |
| 302 | +} | ||
| @@ -0,0 +1,64 @@ | |||
| 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 | +namespace gert { | ||
| 16 | + | ||
| 17 | +EagerArgsHandler::EagerArgsHandler(GertAllocator *allocator, int64_t stream_id) | ||
| 18 | + : allocator_(allocator), stream_id_(stream_id) {} | ||
| 19 | + | ||
| 20 | +void EagerArgsHandler::Initialize(GertAllocator *allocator, int64_t stream_id) { | ||
| 21 | + allocator_ = allocator; | ||
| 22 | + stream_id_ = stream_id; | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +const KernelArgs* EagerArgsHandler::MallocReadOnlyDevArgs(void *host_args, size_t args_size) { | ||
| 26 | + GE_ASSERT_NOTNULL(allocator_); | ||
| 27 | + GE_ASSERT_NOTNULL(host_args); | ||
| 28 | + GE_ASSERT_TRUE(args_size > 0); | ||
🟡 Medium Priority eager_args_handler.cc 第 26 行使用 从代码模式看,
建议:将 ![]() ![]() 不准确? | |||
| 29 | + | ||
| 30 | + auto *block = allocator_->Malloc(args_size); | ||
| 31 | + GE_ASSERT_NOTNULL(block); | ||
| 32 | + | ||
| 33 | + auto ret = aclrtMemcpy(block->GetAddr(), args_size, host_args, args_size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 34 | + GE_ASSERT_RT_OK(ret); | ||
| 35 | + allocated_blocks_.push_back(block); | ||
| 36 | + | ||
| 37 | + KernelArgs args; | ||
| 38 | + args.args_data = block->GetAddr(); | ||
| 39 | + args.args_size = args_size; | ||
| 40 | + args.placement = Placement::kPlacementDevice; | ||
| 41 | + device_args_.push_back(args); | ||
| 42 | + | ||
| 43 | + return &device_args_.back(); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +const std::deque<KernelArgs>& EagerArgsHandler::GetKernelArgs(Placement placement) const { | ||
| 47 | + if (placement == Placement::kPlacementHost) { | ||
| 48 | + static const std::deque<KernelArgs> kEmptyArgs; | ||
| 49 | + return kEmptyArgs; | ||
| 50 | + } | ||
| 51 | + return device_args_; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +void EagerArgsHandler::Release() { | ||
| 55 | + for (auto *block : allocated_blocks_) { | ||
| 56 | + if (block != nullptr) { | ||
| 57 | + block->Free(stream_id_); | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + allocated_blocks_.clear(); | ||
| 61 | + device_args_.clear(); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +} // namespace gert | ||
| @@ -0,0 +1,46 @@ | |||||||||||||||||
| 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 | + | ||||||||||||||||
🔵 Low Priority eager_args_handler.h 在第 26、29、37 行使用了 int64_t 类型,但没有显式包含 建议:在现有 #include 列表中添加 #include 改动建议
![]() ![]() 不准确? | |||||||||||||||||
| 21 | + | ||||||||||||||||
| 22 | +namespace gert { | ||||||||||||||||
| 23 | + | ||||||||||||||||
| 24 | +class EagerArgsHandler : public ArgsHandler { | ||||||||||||||||
| 25 | + public: | ||||||||||||||||
| 26 | + EagerArgsHandler() : allocator_(nullptr), stream_id_(-1) {} | ||||||||||||||||
| 27 | + EagerArgsHandler(GertAllocator *allocator, int64_t stream_id); | ||||||||||||||||
| 28 | + ~EagerArgsHandler() override { Release(); } | ||||||||||||||||
| 29 | + | ||||||||||||||||
| 30 | + void Initialize(GertAllocator *allocator, int64_t stream_id); | ||||||||||||||||
| 31 | + bool IsInitialized() const { return allocator_ != nullptr; } | ||||||||||||||||
| 32 | + const KernelArgs* MallocReadOnlyDevArgs(void *host_args, size_t args_size) override; | ||||||||||||||||
| 33 | + const std::deque<KernelArgs>& GetKernelArgs(Placement placement) const override; | ||||||||||||||||
| 34 | + | ||||||||||||||||
| 35 | + void Release(); | ||||||||||||||||
| 36 | + | ||||||||||||||||
| 37 | + private: | ||||||||||||||||
| 38 | + GertAllocator *allocator_; // 生命周期由框架保证,覆盖整个执行过程 | ||||||||||||||||
| 39 | + int64_t stream_id_; | ||||||||||||||||
| 40 | + std::deque<KernelArgs> device_args_; | ||||||||||||||||
| 41 | + std::vector<GertMemBlock *> allocated_blocks_; | ||||||||||||||||
| 42 | +}; | ||||||||||||||||
| 43 | + | ||||||||||||||||
| 44 | +} // namespace gert | ||||||||||||||||
| 45 | + | ||||||||||||||||
| 46 | + | ||||||||||||||||
| @@ -102,6 +102,24 @@ class TestCompilableCustomOp : public EagerExecuteOp, CompilableOp { | |||
| 102 | std::string mock_compile_path_; | 102 | std::string mock_compile_path_; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | +class TestMallocReadOnlyDevArgsCustomOp : public EagerExecuteOp { | ||
| 106 | + public: | ||
| 107 | + graphStatus Execute(gert::EagerOpExecutionContext *ctx) override { | ||
| 108 | + uint64_t host_args[4] = {0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD}; | ||
| 109 | + auto *dev_args = ctx->MallocReadOnlyDevArgs(host_args, sizeof(host_args)); | ||
| 110 | + GE_ASSERT_NOTNULL(dev_args); | ||
| 111 | + GE_ASSERT_NOTNULL(dev_args->args_data); | ||
| 112 | + GE_ASSERT_EQ(dev_args->args_size, sizeof(host_args)); | ||
| 113 | + GE_ASSERT_EQ(dev_args->placement, gert::Placement::kPlacementDevice); | ||
| 114 | + auto output_tensor = ctx->MallocOutputTensor(0, StorageShape({2048}, {2048}), | ||
| 115 | + StorageFormat(FORMAT_ND, FORMAT_ND, ExpandDimsType()), DT_FLOAT); | ||
| 116 | + GE_ASSERT_NOTNULL(output_tensor); | ||
| 117 | + output_addr = output_tensor->GetAddr(); | ||
| 118 | + GE_ASSERT_NOTNULL(output_addr); | ||
| 119 | + return SUCCESS; | ||
| 120 | + } | ||
| 121 | +}; | ||
| 122 | + | ||
| 105 | class TestCustomOpWithShapeInfer : public EagerExecuteOp, public ShapeInferOp { | 123 | class TestCustomOpWithShapeInfer : public EagerExecuteOp, public ShapeInferOp { |
| 106 | public: | 124 | public: |
| 107 | graphStatus Execute(EagerOpExecutionContext *ctx) override { | 125 | graphStatus Execute(EagerOpExecutionContext *ctx) override { |
| @@ -190,29 +208,36 @@ class TestEmptyOutputInstanceCompileCustomOp : public EagerExecuteOp, Compilable | |||
| 190 | }; | 208 | }; |
| 191 | 209 | ||
| 192 | REG_OP(CustomOp) | 210 | REG_OP(CustomOp) |
| 193 | - .INPUT(x1, TensorType::BasicType()) | 211 | + .INPUT(x1, TensorType::BasicType()) |
| 194 | - .INPUT(x2, TensorType::BasicType()) | 212 | + .INPUT(x2, TensorType::BasicType()) |
| 195 | - .INPUT(x3, TensorType::BasicType()) | 213 | + .INPUT(x3, TensorType::BasicType()) |
| 196 | - .OUTPUT(y, TensorType::BasicType()) | 214 | + .OUTPUT(y, TensorType::BasicType()) |
| 197 | - .OP_END_FACTORY_REG(CustomOp) | 215 | + .OP_END_FACTORY_REG(CustomOp) |
| 198 | 216 | ||
| 199 | - REG_OP(NoInputCompileOutputCustomOp) | 217 | +REG_OP(NoInputCompileOutputCustomOp) |
| 200 | - .OUTPUT(y, TensorType::BasicType()) | 218 | + .OUTPUT(y, TensorType::BasicType()) |
| 201 | - .DYNAMIC_OUTPUT(dy, TensorType::BasicType()) | 219 | + .DYNAMIC_OUTPUT(dy, TensorType::BasicType()) |
| 202 | - .OP_END_FACTORY_REG(NoInputCompileOutputCustomOp) | 220 | + .OP_END_FACTORY_REG(NoInputCompileOutputCustomOp) |
| 203 | 221 | ||
| 204 | - REG_OP(EmptyOutputInstanceCompileCustomOp) | 222 | +REG_OP(EmptyOutputInstanceCompileCustomOp) |
| 205 | - .OUTPUT(y, TensorType::BasicType()) | 223 | + .OUTPUT(y, TensorType::BasicType()) |
| 206 | - .OP_END_FACTORY_REG(EmptyOutputInstanceCompileCustomOp) | 224 | + .OP_END_FACTORY_REG(EmptyOutputInstanceCompileCustomOp) |
| 207 | 225 | ||
| 208 | - REG_OP(StCustomOpWithShapeInfer) | 226 | +REG_OP(StCustomOpWithShapeInfer) |
| 209 | - .INPUT(x1, TensorType::BasicType()) | 227 | + .INPUT(x1, TensorType::BasicType()) |
| 210 | - .INPUT(x2, TensorType::BasicType()) | 228 | + .INPUT(x2, TensorType::BasicType()) |
| 211 | - .INPUT(x3, TensorType::BasicType()) | 229 | + .INPUT(x3, TensorType::BasicType()) |
| 212 | - .OUTPUT(y, TensorType::BasicType()) | 230 | + .OUTPUT(y, TensorType::BasicType()) |
| 213 | - .OP_END_FACTORY_REG(StCustomOpWithShapeInfer) | 231 | + .OP_END_FACTORY_REG(StCustomOpWithShapeInfer) |
| 214 | 232 | ||
| 215 | - TEST_F(TestCustomNodeKernel, custom_op_kernel_execute_test) { | 233 | +REG_OP(MallocReadOnlyDevArgsCustomOp) |
| 234 | + .INPUT(x1, TensorType::BasicType()) | ||
| 235 | + .INPUT(x2, TensorType::BasicType()) | ||
| 236 | + .INPUT(x3, TensorType::BasicType()) | ||
| 237 | + .OUTPUT(y, TensorType::BasicType()) | ||
| 238 | + .OP_END_FACTORY_REG(MallocReadOnlyDevArgsCustomOp) | ||
| 239 | + | ||
| 240 | +TEST_F(TestCustomNodeKernel, custom_op_kernel_execute_test) { | ||
| 216 | auto graph = ShareGraph::BuildCustomOpGraph(); | 241 | auto graph = ShareGraph::BuildCustomOpGraph(); |
| 217 | graph->TopologicalSorting(); | 242 | graph->TopologicalSorting(); |
| 218 | CustomOpFactory::RegisterCustomOpCreator( | 243 | CustomOpFactory::RegisterCustomOpCreator( |
| @@ -249,6 +274,7 @@ REG_OP(CustomOp) | |||
| 249 | GRAPH_SUCCESS); | 274 | GRAPH_SUCCESS); |
| 250 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "ExecuteCustomOp"), 1); | 275 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "ExecuteCustomOp"), 1); |
| 251 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "FreeCustomOpWorkspaces"), 1); | 276 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "FreeCustomOpWorkspaces"), 1); |
| 277 | + EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "FreeArgsGuarder"), 1); | ||
| 252 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "FreeMemory"), 1); | 278 | EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType("CustomOp", "FreeMemory"), 1); |
| 253 | EXPECT_TRUE(MemoryTraceChecker(runtime_stub.GetSlogStub(), output_addr) | 279 | EXPECT_TRUE(MemoryTraceChecker(runtime_stub.GetSlogStub(), output_addr) |
| 254 | .AppendExpectEvent(kAllocRe, 0) // (1) alloc in stream 0 | 280 | .AppendExpectEvent(kAllocRe, 0) // (1) alloc in stream 0 |
| @@ -387,5 +413,67 @@ TEST_F(TestCustomNodeKernel, custom_op_shape_infer_op_execute_test) { | |||
| 387 | EXPECT_EQ(model_executor->UnLoad(), GRAPH_SUCCESS); | 413 | EXPECT_EQ(model_executor->UnLoad(), GRAPH_SUCCESS); |
| 388 | aclrtDestroyStream(stream); | 414 | aclrtDestroyStream(stream); |
| 389 | } | 415 | } |
| 390 | -} // namespace kernel | 416 | + |
| 391 | -} // namespace gert | 417 | +/** |
| 418 | + * 用例描述:验证自定义算子MallocReadOnlyDevArgs接口在V2运行时中正确分配设备侧只读args | ||
| 419 | + * 预置条件: | ||
| 420 | + * 1. 注册一个继承EagerExecuteOp的自定义算子,Execute中调用MallocReadOnlyDevArgs分配kernel args | ||
| 421 | + * 2. 构造包含该自定义算子的计算图,并通过ModelV2Executor加载执行 | ||
| 422 | + * 测试步骤: | ||
| 423 | + * 1. 创建计算图并注册MallocReadOnlyDevArgsCustomOp算子 | ||
| 424 | + * 2. 通过ModelV2Executor编译加载并执行 | ||
| 425 | + * 3. 验证Execute/FreeArgsGuarder/FreeCustomOpWorkspaces kernel执行计数 | ||
| 426 | + * 4. 通过MemoryTraceChecker验证输出Tensor内存的分配和释放事件 | ||
| 427 | + * 5. 调用UnLoad卸载模型 | ||
| 428 | + * 预期结果: | ||
| 429 | + * 1. 算子执行成功,各kernel执行计数符合预期 | ||
| 430 | + * 2. 输出Tensor内存在stream 0上正确分配和释放 | ||
| 431 | + * 3. 模型卸载成功 | ||
| 432 | + */ | ||
| 433 | +TEST_F(TestCustomNodeKernel, custom_op_malloc_read_only_dev_args_test) { | ||
| 434 | + const char *const op_type = "MallocReadOnlyDevArgsCustomOp"; | ||
| 435 | + auto graph = ShareGraph::BuildCustomOpGraph(); | ||
| 436 | + auto custom_op = graph->FindNode("custom_op"); | ||
| 437 | + ASSERT_NE(custom_op, nullptr); | ||
| 438 | + custom_op->GetOpDesc()->SetType(op_type); | ||
| 439 | + graph->TopologicalSorting(); | ||
| 440 | + CustomOpFactory::RegisterCustomOpCreator(op_type, []()->std::unique_ptr<BaseCustomOp> { | ||
| 441 | + return std::make_unique<TestMallocReadOnlyDevArgsCustomOp>(); | ||
| 442 | + }); | ||
| 443 | + GertRuntimeStub runtime_stub; | ||
| 444 | + runtime_stub.GetKernelStub().StubTiling(); | ||
| 445 | + GeModelBuilder builder(graph); | ||
| 446 | + auto ge_root_model = builder.BuildGeRootModel(); | ||
| 447 | + bg::ValueHolder::PopGraphFrame(); | ||
| 448 | + auto exe_graph = ModelConverter().ConvertGeModelToExecuteGraph(ge_root_model, {}); | ||
| 449 | + ASSERT_NE(exe_graph, nullptr); | ||
| 450 | + TaskProducerFactory::GetInstance().SetProducerType(TaskProducerType::KERNEL); | ||
| 451 | + auto model_executor = ModelV2Executor::Create(exe_graph, | ||
| 452 | + ExecutorOption(ExecutorType::kTopologicalPriority), ge_root_model); | ||
| 453 | + ASSERT_NE(model_executor, nullptr); | ||
| 454 | + ASSERT_EQ(model_executor->Load(), GRAPH_SUCCESS); | ||
| 455 | + | ||
| 456 | + auto outputs = FakeTensors({2048}, 1); | ||
| 457 | + auto inputs = FakeTensors({2048}, 3); | ||
| 458 | + rtStream_t stream; | ||
| 459 | + ASSERT_EQ(aclrtCreateStreamWithConfig(&stream, static_cast<uint32_t>(RT_STREAM_PRIORITY_DEFAULT), 0), RT_ERROR_NONE); | ||
| 460 | + auto i3 = FakeValue<uint64_t>(reinterpret_cast<uint64_t>(stream)); | ||
| 461 | + | ||
| 462 | + auto ess = StartExecutorStatistician(model_executor); | ||
| 463 | + ess->Clear(); | ||
| 464 | + ExecutorTracerOn executor_tracer_on; // 开启trace以验证内存事件 | ||
| 465 | + ASSERT_EQ(model_executor->Execute({i3.value}, inputs.GetTensorList(), inputs.size(), | ||
| 466 | + reinterpret_cast<Tensor **>(outputs.GetAddrList()), outputs.size()), | ||
| 467 | + GRAPH_SUCCESS); | ||
| 468 | + EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType(op_type, "ExecuteCustomOp"), 1); | ||
| 469 | + EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType(op_type, "FreeArgsGuarder"), 1); | ||
| 470 | + EXPECT_EQ(ess->GetExecuteCountByNodeTypeAndKernelType(op_type, "FreeCustomOpWorkspaces"), 1); | ||
| 471 | + EXPECT_TRUE(MemoryTraceChecker(runtime_stub.GetSlogStub(), output_addr) | ||
| 472 | + .AppendExpectEvent(kAllocRe, 0) | ||
| 473 | + .AppendExpectEvent(kFreeRe, 0) | ||
| 474 | + .AsYouWish()); | ||
| 475 | + EXPECT_EQ(model_executor->UnLoad(), GRAPH_SUCCESS); | ||
| 476 | + aclrtDestroyStream(stream); | ||
| 477 | +} | ||
| 478 | +} | ||
| 479 | +} | ||
| @@ -17,6 +17,7 @@ list(REMOVE_ITEM RUNTIME2_TEST_SRCS | |||
| 17 | 17 | ||
| 18 | add_executable(ut_fast_runtime2_test | 18 | add_executable(ut_fast_runtime2_test |
| 19 | "${AIR_CODE_DIR}/tests/depends/graph_tuner/rt2_src/graph_tunner_rt2_stub.cc" | 19 | "${AIR_CODE_DIR}/tests/depends/graph_tuner/rt2_src/graph_tunner_rt2_stub.cc" |
| 20 | + "${AIR_CODE_DIR}/tests/graph_metadef/depends/faker/allocator_faker.cc" | ||
| 20 | "${AIR_CODE_DIR}/tests/ge/ut/ge/ffts_plus_proto_tools.cc" | 21 | "${AIR_CODE_DIR}/tests/ge/ut/ge/ffts_plus_proto_tools.cc" |
| 21 | "${AIR_CODE_DIR}/tests/ge/ut/ge/test_tools_task_info.cc" | 22 | "${AIR_CODE_DIR}/tests/ge/ut/ge/test_tools_task_info.cc" |
| 22 | "${AIR_CODE_DIR}/tests/depends/op_stub/op_impl/autotiling/norm.cc" | 23 | "${AIR_CODE_DIR}/tests/depends/op_stub/op_impl/autotiling/norm.cc" |
| @@ -90,6 +90,7 @@ TEST_F(CustomNodeConverterUT, custom_op_convert_test) { | |||
| 90 | {"CalcTensorSizeFromStorage", 3}, | 90 | {"CalcTensorSizeFromStorage", 3}, |
| 91 | {"ExecuteCustomOp", 1}, | 91 | {"ExecuteCustomOp", 1}, |
| 92 | {"FreeCustomOpWorkspaces", 1}, | 92 | {"FreeCustomOpWorkspaces", 1}, |
| 93 | + {"FreeArgsGuarder", 1}, | ||
| 93 | {"FreeMemory", 4}, | 94 | {"FreeMemory", 4}, |
| 94 | {"SelectL2Allocator", 1}, | 95 | {"SelectL2Allocator", 1}, |
| 95 | {"SplitRtStreams", 1}, | 96 | {"SplitRtStreams", 1}, |
| @@ -0,0 +1,198 @@ | |||
| 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 | +namespace gert { | ||
| 19 | +namespace { | ||
| 20 | + | ||
| 21 | +class TrackingAllocatorFaker : public AllocatorFaker { | ||
| 22 | + public: | ||
| 23 | + class TrackingGertMemBlockFaker : public GertMemBlockFaker { | ||
| 24 | + public: | ||
| 25 | + explicit TrackingGertMemBlockFaker(void *addr, size_t *free_count) | ||
| 26 | + : GertMemBlockFaker(addr), free_count_(free_count) {} | ||
| 27 | + void Free(int64_t stream_id) override { | ||
| 28 | + if (free_count_ != nullptr) { | ||
| 29 | + ++(*free_count_); | ||
| 30 | + } | ||
| 31 | + GertMemBlockFaker::Free(stream_id); | ||
| 32 | + } | ||
| 33 | + private: | ||
| 34 | + size_t *free_count_; | ||
| 35 | + }; | ||
| 36 | + | ||
| 37 | + TrackingAllocatorFaker() = default; | ||
| 38 | + ~TrackingAllocatorFaker() override { | ||
| 39 | + for (auto *block : blocks_) { | ||
| 40 | + delete block; | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + size_t GetFreeCount() const { return free_count_; } | ||
| 44 | + | ||
| 45 | + GertMemBlock *Malloc(size_t size) override { | ||
| 46 | + void *addr = malloc(size); | ||
| 47 | + if (addr == nullptr) { | ||
| 48 | + return nullptr; | ||
| 49 | + } | ||
| 50 | + auto *block = new TrackingGertMemBlockFaker(addr, &free_count_); | ||
| 51 | + blocks_.push_back(block); | ||
| 52 | + return block; | ||
| 53 | + } | ||
| 54 | + private: | ||
| 55 | + size_t free_count_ = 0; | ||
| 56 | + std::vector<GertMemBlock *> blocks_; | ||
| 57 | +}; | ||
| 58 | + | ||
| 59 | +class EagerArgsHandlerTest : public ::testing::Test { | ||
| 60 | + protected: | ||
| 61 | + void SetUp() override { | ||
| 62 | + allocator_ = std::make_unique<AllocatorFaker>(); | ||
| 63 | + stream_id_ = 123; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + void TearDown() override { | ||
| 67 | + handler_.reset(); | ||
| 68 | + allocator_.reset(); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + std::unique_ptr<AllocatorFaker> allocator_; | ||
| 72 | + std::unique_ptr<EagerArgsHandler> handler_; | ||
| 73 | + int64_t stream_id_; | ||
| 74 | +}; | ||
| 75 | + | ||
| 76 | +TEST_F(EagerArgsHandlerTest, MallocReadOnlyDevArgs_Success) { | ||
| 77 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 78 | + uint8_t host_data[1024] = {}; | ||
| 79 | + for (size_t i = 0; i < sizeof(host_data); ++i) { | ||
| 80 | + host_data[i] = static_cast<uint8_t>(i & 0xFF); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + const KernelArgs *result = handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 84 | + | ||
| 85 | + ASSERT_NE(result, nullptr); | ||
| 86 | + EXPECT_NE(result->args_data, nullptr); | ||
| 87 | + EXPECT_EQ(result->args_size, sizeof(host_data)); | ||
| 88 | + EXPECT_EQ(result->placement, ge::kPlacementDevice); | ||
| 89 | + EXPECT_EQ(memcmp(result->args_data, host_data, sizeof(host_data)), 0); | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +TEST_F(EagerArgsHandlerTest, MallocReadOnlyDevArgs_MultipleCallsReturnIndependentArgs) { | ||
| 93 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 94 | + uint8_t host_data1[512] = {}; | ||
| 95 | + uint8_t host_data2[256] = {}; | ||
| 96 | + memset_s(host_data1, sizeof(host_data1), 0xAA, sizeof(host_data1)); | ||
| 97 | + memset_s(host_data2, sizeof(host_data2), 0xBB, sizeof(host_data2)); | ||
| 98 | + | ||
| 99 | + const KernelArgs *result1 = handler_->MallocReadOnlyDevArgs(host_data1, sizeof(host_data1)); | ||
| 100 | + const KernelArgs *result2 = handler_->MallocReadOnlyDevArgs(host_data2, sizeof(host_data2)); | ||
| 101 | + | ||
| 102 | + ASSERT_NE(result1, nullptr); | ||
| 103 | + ASSERT_NE(result2, nullptr); | ||
| 104 | + EXPECT_NE(result1->args_data, result2->args_data); | ||
| 105 | + EXPECT_EQ(result1->args_size, sizeof(host_data1)); | ||
| 106 | + EXPECT_EQ(result2->args_size, sizeof(host_data2)); | ||
| 107 | + EXPECT_EQ(memcmp(result1->args_data, host_data1, sizeof(host_data1)), 0); | ||
| 108 | + EXPECT_EQ(memcmp(result2->args_data, host_data2, sizeof(host_data2)), 0); | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +TEST_F(EagerArgsHandlerTest, Release_ClearsAllAllocatedBlocks) { | ||
| 112 | + auto tracking_allocator = std::make_unique<TrackingAllocatorFaker>(); | ||
| 113 | + handler_ = std::make_unique<EagerArgsHandler>(tracking_allocator.get(), stream_id_); | ||
| 114 | + uint8_t host_data[512] = {}; | ||
| 115 | + | ||
| 116 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 117 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 118 | + | ||
| 119 | + const auto &args_before = handler_->GetKernelArgs(ge::kPlacementDevice); | ||
| 120 | + EXPECT_EQ(args_before.size(), 2U); | ||
| 121 | + EXPECT_EQ(tracking_allocator->GetFreeCount(), 0U); | ||
| 122 | + | ||
| 123 | + handler_->Release(); | ||
| 124 | + | ||
| 125 | + const auto &args_after = handler_->GetKernelArgs(ge::kPlacementDevice); | ||
| 126 | + EXPECT_EQ(args_after.size(), 0U); | ||
| 127 | + EXPECT_EQ(tracking_allocator->GetFreeCount(), 2U); | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +TEST_F(EagerArgsHandlerTest, GetKernelArgs_DevicePlacement_ReturnsDeviceArgs) { | ||
| 131 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 132 | + uint8_t host_data[256] = {}; | ||
| 133 | + | ||
| 134 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 135 | + | ||
| 136 | + const auto &args = handler_->GetKernelArgs(ge::kPlacementDevice); | ||
| 137 | + ASSERT_EQ(args.size(), 1U); | ||
| 138 | + EXPECT_EQ(args[0].placement, ge::kPlacementDevice); | ||
| 139 | + EXPECT_EQ(args[0].args_size, sizeof(host_data)); | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +TEST_F(EagerArgsHandlerTest, GetKernelArgs_HostPlacement_ReturnsEmpty) { | ||
| 143 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 144 | + uint8_t host_data[256] = {}; | ||
| 145 | + | ||
| 146 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 147 | + | ||
| 148 | + const auto &args = handler_->GetKernelArgs(ge::kPlacementHost); | ||
| 149 | + EXPECT_EQ(args.size(), 0U); | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +TEST_F(EagerArgsHandlerTest, Destructor_CallsReleaseWithoutCrash) { | ||
| 153 | + auto handler = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 154 | + uint8_t host_data[256] = {}; | ||
| 155 | + handler->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 156 | + handler->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 157 | + handler.reset(); | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +TEST_F(EagerArgsHandlerTest, Release_CanBeCalledMultipleTimes) { | ||
| 161 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 162 | + uint8_t host_data[256] = {}; | ||
| 163 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 164 | + | ||
| 165 | + handler_->Release(); | ||
| 166 | + handler_->Release(); | ||
| 167 | + | ||
| 168 | + const auto &args = handler_->GetKernelArgs(ge::kPlacementDevice); | ||
| 169 | + EXPECT_EQ(args.size(), 0U); | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +TEST_F(EagerArgsHandlerTest, MallocReadOnlyDevArgs_AfterRelease) { | ||
| 173 | + handler_ = std::make_unique<EagerArgsHandler>(allocator_.get(), stream_id_); | ||
| 174 | + uint8_t host_data[256] = {}; | ||
| 175 | + memset_s(host_data, sizeof(host_data), 0xCC, sizeof(host_data)); | ||
| 176 | + | ||
| 177 | + handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 178 | + handler_->Release(); | ||
| 179 | + | ||
| 180 | + const KernelArgs *result = handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 181 | + ASSERT_NE(result, nullptr); | ||
| 182 | + EXPECT_EQ(result->args_size, sizeof(host_data)); | ||
| 183 | + EXPECT_EQ(result->placement, ge::kPlacementDevice); | ||
| 184 | + | ||
| 185 | + const auto &args = handler_->GetKernelArgs(ge::kPlacementDevice); | ||
| 186 | + EXPECT_EQ(args.size(), 1U); | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +TEST_F(EagerArgsHandlerTest, MallocReadOnlyDevArgs_WithoutInitialize_ReturnsNullptr) { | ||
| 190 | + handler_ = std::make_unique<EagerArgsHandler>(); | ||
| 191 | + uint8_t host_data[256] = {}; | ||
| 192 | + | ||
| 193 | + const KernelArgs *result = handler_->MallocReadOnlyDevArgs(host_data, sizeof(host_data)); | ||
| 194 | + EXPECT_EQ(result, nullptr); | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +} // namespace | ||
| 198 | +} // namespace gert | ||
| @@ -133,22 +133,23 @@ TEST_F(UtestUpdateArgsContext, GetKernelArgs_Host_Success) { | |||
| 133 | inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); // IR input 0 | 133 | inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); // IR input 0 |
| 134 | inputs.push_back(nullptr); // additional: allocator | 134 | inputs.push_back(nullptr); // additional: allocator |
| 135 | inputs.push_back(nullptr); // additional: stream | 135 | inputs.push_back(nullptr); // additional: stream |
| 136 | - inputs.push_back(reinterpret_cast<void *>(&handler)); // additional: args_handler | ||
| 137 | 136 | ||
| 138 | - std::vector<void *> outputs; | 137 | + std::vector<void*> outputs; |
| 139 | - outputs.push_back(nullptr); | 138 | + outputs.push_back(nullptr); // compute output 0 |
| 139 | + outputs.push_back(nullptr); // additional: workspace | ||
| 140 | + outputs.push_back(reinterpret_cast<void*>(&handler)); // additional: args_handler | ||
| 140 | 141 | ||
| 141 | auto context_holder = KernelRunContextFaker() | 142 | auto context_holder = KernelRunContextFaker() |
| 142 | - .KernelIONum(4, 1) | 143 | + .KernelIONum(3, 3) |
| 143 | - .NodeIoNum(1, 1) | 144 | + .NodeIoNum(1, 1) |
| 144 | - .IrInputNum(1) | 145 | + .IrInputNum(1) |
| 145 | - .IrOutputNum(0) | 146 | + .IrOutputNum(0) |
| 146 | - .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) | 147 | + .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) |
| 147 | - .Inputs(inputs) | 148 | + .Inputs(inputs) |
| 148 | - .Outputs(outputs) | 149 | + .Outputs(outputs) |
| 149 | - .Build(); | 150 | + .Build(); |
| 150 | 151 | ||
| 151 | - auto *ctx = context_holder.template GetContext<UpdateArgsContext>(); | 152 | + auto* ctx = context_holder.template GetContext<UpdateArgsContext>(); |
| 152 | ASSERT_NE(ctx, nullptr); | 153 | ASSERT_NE(ctx, nullptr); |
| 153 | 154 | ||
| 154 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 0U); | 155 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 0U); |
| @@ -171,22 +172,23 @@ TEST_F(UtestUpdateArgsContext, GetKernelArgs_Device_Success) { | |||
| 171 | inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); // IR input 0 | 172 | inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); // IR input 0 |
| 172 | inputs.push_back(nullptr); // additional: allocator | 173 | inputs.push_back(nullptr); // additional: allocator |
| 173 | inputs.push_back(nullptr); // additional: stream | 174 | inputs.push_back(nullptr); // additional: stream |
| 174 | - inputs.push_back(reinterpret_cast<void *>(&handler)); // additional: args_handler | ||
| 175 | 175 | ||
| 176 | - std::vector<void *> outputs; | 176 | + std::vector<void*> outputs; |
| 177 | - outputs.push_back(nullptr); | 177 | + outputs.push_back(nullptr); // compute output 0 |
| 178 | + outputs.push_back(nullptr); // additional: workspace | ||
| 179 | + outputs.push_back(reinterpret_cast<void*>(&handler)); // additional: args_handler | ||
| 178 | 180 | ||
| 179 | auto context_holder = KernelRunContextFaker() | 181 | auto context_holder = KernelRunContextFaker() |
| 180 | - .KernelIONum(4, 1) | 182 | + .KernelIONum(3, 3) |
| 181 | - .NodeIoNum(1, 1) | 183 | + .NodeIoNum(1, 1) |
| 182 | - .IrInputNum(1) | 184 | + .IrInputNum(1) |
| 183 | - .IrOutputNum(0) | 185 | + .IrOutputNum(0) |
| 184 | - .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) | 186 | + .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) |
| 185 | - .Inputs(inputs) | 187 | + .Inputs(inputs) |
| 186 | - .Outputs(outputs) | 188 | + .Outputs(outputs) |
| 187 | - .Build(); | 189 | + .Build(); |
| 188 | 190 | ||
| 189 | - auto *ctx = context_holder.template GetContext<UpdateArgsContext>(); | 191 | + auto* ctx = context_holder.template GetContext<UpdateArgsContext>(); |
| 190 | ASSERT_NE(ctx, nullptr); | 192 | ASSERT_NE(ctx, nullptr); |
| 191 | 193 | ||
| 192 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementDevice, 0U); | 194 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementDevice, 0U); |
| @@ -210,26 +212,27 @@ TEST_F(UtestUpdateArgsContext, GetKernelArgs_IndexOutOfRange_ReturnsNullptr) { | |||
| 210 | host_args[0].placement = Placement::kPlacementHost; | 212 | host_args[0].placement = Placement::kPlacementHost; |
| 211 | handler.SetHostArgs(host_args); | 213 | handler.SetHostArgs(host_args); |
| 212 | 214 | ||
| 213 | - std::vector<void *> inputs; | 215 | + std::vector<void*> inputs; |
| 214 | - inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); | 216 | + inputs.push_back(reinterpret_cast<void*>(0xAAAA0000ULL)); // IR input 0 |
| 215 | - inputs.push_back(nullptr); | 217 | + inputs.push_back(nullptr); // additional: allocator |
| 216 | - inputs.push_back(nullptr); | 218 | + inputs.push_back(nullptr); // additional: stream |
| 217 | - inputs.push_back(reinterpret_cast<void *>(&handler)); | ||
| 218 | 219 | ||
| 219 | - std::vector<void *> outputs; | 220 | + std::vector<void*> outputs; |
| 220 | - outputs.push_back(nullptr); | 221 | + outputs.push_back(nullptr); // compute output 0 |
| 222 | + outputs.push_back(nullptr); // additional: workspace | ||
| 223 | + outputs.push_back(reinterpret_cast<void*>(&handler)); // additional: args_handler | ||
| 221 | 224 | ||
| 222 | auto context_holder = KernelRunContextFaker() | 225 | auto context_holder = KernelRunContextFaker() |
| 223 | - .KernelIONum(4, 1) | 226 | + .KernelIONum(3, 3) |
| 224 | - .NodeIoNum(1, 1) | 227 | + .NodeIoNum(1, 1) |
| 225 | - .IrInputNum(1) | 228 | + .IrInputNum(1) |
| 226 | - .IrOutputNum(0) | 229 | + .IrOutputNum(0) |
| 227 | - .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) | 230 | + .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) |
| 228 | - .Inputs(inputs) | 231 | + .Inputs(inputs) |
| 229 | - .Outputs(outputs) | 232 | + .Outputs(outputs) |
| 230 | - .Build(); | 233 | + .Build(); |
| 231 | 234 | ||
| 232 | - auto *ctx = context_holder.template GetContext<UpdateArgsContext>(); | 235 | + auto* ctx = context_holder.template GetContext<UpdateArgsContext>(); |
| 233 | ASSERT_NE(ctx, nullptr); | 236 | ASSERT_NE(ctx, nullptr); |
| 234 | 237 | ||
| 235 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 100U); | 238 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 100U); |
| @@ -237,26 +240,27 @@ TEST_F(UtestUpdateArgsContext, GetKernelArgs_IndexOutOfRange_ReturnsNullptr) { | |||
| 237 | } | 240 | } |
| 238 | 241 | ||
| 239 | TEST_F(UtestUpdateArgsContext, GetKernelArgs_NullHandlerInContext_ReturnsNullptr) { | 242 | TEST_F(UtestUpdateArgsContext, GetKernelArgs_NullHandlerInContext_ReturnsNullptr) { |
| 240 | - std::vector<void *> inputs; | 243 | + std::vector<void*> inputs; |
| 241 | - inputs.push_back(reinterpret_cast<void *>(0xAAAA0000ULL)); | 244 | + inputs.push_back(reinterpret_cast<void*>(0xAAAA0000ULL)); // IR input 0 |
| 242 | - inputs.push_back(nullptr); | 245 | + inputs.push_back(nullptr); // additional: allocator |
| 243 | - inputs.push_back(nullptr); | 246 | + inputs.push_back(nullptr); // additional: stream |
| 244 | - inputs.push_back(nullptr); | ||
| 245 | 247 | ||
| 246 | - std::vector<void *> outputs; | 248 | + std::vector<void*> outputs; |
| 247 | - outputs.push_back(nullptr); | 249 | + outputs.push_back(nullptr); // compute output 0 |
| 250 | + outputs.push_back(nullptr); // additional: workspace | ||
| 251 | + outputs.push_back(nullptr); // additional: args_handler (null) | ||
| 248 | 252 | ||
| 249 | auto context_holder = KernelRunContextFaker() | 253 | auto context_holder = KernelRunContextFaker() |
| 250 | - .KernelIONum(4, 1) | 254 | + .KernelIONum(3, 3) |
| 251 | - .NodeIoNum(1, 1) | 255 | + .NodeIoNum(1, 1) |
| 252 | - .IrInputNum(1) | 256 | + .IrInputNum(1) |
| 253 | - .IrOutputNum(0) | 257 | + .IrOutputNum(0) |
| 254 | - .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) | 258 | + .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_NCHW, ge::FORMAT_NCHW) |
| 255 | - .Inputs(inputs) | 259 | + .Inputs(inputs) |
| 256 | - .Outputs(outputs) | 260 | + .Outputs(outputs) |
| 257 | - .Build(); | 261 | + .Build(); |
| 258 | 262 | ||
| 259 | - auto *ctx = context_holder.template GetContext<UpdateArgsContext>(); | 263 | + auto* ctx = context_holder.template GetContext<UpdateArgsContext>(); |
| 260 | ASSERT_NE(ctx, nullptr); | 264 | ASSERT_NE(ctx, nullptr); |
| 261 | 265 | ||
| 262 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 0U); | 266 | const auto *args = ctx->GetKernelArgs(Placement::kPlacementHost, 0U); |


🔵 Low Priority
CustomOpInput枚举中移除了kAllocator和kStream,现在仅保留kFunc(值从AdditionalInputIndex::kNum即 2 开始)。这意味着ExecuteCustomOpWithInferShapeFunc中CopyShapeFromTemplateTensors使用的CustomOpInput::kEnd值(=3)与之前相同,因为旧代码中kAllocator=0, kStream=1, kFunc=2, kEnd=3,新代码中kFunc=2, kEnd=3。数值一致,无偏移。但
ExecuteCustomOpImpl中通过AdditionalInputIndex::kDeviceAllocator(值为 0)获取 allocator,其索引计算为node_input_num + 0。输入布局中 additional inputs 为[allocator, stream, custom_func](共 3 个),其中 allocator 在 index 0(即 kDeviceAllocator),custom_func 在 index 2(即 kFunc)。这与枚举值一致。该变更在概念上正确,但
CustomOpInput移除了kAllocator和kStream后,代码中曾引用这两个值的遗留注释或文档可能会产生误导。不过在当前 diff 范围内无实际问题。这是一个信息性评论,不构成需要修复的缺陷。
建议:无需修改;此评论仅为信息性确认:
CustomOpInput::kEnd的值(3)在枚举重构前后保持一致,不影响CopyShapeFromTemplateTensors的索引计算。