Line data Source code
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 : #include "graph/build/model_builder.h"
12 : #include <securectype.h>
13 : #include <cstring>
14 : #include <iostream>
15 : #include <set>
16 : #include <unordered_map>
17 : #include "mmpa/mmpa_api.h"
18 : #include "common/dump/dump_manager.h"
19 : #include "graph/build/stream/dynamic_stream_allocator.h"
20 : #include "graph/build/stream_graph_optimizer.h"
21 : #include "common/omg_util/omg_util.h"
22 : #include "common/compile_profiling/ge_trace_wrapper.h"
23 : #include "graph/ge_context.h"
24 : #include "graph/optimize/params.h"
25 : #include "graph/unfold/graph_unfolder.h"
26 : #include "graph/utils/graph_utils.h"
27 : #include "graph/utils/node_utils.h"
28 : #include "graph/utils/op_desc_utils.h"
29 : #include "graph/utils/tensor_utils.h"
30 : #include "graph/utils/tensor_utils_ex.h"
31 : #include "graph/utils/type_utils.h"
32 : #include "graph/utils/op_desc_utils_ex.h"
33 : #include "api/gelib/gelib.h"
34 : #include "framework/memory/memory_assigner.h"
35 : #include "framework/omg/version.h"
36 : #include "framework/common/framework_types_internal.h"
37 : #include "graph/passes/memory_conflict/set_input_output_offset_pass.h"
38 : #include "graph/build/memory/block_mem_assigner.h"
39 : #include "common/helper/model_parser_base.h"
40 : #include "framework/common/helper/model_helper.h"
41 : #include "common/proto_util/proto_util.h"
42 : #include "common/checker.h"
43 : #include "exec_runtime/execution_runtime_utils.h"
44 : #include "graph/utils/op_type_utils.h"
45 : #include "common/math/ge_math_util.h"
46 : #include "graph/passes/pass_manager.h"
47 : #include "base/err_msg.h"
48 : #include "ge/ge_api_types.h"
49 :
50 : namespace {
51 : const uint32_t kWeightsStartOffset = 512;
52 : const int32_t kWrongIndex = -2;
53 : const int32_t kInvalidIndexNum = -1;
54 : constexpr size_t kAlignBytes = 32U;
55 :
56 : const std::set<std::string> adjust_layer_type_ = {ge::CONVOLUTION};
57 : constexpr const ge::char_t *kVectorCore = "VectorCore";
58 : constexpr const ge::char_t *kCoreType = "ge.engineType";
59 : constexpr const ge::char_t *kEnableL1Fusion = "ge.l1Fusion";
60 : constexpr const ge::char_t *kAttrEntrySymbolOfElf = "_kernelname";
61 :
62 : bool IsGeLocalOp(const ge::ConstOpDescPtr &op_desc) {
63 : auto type = op_desc->GetType();
64 : if ((type == ge::CONSTANTOP) || (type == ge::CONSTANT)) {
65 : // const op just has one output
66 : ge::GeTensorDesc output_desc = op_desc->GetOutputDesc(0);
67 : return !(output_desc.GetDataType() == ge::DT_STRING);
68 : }
69 : const std::set<std::string> ge_local_set = {
70 : ge::STREAMMERGE, ge::MEMCPYASYNC, ge::STREAMACTIVE, ge::STREAMSWITCH, ge::VARIABLE, ge::NOOP,
71 : ge::CONSTANT, ge::ENTER, ge::REFENTER, ge::LOOPCOND, ge::NEXTITERATION, ge::FILECONSTANT,
72 : ge::EXIT, ge::REFEXIT, ge::MERGE, ge::MEMCPYADDRASYNC, ge::REFNEXTITERATION};
73 : return (ge_local_set.find(type) != ge_local_set.end());
74 : }
75 :
76 : bool IsSameKernelBin(const ge::TBEKernelPtr &lhs, const ge::TBEKernelPtr &rhs) {
77 : if ((lhs == nullptr) || (rhs == nullptr)) {
78 : return lhs == rhs;
79 : }
80 : if (lhs->GetBinDataSize() != rhs->GetBinDataSize()) {
81 : return false;
82 : }
83 : const size_t bin_size = lhs->GetBinDataSize();
84 : if (bin_size == 0U) {
85 : return true;
86 : }
87 : if ((lhs->GetBinData() == nullptr) || (rhs->GetBinData() == nullptr)) {
88 : return false;
89 : }
90 : return std::memcmp(lhs->GetBinData(), rhs->GetBinData(), bin_size) == 0;
91 : }
92 :
93 : ge::Status SaveSoftSyncOpWeightByDependNames(const ge::NodePtr &node, const std::vector<std::string> &depend_names) {
94 : const auto op_desc = node->GetOpDesc();
95 : GE_CHECK_NOTNULL(op_desc);
96 : for (const auto &depend_name : depend_names) {
97 : const int32_t input_idx = op_desc->GetInputIndexByName(depend_name);
98 : if (input_idx == kInvalidIndexNum) {
99 : GELOGW("Cannot find soft sync op[%s]'s input of name: %s.", op_desc->GetName().c_str(), depend_name.c_str());
100 : continue;
101 : }
102 : const auto in_data_anchor = node->GetInDataAnchor(input_idx);
103 : GE_CHECK_NOTNULL(in_data_anchor);
104 : const auto peer_out_data_anchor = in_data_anchor->GetPeerOutAnchor();
105 : GE_CHECK_NOTNULL(peer_out_data_anchor);
106 : auto in_data_node = peer_out_data_anchor->GetOwnerNode();
107 : GE_CHECK_NOTNULL(in_data_node);
108 : if (in_data_node->GetType() == ge::DATA) {
109 : const auto in_desc = in_data_node->GetOpDesc();
110 : GE_CHECK_NOTNULL(in_desc);
111 : if (!in_desc->HasAttr(ge::ATTR_NAME_PARENT_NODE_INDEX)) {
112 : GELOGW("Soft sync op[%s]'s input of name: %s is not const.", op_desc->GetName().c_str(), depend_name.c_str());
113 : continue;
114 : }
115 : }
116 : GE_ASSERT_SUCCESS(ge::NodeUtils::GetInNodeCrossPartionedCallNode(node, in_data_anchor->GetIdx(), in_data_node));
117 : GE_CHECK_NOTNULL(in_data_node);
118 : if (ge::kConstOpTypes.count(in_data_node->GetType()) == 0U) {
119 : GELOGW("Soft sync op[%s]'s input of name: %s is not const.", op_desc->GetName().c_str(), depend_name.c_str());
120 : continue;
121 : }
122 : const auto const_desc = in_data_node->GetOpDesc();
123 : GE_CHECK_NOTNULL(const_desc);
124 : ge::ConstGeTensorPtr weight = nullptr;
125 : GE_ASSERT_TRUE(ge::AttrUtils::GetTensor(const_desc, ge::ATTR_NAME_WEIGHTS, weight));
126 : GE_CHECK_NOTNULL(weight);
127 : auto input_desc = op_desc->MutableInputDesc(depend_name);
128 : GE_CHECK_NOTNULL(input_desc);
129 : GE_ASSERT_TRUE(ge::AttrUtils::SetTensor(input_desc, ge::ATTR_NAME_VALUE, weight));
130 : GELOGD("Save weight to soft sync op[%s]'s input of name: %s.", op_desc->GetName().c_str(), depend_name.c_str());
131 : }
132 : return ge::SUCCESS;
133 : }
134 : } // namespace
135 :
136 : namespace ge {
137 : ModelBuilder::ModelBuilder(uint64_t session_id, ComputeGraphPtr compute_graph, const Graph2SubGraphInfoList &subgraphs,
138 : const std::map<std::string, int32_t> &stream_max_parallel_num, bool hcom_parallel,
139 : int32_t mode)
140 : : session_id_(session_id),
141 : weight_offset_(kWeightsStartOffset),
142 : compute_graph_(std::move(compute_graph)),
143 : subgraphs_(subgraphs),
144 : stream_allocator_(compute_graph_, subgraphs_),
145 : stream_num_(0),
146 : notify_num_(0),
147 : event_num_(0),
148 : label_num_(0),
149 : stream_max_parallel_num_(stream_max_parallel_num),
150 : hcom_parallel_(hcom_parallel),
151 : build_mode_(mode),
152 : max_mem_offset_(0),
153 : host_max_mem_offset_(kMemoryHostFeatureMapLogicBase),
154 : host_svm_max_mem_offset_(kMemoryHostSVMFeatureMapLogicBase),
155 : p2p_mem_offset_(0),
156 : zero_copy_mem_size_(0),
157 : platform_type_(0),
158 : is_loop_graph_(false),
159 : is_l1_fusion_enable_(false),
160 : has_assigned_var_mem(false) {}
161 :
162 : ModelBuilder::~ModelBuilder() {}
163 :
164 : Status ModelBuilder::CalcOutputSize(const ge::NodePtr &n) const {
165 : GE_CHECK_NOTNULL(n);
166 : auto node_op_desc = n->GetOpDesc();
167 : GE_CHECK_NOTNULL(node_op_desc);
168 : uint32_t index = 0;
169 : for (const auto &output_desc_ptr : node_op_desc->GetAllOutputsDescPtr()) {
170 : GeTensorDesc &desc_temp = *output_desc_ptr;
171 :
172 : uint32_t dim_num = static_cast<uint32_t>(desc_temp.GetShape().GetDimNum());
173 : GE_IF_BOOL_EXEC(dim_num > DIM_DEFAULT_SIZE, TensorUtils::SetRealDimCnt(desc_temp, dim_num));
174 : // calculate tensor size
175 : int64_t size_temp = 0;
176 : graphStatus graph_status = TensorUtilsEx::GetTensorMemorySizeInBytesWithAutoPadding(desc_temp, size_temp);
177 : if (graph_status != GRAPH_SUCCESS) {
178 : REPORT_INNER_ERR_MSG("E19999", "Get tensor size in bytes failed for op:%s(%s) index:%u",
179 : node_op_desc->GetName().c_str(), node_op_desc->GetType().c_str(), index);
180 : GELOGE(graph_status, "[Get][TensorMemorySize] In Bytes failed for op:%s(%s) index:%u",
181 : node_op_desc->GetName().c_str(), node_op_desc->GetType().c_str(), index);
182 : return FAILED;
183 : }
184 : TensorUtils::SetSize(desc_temp, size_temp);
185 : GELOGD("Update output desc, dim_size: %u, mem_size: %ld, format: %s, type: %s, node name:%s", dim_num, size_temp,
186 : TypeUtils::FormatToSerialString(desc_temp.GetFormat()).c_str(),
187 : TypeUtils::DataTypeToSerialString(desc_temp.GetDataType()).c_str(), node_op_desc->GetName().c_str());
188 : index++;
189 : }
190 :
191 : return SUCCESS;
192 : }
193 :
194 : bool ModelBuilder::SetInputConst(const OpDescPtr &op_desc, const NodePtr &src_node, size_t index,
195 : std::vector<bool> &is_input_const) const {
196 : GELOGI("SetIsInputConst const: %s, source node: %s", op_desc->GetName().c_str(), src_node->GetName().c_str());
197 : for (size_t i = is_input_const.size(); i <= index; ++i) {
198 : is_input_const.push_back(false);
199 : }
200 : is_input_const[index] = true;
201 :
202 : std::vector<GeTensorPtr> weights = OpDescUtils::MutableWeights(src_node);
203 : if (weights.empty()) {
204 : GELOGW("SetInputIsConst weights is empty, node: %s", src_node->GetName().c_str());
205 : return false;
206 : }
207 : GeTensorPtr weight = weights[0];
208 : GE_IF_BOOL_EXEC(weight == nullptr, return true);
209 : GeTensorDesc &tensor_desc = weight->MutableTensorDesc();
210 : int64_t data_offset = 0;
211 : if (TensorUtils::GetDataOffset(tensor_desc, data_offset) != GRAPH_SUCCESS) {
212 : GELOGW("Get Offset from weight failed");
213 : return false;
214 : }
215 : auto input_tensor = op_desc->MutableInputDesc(static_cast<uint32_t>(index));
216 : if (input_tensor == nullptr) {
217 : GELOGW("Get input_tensor failed");
218 : return false;
219 : }
220 : TensorUtils::SetDataOffset(*input_tensor, data_offset);
221 : return true;
222 : }
223 :
224 : void ModelBuilder::SetInputIsConst(const ge::NodePtr &n) const {
225 : auto node_op_desc = n->GetOpDesc();
226 : GE_CHECK_NOTNULL_JUST_RETURN(node_op_desc);
227 :
228 : // must set all true input_const to false
229 : std::vector<bool> is_input_const(n->GetAllInDataAnchorsSize(), false);
230 :
231 : std::string const_type;
232 : auto in_data_anchors = n->GetAllInDataAnchors();
233 : for (size_t index = 0; index < in_data_anchors.size(); index++) {
234 : auto in_data_anchor = in_data_anchors.at(index);
235 : const auto &peer_out_anchor = in_data_anchor->GetPeerOutAnchor();
236 : GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue);
237 : const auto &src_node = peer_out_anchor->GetOwnerNode();
238 : if ((!NodeUtils::GetConstOpType(src_node, const_type)) || gert::GraphUnfolder::IsDataNotNeedRefConst(src_node)) {
239 : continue;
240 : }
241 :
242 : if (const_type == CONSTANT) {
243 : if (!SetInputConst(node_op_desc, src_node, index, is_input_const)) {
244 : return;
245 : }
246 : } else {
247 : if ((index < is_input_const.size()) && is_input_const[index]) {
248 : is_input_const[index] = false;
249 : }
250 : }
251 : }
252 :
253 : GELOGD("Update opdesc:%s InputConst:%s", node_op_desc->GetName().c_str(), ToString(is_input_const).c_str());
254 : node_op_desc->SetIsInputConst(is_input_const);
255 : }
256 :
257 : void ModelBuilder::ReuseWeightMem(const size_t output_size, GeTensorPtr &weight, bool &find_same_const,
258 : size_t ¤t_mem_offset) {
259 : if (ExecutionRuntimeUtils::IsHeterogeneous()) {
260 : // helper is not supported due to some bug
261 : weight_offset_need_feeded_.insert(current_mem_offset);
262 : return;
263 : }
264 : const auto it = reuse_weight_map_.find(output_size);
265 : if (it == reuse_weight_map_.end()) {
266 : GELOGD("cannot find same size %zu", output_size);
267 : std::vector<std::pair<void *, size_t>> tmp_weight_info;
268 : tmp_weight_info.emplace_back(std::make_pair(static_cast<void *>(weight->MutableData().data()), current_mem_offset));
269 : reuse_weight_map_.insert({output_size, tmp_weight_info});
270 : weight_offset_need_feeded_.insert(current_mem_offset);
271 : } else {
272 : auto &weights_info = it->second;
273 : for (auto &weight_info : weights_info) {
274 : if (memcmp(reinterpret_cast<void *>(weight->MutableData().data()), reinterpret_cast<void *>(weight_info.first),
275 : output_size) == 0) {
276 : current_mem_offset = weight_info.second;
277 : find_same_const = true;
278 : break;
279 : }
280 : }
281 : if (!find_same_const) {
282 : GELOGD("Cannot find same const value, size is %zu", output_size);
283 : weights_info.emplace_back(std::make_pair(static_cast<void *>(weight->MutableData().data()), current_mem_offset));
284 : weight_offset_need_feeded_.insert(current_mem_offset);
285 : }
286 : }
287 : }
288 :
289 : Status ModelBuilder::AdjustConstWeightSize(const ge::NodePtr &node, size_t &mem_offset) {
290 : GE_CHECK_NOTNULL(node);
291 : if (node->GetType() == CONSTANT) {
292 : std::vector<GeTensorPtr> weights = OpDescUtils::MutableWeights(node);
293 : if (weights.empty()) {
294 : REPORT_INNER_ERR_MSG("E19999", "Check weights size of node %s(%s) is empty", node->GetName().c_str(),
295 : node->GetType().c_str());
296 : GELOGE(FAILED, "[Check][Param] weights size of node %s is empty", node->GetName().c_str());
297 : return FAILED;
298 : }
299 : GeTensorPtr weight = weights[0];
300 : if (weight == nullptr) {
301 : REPORT_INNER_ERR_MSG("E19999", "Check weight of node %s(%s) is nullptr", node->GetName().c_str(),
302 : node->GetType().c_str());
303 : GELOGE(FAILED, "[Check][Param] weights[0] is null, node:%s.", node->GetName().c_str());
304 : return FAILED;
305 : }
306 : GeTensorDesc &tensor_desc = weight->MutableTensorDesc();
307 : size_t output_size = weight->GetData().size();
308 : size_t current_mem_offset = mem_offset;
309 : bool find_same_const = false;
310 : ReuseWeightMem(output_size, weight, find_same_const, current_mem_offset);
311 : TensorUtils::SetDataOffset(tensor_desc, current_mem_offset);
312 : GELOGD("Node: %s, weight size: %zu, current_mem_offset: %zu", node->GetName().c_str(), output_size,
313 : current_mem_offset);
314 : if (!find_same_const) {
315 : mem_offset += output_size;
316 : }
317 : }
318 : return SUCCESS;
319 : }
320 :
321 : Status ModelBuilder::SetNodeFormatToND(const ge::OpDescPtr &node_op_desc) const {
322 : auto inputDescsPtr = node_op_desc->GetAllInputsDescPtr();
323 : auto outputDescsPtr = node_op_desc->GetAllOutputsDescPtr();
324 : ge::Format format = ge::FORMAT_ND;
325 : for (auto &inputDescPtr : inputDescsPtr) {
326 : GE_CHECK_NOTNULL(inputDescPtr);
327 : if (AttrUtils::HasAttr(*inputDescPtr, ATTR_NAME_ORIGIN_FORMAT_IS_SET)) {
328 : continue;
329 : }
330 : inputDescPtr->SetFormat(format);
331 : inputDescPtr->SetOriginFormat(format);
332 : }
333 : for (auto &outputDescPtr : outputDescsPtr) {
334 : GE_CHECK_NOTNULL(outputDescPtr);
335 : if (AttrUtils::HasAttr(*outputDescPtr, ATTR_NAME_ORIGIN_FORMAT_IS_SET)) {
336 : continue;
337 : }
338 : outputDescPtr->SetFormat(format);
339 : outputDescPtr->SetOriginFormat(format);
340 : }
341 : return SUCCESS;
342 : }
343 :
344 : // 图编译后期,在 CalcOutputSize里面对opdesc上面的输出size进行了padding
345 : // 32操作,但是实际weight申请内存时并没有做padding32操作 导致在加载期,会存在拷贝越界情况。实际修改我们padding
346 : // 32后做了512对齐,目的是确保下一个子图起始地址是512对齐的,不然copy性能会变差
347 : Status ModelBuilder::AlignWeightOffset() {
348 : GELOGD("Before alignment processing, weight_offset_ is %zu", weight_offset_);
349 : if (weight_offset_ > 0U) {
350 : const size_t padding_size = static_cast<size_t>(ge::TensorUtilsEx::GetPaddingSize());
351 : GE_CHK_STATUS_RET(CheckSizeTAddOverflow(weight_offset_, (padding_size + MEM_ALIGN_SIZE - 1)),
352 : "32-aligned weights overflow, weight_offset_ is %zu", weight_offset_);
353 : weight_offset_ = (weight_offset_ + padding_size + MEM_ALIGN_SIZE - 1) / MEM_ALIGN_SIZE * MEM_ALIGN_SIZE;
354 : }
355 : GELOGD("After add 32 and then do 512 alignment, weight_offset_ is %zu", weight_offset_);
356 : return SUCCESS;
357 : }
358 :
359 : Status ModelBuilder::SetInputOutputDesc() {
360 : Status ret;
361 : for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
362 : auto node_op_desc = n->GetOpDesc();
363 : GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue);
364 : const auto &type = node_op_desc->GetType();
365 : if (!is_loop_graph_ && (type == LOOPCOND)) {
366 : is_loop_graph_ = true;
367 : }
368 : // if user set input node format ND, the expected node for data and netoutput format is ND in
369 : // final graph.
370 : bool set_nd = (compute_graph_->GetParentGraph() == nullptr) &&
371 : (GetLocalOmgContext().format == domi::DOMI_TENSOR_ND) && (!node_op_desc->HasAttr("_is_single_op")) &&
372 : (OpTypeUtils::IsDataNode(type) || (type == NETOUTPUT));
373 : if (set_nd) {
374 : GE_CHK_STATUS_RET(SetNodeFormatToND(node_op_desc), "[Set][NodeFormatToND] failed");
375 : }
376 : if (OpTypeUtils::IsDataNode(type)) {
377 : GELOGD("Data node: %s.", n->GetName().c_str());
378 : continue;
379 : }
380 :
381 : GE_IF_BOOL_EXEC((n->GetInNodesSize() == 0U) && (n->GetOutNodesSize() == 0U), continue;);
382 : SetInputIsConst(n);
383 : bool is_unknow = false;
384 : (void)NodeUtils::GetNodeUnknownShapeStatus(*n, is_unknow);
385 : if ((IsGeLocalOp(n->GetOpDesc())) && (!is_unknow)) {
386 : GE_CHK_STATUS_RET(CalcOutputSize(n), "[Calc][OutputSize] failed, node:%s", n->GetName().c_str());
387 : }
388 : ret = AdjustConstWeightSize(n, weight_offset_);
389 : GE_CHK_STATUS_RET(ret, "[Adjust][ConstWeightSize] failed, node:%s", n->GetName().c_str());
390 :
391 : GE_IF_BOOL_EXEC(((weight_offset_ > 0) && (weight_offset_ % MEM_ALIGN_SIZE != 0)),
392 : weight_offset_ = (weight_offset_ + MEM_ALIGN_SIZE - 1) / MEM_ALIGN_SIZE * MEM_ALIGN_SIZE);
393 : }
394 : GE_CHK_STATUS_RET(AlignWeightOffset(), "[Align][WeightOffset] failed");
395 : GE_CHK_STATUS_RET(compute_graph_->TopologicalSorting(), "[Call][TopologicalSorting] failed, graph:%s",
396 : compute_graph_->GetName().c_str());
397 : return SUCCESS;
398 : }
399 :
400 : void ModelBuilder::AddNodeInputProperty() const {
401 : for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
402 : auto node_op_desc = node->GetOpDesc();
403 : GE_IF_BOOL_EXEC(node_op_desc == nullptr, GELOGW("node_op_desc is nullptr!"); return);
404 : std::vector<std::string> src_name_list;
405 : src_name_list.reserve(node->GetInNodesSize());
406 : std::vector<int64_t> src_index_list;
407 : src_index_list.reserve(node->GetInNodesSize());
408 :
409 : for (const auto in_data_anchor : node->GetAllInDataAnchorsPtr()) {
410 : const auto &peer_out_anchor = in_data_anchor->GetPeerOutAnchor();
411 : GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue);
412 : GE_IF_BOOL_EXEC(node_op_desc->HasAttr(MERGE_PRENODE_FLAG), continue);
413 :
414 : const auto src_node = peer_out_anchor->GetOwnerNodeBarePtr();
415 : src_name_list.emplace_back(src_node->GetName());
416 : src_index_list.emplace_back(peer_out_anchor->GetIdx());
417 : }
418 : auto in_control_anchor = node->GetInControlAnchor();
419 : if (in_control_anchor != nullptr) {
420 : std::string src_name_temp;
421 : for (const auto out_control_anchor : in_control_anchor->GetPeerOutControlAnchorsPtr()) {
422 : const auto src_node = out_control_anchor->GetOwnerNodeBarePtr();
423 : src_name_temp += src_name_temp.empty() ? src_node->GetName() : ":" + src_node->GetName();
424 : }
425 : GE_IF_BOOL_EXEC(!src_name_temp.empty(), src_name_list.emplace_back(src_name_temp);)
426 : }
427 : node_op_desc->SetSrcName(src_name_list);
428 : node_op_desc->SetSrcIndex(src_index_list);
429 : }
430 :
431 : for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
432 : const auto &node_op_desc = node->GetOpDesc();
433 : GE_IF_BOOL_EXEC(node_op_desc == nullptr, GELOGW("node_op_desc is nullptr!"); return);
434 : GE_IF_BOOL_EXEC(node_op_desc->GetType() == NETOUTPUT, continue);
435 : auto out_control_anchor = node->GetOutControlAnchor();
436 : GE_IF_BOOL_EXEC(out_control_anchor == nullptr, GELOGW("out_control_anchor is nullptr!"); return);
437 : std::vector<std::string> dst_name_list;
438 : dst_name_list.reserve(node->GetOutNodesSize());
439 : std::vector<int64_t> dst_index_list;
440 : dst_index_list.reserve(node->GetOutNodesSize());
441 : std::string dst_name_temp;
442 : for (const auto in_control_anchor : out_control_anchor->GetPeerInControlAnchorsPtr()) {
443 : const auto dst_node = in_control_anchor->GetOwnerNodeBarePtr(); // dst_node must not be null
444 : dst_name_temp += dst_name_temp.empty() ? dst_node->GetName() : ":" + dst_node->GetName();
445 : }
446 : GE_IF_BOOL_EXEC(!dst_name_temp.empty(), dst_name_list.emplace_back(dst_name_temp));
447 :
448 : GE_IF_BOOL_EXEC(!out_control_anchor->GetPeerInControlAnchorsPtr().empty(),
449 : dst_index_list.emplace_back(kInvalidIndexNum));
450 :
451 : for (const auto out_data_anchor : node->GetAllOutDataAnchorsPtr()) {
452 : GE_IF_BOOL_EXEC(node_op_desc->HasAttr(MERGE_PRENODE_FLAG), break);
453 : dst_name_temp = "";
454 : int64_t dst_index = kWrongIndex; // assign an impossible value to dst_index.
455 : for (const auto in_data_anchor : out_data_anchor->GetPeerInDataAnchorsPtr()) {
456 : GE_IF_BOOL_EXEC(in_data_anchor == nullptr, GELOGW("in_data_anchor is nullptr!"); return);
457 : const auto dst_node = in_data_anchor->GetOwnerNodeBarePtr(); // dst_node must not be null
458 : dst_name_temp += dst_name_temp.empty() ? dst_node->GetName() : ":" + dst_node->GetName();
459 : dst_index = in_data_anchor->GetIdx();
460 : }
461 : GE_IF_BOOL_EXEC(dst_index != kWrongIndex, dst_index_list.emplace_back(dst_index)); // not found
462 : GE_IF_BOOL_EXEC(!dst_name_temp.empty(), dst_name_list.emplace_back(dst_name_temp));
463 : }
464 : node_op_desc->SetDstName(dst_name_list);
465 : node_op_desc->SetDstIndex(dst_index_list);
466 : }
467 : }
468 :
469 : Status ModelBuilder::AdjustInputTensorFlag() const {
470 : for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
471 : if (OpTypeUtils::IsDataNode(n->GetType())) {
472 : GELOGD("Data node: %s.", n->GetName().c_str());
473 : for (const auto &anchor : n->GetAllOutDataAnchors()) {
474 : for (const auto &in_anchors : anchor->GetPeerInDataAnchors()) {
475 : GE_IF_BOOL_EXEC(in_anchors == nullptr, continue);
476 : auto owner_node_op_desc = in_anchors->GetOwnerNodeBarePtr()->GetOpDesc();
477 : GE_IF_BOOL_EXEC(owner_node_op_desc == nullptr, continue);
478 : const auto &input_desc = owner_node_op_desc->MutableInputDesc(in_anchors->GetIdx());
479 : if (input_desc == nullptr) {
480 : continue;
481 : }
482 : ge::TensorUtils::SetInputTensor(*input_desc, true);
483 : }
484 : }
485 : }
486 : }
487 : return SUCCESS;
488 : }
489 : Status ModelBuilder::InitL1FusionOption() {
490 : std::string buffer_optimize = "off_optimize";
491 : graphStatus ret = ge::GetContext().GetOption(BUFFER_OPTIMIZE, buffer_optimize);
492 : if (ret == GRAPH_SUCCESS) {
493 : bool off_superkernel = true; // 默认关闭
494 : (void)AttrUtils::GetBool(compute_graph_, ATTR_NAME_OFF_SUPERKERNEL_ATTR, off_superkernel);
495 : // l1fusion只有小海思才会使能,l1 fusion依赖superkernel使能进行绑核
496 : // 如果l1fusion的代码要使能,sgat组件会同步设置ATTR_NAME_OFF_SUPERKERNEL_ATTR为false来使能superkernel
497 : is_l1_fusion_enable_ = ((buffer_optimize == "l1_optimize") && (!off_superkernel));
498 : GELOGI("Compute graph %s the value of %s is %s, superkernel flag %d.", compute_graph_->GetName().c_str(),
499 : BUFFER_OPTIMIZE.c_str(), buffer_optimize.c_str(), is_l1_fusion_enable_);
500 : } else {
501 : GELOGW("The value of %s is empty.", kEnableL1Fusion);
502 : return SUCCESS;
503 : }
504 :
505 : if (is_l1_fusion_enable_) {
506 : std::string virtual_type = "0";
507 : ret = ge::GetContext().GetOption(VIRTUAL_TYPE, virtual_type);
508 : if ((ret == GRAPH_SUCCESS) && (virtual_type == "1")) {
509 : std::string situation = "L1_fusion is not supported in the virtual instance scenario";
510 : REPORT_PREDEFINED_ERR_MSG("E13024", std::vector<const char_t *>({"value", "env", "situation"}),
511 : std::vector<const char_t *>({virtual_type.c_str(), "VIRTUAL_TYPE", situation.c_str()}));
512 : GELOGE(FAILED, "BuildModelDef fail because l1fusion enable and virtual type is %s.", virtual_type.c_str());
513 : return FAILED;
514 : }
515 : GELOGW("Get virtual type ret %d , the type is %s.", ret, virtual_type.c_str());
516 : }
517 : GELOGI("Compute graph %s, l1fusion is %d.", compute_graph_->GetName().c_str(), is_l1_fusion_enable_);
518 : return SUCCESS;
519 : }
520 :
521 : Status ModelBuilder::BuildModelDef(ge::Model &model) {
522 : GE_ASSERT_SUCCESS(BuildModelDefForMem(model), "[Build][ModelDef] Part one failed!");
523 : GE_ASSERT_SUCCESS(BuildModelDefForStream(model), "[Build][ModelDef] Part two failed!");
524 : return SUCCESS;
525 : }
526 :
527 : Status ModelBuilder::BuildModelDefForMem(ge::Model &model) {
528 : ClearOriginalFormat();
529 :
530 : max_mem_offset_ = mem_type_to_mem_offset_[RT_MEMORY_HBM];
531 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_MEMORY_SIZE, max_mem_offset_),
532 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_MEMORY_SIZE.c_str());
533 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_MEMORY_SIZE.c_str()); return FAILED);
534 : auto mem_type_session_scope = (kSessionScopeMemory | RT_MEMORY_HBM);
535 : size_t session_scope_mem_offset = 0;
536 : std::map<uint64_t, size_t>::const_iterator it = mem_type_to_mem_offset_.find(mem_type_session_scope);
537 : if (it != mem_type_to_mem_offset_.cend()) {
538 : session_scope_mem_offset = it->second;
539 : }
540 : if (mem_type_to_mem_offset_.find(RT_MEMORY_P2P_DDR) != mem_type_to_mem_offset_.cend()) {
541 : p2p_mem_offset_ = mem_type_to_mem_offset_[RT_MEMORY_P2P_DDR];
542 : }
543 : if (mem_type_to_mem_offset_.find(RT_MEMORY_HOST) != mem_type_to_mem_offset_.cend()) {
544 : host_max_mem_offset_ = mem_type_to_mem_offset_[RT_MEMORY_HOST];
545 : }
546 : if (mem_type_to_mem_offset_.find(RT_MEMORY_HOST_SVM) != mem_type_to_mem_offset_.cend()) {
547 : host_svm_max_mem_offset_ = mem_type_to_mem_offset_[RT_MEMORY_HOST_SVM];
548 : }
549 :
550 : GE_CHK_BOOL_EXEC(
551 : ge::AttrUtils::SetInt(&model, ATTR_MODEL_SESSION_SCOPE_MEMORY_SIZE, session_scope_mem_offset),
552 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_SESSION_SCOPE_MEMORY_SIZE.c_str());
553 : GELOGE(FAILED, "SetInt of ATTR_NAME_SESSION_SCOPE_MEMORY_SIZE failed."); return FAILED);
554 : GE_CHK_BOOL_EXEC(
555 : ge::AttrUtils::SetInt(&model, MODEL_ATTR_TASK_GEN_HOST_BASE_ADDR, kMemoryHostFeatureMapLogicBase),
556 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", MODEL_ATTR_TASK_GEN_HOST_BASE_ADDR.c_str());
557 : GELOGE(FAILED, "[Set][Attr] %s in model failed", MODEL_ATTR_TASK_GEN_HOST_BASE_ADDR.c_str()); return FAILED);
558 : GE_CHECK_GE(host_max_mem_offset_, kMemoryHostFeatureMapLogicBase);
559 : const auto host_memory_size = host_max_mem_offset_ - kMemoryHostFeatureMapLogicBase;
560 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, MODEL_ATTR_HOST_MEMORY_SIZE, host_memory_size),
561 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", MODEL_ATTR_HOST_MEMORY_SIZE.c_str());
562 : GELOGE(FAILED, "[Set][Attr] %s in model failed", MODEL_ATTR_HOST_MEMORY_SIZE.c_str());
563 : return FAILED);
564 : GE_CHK_BOOL_EXEC(
565 : ge::AttrUtils::SetInt(&model, MODEL_ATTR_TASK_GEN_HOST_SVM_BASE_ADDR, kMemoryHostSVMFeatureMapLogicBase),
566 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", MODEL_ATTR_TASK_GEN_HOST_SVM_BASE_ADDR.c_str());
567 : GELOGE(FAILED, "[Set][Attr] %s in model failed", MODEL_ATTR_TASK_GEN_HOST_SVM_BASE_ADDR.c_str()); return FAILED);
568 : GE_CHECK_GE(host_svm_max_mem_offset_, kMemoryHostSVMFeatureMapLogicBase);
569 : const auto host_svm_memory_size = host_svm_max_mem_offset_ - kMemoryHostSVMFeatureMapLogicBase;
570 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, MODEL_ATTR_HOST_SVM_SIZE, host_svm_memory_size),
571 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", MODEL_ATTR_HOST_SVM_SIZE.c_str());
572 : GELOGE(FAILED, "[Set][Attr] %s in model failed", MODEL_ATTR_HOST_SVM_SIZE.c_str()); return FAILED);
573 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_P2P_MEMORY_SIZE, p2p_mem_offset_),
574 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_P2P_MEMORY_SIZE.c_str());
575 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_P2P_MEMORY_SIZE.c_str()); return FAILED);
576 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_WEIGHT_SIZE, weight_offset_),
577 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_WEIGHT_SIZE.c_str());
578 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_WEIGHT_SIZE.c_str()); return FAILED);
579 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_NOTIFY_NUM, notify_num_),
580 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_NOTIFY_NUM.c_str());
581 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_NOTIFY_NUM.c_str()); return FAILED);
582 : GE_ASSERT_TRUE(ge::AttrUtils::SetListInt(&model, ATTR_MODEL_NOTIFY_TYPES, notify_types_));
583 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_EVENT_NUM, event_num_),
584 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_EVENT_NUM.c_str());
585 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_EVENT_NUM.c_str()); return FAILED);
586 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetInt(&model, ATTR_MODEL_LABEL_NUM, label_num_),
587 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_LABEL_NUM.c_str());
588 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_LABEL_NUM.c_str()); return FAILED);
589 : GE_CHK_BOOL_EXEC(
590 : ge::AttrUtils::SetInt(&model, ATTR_MODEL_ZERO_COPY_MEMORY_SIZE, zero_copy_mem_size_),
591 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_ZERO_COPY_MEMORY_SIZE.c_str());
592 : GELOGE(FAILED, "[Set][Attr] %s in model failed.", ATTR_MODEL_ZERO_COPY_MEMORY_SIZE.c_str()); return FAILED);
593 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListStr(&model, ATTR_MODEL_OUT_NODES_NAME, GetLocalOmgContext().net_out_nodes),
594 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_OUT_NODES_NAME.c_str());
595 : GELOGE(FAILED, "[Set][Str] %s in model failed.", ATTR_MODEL_OUT_NODES_NAME.c_str()); return FAILED);
596 : (void)ge::AttrUtils::SetListListInt(&model, ATTR_MODEL_SUB_MEMORY_INFO, sub_mem_offsets_);
597 :
598 : // Set output reuse input memory indexes from option
599 : std::string output_reuse_input_mem_indexes;
600 : if (ge::GetContext().GetOption(OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES, output_reuse_input_mem_indexes) == SUCCESS) {
601 : if (!output_reuse_input_mem_indexes.empty()) {
602 : if (!ge::AttrUtils::SetStr(&model, ATTR_MODEL_OUTPUT_REUSE_INPUT_MEM_INDEXES, output_reuse_input_mem_indexes)) {
603 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed",
604 : ATTR_MODEL_OUTPUT_REUSE_INPUT_MEM_INDEXES.c_str());
605 : GELOGE(FAILED, "[Set][Str] %s in model failed", ATTR_MODEL_OUTPUT_REUSE_INPUT_MEM_INDEXES.c_str());
606 : return FAILED;
607 : }
608 : GELOGI("Set attr output_reuse_input_mem_indexes to model, value is %s.", output_reuse_input_mem_indexes.c_str());
609 : }
610 : }
611 :
612 : GELOGI(
613 : "For model, max_mem_offset: %zu, host_max_mem_offset: %zu, host_svm_max_mem_offset: %zu, p2p_mem_size: %zu, "
614 : "zero_copy_mem_size: %zu, "
615 : "session_scope_mem_size: %zu",
616 : max_mem_offset_, host_max_mem_offset_, host_svm_max_mem_offset_, p2p_mem_offset_, zero_copy_mem_size_,
617 : session_scope_mem_offset);
618 : std::string fp_ceiling_mode;
619 : if (ge::GetContext().GetOption("ge.fpCeilingMode", fp_ceiling_mode) == SUCCESS) {
620 : if (!ge::AttrUtils::SetStr(&model, ATTR_FP_CEILING_MODE, fp_ceiling_mode)) {
621 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_FP_CEILING_MODE.c_str());
622 : GELOGE(FAILED, "[Set][Str] %s in model failed", ATTR_FP_CEILING_MODE.c_str());
623 : return FAILED;
624 : }
625 : GELOGI("Set attr ATTR_FP_CEILING_MODE to model, value is %s.", fp_ceiling_mode.c_str());
626 : }
627 :
628 : std::string ge_core_type;
629 : Status ret = ge::GetContext().GetOption(kCoreType, ge_core_type);
630 : if (ret != SUCCESS) {
631 : GELOGW("get the option CORE_TYPE fail, set it to default value VECTOR_ENGINE");
632 : }
633 : int64_t core_type = (ge_core_type == kVectorCore) ? 1 : 0;
634 : GELOGI("core_type: %ld", core_type);
635 : if (!ge::AttrUtils::SetInt(&model, ATTR_MODEL_CORE_TYPE, core_type)) {
636 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_MODEL_CORE_TYPE.c_str());
637 : GELOGE(FAILED, "[Set][Attr] %s in model failed", ATTR_MODEL_CORE_TYPE.c_str());
638 : }
639 : GE_CHK_STATUS_RET_NOLOG(InitL1FusionOption());
640 :
641 : GE_CHK_BOOL_EXEC(
642 : ge::AttrUtils::SetBool(&model, ATTR_NAME_SWITCH_FOR_L1_FUSION, is_l1_fusion_enable_),
643 : REPORT_INNER_ERR_MSG("E19999", "Set Attr:%s in model failed", ATTR_NAME_SWITCH_FOR_L1_FUSION.c_str());
644 : GELOGE(FAILED, "[Set][Attr] %s in model failed.", ATTR_NAME_SWITCH_FOR_L1_FUSION.c_str()); return FAILED);
645 :
646 : model.SetName(compute_graph_->GetName());
647 : model.SetGraph(compute_graph_);
648 : GELOGI("weight_offset_: %zu event_num: %ld notify_num: %ld.", weight_offset_, event_num_, notify_num_);
649 :
650 : if (Params::Instance() == nullptr) {
651 : return FAILED;
652 : }
653 :
654 : platform_type_ = Params::Instance()->GetTarget_8bit();
655 : return SUCCESS;
656 : }
657 :
658 : void ModelBuilder::ClearOriginalFormat() const {
659 : for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
660 : auto node_op_desc = n->GetOpDesc();
661 : if (node_op_desc != nullptr) {
662 : if (node_op_desc->HasAttr(ATTR_NAME_FORMAT)) {
663 : if (node_op_desc->DelAttr(ATTR_NAME_FORMAT) != SUCCESS) {
664 : GELOGW("DelAttr ATTR_NAME_FORMAT failed.");
665 : }
666 : }
667 :
668 : GE_IF_BOOL_EXEC(
669 : node_op_desc->HasAttr(ATTR_NAME_INFERRED_FORMAT),
670 : if (node_op_desc->DelAttr(ATTR_NAME_INFERRED_FORMAT) != SUCCESS) {
671 : GELOGW("DelAttr ATTR_NAME_INFERRED_FORMAT failed.");
672 : });
673 :
674 : GE_IF_BOOL_EXEC(
675 : node_op_desc->HasAttr(ATTR_NAME_PRED_PERMUTE_DELETED),
676 : if (node_op_desc->DelAttr(ATTR_NAME_PRED_PERMUTE_DELETED) != SUCCESS) {
677 : GELOGW("DelAttr ATTR_NAME_PRED_PERMUTE_DELETED failed.");
678 : });
679 :
680 : GE_IF_BOOL_EXEC(
681 : node_op_desc->HasAttr(ATTR_NAME_IGNORE_PRED_FORMAT),
682 : if (node_op_desc->DelAttr(ATTR_NAME_IGNORE_PRED_FORMAT) != SUCCESS) {
683 : GELOGW("DelAttr ATTR_NAME_IGNORE_PRED_FORMAT failed.");
684 : });
685 : }
686 : }
687 : }
688 :
689 : Status ModelBuilder::MergeWeights() {
690 : if (weight_offset_ == 0) {
691 : return SUCCESS;
692 : }
693 :
694 : ge::Buffer buffer(weight_offset_);
695 : weight_buffer_ = buffer;
696 : auto base_addr = weight_buffer_.GetData();
697 :
698 : for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
699 : auto op_desc = node->GetOpDesc();
700 : GE_IF_BOOL_EXEC(op_desc == nullptr, continue);
701 : if (node->GetType() != CONSTANT) {
702 : continue;
703 : }
704 :
705 : // Get const op weight pointer
706 : ge::GeTensorPtr weight = nullptr;
707 : // If MutableTensor failed, weight is nullptr.
708 : (void)ge::AttrUtils::MutableTensor(op_desc, ATTR_NAME_WEIGHTS, weight);
709 : if (weight == nullptr) {
710 : REPORT_INNER_ERR_MSG("E19999", "Can't get const weight in op:%s(%s)", op_desc->GetName().c_str(),
711 : op_desc->GetType().c_str());
712 : GELOGE(FAILED, "[Call][MutableTensor] Can't get const op weight, name:%s", node->GetName().c_str());
713 : return FAILED;
714 : }
715 :
716 : // Get const op weight offset
717 : int64_t offset = 0;
718 : if (ge::TensorUtils::GetDataOffset(weight->GetTensorDesc(), offset) != SUCCESS) {
719 : GELOGW("Can't get const op offset, name: %s", node->GetName().c_str());
720 : continue; // continue to merge if cannot get offset
721 : }
722 :
723 : // Get const op weight data
724 : auto weight_data = weight->MutableData();
725 :
726 : // copy const op weight data to buffer
727 : GELOGI("Move to buffer, name: %s offset: %ld size: %zu", node->GetName().c_str(), offset, weight_data.size());
728 : ge::TensorUtils::SetWeightSize(weight->MutableTensorDesc(), static_cast<int64_t>(weight_data.size()));
729 : if ((offset == 0) || (weight_data.size() == 0)) {
730 : GELOGI("Size or offset is 0. size: %lu offset: %ld", weight_data.size(), offset);
731 : continue;
732 : }
733 : if (weight_offset_need_feeded_.find(static_cast<size_t>(offset)) == weight_offset_need_feeded_.end()) {
734 : GELOGI("name %s weight offset mem %ld has been fed, no need fed again", node->GetName().c_str(), offset);
735 : weight->ClearData();
736 : continue;
737 : }
738 : if (weight_data.data() != nullptr) {
739 : GE_IF_BOOL_EXEC(base_addr == nullptr,
740 : REPORT_INNER_ERR_MSG("E19999", "Check weight in op:%s(%s) is nullptr", op_desc->GetName().c_str(),
741 : op_desc->GetType().c_str());
742 : GELOGE(FAILED, "[Check][Param] weight in op:%s(%s) is nullptr", op_desc->GetName().c_str(),
743 : op_desc->GetType().c_str());
744 : return FAILED);
745 : if (weight_offset_ - offset < weight_data.size()) {
746 : REPORT_INNER_ERR_MSG("E19999", "left weight size not enough for op:%s(%s) left_size:%zu, weight_size:%zu",
747 : op_desc->GetName().c_str(), op_desc->GetType().c_str(), weight_offset_ - offset,
748 : weight_data.size());
749 : GELOGE(FAILED, "[Check][Param] left weight size not enough for op:%s(%s). left_size:%lu, weight_size:%lu",
750 : op_desc->GetName().c_str(), op_desc->GetType().c_str(), weight_offset_ - offset, weight_data.size());
751 : return FAILED;
752 : }
753 : uintptr_t dst_ptr = reinterpret_cast<uintptr_t>(base_addr) + offset;
754 : uintptr_t src_ptr = reinterpret_cast<uintptr_t>(weight_data.data());
755 : size_t left_size = weight_data.size();
756 : while (left_size > SECUREC_MEM_MAX_LEN) {
757 : auto err = memcpy_s(reinterpret_cast<void *>(dst_ptr), SECUREC_MEM_MAX_LEN, reinterpret_cast<void *>(src_ptr),
758 : SECUREC_MEM_MAX_LEN);
759 : GE_ASSERT_EOK(err, "mem copy failed. err_ret:%d, dst_ptr:%lx, dst_size:%lu, src_ptr:%lx, src_size:%lu", err,
760 : dst_ptr, SECUREC_MEM_MAX_LEN, src_ptr, SECUREC_MEM_MAX_LEN);
761 : left_size -= SECUREC_MEM_MAX_LEN;
762 : dst_ptr = dst_ptr + SECUREC_MEM_MAX_LEN;
763 : src_ptr = src_ptr + SECUREC_MEM_MAX_LEN;
764 : }
765 : auto err = memcpy_s(reinterpret_cast<void *>(dst_ptr), left_size, reinterpret_cast<void *>(src_ptr), left_size);
766 : GE_ASSERT_EOK(err, "mem copy failed. err ret:%d, dst_ptr:%lx, dst_size:%lu, src_ptr:%lx, src_size:%lu,", err,
767 : dst_ptr, SECUREC_MEM_MAX_LEN, src_ptr, SECUREC_MEM_MAX_LEN);
768 : weight_offset_need_feeded_.erase(static_cast<size_t>(offset));
769 : }
770 : weight->ClearData();
771 : }
772 :
773 : return SUCCESS;
774 : }
775 :
776 : Status ModelBuilder::SavaAtomicWorkspace(const OpDescPtr &op_desc) const {
777 : auto workspace_info =
778 : op_desc->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, std::map<std::string, std::map<int64_t, int64_t>>{});
779 : if (workspace_info.empty()) {
780 : return SUCCESS;
781 : }
782 : GeAttrValue::NAMED_ATTRS workspaces;
783 : for (const auto &iter : workspace_info) {
784 : const std::string &op_name = iter.first;
785 : const auto &index_offset_map = iter.second;
786 : std::vector<int64_t> value;
787 : for (const auto &iter2 : index_offset_map) {
788 : value.emplace_back(iter2.first);
789 : value.emplace_back(iter2.second);
790 : }
791 : workspaces.SetAttr(op_name, GeAttrValue::CreateFrom<GeAttrValue::LIST_INT>(value));
792 : }
793 : (void)AttrUtils::SetNamedAttrs(op_desc, EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspaces);
794 : return SUCCESS;
795 : }
796 :
797 : Status ModelBuilder::SaveAtomicTBEKernel(const OpDescPtr &op_desc) {
798 : ge::NodePtr atomic_clean_node = nullptr;
799 : atomic_clean_node = op_desc->TryGetExtAttr("memset_node_ptr", atomic_clean_node);
800 : if (atomic_clean_node == nullptr) {
801 : return SUCCESS;
802 : }
803 :
804 : ge::OpDescPtr atomic_op_desc = atomic_clean_node->GetOpDesc();
805 : GE_CHECK_NOTNULL(atomic_op_desc);
806 : TBEKernelPtr tbe_kernel = atomic_op_desc->TryGetExtAttr(ge::OP_EXTATTR_NAME_TBE_KERNEL, TBEKernelPtr());
807 : if (tbe_kernel == nullptr) {
808 : std::string kernel_name;
809 : Buffer kernel_buffer;
810 : (void)AttrUtils::GetStr(atomic_op_desc, ATTR_NAME_TBE_KERNEL_NAME, kernel_name);
811 : (void)AttrUtils::GetBytes(atomic_op_desc, ATTR_NAME_TBE_KERNEL_BUFFER, kernel_buffer);
812 : if (!kernel_name.empty() && (kernel_buffer.GetSize() > 0)) {
813 : GE_CHECK_NOTNULL(kernel_buffer.GetData());
814 : std::vector<char> data(kernel_buffer.GetData(), kernel_buffer.GetData() + kernel_buffer.GetSize());
815 : tbe_kernel = MakeShared<OpKernelBin>(kernel_name, std::move(data));
816 : GE_CHECK_NOTNULL(tbe_kernel);
817 : GELOGI("Node [%s][%s] start recovery extra attr %s from %s", atomic_op_desc->GetName().c_str(),
818 : atomic_op_desc->GetType().c_str(), ge::OP_EXTATTR_NAME_TBE_KERNEL, ATTR_NAME_TBE_KERNEL_NAME.c_str());
819 : if (!(atomic_op_desc->SetExtAttr(ge::OP_EXTATTR_NAME_TBE_KERNEL, tbe_kernel))) {
820 : std::string error = "Node" + FmtToStr(atomic_op_desc->GetName()) + "set extra tbeKernel attr failed";
821 : GE_ERRORLOG_AND_ERRORMSG(ge::FAILED, error.c_str());
822 : return ge::FAILED;
823 : }
824 : }
825 : }
826 : if (tbe_kernel == nullptr) {
827 : GELOGD("Atomic_clean_node doesn't have tbe_kernel.");
828 : return SUCCESS;
829 : }
830 : auto atomic_kernel_key = kAtomicPrefix + std::string(ge::OP_EXTATTR_NAME_TBE_KERNEL);
831 : if (!(op_desc->SetExtAttr(atomic_kernel_key, tbe_kernel))) {
832 : std::string error = "Node" + FmtToStr(atomic_op_desc->GetName()) + "set extra tbeKernel attr failed";
833 : GE_ERRORLOG_AND_ERRORMSG(ge::FAILED, error.c_str());
834 : return ge::FAILED;
835 : }
836 :
837 : GE_ASSERT_SUCCESS(AddTBEKernelToStore(op_desc, tbe_kernel, "atomic"));
838 : GELOGD("Atomic_clean_node tbe_kernel_name %s!", tbe_kernel->GetName().c_str());
839 : (void)AttrUtils::SetStr(op_desc, ATOMIC_ATTR_TBE_KERNEL_NAME, tbe_kernel->GetName());
840 :
841 : std::string kernel_name;
842 : (void)AttrUtils::GetStr(atomic_op_desc, atomic_op_desc->GetName() + "_kernelname", kernel_name);
843 : // Compat for compiler changes: remove prefix (node name) of attr name for symbol of kernel elf
844 : if (kernel_name.empty()) {
845 : (void)AttrUtils::GetStr(atomic_op_desc, kAttrEntrySymbolOfElf, kernel_name);
846 : }
847 : (void)AttrUtils::SetStr(op_desc, op_desc->GetName() + "_atomic_kernelname", kernel_name);
848 : std::string kernel_name_for_atomic = kAtomicPrefix + op_desc->GetName() + "_kernelname";
849 : (void)AttrUtils::SetStr(op_desc, kernel_name_for_atomic, kernel_name);
850 : GELOGI("op %s set attr name %s", op_desc->GetName().c_str(), kernel_name_for_atomic.c_str());
851 :
852 : std::string meta_data;
853 : (void)AttrUtils::GetStr(atomic_op_desc, TVM_ATTR_NAME_METADATA, meta_data);
854 : (void)AttrUtils::SetStr(op_desc, ATOMIC_ATTR_TVM_METADATA, meta_data);
855 : std::string meta_data_for_atomic = kAtomicPrefix + TVM_ATTR_NAME_METADATA;
856 : (void)AttrUtils::SetStr(op_desc, meta_data_for_atomic, meta_data);
857 : GELOGI("op %s set attr name %s", op_desc->GetName().c_str(), meta_data_for_atomic.c_str());
858 :
859 : std::string json_string;
860 : (void)AttrUtils::GetStr(atomic_op_desc, TVM_ATTR_NAME_MAGIC, json_string);
861 : (void)AttrUtils::SetStr(op_desc, ATOMIC_ATTR_TVM_MAGIC, json_string);
862 : std::string json_string_for_atomic = kAtomicPrefix + TVM_ATTR_NAME_MAGIC;
863 : (void)AttrUtils::SetStr(op_desc, json_string_for_atomic, json_string);
864 : GELOGI("op %s set attr name %s", op_desc->GetName().c_str(), json_string_for_atomic.c_str());
865 : return SUCCESS;
866 : }
867 :
868 : Status ModelBuilder::AddTBEKernelToStore(const OpDescPtr &op_desc, const TBEKernelPtr &tbe_kernel,
869 : const std::string &kernel_type) {
870 : if (tbe_kernel == nullptr) {
871 : return SUCCESS;
872 : }
873 : // TBEKernelStore 以 kernel name 为键,并保留最后写入的 bin。这里记录当前 bin 的归属及来源,
874 : // 用于在不改变原有 last-writer-wins 行为的前提下,诊断同名不同 bin 的覆盖场景。
875 : const std::string &kernel_name = tbe_kernel->GetName();
876 : const bool is_custom = op_desc->GetOpKernelLibName() == ge::kCustomOpKernelLibName;
877 : const auto origin_iter = tbe_kernel_origins_.find(kernel_name);
878 : const bool previous_is_custom = (origin_iter != tbe_kernel_origins_.end()) && origin_iter->second.is_custom;
879 : // 该标记描述当前 bin 内容是否曾被自定义算子使用,而不是 kernel name 是否曾被自定义算子使用。
880 : // 因此,当前 bin 被不同内容覆盖后,不会继续传递与新 bin 无关的自定义算子历史。
881 : const bool previous_bin_has_custom_user =
882 : (origin_iter != tbe_kernel_origins_.end()) && origin_iter->second.current_bin_has_custom_user;
883 : const auto existing_kernel = tbe_kernel_store_.FindKernel(kernel_name);
884 : const bool is_same_kernel_bin = (existing_kernel != nullptr) && IsSameKernelBin(existing_kernel, tbe_kernel);
885 : if ((existing_kernel != nullptr) && !is_same_kernel_bin && (previous_bin_has_custom_user || is_custom)) {
886 : const std::string previous_op_name =
887 : (origin_iter == tbe_kernel_origins_.end()) ? "unknown" : origin_iter->second.op_name;
888 : const std::string previous_op_type =
889 : (origin_iter == tbe_kernel_origins_.end()) ? "unknown" : origin_iter->second.op_type;
890 : const std::string previous_kernel_type =
891 : (origin_iter == tbe_kernel_origins_.end()) ? "unknown" : origin_iter->second.kernel_type;
892 : GELOGW(
893 : "Custom-related TBE kernel collision, kernel_name:%s, previous_op:%s(%s), previous_op_is_custom:%s, "
894 : "previous_kernel_type:%s, previous_bin_size:%zu, current_op:%s(%s), current_op_is_custom:%s, "
895 : "current_kernel_type:%s, current_bin_size:%zu. ",
896 : kernel_name.c_str(), previous_op_name.c_str(), previous_op_type.c_str(), previous_is_custom ? "true" : "false",
897 : previous_kernel_type.c_str(), existing_kernel->GetBinDataSize(), op_desc->GetNamePtr(), op_desc->GetTypePtr(),
898 : is_custom ? "true" : "false", kernel_type.c_str(), tbe_kernel->GetBinDataSize());
899 : }
900 : tbe_kernel_store_.AddTBEKernel(tbe_kernel);
901 : // 相同内容的写入继承已有 bin 的来源;不同内容的写入则以当前算子为起点重新记录来源,
902 : // 避免早先的自定义算子 bin 导致后续无关 bin 产生告警。
903 : const bool current_bin_has_custom_user = is_custom || (is_same_kernel_bin && previous_bin_has_custom_user);
904 : tbe_kernel_origins_[kernel_name] = {is_custom, current_bin_has_custom_user, op_desc->GetName(), op_desc->GetType(),
905 : kernel_type};
906 : return SUCCESS;
907 : }
908 :
909 : Status ModelBuilder::SaveNormalTBEKernel(const OpDescPtr &op_desc) {
910 : TBEKernelPtr tbe_kernel = op_desc->TryGetExtAttr(OP_EXTATTR_NAME_TBE_KERNEL, TBEKernelPtr());
911 : if (tbe_kernel == nullptr) {
912 : tbe_kernel = CreateOpTBEKernel(op_desc, "");
913 : }
914 : if (tbe_kernel == nullptr) {
915 : return SUCCESS; // Not TBE node.
916 : }
917 : (void)AttrUtils::SetStr(op_desc, "_kernelname", tbe_kernel->GetName());
918 : GE_ASSERT_SUCCESS(AddTBEKernelToStore(op_desc, tbe_kernel, "normal"));
919 :
920 : // Compat for compiler changes: remove prefix (node name) of attr name for symbol of kernel elf
921 : std::string symbol_of_elf;
922 : if (AttrUtils::GetStr(op_desc, kAttrEntrySymbolOfElf, symbol_of_elf) && !symbol_of_elf.empty()) {
923 : GE_ASSERT_TRUE(AttrUtils::SetStr(op_desc, op_desc->GetName() + kAttrEntrySymbolOfElf, symbol_of_elf));
924 : }
925 : return SUCCESS;
926 : }
927 :
928 : Status ModelBuilder::SaveCustAiCpuKernel(const OpDescPtr &op_desc, std::set<std::string> &aicpu_name_set) {
929 : const auto cust_aicpu_kernel = op_desc->TryGetExtAttr(OP_EXTATTR_CUSTAICPU_KERNEL, CustAICPUKernelPtr());
930 : if (cust_aicpu_kernel == nullptr) {
931 : return SUCCESS; // Not cust aicpu node.
932 : }
933 :
934 : if (aicpu_name_set.count(cust_aicpu_kernel->GetName()) > 0) {
935 : REPORT_PREDEFINED_ERR_MSG(
936 : "E10001", std::vector<const char_t *>({"value", "parameter", "reason"}),
937 : std::vector<const char_t *>({cust_aicpu_kernel->GetName().c_str(), op_desc->GetName().c_str(),
938 : "Parameter aicpu_kernel_name must be unique."}));
939 : GELOGE(FAILED, "[Check][Param] aicpu_kernel name %s can't be the same, judge for op:%s(%s)",
940 : cust_aicpu_kernel->GetName().c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
941 : return FAILED;
942 : }
943 : aicpu_name_set.insert(cust_aicpu_kernel->GetName());
944 : cust_aicpu_kernel_store_.AddCustAICPUKernel(cust_aicpu_kernel);
945 : GELOGI("Add cust aicpu kernel bin %s", cust_aicpu_kernel->GetName().c_str());
946 : return SUCCESS;
947 : }
948 :
949 : Status ModelBuilder::SaveFftsPlusTBEKernel(const OpDescPtr &op_desc) {
950 : const auto thread_tbe_kernel =
951 : op_desc->TryGetExtAttr(OP_EXTATTR_NAME_THREAD_TBE_KERNEL, std::vector<OpKernelBinPtr>{});
952 : for (size_t i = 0UL; i < thread_tbe_kernel.size(); ++i) {
953 : GE_ASSERT_SUCCESS(AddTBEKernelToStore(op_desc, thread_tbe_kernel[i], "thread"));
954 : }
955 :
956 : const auto SaveMixTBE = [&op_desc, this](const std::string &prefix, const std::string &core_type) -> Status {
957 : TBEKernelPtr tbe_kernel = op_desc->TryGetExtAttr(prefix + OP_EXTATTR_NAME_TBE_KERNEL, TBEKernelPtr());
958 : if (tbe_kernel == nullptr) {
959 : tbe_kernel = CreateOpTBEKernel(op_desc, prefix);
960 : }
961 : GE_CHECK_NOTNULL(tbe_kernel);
962 : GE_ASSERT_SUCCESS(AddTBEKernelToStore(op_desc, tbe_kernel, core_type));
963 : GELOGD("Add %s kernel bin, Op(%s:%s)", core_type.c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
964 : return SUCCESS;
965 : };
966 :
967 : std::vector<std::string> names_prefix;
968 : (void)AttrUtils::GetListStr(op_desc, ATTR_NAME_KERNEL_NAMES_PREFIX, names_prefix);
969 : if (!names_prefix.empty()) {
970 : std::string core_type;
971 : (void)AttrUtils::GetStr(op_desc, ATTR_NAME_CUBE_VECTOR_CORE_TYPE, core_type);
972 : for (const auto &prefix : names_prefix) {
973 : GE_CHK_STATUS_RET_NOLOG(SaveMixTBE(prefix, core_type));
974 : }
975 : }
976 :
977 : return SUCCESS;
978 : }
979 :
980 : TBEKernelPtr ModelBuilder::CreateOpTBEKernel(const OpDescPtr &op_desc, const std::string &prefix_kernel_name) const {
981 : std::string kernel_name;
982 : Buffer kernel_buffer;
983 : TBEKernelPtr tbe_kernel = nullptr;
984 : (void)AttrUtils::GetStr(op_desc, prefix_kernel_name + ATTR_NAME_TBE_KERNEL_NAME, kernel_name);
985 : (void)AttrUtils::GetBytes(op_desc, prefix_kernel_name + ATTR_NAME_TBE_KERNEL_BUFFER, kernel_buffer);
986 : if (!kernel_name.empty() && (kernel_buffer.GetSize() > 0U)) {
987 : if (kernel_buffer.GetData() == nullptr) {
988 : GELOGW("kernel data of op:%s(%s) is nullptr", op_desc->GetName().c_str(), op_desc->GetType().c_str());
989 : return nullptr;
990 : }
991 : std::vector<char> data(kernel_buffer.GetData(), kernel_buffer.GetData() + kernel_buffer.GetSize());
992 : tbe_kernel = MakeShared<OpKernelBin>(kernel_name, std::move(data));
993 : GE_CHK_BOOL_EXEC(tbe_kernel != nullptr, return nullptr, "[Create][TBEKernel] failed");
994 : const std::string ext_attr_name = prefix_kernel_name + OP_EXTATTR_NAME_TBE_KERNEL;
995 : if (!op_desc->SetExtAttr(ext_attr_name, tbe_kernel)) {
996 : GELOGW("set ext attr:%s for op:%s(%s) failed", ext_attr_name.c_str(), op_desc->GetName().c_str(),
997 : op_desc->GetType().c_str());
998 : return nullptr;
999 : }
1000 : }
1001 : return tbe_kernel;
1002 : }
1003 :
1004 : Status ModelBuilder::SaveDataToModel(ge::Model &model, ge::GeModel &ge_model) {
1005 : // Add weight
1006 : ge_model.SetWeight(weight_buffer_);
1007 :
1008 : // Add TBE Kernels and custom aicpu op bin
1009 : std::set<std::string> aicpu_name_set;
1010 : std::set<std::string> aicpu_op_types;
1011 : std::set<std::string> aicpu_tf_op_types;
1012 : for (const auto &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
1013 : const auto node_op_desc = node->GetOpDesc();
1014 : GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue);
1015 : // check aicpu op type
1016 : CollectCheckAicpuAttr(node_op_desc, aicpu_op_types, aicpu_tf_op_types);
1017 : GE_CHK_STATUS_RET_NOLOG(SaveNormalTBEKernel(node_op_desc));
1018 : GE_CHK_STATUS_RET_NOLOG(SaveCustAiCpuKernel(node_op_desc, aicpu_name_set));
1019 : GE_CHK_STATUS_RET_NOLOG(SaveFftsPlusTBEKernel(node_op_desc));
1020 : GE_CHK_STATUS_RET(SaveAtomicTBEKernel(node_op_desc),
1021 : "[Save][TBEKernel] Node[%s] type[%s] save atomic tbekernel failed!",
1022 : node_op_desc->GetName().c_str(), node_op_desc->GetType().c_str());
1023 : GE_CHK_STATUS_RET(SavaAtomicWorkspace(node_op_desc),
1024 : "[Save][TBEKernel] Node[%s] type[%s] save atomic work space failed!",
1025 : node_op_desc->GetName().c_str(), node_op_desc->GetType().c_str());
1026 :
1027 : if ((!compute_graph_->GetGraphUnknownFlag()) || (node_op_desc->GetType() != PARTITIONEDCALL)) {
1028 : continue;
1029 : }
1030 : // For dynamic FFTS-Plus subgraph node.
1031 : if (node_op_desc->HasAttr(ATTR_NAME_FFTS_SUB_GRAPH) || node_op_desc->HasAttr(ATTR_NAME_FFTS_PLUS_SUB_GRAPH)) {
1032 : const auto sgt_graph = compute_graph_->GetSubgraph(node_op_desc->GetSubgraphInstanceName(0U));
1033 : GE_IF_BOOL_EXEC(sgt_graph == nullptr, continue);
1034 : for (const auto &sgt_node : sgt_graph->GetAllNodes()) {
1035 : const auto sgt_op_desc = sgt_node->GetOpDesc();
1036 : GE_IF_BOOL_EXEC(sgt_op_desc == nullptr, continue);
1037 : GE_CHK_STATUS_RET_NOLOG(SaveNormalTBEKernel(sgt_op_desc));
1038 : GE_CHK_STATUS_RET_NOLOG(SaveCustAiCpuKernel(sgt_op_desc, aicpu_name_set));
1039 : GE_CHK_STATUS_RET_NOLOG(SaveFftsPlusTBEKernel(sgt_op_desc));
1040 : GE_CHK_STATUS_RET_NOLOG(SaveAtomicTBEKernel(sgt_op_desc));
1041 : GE_CHK_STATUS_RET_NOLOG(SavaAtomicWorkspace(sgt_op_desc));
1042 : }
1043 : }
1044 : }
1045 :
1046 : SetModelCheckAicpuAttr(model, aicpu_op_types, aicpu_tf_op_types);
1047 :
1048 : if (!tbe_kernel_store_.Build()) {
1049 : GELOGE(FAILED, "[Call][Build] TBE Kernels store build failed!");
1050 : return FAILED;
1051 : }
1052 : if (!cust_aicpu_kernel_store_.Build()) {
1053 : GELOGE(FAILED, "[Call][Build] custom AICPU kernels store build failed!");
1054 : return FAILED;
1055 : }
1056 : ge_model.SetTBEKernelStore(tbe_kernel_store_);
1057 : ge_model.SetCustAICPUKernelStore(cust_aicpu_kernel_store_);
1058 : DelNodeRepeatSaveAttr();
1059 :
1060 : // Add task
1061 : Buffer task_def_bytes;
1062 : if (!AttrUtils::GetZeroCopyBytes(model, MODEL_ATTR_TASKS, task_def_bytes)) {
1063 : REPORT_INNER_ERR_MSG("E19999", "Get attr:%s in model failed", MODEL_ATTR_TASKS.c_str());
1064 : GELOGE(INTERNAL_ERROR, "[Get][Attr] %s in model failed", MODEL_ATTR_TASKS.c_str());
1065 : return INTERNAL_ERROR;
1066 : }
1067 : int32_t byte_size = static_cast<int32_t>(task_def_bytes.GetSize());
1068 : std::shared_ptr<domi::ModelTaskDef> task = ge::MakeShared<domi::ModelTaskDef>();
1069 : GE_CHECK_NOTNULL(task);
1070 : GE_CHK_BOOL_EXEC(ReadProtoFromArray(task_def_bytes.GetData(), byte_size, task.get()), return INTERNAL_ERROR,
1071 : "[Read][Proto] From Array failed.");
1072 : ge_model.SetModelTaskDef(task);
1073 :
1074 : // Add graph
1075 : ge_model.SetName(model.GetName());
1076 : ge_model.SetGraph(model.GetGraph());
1077 : ge_model.SetVersion(model.GetVersion());
1078 : ge_model.SetPlatformVersion(model.GetPlatformVersion());
1079 : ge_model.SetPlatformType(platform_type_);
1080 : ge_model.SetAttrMap(model.MutableAttrMap());
1081 :
1082 : if (IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) {
1083 : const ModelPtr model_for_print = ge::MakeShared<ge::Model>(ge_model.GetName(), ge_model.GetPlatformVersion());
1084 : GE_CHECK_NOTNULL(model_for_print);
1085 : model_for_print->SetGraph(model.GetGraph());
1086 : model_for_print->SetVersion(ge_model.GetVersion());
1087 : model_for_print->SetAttr(ge_model.MutableAttrMap());
1088 : ge::Buffer model_buff;
1089 : (void)model_for_print->Save(model_buff);
1090 : const size_t model_buff_size = model_buff.GetSize();
1091 : const size_t weight_size = ge_model.GetWeightSize();
1092 : const size_t tbe_kernelstore_size = ge_model.GetTBEKernelStore().DataSize();
1093 : const size_t aicpu_kernelstore_size = ge_model.GetCustAICPUKernelStore().DataSize();
1094 : const size_t task_size = ge_model.GetModelTaskDefPtr()->ByteSizeLong();
1095 : const size_t total_size = model_buff_size + weight_size + tbe_kernelstore_size + aicpu_kernelstore_size + task_size;
1096 : GELOGD(
1097 : "Print model total size:%zu, model def size:%zu, weight data size:%zu, "
1098 : "tbe kernel size:%zu, cust aicpu kernel size:%zu, task info size:%zu",
1099 : total_size, model_buff_size, weight_size, tbe_kernelstore_size, aicpu_kernelstore_size, task_size);
1100 : }
1101 : return SUCCESS;
1102 : }
1103 :
1104 : void ModelBuilder::DelNodeRepeatSaveAttr() {
1105 : for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
1106 : auto node_op_desc = n->GetOpDesc();
1107 : GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue);
1108 : (void)node_op_desc->DelAttr(ATTR_NAME_TBE_KERNEL_BUFFER);
1109 : (void)node_op_desc->DelAttr(ATTR_NAME_TBE_KERNEL_NAME);
1110 : // Load need kernel_name attr as key, so just remove kernel_buffer, which is more larger
1111 : std::vector<std::string> names_prefix;
1112 : (void)AttrUtils::GetListStr(node_op_desc, ATTR_NAME_KERNEL_NAMES_PREFIX, names_prefix);
1113 : for (const auto &prefix : names_prefix) {
1114 : (void)node_op_desc->DelAttr(prefix + ATTR_NAME_TBE_KERNEL_BUFFER);
1115 : }
1116 : }
1117 : }
1118 :
1119 : void ModelBuilder::SetModelVersion(ge::Model &model) const {
1120 : // set framework_version TO model
1121 : std::string framework_version;
1122 : uint32_t counter = 0;
1123 : Status frame_rt = PlatformVersionManager::GetPlatformVersion(framework_version);
1124 : GE_IF_BOOL_EXEC((frame_rt == SUCCESS),
1125 : std::string model_framework_version = framework_version + "." + std::to_string(counter);
1126 : model.SetPlatformVersion(model_framework_version););
1127 :
1128 : // set IR Version TO model
1129 : model.SetVersion(static_cast<uint32_t>(OM_PROTO_VERSION));
1130 : }
1131 :
1132 : Status ModelBuilder::PreBuildModel() {
1133 : if ((compute_graph_ == nullptr) || !(compute_graph_->IsValid())) {
1134 : REPORT_INNER_ERR_MSG("E19999", "Check compute_graph no valid");
1135 : GELOGE(FAILED, "[Check][Param] Graph_ is not valid.");
1136 : return FAILED;
1137 : }
1138 :
1139 : GE_CHK_STATUS_RET(SetInputOutputDesc(), "[Set][InputOutputDesc] Failed! graph:%s", compute_graph_->GetName().c_str());
1140 :
1141 : AddNodeInputProperty();
1142 :
1143 : return SUCCESS;
1144 : }
1145 :
1146 : Status ModelBuilder::RefreshRealStream(std::unordered_map<int64_t, std::vector<domi::TaskDef>> &node_id_2_node_tasks) {
1147 : GE_ASSERT_SUCCESS(
1148 : stream_allocator_.SplitStreamAndRefreshTaskDef(node_id_2_node_tasks, stream_num_, event_num_, notify_num_),
1149 : "SplitStreamAndRefreshTaskDef failed, graph:%s", compute_graph_->GetName().c_str());
1150 : huge_streams_ = stream_allocator_.GetHugeStreams();
1151 : return SUCCESS;
1152 : }
1153 :
1154 : Status ModelBuilder::BuildModelForGetTask(ge::Model &model) {
1155 : GE_CHK_STATUS_RET(AdjustInputTensorFlag(), "[Adjust][InputTensorFlag] failed! graph:%s",
1156 : compute_graph_->GetName().c_str());
1157 :
1158 : // Assign logical streams.
1159 : GE_TRACE_START(AssignLogicalStreams);
1160 : GE_ASSERT_SUCCESS(stream_allocator_.AssignLogicalStreams(stream_max_parallel_num_, hcom_parallel_),
1161 : "[Assign][LogicalStreams] failed. graph:%s", compute_graph_->GetName().c_str());
1162 : GE_COMPILE_TRACE_TIMESTAMP_END(AssignLogicalStreams, "GraphBuilder::AssignLogicalStreams");
1163 9092 : GE_DUMP(compute_graph_, "AfterAssignLogicalStreams");
1164 :
1165 : // Assign functional op labels.
1166 : auto root_graph = GraphUtils::FindRootGraph(compute_graph_);
1167 : (void)AttrUtils::GetInt(*root_graph, ATTR_MODEL_LABEL_NUM, label_num_);
1168 :
1169 : GE_TRACE_START(AssignMemory);
1170 : MemoryAssigner mem_assigner(compute_graph_);
1171 : GE_CHK_STATUS_RET(mem_assigner.AssignMemory(mem_type_to_mem_offset_, zero_copy_mem_size_, GetHasAssignedVarMemFlag()),
1172 : "[Assign][Memory] Failed! graph:%s", compute_graph_->GetName().c_str());
1173 : GE_COMPILE_TRACE_TIMESTAMP_END(AssignMemory, "GraphBuilder::AssignMemory");
1174 : sub_mem_offsets_ = mem_assigner.GetSubMemOffsets();
1175 :
1176 : GE_TRACE_START(SetInputOutputOffset);
1177 : PassManager io_offset_pass_manager;
1178 : GE_CHK_STATUS_RET(
1179 : io_offset_pass_manager.AddPass("SetInputOutputOffsetPass", new (std::nothrow) SetInputOutputOffsetPass));
1180 : GE_CHK_STATUS_RET(io_offset_pass_manager.Run(compute_graph_), "[Set][InputOutputOffset] failed. graph:%s",
1181 : compute_graph_->GetName().c_str());
1182 : GE_COMPILE_TRACE_TIMESTAMP_END(SetInputOutputOffset, "SetInputOutputOffsetPass::Run");
1183 :
1184 : // Compile single op in graph build stage
1185 : GE_TRACE_START(CompileSingleOp);
1186 : GE_CHK_STATUS_RET(CompileSingleOp(), "[Compile][SingleOp] fail. graph:%s", compute_graph_->GetName().c_str());
1187 : GE_COMPILE_TRACE_TIMESTAMP_END(CompileSingleOp, "GraphBuilder::CompileSingleOp");
1188 :
1189 : // insert event notify nodes by logical stream id.
1190 : GE_TRACE_START(InsertSyncNodesByLogicStream);
1191 : GE_ASSERT_SUCCESS(stream_allocator_.InsertSyncNodesByLogicStream(stream_num_, event_num_, notify_num_),
1192 : "[Refresh][RealStream] failed. graph:%s", compute_graph_->GetName().c_str());
1193 : notify_types_ = stream_allocator_.GetNotifyTypes();
1194 : GE_ASSERT_EQ(static_cast<int64_t>(notify_types_.size()), notify_num_);
1195 : GE_COMPILE_TRACE_TIMESTAMP_END(InsertSyncNodesByLogicStream, "GraphBuilder::InsertSyncNodesByLogicStream");
1196 : GE_TRACE_START(OptimizeStreamedWholeGraph);
1197 : StreamGraphOptimizer stream_graph_optimizer;
1198 : GE_CHK_STATUS_RET(stream_graph_optimizer.OptimizeStreamedWholeGraph(compute_graph_),
1199 : "[Optimize][StreamedWholeGraph] fail. graph:%s", compute_graph_->GetName().c_str());
1200 : GE_COMPILE_TRACE_TIMESTAMP_END(OptimizeStreamedWholeGraph, "GraphBuilder::OptimizeStreamedWholeGraph");
1201 :
1202 : GE_CHK_STATUS_RET(SaveSoftSyncOpWeight(), "[Save][Weights] Failed! graph:%s", compute_graph_->GetName().c_str());
1203 :
1204 : GE_TRACE_START(MergeWeights);
1205 : GE_CHK_STATUS_RET(MergeWeights(), "[Merge][Weights] Failed! graph:%s", compute_graph_->GetName().c_str());
1206 : GE_COMPILE_TRACE_TIMESTAMP_END(MergeWeights, "GraphBuilder::MergeWeights");
1207 :
1208 : GE_TRACE_START(BuildModelDefForMem);
1209 : GE_ASSERT_SUCCESS(BuildModelDefForMem(model), "[Build][ModelDef] Part one failed! graph:%s",
1210 : compute_graph_->GetName().c_str());
1211 : GE_COMPILE_TRACE_TIMESTAMP_END(BuildModelDefForMem, "GraphBuilder::BuildModelDefForMem");
1212 :
1213 : SetModelVersion(model);
1214 :
1215 : return SUCCESS;
1216 : }
1217 :
1218 : Status ModelBuilder::BuildModelDefForStream(ge::Model &model) {
1219 : GE_ASSERT_TRUE(ge::AttrUtils::SetInt(&model, ATTR_MODEL_STREAM_NUM, stream_num_), "[Set][Attr] %s in model failed",
1220 : ATTR_MODEL_STREAM_NUM.c_str());
1221 : GE_ASSERT_TRUE(ge::AttrUtils::SetInt(&model, ATTR_MODEL_NOTIFY_NUM, notify_num_), "[Set][Attr] %s in model failed",
1222 : ATTR_MODEL_NOTIFY_NUM.c_str());
1223 : GE_ASSERT_TRUE(ge::AttrUtils::SetListInt(&model, ATTR_MODEL_NOTIFY_TYPES, notify_types_));
1224 : GE_ASSERT_TRUE(ge::AttrUtils::SetInt(&model, ATTR_MODEL_EVENT_NUM, event_num_), "[Set][Attr] %s in model failed",
1225 : ATTR_MODEL_EVENT_NUM.c_str());
1226 : GE_ASSERT_TRUE(ge::AttrUtils::SetListInt(&model, ATTR_MODEL_HUGE_STREAM_LIST, huge_streams_),
1227 : "[Set][Attr] %s in model failed", ATTR_MODEL_HUGE_STREAM_LIST.c_str());
1228 : const auto root_graph = GraphUtils::FindRootGraph(compute_graph_);
1229 : GE_ASSERT_NOTNULL(root_graph);
1230 : std::string tuning_mode;
1231 : if (ge::AttrUtils::GetStr(root_graph, ATTR_MODEL_AUTO_MULTISTREAM_TUNING_MODE, tuning_mode) &&
1232 : (!tuning_mode.empty())) {
1233 : GE_ASSERT_TRUE(ge::AttrUtils::SetStr(&model, ATTR_MODEL_AUTO_MULTISTREAM_TUNING_MODE, tuning_mode),
1234 : "[Set][Attr] %s in model failed", ATTR_MODEL_AUTO_MULTISTREAM_TUNING_MODE.c_str());
1235 : }
1236 : const auto graph = model.GetGraph();
1237 : GE_ASSERT_NOTNULL(graph);
1238 : GE_ASSERT_TRUE(ge::AttrUtils::SetStr(graph, "_split_logic_stream_2_origin_logic_stream",
1239 : StreamUtils::TransMapToStr(stream_allocator_.GetSplitStreamToLogicStream())));
1240 : GELOGI("build model def about stream, stream num: %ld, event_num: %ld, notify_num: %ld", stream_num_, event_num_,
1241 : notify_num_);
1242 : return SUCCESS;
1243 : }
1244 :
1245 : Status ModelBuilder::SaveSoftSyncOpWeight() const {
1246 : GELOGD("Start to recover soft sync op's weight of graph: %s.", compute_graph_->GetName().c_str());
1247 : for (const auto &node : compute_graph_->GetAllNodes()) {
1248 : const auto op_desc = node->GetOpDesc();
1249 : GE_CHECK_NOTNULL(op_desc);
1250 : bool is_soft_sync = false;
1251 : if ((!ge::AttrUtils::GetBool(op_desc, ATTR_NAME_STATIC_TO_DYNAMIC_SOFT_SYNC_OP, is_soft_sync)) || (!is_soft_sync)) {
1252 : continue;
1253 : }
1254 : const auto depend_names = op_desc->GetOpInferDepends();
1255 : if (depend_names.empty()) {
1256 : continue;
1257 : }
1258 : GE_ASSERT_SUCCESS(SaveSoftSyncOpWeightByDependNames(node, depend_names));
1259 : }
1260 : GELOGD("Finished to recover soft sync op's weight of graph: %s.", compute_graph_->GetName().c_str());
1261 : return SUCCESS;
1262 : }
1263 :
1264 : Status ModelBuilder::BuildModelForGetDynShapeTask(ge::Model &model_def) {
1265 : GE_TRACE_START(BuildModelDef);
1266 : GE_CHK_STATUS_RET(BuildModelDef(model_def), "[Build][ModelDef] failed!");
1267 : GE_COMPILE_TRACE_TIMESTAMP_END(BuildModelDef, "GraphBuilder::BuildModelDef");
1268 : SetModelVersion(model_def);
1269 : return SUCCESS;
1270 : }
1271 :
1272 : ge::Buffer ModelBuilder::GetWeightBuffer() const {
1273 : return weight_buffer_;
1274 : }
1275 : Status ModelBuilder::CompileSingleOp() const {
1276 : GELOGD("Begin to compile single op.");
1277 : // Create ge instance
1278 : std::shared_ptr<GELib> instance = ge::GELib::GetInstance();
1279 : if ((instance == nullptr) || !instance->InitFlag()) {
1280 : REPORT_INNER_ERR_MSG("E19999", "Check GELib instance not init before");
1281 : GELOGE(ge::GE_CLI_GE_NOT_INITIALIZED, "[Check][Param] CompileSingleOp failed.");
1282 : return ge::GE_CLI_GE_NOT_INITIALIZED;
1283 : }
1284 :
1285 : GE_TIMESTAMP_CALLNUM_START(BatchCompileOp);
1286 : std::unordered_map<std::string, std::vector<ge::NodePtr>> node_vector_map;
1287 : for (auto &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) {
1288 : auto op_desc = node->GetOpDesc();
1289 : if (op_desc == nullptr) {
1290 : continue;
1291 : }
1292 :
1293 : // Graph build stage only supports the individual compilation of atomic clean operator
1294 : if (NodeUtils::IsLikeAtomicClean(node)) {
1295 : std::string kernel_lib_name = op_desc->GetOpKernelLibName();
1296 : if (kernel_lib_name.empty()) {
1297 : // Reset op kernel lib
1298 : (void)instance->DNNEngineManagerObj().GetDNNEngineName(node);
1299 : kernel_lib_name = op_desc->GetOpKernelLibName();
1300 : if (kernel_lib_name.empty()) {
1301 : REPORT_INNER_ERR_MSG("E19999", "Check kernel lib name empty of op:%s(%s)", node->GetName().c_str(),
1302 : node->GetType().c_str());
1303 : GELOGE(ge::INTERNAL_ERROR, "[Get][Name] of node:%s(%s) kernel lib failed.", node->GetName().c_str(),
1304 : node->GetType().c_str());
1305 : return ge::INTERNAL_ERROR;
1306 : }
1307 : }
1308 : GELOGI("Begin to compile single op, lib is %s, op name is %s, op type is %s.", kernel_lib_name.c_str(),
1309 : op_desc->GetName().c_str(), op_desc->GetType().c_str());
1310 : OpsKernelInfoStorePtr kernel_info = instance->OpsKernelManagerObj().GetOpsKernelInfoStore(kernel_lib_name);
1311 : if (kernel_info != nullptr) {
1312 : node_vector_map[kernel_lib_name].emplace_back(node);
1313 : } else {
1314 : REPORT_INNER_ERR_MSG("E19999", "Get ops kernel info store failed for op:%s(%s), op_kernel_name:%s,",
1315 : node->GetName().c_str(), node->GetType().c_str(), kernel_lib_name.c_str());
1316 : GELOGE(ge::GE_GRAPH_PARAM_NULLPTR, "[Get][OpsKernelInfoStore] for op %s failed", node->GetName().c_str());
1317 : return ge::GE_GRAPH_PARAM_NULLPTR;
1318 : }
1319 : }
1320 : }
1321 : for (auto &it : node_vector_map) {
1322 : auto &kernel_lib_name = it.first;
1323 : auto &node_vector = it.second;
1324 : OpsKernelInfoStorePtr kernel_info = instance->OpsKernelManagerObj().GetOpsKernelInfoStore(kernel_lib_name);
1325 : GE_CHECK_NOTNULL(kernel_info);
1326 : GE_TIMESTAMP_RESTART(BatchCompileOp);
1327 : auto ret = kernel_info->CompileOp(node_vector);
1328 : GELOGI("[GEPERFTRACE] The node size of compile op of %s is %zu", kernel_lib_name.c_str(), node_vector.size());
1329 : GE_TIMESTAMP_ADD(BatchCompileOp);
1330 : if (ret != ge::SUCCESS) {
1331 : REPORT_INNER_ERR_MSG("E19999", "Batch compile op failed, kernel lib name, node size:%zu,", node_vector.size());
1332 : GELOGE(ret, "[Compile][Op] failed, kernel lib name is %s", kernel_lib_name.c_str());
1333 : return ret;
1334 : }
1335 : }
1336 : GE_TIMESTAMP_CALLNUM_END(BatchCompileOp, "GraphBuild::CompileOp");
1337 : return ge::SUCCESS;
1338 : }
1339 :
1340 : void ModelBuilder::CollectCheckAicpuAttr(const OpDescPtr &op_desc, std::set<std::string> &aicpu_op_types,
1341 : std::set<std::string> &aicpu_tf_op_types) const {
1342 : std::string aicpu_optype;
1343 : bool has_attr_check_cpu = ge::AttrUtils::GetStr(op_desc, "needCheckCpu", aicpu_optype);
1344 : std::vector<std::string> tf_optypes;
1345 : bool has_attr_check_tf = ge::AttrUtils::GetListStr(op_desc, "needCheckTf", tf_optypes);
1346 : if (has_attr_check_cpu && !aicpu_optype.empty()) {
1347 : aicpu_op_types.insert(aicpu_optype);
1348 : }
1349 :
1350 : if (has_attr_check_tf && !tf_optypes.empty()) {
1351 : aicpu_tf_op_types.insert(tf_optypes.cbegin(), tf_optypes.cend());
1352 : }
1353 :
1354 : return;
1355 : }
1356 :
1357 : void ModelBuilder::SetModelCheckAicpuAttr(ge::Model &model, std::set<std::string> &aicpu_op_types,
1358 : std::set<std::string> &aicpu_tf_op_types) const {
1359 : std::vector<std::string> aicpu_optype_list;
1360 : std::vector<std::string> aicpu_tf_optype_list;
1361 : if (ge::AttrUtils::GetListStr(&model, "needCheckCpu", aicpu_optype_list)) {
1362 : GELOGI("Already have aicpu optype size: %zu", aicpu_optype_list.size());
1363 : aicpu_op_types.insert(aicpu_optype_list.cbegin(), aicpu_optype_list.cend());
1364 : }
1365 :
1366 : if (ge::AttrUtils::GetListStr(&model, "needCheckTf", aicpu_tf_optype_list)) {
1367 : GELOGI("Already have aicpu tf optype size: %zu", aicpu_tf_optype_list.size());
1368 : aicpu_tf_op_types.insert(aicpu_tf_optype_list.cbegin(), aicpu_tf_optype_list.cend());
1369 : }
1370 :
1371 : // reset list with set
1372 : aicpu_optype_list.assign(aicpu_op_types.begin(), aicpu_op_types.end());
1373 : aicpu_tf_optype_list.assign(aicpu_tf_op_types.begin(), aicpu_tf_op_types.end());
1374 : GELOGI(
1375 : "Check Aicpu op types ComputeGraph: %s aicpu_op_types: %zu, aicpu_optype_list: %zu, aicpu_tf_op_types: %zu, "
1376 : "aicpu_tf_optype_list:%zu.",
1377 : compute_graph_->GetName().c_str(), aicpu_op_types.size(), aicpu_optype_list.size(), aicpu_tf_op_types.size(),
1378 : aicpu_tf_optype_list.size());
1379 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListStr(&model, "needCheckCpu", aicpu_optype_list), return,
1380 : "[Set][Attr] needCheckCpu fail.");
1381 :
1382 : GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListStr(&model, "needCheckTf", aicpu_tf_optype_list), return,
1383 : "[Set][Attr] needCheckTf fail.");
1384 : return;
1385 : }
1386 :
1387 : Status ModelBuilder::BuildModelForEvaluate(ModelDataInfo &model) const {
1388 : // Assign logical streams.
1389 : StreamAllocator stream_allocator(compute_graph_, subgraphs_);
1390 : GE_TRACE_START(AssignLogicalStreams);
1391 : GE_CHK_STATUS_RET(stream_allocator.AssignLogicalStreams(stream_max_parallel_num_, hcom_parallel_),
1392 : "[Assign][LogicalStreams] failed. graph:%s", compute_graph_->GetName().c_str());
1393 : GE_COMPILE_TRACE_TIMESTAMP_END(AssignLogicalStreams, "GraphBuilder::AssignLogicalStreams");
1394 :
1395 : GE_TRACE_START(AssignMemory);
1396 : MemoryAssigner mem_assigner(compute_graph_);
1397 : std::map<uint64_t, size_t> mem_type_to_mem_offset;
1398 : size_t zero_copy_mem_size;
1399 : GE_CHK_STATUS_RET(mem_assigner.AssignMemory(mem_type_to_mem_offset, zero_copy_mem_size),
1400 : "[Assign][Memory] Failed! graph:%s", compute_graph_->GetName().c_str());
1401 : GE_COMPILE_TRACE_TIMESTAMP_END(AssignMemory, "GraphBuilder::AssignMemory");
1402 : size_t graph_memory_size = 0;
1403 : for (const auto &memory_size : mem_type_to_mem_offset) {
1404 : graph_memory_size += memory_size.second;
1405 : }
1406 : model.SetGraphMemorySize(graph_memory_size);
1407 : const auto &var_manager = ge::VarManager::Instance(compute_graph_->GetSessionID());
1408 : GE_ASSERT_NOTNULL(var_manager);
1409 : model.SetVarMemorySize(var_manager->GetVarMemSize(RT_MEMORY_HBM));
1410 : return SUCCESS;
1411 : }
1412 :
1413 : Status ModelBuilder::AssignStreamForDynamicShapeGraph(ComputeGraphPtr &compute_graph) {
1414 : if (compute_graph->GetParentGraph() != nullptr) {
1415 : return SUCCESS;
1416 : }
1417 :
1418 : if (!StreamUtils::EnableDynamicShapeMultiStream()) {
1419 : return SUCCESS;
1420 : }
1421 :
1422 : if (GraphUtils::IsSingleOpScene(compute_graph)) {
1423 : return SUCCESS;
1424 : }
1425 :
1426 : // to make sure topo id is accurate, to sorting before assign stream
1427 : GE_CHK_STATUS_RET(compute_graph->TopologicalSorting(), "[Call][TopologicalSorting] failed, graph:%s",
1428 : compute_graph->GetName().c_str());
1429 :
1430 : const auto dynamic_stream_allocator = MakeShared<DynamicStreamAllocator>();
1431 : GE_CHECK_NOTNULL(dynamic_stream_allocator);
1432 : GE_ASSERT_SUCCESS(dynamic_stream_allocator->AssignStreamsForDynamicShapeGraph(compute_graph, subgraphs_));
1433 :
1434 : stream_num_ = dynamic_stream_allocator->GetStreamNum();
1435 : event_num_ = dynamic_stream_allocator->GetEventNum();
1436 :
1437 : return SUCCESS;
1438 : }
1439 : } // namespace ge
|