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 "adapter/tbe_adapter/kernel_launch/l2_cache_kernel_launch.h"
12 : #include <memory>
13 : #include <vector>
14 : #include "common/fe_log.h"
15 : #include "common/configuration.h"
16 : #include "common/fe_type_utils.h"
17 : #include "graph/utils/anchor_utils.h"
18 : #include "graph/utils/attr_utils.h"
19 : #include "graph/utils/node_utils.h"
20 :
21 : namespace fe {
22 : namespace {
23 : const std::string ATTR_NAME_L2CACHE_GRAPH_READ_MODE = "_fe_l2cache_graph_read_mode";
24 : const std::set<std::string> LIFECYCLE_IS_END_OPS = {DATA, AIPPDATA, ANN_DATA, CONSTANT, CONSTANTOP};
25 : const std::set<std::string> LIFECYCLE_IS_NOT_END_OPS = {VARIABLE};
26 : } // namespace
27 39 : size_t L2CacheKernelLaunch::GetAppendArgsSizeOf() const {
28 : return sizeof(uint64_t); // uinit64_t: 8
29 : }
30 :
31 65 : size_t L2CacheKernelLaunch::GetAppendArgsNum() const {
32 : return input_num_;
33 : }
34 :
35 : Status L2CacheKernelLaunch::AddAppendArgs(const ge::Node &node, void *all_args_buff, const uint32_t &args_size) {
36 : auto op_desc_ptr = node.GetOpDesc();
37 : auto op_name = node.GetName();
38 : auto op_type = node.GetType();
39 :
40 : // 1. generate read mode
41 : vector<uint64_t> read_modes;
42 : if (GenerateReadModes(node, read_modes) != SUCCESS) {
43 : REPORT_FE_ERROR("[GenTask][AddAppendArgs][Op %s,type %s] failed to generate the read mode.", op_name.c_str(),
44 : op_type.c_str());
45 : return FAILED;
46 : }
47 :
48 : if (read_modes.size() != GetAppendArgsNum()) {
49 : REPORT_FE_ERROR("[GenTask][AddAppendArgs] Node[%s, %s]: append_args_num %zu is not equal to read_modes_size %zu.",
50 : op_name.c_str(), op_type.c_str(), GetAppendArgsNum(), read_modes.size());
51 : return FAILED;
52 : }
53 :
54 : // 2. add append args
55 : size_t each_append_arg_size = GetAppendArgsSizeOf();
56 : size_t left_append_arg_size = each_append_arg_size * GetAppendArgsNum();
57 : uint64_t cur_ptr = ge::PtrToValue(all_args_buff) + args_size;
58 : for (uint64_t &read_mode : read_modes) {
59 : errno_t ret = memcpy_s(reinterpret_cast<void *>(cur_ptr), left_append_arg_size,
60 : reinterpret_cast<void *>(&read_mode), each_append_arg_size);
61 : if (ret != EOK) {
62 : return FAILED;
63 : }
64 : left_append_arg_size -= each_append_arg_size;
65 : cur_ptr += each_append_arg_size;
66 : }
67 : return SUCCESS;
68 : }
69 :
70 : Status L2CacheKernelLaunch::GenerateReadModes(const ge::Node &node, vector<uint64_t> &read_modes) const {
71 : auto op_desc_ptr = node.GetOpDesc();
72 : auto op_name = op_desc_ptr->GetName();
73 : auto op_type = op_desc_ptr->GetType();
74 : bool is_enable_reuse_mem = Configuration::Instance(AI_CORE_NAME).IsEnableReuseMemory();
75 :
76 : for (const auto &in_data_anchor : node.GetAllInDataAnchors()) {
77 : if (in_data_anchor == nullptr) {
78 : continue;
79 : }
80 : auto peer_out_anchor = in_data_anchor->GetPeerOutAnchor();
81 : if (peer_out_anchor == nullptr) {
82 : continue;
83 : }
84 :
85 : auto idx = in_data_anchor->GetIdx();
86 : auto input_desc = op_desc_ptr->MutableInputDesc(idx);
87 : if (input_desc == nullptr) {
88 : continue;
89 : }
90 : // 1. get the src node of the input
91 : auto src_node = peer_out_anchor->GetOwnerNode();
92 : FE_CHECK_NOTNULL(src_node);
93 : auto read_mode = GenRmForSpecialInputOps(src_node, is_enable_reuse_mem);
94 : if (read_mode == L2CacheReadMode::RM_NONE) {
95 : // 2. get the life cycle of the input desc
96 : auto is_life_cycle_end = IsLifeCycleEnd(node, input_desc, idx);
97 : // 3. generate rm by life cycle and read distance
98 : read_mode = GenerateReadMode(node, input_desc, idx, is_life_cycle_end);
99 : }
100 : // 4. set the attr
101 : (void)ge::AttrUtils::SetInt(input_desc, ATTR_NAME_L2CACHE_GRAPH_READ_MODE, static_cast<int64_t>(read_mode));
102 :
103 : read_modes.emplace_back(static_cast<uint64_t>(read_mode));
104 : FE_LOGD("Op[name=%s,type=%s,input=%d]: the graph read_mode=[%s].", op_name.c_str(), op_type.c_str(), idx,
105 : L2CacheReadMode2Str(read_mode).c_str());
106 : }
107 :
108 : return SUCCESS;
109 : }
110 :
111 : L2CacheReadMode L2CacheKernelLaunch::GenRmForSpecialInputOps(const ge::NodePtr &src_node,
112 : bool is_enable_reuse_mem) const {
113 : auto src_node_type = ge::NodeUtils::GetInConstNodeTypeCrossSubgraph(src_node);
114 : // Const/Data
115 : if (LIFECYCLE_IS_END_OPS.count(src_node_type) != 0) {
116 : return is_enable_reuse_mem ? L2CacheReadMode::NOT_NEED_WRITEBACK : L2CacheReadMode::READ_LAST;
117 : }
118 :
119 : // Variable
120 : if (LIFECYCLE_IS_NOT_END_OPS.count(src_node_type) != 0) {
121 : return L2CacheReadMode::READ_LAST;
122 : }
123 : return L2CacheReadMode::RM_NONE;
124 : }
125 :
126 : bool L2CacheKernelLaunch::IsLifeCycleEnd(const ge::Node &node, const ge::GeTensorDescPtr &input_desc,
127 : int input_idx) const {
128 : auto op_desc = node.GetOpDesc();
129 : auto op_name = op_desc->GetName();
130 : auto op_type = op_desc->GetType();
131 :
132 : bool is_life_cycle_end = false;
133 : if (ge::AttrUtils::HasAttr(input_desc, ge::ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE)) {
134 : (void)ge::AttrUtils::GetBool(input_desc, ge::ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE, is_life_cycle_end);
135 : FE_LOGD("Op[name=%s,type=%s,input=%d]: has attr %s, the life_cycle is %s.", op_name.c_str(), op_type.c_str(),
136 : input_idx, ge::ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE.c_str(), is_life_cycle_end ? "end" : "not end");
137 : return is_life_cycle_end;
138 : }
139 : return is_life_cycle_end;
140 : }
141 :
142 : L2CacheReadMode L2CacheKernelLaunch::GenerateReadMode(const ge::Node &node, const ge::GeTensorDescPtr &input_desc,
143 : int input_idx, bool is_life_cycle_end) const {
144 : auto op_desc = node.GetOpDesc();
145 : auto op_name = op_desc->GetName();
146 : auto op_type = op_desc->GetType();
147 :
148 : // 1. no read distance on the input desc
149 : if (!ge::AttrUtils::HasAttr(input_desc, ge::ATTR_NAME_DATA_VISIT_DISTANCE)) {
150 : FE_LOGD("Op[name=%s,type=%s,input=%d]: no attr %s.", op_name.c_str(), op_type.c_str(), input_idx,
151 : ge::ATTR_NAME_DATA_VISIT_DISTANCE.c_str());
152 : return is_life_cycle_end ? L2CacheReadMode::NOT_NEED_WRITEBACK : L2CacheReadMode::READ_LAST;
153 : }
154 :
155 : // 2. there is the read distance on the input desc
156 : vector<int32_t> data_visit_dist_vec;
157 : (void)ge::AttrUtils::GetListInt(input_desc, ge::ATTR_NAME_DATA_VISIT_DISTANCE, data_visit_dist_vec);
158 : auto data_visit_dist_size = data_visit_dist_vec.size();
159 :
160 : // 3. life cycle is end
161 : if (is_life_cycle_end) {
162 : int32_t data_visit_dist_from_pre_node = 0;
163 : if (data_visit_dist_size == 0) {
164 : FE_LOGD(
165 : "Op[name=%s,type=%s,input=%d]: no read distance from previous node, set data_visit_dist_from_pre_node to be "
166 : "-1.",
167 : op_name.c_str(), op_type.c_str(), input_idx);
168 : data_visit_dist_from_pre_node = -1;
169 : } else {
170 : data_visit_dist_from_pre_node = data_visit_dist_vec[0];
171 : }
172 :
173 : FE_LOGD("Op[name=%s,type=%s,input=%d]: data_visit_dist_from_pre_node=[%d], data_visit_dist_threshold=[%d].",
174 : op_name.c_str(), op_type.c_str(), input_idx, data_visit_dist_from_pre_node, kDataVisitDistThreshold);
175 : return L2CacheReadMode::READ_INVALID;
176 : }
177 :
178 : // 4. life cycle is not end
179 : int32_t data_visit_dist_to_next_node = 0;
180 : if (data_visit_dist_size < 2) {
181 : FE_LOGW("Op[name=%s,type=%s,input=%d]: no read distance to next node, set data_visit_dist_to_next_node to be -1.",
182 : op_name.c_str(), op_type.c_str(), input_idx);
183 : data_visit_dist_to_next_node = -1;
184 : } else {
185 : data_visit_dist_to_next_node = data_visit_dist_vec[1];
186 : }
187 : FE_LOGD("Op[name=%s,type=%s,input=%d]: data_visit_dist_to_next_node=[%d], data_visit_dist_threshold=[%d].",
188 : op_name.c_str(), op_type.c_str(), input_idx, data_visit_dist_to_next_node, kDataVisitDistThreshold);
189 : return data_visit_dist_to_next_node <= kDataVisitDistThreshold ? L2CacheReadMode::READ_LAST
190 : : L2CacheReadMode::READ_INVALID;
191 : }
192 : } // namespace fe
|