You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mem_rw_conflict_optimize.cc 32 kB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /**
  2. * Copyright 2020 Huawei Technologies Co., Ltd
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. * Unless required by applicable law or agreed to in writing, software
  8. * distributed under the License is distributed on an "AS IS" BASIS,
  9. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. * See the License for the specific language governing permissions and
  11. * limitations under the License.
  12. */
  13. #include <string>
  14. #include <vector>
  15. #include "common/ge/ge_util.h"
  16. #include "graph/common/omg_util.h"
  17. #include "graph/debug/ge_attr_define.h"
  18. #include "graph/optimize/graph_optimize.h"
  19. #include "graph/utils/graph_utils.h"
  20. #include "graph/utils/node_utils.h"
  21. namespace {
  22. using namespace ge;
  23. const int kIdentityAnchorIndex = 0;
  24. const size_t kSerialStringVecSize = 4;
  25. const int kCaseReadOnly = 0;
  26. const int kCaseScopeWriteable = 2;
  27. const int kCaseWriteable = 3;
  28. const int kCaseInvalidRWType = 5;
  29. // attr _input_mutable = true means node will modify its input in runtime
  30. const char *const kModifyInput = "_input_mutable";
  31. // rw type of input.
  32. enum class InputRWType {
  33. kReadOnly, // Normal op input only read
  34. kWriteable, // Op like Assign/ApplyMomentum
  35. kScopeWriteable, // Op like hcom_allreduce, it will modify input ,but not expect take effect on pre ouput
  36. kInvalidRWType
  37. };
  38. // rw type of output
  39. enum class OutputRWType {
  40. kReadOnly, // 1.const output 2.not ref output but has several peer output
  41. kSoftRead, // not ref output but only has one output node
  42. kWriteable, // ref output. Like Assign/ApplyMomentum
  43. kInvalidRWType
  44. };
  45. // input and output rw_type of one node. key is anchor_idx, value is rw_type
  46. struct NodeInputOutputRWType {
  47. map<uint32_t, InputRWType> input_rw_type_map;
  48. map<uint32_t, OutputRWType> output_rw_type_map;
  49. };
  50. // input and output rw_type of node in current graph
  51. thread_local map<string, NodeInputOutputRWType> node_rwtype_map_;
  52. ///
  53. /// @brief Convert input rw_type enum to string. For log print.
  54. /// @param rw_type
  55. /// @return rw_type_name
  56. ///
  57. static std::string InputRWTypeToSerialString(InputRWType rw_type) {
  58. const static char *names[kSerialStringVecSize] = {"ReadOnly", "Writeable", "ScopeWriteable", "InvalidRWType"};
  59. return names[static_cast<int>(rw_type)];
  60. }
  61. ///
  62. /// @brief Convert output rw_type enum to string. For log print.
  63. /// @param rw_type
  64. /// @return rw_type_name
  65. ///
  66. static std::string OutputRWTypeToSerialString(OutputRWType rw_type) {
  67. const static char *names[kSerialStringVecSize] = {"ReadOnly", "SoftRead", "Writeable", "InvalidRWType"};
  68. return names[static_cast<int>(rw_type)];
  69. }
  70. OutputRWType GetSingleNodeOutputRWTypeByIndex(const Node &node, uint32_t index) {
  71. auto op_desc = node.GetOpDesc();
  72. if (op_desc == nullptr) {
  73. return OutputRWType::kInvalidRWType;
  74. }
  75. if (op_desc->GetType() == VARIABLE) {
  76. return OutputRWType::kWriteable;
  77. }
  78. // check if it is ref output
  79. auto input_names = op_desc->GetAllInputName();
  80. for (auto &input_name_2_idx : input_names) {
  81. if (op_desc->GetOutputNameByIndex(index) == input_name_2_idx.first) {
  82. return OutputRWType::kWriteable;
  83. }
  84. }
  85. // check if it is ref switch
  86. std::string type;
  87. if ((node.GetType() == FRAMEWORK_OP_TYPE) && AttrUtils::GetStr(op_desc, ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type)
  88. && (type == REFSWITCH)) {
  89. return OutputRWType::kWriteable;
  90. }
  91. if (op_desc->GetType() == CONSTANT || op_desc->GetType() == CONSTANTOP) {
  92. return OutputRWType::kReadOnly;
  93. }
  94. auto out_data_anchor = node.GetOutDataAnchor(index);
  95. if (out_data_anchor == nullptr) {
  96. return OutputRWType::kInvalidRWType;
  97. }
  98. if (out_data_anchor->GetPeerInDataNodesSize() > 1) {
  99. return OutputRWType::kReadOnly;
  100. } else {
  101. return OutputRWType::kSoftRead;
  102. }
  103. }
  104. ///
  105. /// @brief Get input rw_type of one node with sub graph. It will return rw_type after solve conflict scene.
  106. /// @param rw_type_set
  107. /// @return
  108. ///
  109. InputRWType GetInputRwTypeInConflict(const std::set<int> &rw_type_set) {
  110. // for input rw type calc
  111. int total_rw_type = 0;
  112. for (const auto rw : rw_type_set) {
  113. total_rw_type += rw;
  114. }
  115. switch (total_rw_type) {
  116. case kCaseReadOnly:
  117. return InputRWType::kReadOnly; // all input rw type is readonly
  118. case kCaseScopeWriteable:
  119. return InputRWType::kScopeWriteable; // readonly 2 scope_writeable
  120. case kCaseWriteable:
  121. return InputRWType::kWriteable; // all input rw type is writeable or readonly 2 writeable
  122. case kCaseInvalidRWType:
  123. return InputRWType::kInvalidRWType; // writeable 2 scope_writeable
  124. default:
  125. return InputRWType::kInvalidRWType;
  126. }
  127. }
  128. bool IsSubgraphInputNode(const NodePtr &node) {
  129. if ((node == nullptr) || (node->GetOpDesc() == nullptr) || (node->GetType() != DATA) ||
  130. (node->GetOwnerComputeGraph()->GetParentNode() == nullptr)) {
  131. return false;
  132. }
  133. return true;
  134. }
  135. bool IsSubgraphOutputNode(const NodePtr &node) {
  136. if ((node == nullptr) || (node->GetOpDesc() == nullptr) || (node->GetType() != NETOUTPUT) ||
  137. (node->GetOwnerComputeGraph()->GetParentNode() == nullptr)) {
  138. return false;
  139. }
  140. return true;
  141. }
  142. NodePtr CreateIdentityAfterSrcNode(const Node &src_node, int out_anchor_idx) {
  143. if (src_node.GetOpDesc() == nullptr) {
  144. return nullptr;
  145. }
  146. static std::atomic_long identity_num(0);
  147. auto next_num = identity_num.fetch_add(1);
  148. // 1. create new identity op desc
  149. string identity_name = src_node.GetName() + "_" + IDENTITY + std::to_string(next_num);
  150. auto identity_opdesc = MakeShared<OpDesc>(identity_name, IDENTITY);
  151. if (identity_opdesc == nullptr) {
  152. GELOGE(OUT_OF_MEMORY, "Failed to insert identity node, name %s", identity_name.c_str());
  153. return nullptr;
  154. }
  155. auto data_desc = src_node.GetOpDesc()->GetOutputDesc(out_anchor_idx);
  156. // 2. add input_desc & output_desc for new identity
  157. Status ret = identity_opdesc->AddInputDesc("x", data_desc);
  158. if (ret != SUCCESS) {
  159. GELOGE(ret, "Add Input desc failed for new identity %s.", identity_name.c_str());
  160. return nullptr;
  161. }
  162. ret = identity_opdesc->AddOutputDesc("y", data_desc);
  163. if (ret != SUCCESS) {
  164. GELOGE(ret, "Add Output desc failed for new Identity %s.", identity_name.c_str());
  165. return nullptr;
  166. }
  167. GELOGI("Insert new Identity node %s.", identity_name.c_str());
  168. auto graph = src_node.GetOwnerComputeGraph();
  169. if (graph == nullptr) {
  170. GELOGE(GRAPH_PARAM_INVALID, "Node %s owner compute graph is null.", src_node.GetName().c_str());
  171. return nullptr;
  172. }
  173. return graph->AddNode(identity_opdesc);
  174. }
  175. OutputRWType GetOutputRWTypeByIndex(const Node &node, uint32_t index) {
  176. auto op_desc = node.GetOpDesc();
  177. if (op_desc == nullptr) {
  178. return OutputRWType::kInvalidRWType;
  179. }
  180. if (op_desc->GetType() == WHILE) {
  181. return OutputRWType::kSoftRead;
  182. }
  183. vector<string> subgraph_names = op_desc->GetSubgraphInstanceNames();
  184. if (subgraph_names.empty()) {
  185. // single node without sub graph
  186. return GetSingleNodeOutputRWTypeByIndex(node, index);
  187. } else {
  188. // node with sub graph
  189. auto output_node_vec = NodeUtils::GetSubgraphOutputNodes(node);
  190. auto output_rw_type = OutputRWType::kInvalidRWType;
  191. if (output_node_vec.size() == 1) {
  192. // find rw type from map.
  193. auto iter = node_rwtype_map_.find(output_node_vec.at(0)->GetName());
  194. if (iter == node_rwtype_map_.end()) {
  195. GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.",
  196. output_node_vec.at(0)->GetName().c_str());
  197. return OutputRWType::kInvalidRWType;
  198. }
  199. auto index_2_output_rw_type = iter->second.output_rw_type_map.find(index);
  200. if (index_2_output_rw_type == iter->second.output_rw_type_map.end()) {
  201. GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.",
  202. output_node_vec.at(0)->GetName().c_str());
  203. return OutputRWType::kInvalidRWType;
  204. }
  205. output_rw_type = index_2_output_rw_type->second;
  206. } else {
  207. output_rw_type = OutputRWType::kSoftRead;
  208. }
  209. // check peer input
  210. auto out_data_anchor = node.GetOutDataAnchor(index);
  211. if (out_data_anchor == nullptr) {
  212. return OutputRWType::kInvalidRWType;
  213. }
  214. if (out_data_anchor->GetPeerInDataNodesSize() > 1) {
  215. return OutputRWType::kReadOnly;
  216. } else {
  217. return output_rw_type;
  218. }
  219. }
  220. }
  221. InputRWType GetSingleNodeInputRWTypeByIndex(const Node &node, uint32_t index) {
  222. auto op_desc = node.GetOpDesc();
  223. if (op_desc == nullptr) {
  224. return InputRWType::kInvalidRWType;
  225. }
  226. if (op_desc->GetType() == HCOMALLREDUCE || op_desc->GetType() == HCOMALLGATHER
  227. || op_desc->GetType() == HCOMREDUCESCATTER || op_desc->GetType() == HCOMREDUCE) {
  228. return InputRWType::kScopeWriteable;
  229. }
  230. // check if it is ref input
  231. auto output_names = op_desc->GetAllOutputName();
  232. for (auto &output_name_2_idx : output_names) {
  233. if (op_desc->GetInputNameByIndex(index) == output_name_2_idx.first) {
  234. return InputRWType::kWriteable;
  235. }
  236. }
  237. // check if it is ref switch
  238. std::string type;
  239. if ((node.GetType() == FRAMEWORK_OP_TYPE) && (AttrUtils::GetStr(op_desc, ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type))
  240. && (type == REFSWITCH) && (index == 0)) {
  241. return InputRWType::kWriteable;
  242. }
  243. return InputRWType::kReadOnly;
  244. }
  245. InputRWType GetInputRWTypeByIndex(const Node &node, uint32_t index) {
  246. auto op_desc = node.GetOpDesc();
  247. if (op_desc == nullptr) {
  248. return InputRWType::kInvalidRWType;
  249. }
  250. if (op_desc->GetType() == WHILE) {
  251. return InputRWType::kScopeWriteable;
  252. }
  253. vector<string> subgraph_names = op_desc->GetSubgraphInstanceNames();
  254. if (subgraph_names.empty()) {
  255. // single node without sub graph
  256. return GetSingleNodeInputRWTypeByIndex(node, index);
  257. } else {
  258. auto data_node_vec = NodeUtils::GetSubgraphDataNodesByIndex(node, index);
  259. // get all input data node in subgraph
  260. std::set<int> anchor_rw_type_set;
  261. for (const auto &data_node : data_node_vec) {
  262. // Data only has 1 out data anchor. Here just take first out data anchor. And index 0 is valid.
  263. auto out_data_anchor = data_node->GetOutDataAnchor(0);
  264. if (out_data_anchor == nullptr) {
  265. continue;
  266. }
  267. auto data_op_desc = data_node->GetOpDesc();
  268. if (data_op_desc == nullptr) {
  269. continue;
  270. }
  271. // find rw type from map.
  272. auto iter = node_rwtype_map_.find(data_op_desc->GetName());
  273. if (iter == node_rwtype_map_.end()) {
  274. GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.",
  275. data_op_desc->GetName().c_str());
  276. return InputRWType::kInvalidRWType;
  277. }
  278. auto input_rw_type = iter->second.input_rw_type_map.find(out_data_anchor->GetIdx());
  279. if (input_rw_type == iter->second.input_rw_type_map.end()) {
  280. GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.",
  281. data_op_desc->GetName().c_str());
  282. return InputRWType::kInvalidRWType;
  283. }
  284. anchor_rw_type_set.emplace(static_cast<int>(input_rw_type->second));
  285. }
  286. return GetInputRwTypeInConflict(anchor_rw_type_set);
  287. }
  288. }
  289. Status MarkRWTypeForSubgraph(const ComputeGraphPtr &sub_graph) {
  290. for (const auto &node : sub_graph->GetDirectNode()) {
  291. GE_CHECK_NOTNULL(node);
  292. GE_CHECK_NOTNULL(node->GetOpDesc());
  293. std::set<int> anchor_rw_type_set;
  294. if (node->GetType() == DATA) {
  295. // calc all input_rw_type of peer output , as input_rw_type of DATA. Index 0 is valid.
  296. auto anchor_2_node_vec = NodeUtils::GetOutDataNodesWithAnchorByIndex(*node, 0);
  297. for (const auto anchor_2_node_pair : anchor_2_node_vec) {
  298. auto input_rw_type = GetInputRWTypeByIndex(*anchor_2_node_pair.second, anchor_2_node_pair.first->GetIdx());
  299. GELOGD("Input rw type of Node %s %dth input anchor is %s", anchor_2_node_pair.second->GetName().c_str(),
  300. anchor_2_node_pair.first->GetIdx(), InputRWTypeToSerialString(input_rw_type).c_str());
  301. anchor_rw_type_set.emplace(static_cast<int>(input_rw_type));
  302. }
  303. auto anchor_rw_type = GetInputRwTypeInConflict(anchor_rw_type_set);
  304. GELOGD("Input rw type of Node %s is %s", node->GetName().c_str(),
  305. InputRWTypeToSerialString(anchor_rw_type).c_str());
  306. map<uint32_t, InputRWType> input_rw_type_map{std::make_pair(0, anchor_rw_type)};
  307. NodeInputOutputRWType data_rw_type{input_rw_type_map};
  308. node_rwtype_map_.emplace(std::make_pair(node->GetName(), data_rw_type));
  309. }
  310. if (node->GetType() == NETOUTPUT) {
  311. // calc all output_rw_type of peer input , as output_rw_type of DATA
  312. map<uint32_t, OutputRWType> output_rw_type_map;
  313. for (const auto &in_data_anchor : node->GetAllInDataAnchors()) {
  314. GE_CHECK_NOTNULL(in_data_anchor);
  315. auto pre_out_anchor = in_data_anchor->GetPeerOutAnchor();
  316. GE_CHECK_NOTNULL(pre_out_anchor);
  317. auto pre_node = pre_out_anchor->GetOwnerNode();
  318. GE_CHECK_NOTNULL(pre_node);
  319. auto pre_output_rw_type = GetOutputRWTypeByIndex(*pre_node, pre_out_anchor->GetIdx());
  320. GELOGD("Output rw type of Node %s %dth output anchor is %s", pre_node->GetName().c_str(),
  321. pre_out_anchor->GetIdx(), OutputRWTypeToSerialString(pre_output_rw_type).c_str());
  322. auto parent_node = sub_graph->GetParentNode();
  323. if (pre_output_rw_type == OutputRWType::kWriteable && parent_node->GetType() != PARTITIONEDCALL) {
  324. // insert identity
  325. auto identity_node = CreateIdentityAfterSrcNode(*pre_node, pre_out_anchor->GetIdx());
  326. GE_CHECK_NOTNULL(identity_node);
  327. auto ret = GraphUtils::InsertNodeBetweenDataAnchors(pre_out_anchor, in_data_anchor, identity_node);
  328. if (ret != SUCCESS) {
  329. GELOGE(ret, "Fail to insert identity");
  330. return ret;
  331. }
  332. GELOGI("InsertNode %s between %s and %s successfully.", identity_node->GetName().c_str(),
  333. pre_node->GetName().c_str(), node->GetName().c_str());
  334. pre_output_rw_type = OutputRWType::kSoftRead;
  335. }
  336. output_rw_type_map.emplace(std::make_pair(in_data_anchor->GetIdx(), pre_output_rw_type));
  337. }
  338. NodeInputOutputRWType output_rw_type{{}, output_rw_type_map};
  339. node_rwtype_map_.emplace(std::make_pair(node->GetName(), output_rw_type));
  340. }
  341. }
  342. return SUCCESS;
  343. }
  344. ///
  345. /// @brief Reverse traversal all subgraph and mark rw_type for Data/Netoutput.
  346. /// @param sub_graph_vecgs
  347. ///
  348. Status MarkRWTypeForAllSubgraph(const vector<ComputeGraphPtr> &sub_graph_vec) {
  349. for (auto iter = sub_graph_vec.rbegin(); iter != sub_graph_vec.rend(); ++iter) {
  350. auto parent_node = (*iter)->GetParentNode();
  351. if (parent_node == nullptr) {
  352. GELOGD("Current sub graph has no parent node. Ignore it.");
  353. continue;
  354. }
  355. if (parent_node->GetType() == WHILE) {
  356. continue;
  357. }
  358. auto ret = MarkRWTypeForSubgraph(*iter);
  359. if (ret != SUCCESS) {
  360. return ret;
  361. }
  362. }
  363. return SUCCESS;
  364. }
  365. ///
  366. /// @brief Check identity is near subgraph.
  367. /// Eg. As output of Data node in subgraph
  368. /// or as input of Netoutput of subgraph
  369. /// or as input of one node with subgraph
  370. /// or as output of one node with subgraph
  371. /// @param node
  372. /// @return is_near_subgraph
  373. ///
  374. bool CheckIdentityIsNearSubgraph(const Node &node) {
  375. for (const auto &in_node : node.GetInDataNodes()) {
  376. auto in_node_opdesc = in_node->GetOpDesc();
  377. if (in_node_opdesc == nullptr) {
  378. continue;
  379. }
  380. // near entrance of subgraph
  381. if (IsSubgraphInputNode(in_node)) {
  382. return true;
  383. }
  384. // near subgraph
  385. if (!in_node_opdesc->GetSubgraphInstanceNames().empty()) {
  386. return true;
  387. }
  388. }
  389. for (const auto &out_node : node.GetOutDataNodes()) {
  390. auto out_node_opdesc = out_node->GetOpDesc();
  391. if (out_node_opdesc == nullptr) {
  392. continue;
  393. }
  394. // near output of subgraph
  395. if (IsSubgraphOutputNode(out_node)) {
  396. return true;
  397. }
  398. // near subgraph
  399. if (!out_node_opdesc->GetSubgraphInstanceNames().empty()) {
  400. return true;
  401. }
  402. }
  403. return false;
  404. }
  405. enum ConflictResult { DO_NOTHING, WRONG_GRAPH, INSERT_IDENTITY };
  406. vector<vector<ConflictResult>> output_2_input_rwtype = {{DO_NOTHING, WRONG_GRAPH, INSERT_IDENTITY},
  407. {DO_NOTHING, WRONG_GRAPH, DO_NOTHING},
  408. {DO_NOTHING, DO_NOTHING, INSERT_IDENTITY}};
  409. ConflictResult GetConflictResultBetweenNode(const OutputRWType output_rw_type, const InputRWType input_rw_type) {
  410. if (output_rw_type == OutputRWType::kInvalidRWType || input_rw_type == InputRWType::kInvalidRWType) {
  411. return WRONG_GRAPH;
  412. }
  413. auto n = static_cast<int>(output_rw_type);
  414. auto m = static_cast<int>(input_rw_type);
  415. // no need to check index or container, because container and index is all defined.
  416. return output_2_input_rwtype[n][m];
  417. }
  418. ///
  419. /// @brief Keep identity_node which near subgraph or has multi output
  420. /// @param node
  421. /// @return
  422. ///
  423. Status RemoveNoUseIdentity(const NodePtr &node) {
  424. if (node->GetInDataNodes().empty() || node->GetOutDataNodesSize() > 1) {
  425. return SUCCESS;
  426. }
  427. if (node->GetOutDataNodesSize() == 1 && node->GetOutDataNodes().at(0)->GetType() == STREAMMERGE) {
  428. return SUCCESS;
  429. }
  430. if (CheckIdentityIsNearSubgraph(*node)) {
  431. return SUCCESS;
  432. }
  433. GE_CHECK_NOTNULL(node->GetInDataAnchor(kIdentityAnchorIndex));
  434. auto pre_out_anchor = node->GetInDataAnchor(kIdentityAnchorIndex)->GetPeerOutAnchor();
  435. GE_CHECK_NOTNULL(pre_out_anchor);
  436. auto pre_node = pre_out_anchor->GetOwnerNode();
  437. auto pre_output_rw_type = GetOutputRWTypeByIndex(*pre_node, pre_out_anchor->GetIdx());
  438. auto anchor_2_outnode_vec = NodeUtils::GetOutDataNodesWithAnchorByIndex(*node, kIdentityAnchorIndex);
  439. ConflictResult conflict_result = WRONG_GRAPH;
  440. if (!anchor_2_outnode_vec.empty()) {
  441. auto anchor_2_outnode = anchor_2_outnode_vec.at(0);
  442. auto peer_input_rw_type = GetInputRWTypeByIndex(*anchor_2_outnode.second, anchor_2_outnode.first->GetIdx());
  443. GELOGD("Pre Node %s %dth output rw type is %s, peer node %s %dth input rw type is %s.", pre_node->GetName().c_str(),
  444. pre_out_anchor->GetIdx(), OutputRWTypeToSerialString(pre_output_rw_type).c_str(),
  445. anchor_2_outnode.second->GetName().c_str(), anchor_2_outnode.first->GetIdx(),
  446. InputRWTypeToSerialString(peer_input_rw_type).c_str());
  447. conflict_result = GetConflictResultBetweenNode(pre_output_rw_type, peer_input_rw_type);
  448. } else {
  449. // identity node has no out data node, it can be removed
  450. conflict_result = DO_NOTHING;
  451. }
  452. if (conflict_result != DO_NOTHING) {
  453. return SUCCESS;
  454. }
  455. GELOGI("No need insert Identity. Node %s need to remove.", node->GetName().c_str());
  456. auto ret = GraphUtils::IsolateNode(node, {0});
  457. if (ret != SUCCESS) {
  458. GELOGE(ret, "Fail to isolate node %s.", node->GetName().c_str());
  459. return ret;
  460. }
  461. ret = GraphUtils::RemoveNodeWithoutRelink(node->GetOwnerComputeGraph(), node);
  462. if (ret != SUCCESS) {
  463. GELOGE(ret, "Fail to isolate node %s.", node->GetName().c_str());
  464. return ret;
  465. }
  466. GELOGI("Pre node is %s and %dth output rw type is %s. Isolate and remove Identity node %s.",
  467. pre_node->GetName().c_str(), pre_out_anchor->GetIdx(), OutputRWTypeToSerialString(pre_output_rw_type).c_str(),
  468. node->GetName().c_str());
  469. return SUCCESS;
  470. }
  471. Status SplitIdentityAlongAnchor(const OutDataAnchorPtr &out_data_anchor, const InDataAnchorPtr &peer_in_data_anchor,
  472. const OutDataAnchorPtr &pre_out_data_anchor, NodePtr &pre_node) {
  473. // 1.check peer in node RW type.
  474. GE_CHECK_NOTNULL(peer_in_data_anchor);
  475. auto peer_in_data_node = peer_in_data_anchor->GetOwnerNode();
  476. GE_CHECK_NOTNULL(peer_in_data_node);
  477. auto input_rw_type = GetInputRWTypeByIndex(*peer_in_data_node, peer_in_data_anchor->GetIdx());
  478. auto ret = out_data_anchor->Unlink(peer_in_data_anchor);
  479. auto old_identity = out_data_anchor->GetOwnerNode();
  480. if (ret != SUCCESS) {
  481. GELOGE(ret, "Failed to unlink from %s %dth out to %s.", old_identity->GetName().c_str(), out_data_anchor->GetIdx(),
  482. peer_in_data_anchor->GetOwnerNode()->GetName().c_str());
  483. return ret;
  484. }
  485. if (input_rw_type == InputRWType::kScopeWriteable || input_rw_type == InputRWType::kWriteable) {
  486. auto new_identity = CreateIdentityAfterSrcNode(*pre_node, pre_out_data_anchor->GetIdx());
  487. GE_CHECK_NOTNULL(new_identity);
  488. if (GraphUtils::AddEdge(pre_out_data_anchor, new_identity->GetInDataAnchor(kIdentityAnchorIndex)) != SUCCESS
  489. || GraphUtils::AddEdge(new_identity->GetOutDataAnchor(kIdentityAnchorIndex), peer_in_data_anchor) != SUCCESS) {
  490. GELOGE(INTERNAL_ERROR, "Failed to insert Identity between node %s and %s",
  491. pre_out_data_anchor->GetOwnerNode()->GetName().c_str(),
  492. peer_in_data_anchor->GetOwnerNode()->GetName().c_str());
  493. return INTERNAL_ERROR;
  494. }
  495. // 2. copy in-control-edge from dst to Identity
  496. if (GraphUtils::CopyInCtrlEdges(peer_in_data_node, new_identity) != SUCCESS) {
  497. GELOGE(INTERNAL_ERROR, "Failed to copy in_control edges from node %s to %s", peer_in_data_node->GetName().c_str(),
  498. new_identity->GetName().c_str());
  499. return INTERNAL_ERROR;
  500. }
  501. GELOGI("Node %s intput rw type is %s. Insert Identity between %s and %s.", peer_in_data_node->GetName().c_str(),
  502. InputRWTypeToSerialString(input_rw_type).c_str(), pre_out_data_anchor->GetOwnerNode()->GetName().c_str(),
  503. peer_in_data_anchor->GetOwnerNode()->GetName().c_str());
  504. } else {
  505. // copy control edge to pre and peer node
  506. if (GraphUtils::CopyInCtrlEdges(old_identity, peer_in_data_node) != SUCCESS
  507. || GraphUtils::CopyOutCtrlEdges(old_identity, pre_node) != SUCCESS) {
  508. GELOGW("Fail to copy control edge from node %s.", old_identity->GetName().c_str());
  509. return FAILED;
  510. }
  511. // link identity pre node to next node directly
  512. if (GraphUtils::AddEdge(pre_out_data_anchor, peer_in_data_anchor) != SUCCESS) {
  513. GELOGW("Fail to link data edge from node %s to %s.", pre_out_data_anchor->GetOwnerNode()->GetName().c_str(),
  514. peer_in_data_anchor->GetOwnerNode()->GetName().c_str());
  515. return FAILED;
  516. }
  517. GELOGI("Node %s input rw type is %s, link data edge from Identity input node %s to out node %s directly.",
  518. peer_in_data_node->GetName().c_str(), InputRWTypeToSerialString(input_rw_type).c_str(),
  519. pre_node->GetName().c_str(), peer_in_data_node->GetName().c_str());
  520. }
  521. return SUCCESS;
  522. }
  523. Status SplitIdentity(const NodePtr &node) {
  524. GE_CHECK_NOTNULL(node);
  525. auto out_data_anchor = node->GetOutDataAnchor(kIdentityAnchorIndex);
  526. GE_CHECK_NOTNULL(out_data_anchor);
  527. if (out_data_anchor->GetPeerInDataNodesSize() <= 1) {
  528. return SUCCESS;
  529. }
  530. // get pre node and next node of identity
  531. GE_CHECK_NOTNULL(node->GetInDataAnchor(kIdentityAnchorIndex));
  532. auto pre_out_data_anchor = node->GetInDataAnchor(kIdentityAnchorIndex)->GetPeerOutAnchor();
  533. GE_CHECK_NOTNULL(pre_out_data_anchor);
  534. auto pre_node = pre_out_data_anchor->GetOwnerNode();
  535. GE_CHECK_NOTNULL(pre_node);
  536. for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) {
  537. Status ret = SplitIdentityAlongAnchor(out_data_anchor, peer_in_data_anchor, pre_out_data_anchor, pre_node);
  538. if (ret != SUCCESS) {
  539. GELOGE(ret, "Split identity node along anchor failed.");
  540. return ret;
  541. }
  542. }
  543. // 2.isolate Identity node with no data output
  544. if (node->GetOutDataNodesSize() == 0) {
  545. Status ret = GraphUtils::IsolateNode(node, {});
  546. if (ret != SUCCESS) {
  547. GELOGE(FAILED, "IsolateAndDelete identity node %s.", node->GetName().c_str());
  548. return FAILED;
  549. }
  550. ret = GraphUtils::RemoveNodeWithoutRelink(node->GetOwnerComputeGraph(), node);
  551. if (ret != SUCCESS) {
  552. GELOGE(FAILED, "IsolateAndDelete identity node %s.", node->GetName().c_str());
  553. return FAILED;
  554. }
  555. GELOGI("IsolateAndDelete identity node %s.", node->GetName().c_str());
  556. }
  557. return SUCCESS;
  558. }
  559. Status InsertIdentityAsNeeded(const NodePtr &node) {
  560. auto op_desc = node->GetOpDesc();
  561. GE_CHECK_NOTNULL(op_desc);
  562. if (node->GetOutDataNodesSize() == 0) {
  563. return SUCCESS;
  564. }
  565. for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) {
  566. GE_CHECK_NOTNULL(out_data_anchor);
  567. auto output_rw_type = GetOutputRWTypeByIndex(*node, out_data_anchor->GetIdx());
  568. for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) {
  569. GE_CHECK_NOTNULL(peer_in_data_anchor);
  570. auto peer_in_node = peer_in_data_anchor->GetOwnerNode();
  571. GE_CHECK_NOTNULL(peer_in_node);
  572. auto input_rw_type = GetInputRWTypeByIndex(*peer_in_node, peer_in_data_anchor->GetIdx());
  573. GELOGD("Node %s output rw type is %s, Node %s input rw type is %s", node->GetName().c_str(),
  574. OutputRWTypeToSerialString(output_rw_type).c_str(), peer_in_node->GetName().c_str(),
  575. InputRWTypeToSerialString(input_rw_type).c_str());
  576. auto conflict_result = GetConflictResultBetweenNode(output_rw_type, input_rw_type);
  577. switch (conflict_result) {
  578. case DO_NOTHING:
  579. case WRONG_GRAPH:
  580. GELOGD("No need insert Identity.");
  581. continue;
  582. case INSERT_IDENTITY:
  583. auto identity_node = CreateIdentityAfterSrcNode(*node, out_data_anchor->GetIdx());
  584. if (identity_node == nullptr) {
  585. GELOGE(FAILED, "Create identity node failed.");
  586. return FAILED;
  587. }
  588. auto ret = GraphUtils::InsertNodeBetweenDataAnchors(out_data_anchor, peer_in_data_anchor, identity_node);
  589. if (ret != GRAPH_SUCCESS) {
  590. GELOGE(INTERNAL_ERROR, "Failed to insert reshape between node %s and %s", node->GetName().c_str(),
  591. peer_in_node->GetName().c_str());
  592. return INTERNAL_ERROR;
  593. }
  594. GELOGI("Insert Identity between %s and %s to handle memory conflict.", node->GetName().c_str(),
  595. peer_in_node->GetName().c_str());
  596. continue;
  597. }
  598. }
  599. }
  600. return SUCCESS;
  601. }
  602. Status HandleAllreduceDuplicateInput(ComputeGraphPtr &compute_graph) {
  603. for (const auto &node : compute_graph->GetDirectNode()) {
  604. bool mutable_input_flag = false;
  605. (void)AttrUtils::GetBool(node->GetOpDesc(), kModifyInput, mutable_input_flag);
  606. if (!mutable_input_flag) {
  607. continue;
  608. }
  609. std::set<OutDataAnchorPtr> pre_out_anchor_set;
  610. for (const auto &in_data_anchor : node->GetAllInDataAnchors()) {
  611. auto pre_out_anchor = in_data_anchor->GetPeerOutAnchor();
  612. GE_CHECK_NOTNULL(pre_out_anchor);
  613. if (pre_out_anchor_set.insert(pre_out_anchor).second) {
  614. continue;
  615. }
  616. // need insert identity
  617. auto pre_node = pre_out_anchor->GetOwnerNode();
  618. auto identity_node = CreateIdentityAfterSrcNode(*pre_node, pre_out_anchor->GetIdx());
  619. GE_CHECK_NOTNULL(identity_node);
  620. auto ret = GraphUtils::InsertNodeBetweenDataAnchors(pre_out_anchor, in_data_anchor, identity_node);
  621. GE_CHK_STATUS_RET(ret, "Fail to insert identity.");
  622. GELOGI("InsertNode %s between %s and %s successfully.", identity_node->GetName().c_str(),
  623. pre_node->GetName().c_str(), node->GetName().c_str());
  624. }
  625. }
  626. return SUCCESS;
  627. }
  628. } // namespace
  629. namespace ge {
  630. Status GraphOptimize::CheckRWConflict(ComputeGraphPtr &compute_graph, bool &has_conflict) {
  631. node_rwtype_map_.clear();
  632. auto sub_graph_vec = compute_graph->GetAllSubgraphs();
  633. if (sub_graph_vec.empty()) {
  634. GELOGD("No sub graph here. Ignore memory conflict handle.");
  635. return SUCCESS;
  636. }
  637. // 1.loop all subgraph, mark rw type from inside to outside
  638. Status ret = MarkRWTypeForAllSubgraph(sub_graph_vec);
  639. if (ret != SUCCESS) {
  640. GELOGE(ret, "Fail to mark rw type for subgraph.");
  641. return ret;
  642. }
  643. has_conflict = false;
  644. for (const auto &node : compute_graph->GetAllNodes()) {
  645. auto op_desc = node->GetOpDesc();
  646. GE_CHECK_NOTNULL(op_desc);
  647. if (node->GetOutDataNodesSize() == 0) {
  648. return SUCCESS;
  649. }
  650. if (node->GetType() == WHILE) {
  651. return SUCCESS;
  652. }
  653. for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) {
  654. GE_CHECK_NOTNULL(out_data_anchor);
  655. auto output_rw_type = GetOutputRWTypeByIndex(*node, out_data_anchor->GetIdx());
  656. for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) {
  657. GE_CHECK_NOTNULL(peer_in_data_anchor);
  658. auto peer_in_node = peer_in_data_anchor->GetOwnerNode();
  659. GE_CHECK_NOTNULL(peer_in_node);
  660. if (peer_in_node->GetType() == WHILE) {
  661. return SUCCESS;
  662. }
  663. auto input_rw_type = GetInputRWTypeByIndex(*peer_in_node, peer_in_data_anchor->GetIdx());
  664. auto conflict_result = GetConflictResultBetweenNode(output_rw_type, input_rw_type);
  665. switch (conflict_result) {
  666. case DO_NOTHING:
  667. GELOGD("No rw conflict.");
  668. continue;
  669. case WRONG_GRAPH:
  670. has_conflict = true;
  671. GELOGI("Node %s output rw type is %s, next node %s input_rw_type is %s.It is wrong graph.",
  672. node->GetName().c_str(), OutputRWTypeToSerialString(output_rw_type).c_str(),
  673. peer_in_node->GetName().c_str(), InputRWTypeToSerialString(input_rw_type).c_str());
  674. return SUCCESS;
  675. case INSERT_IDENTITY:
  676. GELOGD("There is rw conflict. It will handle later.");
  677. continue;
  678. }
  679. }
  680. }
  681. }
  682. return SUCCESS;
  683. }
  684. Status GraphOptimize::HandleMemoryRWConflict(ComputeGraphPtr &compute_graph) {
  685. GE_DUMP(compute_graph, "BeforeHandleMemConflict");
  686. node_rwtype_map_.clear();
  687. auto sub_graph_vec = compute_graph->GetAllSubgraphs();
  688. if (sub_graph_vec.empty()) {
  689. // only root graph, to handle allreduce servral input from one output anchor
  690. return HandleAllreduceDuplicateInput(compute_graph);
  691. }
  692. // 1.loop all subgraph, mark rw type from inside to outside
  693. Status ret = MarkRWTypeForAllSubgraph(sub_graph_vec);
  694. if (ret != SUCCESS) {
  695. GELOGE(ret, "Fail to mark rw type for subgraph.");
  696. return ret;
  697. }
  698. // 2.loop all node, including node in subgraph and handle memory rw conflict
  699. for (auto &node : compute_graph->GetAllNodes()) {
  700. // ignore while subgraph node
  701. const auto parent_node = node->GetOwnerComputeGraph()->GetParentNode();
  702. if ((parent_node != nullptr) && (kWhileOpTypes.count(parent_node->GetType()) > 0)) {
  703. continue;
  704. }
  705. // ignore data / netoutput of subgraph
  706. if (node->GetType() == DATA && AttrUtils::HasAttr(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX)) {
  707. continue;
  708. }
  709. if (node->GetType() == NETOUTPUT && AttrUtils::HasAttr(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX)) {
  710. continue;
  711. }
  712. bool identity_reserved = false;
  713. AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_CANNOT_BE_DELETED, identity_reserved);
  714. if (identity_reserved) {
  715. GELOGD("Identity [%s] need to be reserved", node->GetName().c_str());
  716. continue;
  717. }
  718. if (node->GetType() == IDENTITY || node->GetType() == READVARIABLEOP) {
  719. // split identity
  720. ret = SplitIdentity(node);
  721. if (ret != SUCCESS) {
  722. GELOGE(ret, "Fail to split identity node %s.", node->GetName().c_str());
  723. return ret;
  724. }
  725. // remove no use identity
  726. ret = RemoveNoUseIdentity(node);
  727. if (ret != SUCCESS) {
  728. GELOGE(ret, "Fail to remove useless identity node %s.", node->GetName().c_str());
  729. return ret;
  730. }
  731. }
  732. // insert Identity
  733. ret = InsertIdentityAsNeeded(node);
  734. if (ret != SUCCESS) {
  735. GELOGE(ret, "Fail to insert Identity node.");
  736. return ret;
  737. }
  738. }
  739. GE_DUMP(compute_graph, "AfterHandleMemConflict");
  740. return SUCCESS;
  741. }
  742. } // namespace ge

图引擎模块(GE)是MindSpore的一个子模块,其代码由C++实现,位于前端模块ME和底层硬件之间,起到承接作用。图引擎模块以ME下发的图作为输入,然后进行一系列的深度图优化操作,最后输出一张可以在底层硬件上高效运行的图。GE针对昇腾AI处理器的硬件结构特点,做了特定的优化工作,以此来充分发挥出昇腾AI处理器的强大算力。在进行模型训练/推理时,GE会被自动调用而用户并不感知。GE主要由GE API和GE Core两部分组成,详细的架构图如下所示