1 /**
2 * Copyright 2022 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "tools/graph_kernel/converter/graph_kernel_pass_manager_lite.h"
17
18 #include <vector>
19 #include <string>
20 #include <memory>
21 #include <algorithm>
22 #include <iomanip>
23 #include <optional>
24 #include "ir/graph_utils.h"
25 #include "src/common/file_utils.h"
26 #include "utils/file_utils.h"
27 #include "src/common/utils.h"
28 #include "utils/anf_utils.h"
29 #include "tools/graph_kernel/common/utils.h"
30
31 namespace mindspore::graphkernel {
32 namespace dumpir {
33 struct SubGraphIRInfo {
34 int32_t local_var;
35 std::ostringstream dumpbuf;
36 OrderedMap<AnfNodePtr, int32_t> local_var_map;
37 };
38
DumpGlobalInfoEntry(const FuncGraphPtr & graph,std::ostringstream & dumpbuf)39 void DumpGlobalInfoEntry(const FuncGraphPtr &graph, std::ostringstream &dumpbuf) {
40 if (graph == nullptr) {
41 return;
42 }
43 dumpbuf << "#IR entry : @" << graph->ToString() << std::endl;
44 dumpbuf << "#attrs :" << std::endl;
45 for (const auto &attr : graph->attrs()) {
46 dumpbuf << attr.first << " : ";
47 if (attr.second->isa<BoolImm>()) {
48 dumpbuf << (GetValue<bool>(attr.second));
49 } else if (attr.second->isa<StringImm>()) {
50 dumpbuf << (GetValue<std::string>(attr.second));
51 }
52 dumpbuf << std::endl;
53 }
54 }
55
PrintNodeOutputType(std::ostringstream & dumpbuf,const AnfNodePtr & nd)56 void PrintNodeOutputType(std::ostringstream &dumpbuf, const AnfNodePtr &nd) {
57 if (nd == nullptr) {
58 return;
59 }
60 ValuePtr tensor_value = nullptr;
61 auto abstract = nd->abstract();
62 if (abstract != nullptr && abstract->isa<abstract::AbstractTensor>()) {
63 tensor_value = abstract->BuildValue();
64 }
65 abstract::ShapePtr shape = dyn_cast<abstract::Shape>(nd->Shape());
66 TypePtr type = dyn_cast<Type>(nd->Type());
67 if ((shape != nullptr) && (type != nullptr)) {
68 dumpbuf << "<" << type << ", " << shape->ToString();
69 if (tensor_value != nullptr && tensor_value != kValueAny) {
70 dumpbuf << ", value=...";
71 }
72 dumpbuf << ">";
73 } else if (type != nullptr) {
74 dumpbuf << "<" << type;
75 if (tensor_value != nullptr && tensor_value != kValueAny) {
76 dumpbuf << ", value=...";
77 }
78 dumpbuf << ">";
79 } else {
80 dumpbuf << "<null>";
81 }
82 }
83
DumpParams(const FuncGraphPtr & graph,std::ostringstream & dumpbuf,OrderedMap<AnfNodePtr,int32_t> * para_map)84 int32_t DumpParams(const FuncGraphPtr &graph, std::ostringstream &dumpbuf, OrderedMap<AnfNodePtr, int32_t> *para_map) {
85 if (graph == nullptr) {
86 MS_LOG(INFO) << "Param graph is nullptr.";
87 return 0;
88 }
89 std::vector<AnfNodePtr> parameters = graph->parameters();
90 dumpbuf << "#Total params : " << parameters.size() << std::endl;
91 dumpbuf << std::endl;
92
93 // dump parameters
94 int32_t para = 1;
95 for (const auto &p : parameters) {
96 if (p == nullptr) {
97 continue;
98 }
99 auto parameter_ptr = p->cast<ParameterPtr>();
100 if (parameter_ptr == nullptr) {
101 MS_LOG(EXCEPTION) << "p cannot cast to ParameterPtr";
102 }
103 dumpbuf << "%para" << para << "_" << parameter_ptr->name() << " : ";
104 // print parameters' type and shape
105 PrintNodeOutputType(dumpbuf, p);
106 dumpbuf << std::endl;
107
108 if (para_map != nullptr) {
109 (*para_map)[p] = para++;
110 }
111 MS_LOG(DEBUG) << "Record param: " << p->ToString() << " graph belong : " << p->func_graph()->ToString();
112 }
113 return para;
114 }
115
DumpOperator(const AnfNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)116 void DumpOperator(const AnfNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
117 if (op == nullptr || gsub == nullptr) {
118 return;
119 }
120
121 if (IsValueNode<FuncGraph>(op)) {
122 FuncGraphPtr fg = GetValueNode<FuncGraphPtr>(op);
123 if (fg != nullptr) {
124 gsub->dumpbuf << "call @" << fg->ToString();
125 }
126 } else if (op->isa<CNode>()) {
127 if (gsub->local_var_map.find(op) != gsub->local_var_map.end()) {
128 gsub->dumpbuf << "%" << gsub->local_var_map[op];
129 } else {
130 auto node = op->cast<CNodePtr>();
131 auto fg = node->func_graph();
132 gsub->dumpbuf << "$(" << fg->ToString() << ":" << node->ToString() << ")";
133 }
134 } else if (op->isa<ValueNode>()) {
135 gsub->dumpbuf << GetValueNode(op)->ToString();
136 } else {
137 gsub->dumpbuf << op->ToString();
138 }
139 }
140
DumpOperands(const AnfNodePtr & nd,OrderedMap<AnfNodePtr,int32_t> * para_map,const std::shared_ptr<SubGraphIRInfo> & gsub)141 void DumpOperands(const AnfNodePtr &nd, OrderedMap<AnfNodePtr, int32_t> *para_map,
142 const std::shared_ptr<SubGraphIRInfo> &gsub) {
143 if (nd == nullptr || para_map == nullptr || gsub == nullptr) {
144 return;
145 }
146
147 gsub->dumpbuf << "(";
148 const auto &inputs = GetInputs(nd);
149 size_t len = inputs.size();
150 if (len > 1) {
151 // skip inputs[0] which is Primitive valuenode
152 for (size_t i = 1; i < len; ++i) {
153 AnfNodePtr in = inputs[i];
154 MS_EXCEPTION_IF_NULL(in);
155 if (i != 1) {
156 gsub->dumpbuf << ", ";
157 }
158 if (in->isa<Parameter>()) {
159 if (!(*para_map)[in]) {
160 gsub->dumpbuf << "%para_" << in->ToString();
161 } else {
162 gsub->dumpbuf << "%para" << (*para_map)[in] << "_" << in->ToString();
163 }
164 } else if (in->isa<CNode>()) {
165 if (gsub->local_var_map.find(in) != gsub->local_var_map.end()) {
166 gsub->dumpbuf << "%" << gsub->local_var_map[in];
167 } else {
168 auto node = in->cast<CNodePtr>();
169 auto fg = node->func_graph();
170 gsub->dumpbuf << "$(" << fg->ToString() << ":" << node->ToString() << ")";
171 }
172 } else if (in->isa<ValueNode>() && !IsValueNode<FuncGraph>(in)) {
173 // non Primitive valuenode
174 gsub->dumpbuf << GetValueNode(in)->ToString();
175 } else if (IsValueNode<FuncGraph>(in)) {
176 FuncGraphPtr fg = GetValueNode<FuncGraphPtr>(in);
177 gsub->dumpbuf << "@" << fg->ToString();
178 } else {
179 gsub->dumpbuf << in->ToString();
180 }
181 }
182 }
183 gsub->dumpbuf << ")";
184 }
185
DumpAttrs(const mindspore::HashMap<std::string,ValuePtr> & attrs,const std::shared_ptr<SubGraphIRInfo> & gsub,bool check_strategy=false)186 void DumpAttrs(const mindspore::HashMap<std::string, ValuePtr> &attrs, const std::shared_ptr<SubGraphIRInfo> &gsub,
187 bool check_strategy = false) {
188 int i = 0;
189 for (const auto &attr : attrs) {
190 if (i++ != 0) {
191 gsub->dumpbuf << ", ";
192 }
193 gsub->dumpbuf << attr.first << ": ";
194 if (attr.second == nullptr) {
195 gsub->dumpbuf << "null";
196 } else {
197 gsub->dumpbuf << attr.second->ToString();
198 }
199 }
200 }
201
DumpOperateAttrs(const AnfNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)202 void DumpOperateAttrs(const AnfNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
203 if (op == nullptr || gsub == nullptr) {
204 return;
205 }
206
207 if (IsValueNode<Primitive>(op)) {
208 auto primitive = GetValueNode<PrimitivePtr>(op);
209 if (!primitive->instance_name().empty()) {
210 gsub->dumpbuf << " {";
211 gsub->dumpbuf << "instance name"
212 << ": ";
213 gsub->dumpbuf << primitive->instance_name();
214 gsub->dumpbuf << "}";
215 }
216 auto attrs = primitive->attrs();
217 if (!attrs.empty()) {
218 gsub->dumpbuf << " primitive_attrs: {";
219 DumpAttrs(attrs, gsub, true);
220 gsub->dumpbuf << "}";
221 }
222 }
223 }
224
DumpCNodeAttrs(const CNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)225 void DumpCNodeAttrs(const CNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
226 if (op == nullptr || gsub == nullptr) {
227 return;
228 }
229 auto &attrs = op->attrs();
230 if (attrs.empty()) {
231 return;
232 }
233
234 gsub->dumpbuf << " cnode_attrs: {";
235 DumpAttrs(attrs, gsub);
236 gsub->dumpbuf << "}";
237 }
238
DumpCNodePrimalAttrs(const CNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)239 void DumpCNodePrimalAttrs(const CNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
240 if (op == nullptr || gsub == nullptr) {
241 return;
242 }
243 if (op->primal_attrs().empty()) {
244 gsub->dumpbuf << std::endl;
245 return;
246 }
247 auto primal_attrs = op->primal_attrs();
248 gsub->dumpbuf << " cnode_primal_attrs: {";
249 DumpAttrs(primal_attrs, gsub);
250 gsub->dumpbuf << "}";
251 gsub->dumpbuf << std::endl;
252 }
253
PrintNodeInputType(std::ostringstream & dumpbuf,const AnfNodePtr & nd)254 void PrintNodeInputType(std::ostringstream &dumpbuf, const AnfNodePtr &nd) {
255 if (nd == nullptr) {
256 return;
257 }
258 const auto &inputs = GetInputs(nd);
259 size_t len = inputs.size();
260 if (len > 1) {
261 // skip inputs[0] which is Primitive value node
262 for (size_t i = 1; i < len; ++i) {
263 AnfNodePtr in = inputs[i];
264 if (i != 1) {
265 dumpbuf << ", ";
266 }
267 PrintNodeOutputType(dumpbuf, in);
268 }
269 }
270 }
271
DumpShape(const AnfNodePtr & nd,const FuncGraphPtr & sub_graph,const std::shared_ptr<SubGraphIRInfo> & gsub)272 void DumpShape(const AnfNodePtr &nd, const FuncGraphPtr &sub_graph, const std::shared_ptr<SubGraphIRInfo> &gsub) {
273 if (nd == nullptr || sub_graph == nullptr || gsub == nullptr) {
274 return;
275 }
276
277 if (nd != sub_graph->get_return()) {
278 gsub->dumpbuf << " : (";
279 PrintNodeInputType(gsub->dumpbuf, nd);
280 gsub->dumpbuf << ") -> (";
281 PrintNodeOutputType(gsub->dumpbuf, nd);
282 gsub->dumpbuf << ")";
283 } else {
284 gsub->dumpbuf << " : (";
285 PrintNodeInputType(gsub->dumpbuf, nd);
286 gsub->dumpbuf << ")";
287 }
288
289 gsub->dumpbuf << std::endl;
290 }
291
PrintKernelFormatAndType(const std::string & fmt,const TypeId & type,const std::vector<int64_t> & shape)292 std::string PrintKernelFormatAndType(const std::string &fmt, const TypeId &type, const std::vector<int64_t> &shape) {
293 std::ostringstream buffer;
294 buffer << "<" << TypeIdLabel(type);
295 if (!fmt.empty()) {
296 buffer << "x" << fmt << shape;
297 }
298 buffer << ">";
299 return buffer.str();
300 }
301
PrintOutputTypeShapeFormat(const std::shared_ptr<AnfNode> & node)302 std::string PrintOutputTypeShapeFormat(const std::shared_ptr<AnfNode> &node) {
303 if (node == nullptr) {
304 return "";
305 }
306 std::ostringstream buffer;
307 auto kernel_build_info = GetKernelInfo(node);
308 if (kernel_build_info == nullptr) {
309 return "";
310 }
311 size_t output_num = kernel_build_info->GetOutputNum();
312 buffer << "OutputFormats:";
313 for (size_t i = 0; i < output_num; ++i) {
314 if (i != 0) {
315 buffer << ", ";
316 }
317 auto format = GetOutputFormatFromAnfNode(node, i);
318 if (!format.empty()) {
319 buffer << format;
320 }
321 }
322 return buffer.str();
323 }
324
DumpKernelInfo(const CNodePtr & node,const std::shared_ptr<SubGraphIRInfo> & gsub)325 void DumpKernelInfo(const CNodePtr &node, const std::shared_ptr<SubGraphIRInfo> &gsub) {
326 if (node == nullptr || gsub == nullptr) {
327 return;
328 }
329 auto kernel_info = node->kernel_info();
330 if (kernel_info == nullptr || !kernel_info->has_build_info()) {
331 return;
332 }
333 gsub->dumpbuf << " : (";
334 gsub->dumpbuf << PrintOutputTypeShapeFormat(node);
335 gsub->dumpbuf << ")";
336 gsub->dumpbuf << std::endl;
337 }
338
DumpCNode(const CNodePtr & nd,const FuncGraphPtr & sub_graph,OrderedMap<AnfNodePtr,int32_t> * const para_map,const std::shared_ptr<SubGraphIRInfo> & gsub,bool dump_full_name=false)339 void DumpCNode(const CNodePtr &nd, const FuncGraphPtr &sub_graph, OrderedMap<AnfNodePtr, int32_t> *const para_map,
340 const std::shared_ptr<SubGraphIRInfo> &gsub, bool dump_full_name = false) {
341 if (nd == nullptr || sub_graph == nullptr || para_map == nullptr || gsub == nullptr) {
342 return;
343 }
344
345 if (nd != sub_graph->get_return()) {
346 gsub->dumpbuf << " %" << gsub->local_var << "(" << nd->ToString() << ")"
347 << " = ";
348 gsub->local_var_map[nd] = gsub->local_var++;
349 } else {
350 gsub->dumpbuf << " ";
351 }
352
353 if (nd->inputs().empty()) {
354 MS_LOG(EXCEPTION) << "Input of apply node is empty";
355 }
356 AnfNodePtr op = nd->input(0);
357 DumpOperator(op, gsub);
358 DumpOperands(nd, para_map, gsub);
359 DumpOperateAttrs(op, gsub);
360 DumpCNodeAttrs(nd, gsub);
361 DumpCNodePrimalAttrs(nd, gsub);
362 DumpShape(nd, sub_graph, gsub);
363 DumpKernelInfo(nd, gsub);
364 if (dump_full_name) {
365 gsub->dumpbuf << " : (" << nd->fullname_with_scope() << ")" << std::endl;
366 }
367 }
368
DumpIRInSubgraph(const std::vector<AnfNodePtr> & nodes,OrderedMap<AnfNodePtr,int32_t> * para_map,OrderedMap<FuncGraphPtr,std::shared_ptr<SubGraphIRInfo>> * const sub_graphs,int32_t total_para,bool dump_full_name=false)369 void DumpIRInSubgraph(const std::vector<AnfNodePtr> &nodes, OrderedMap<AnfNodePtr, int32_t> *para_map,
370 OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> *const sub_graphs, int32_t total_para,
371 bool dump_full_name = false) {
372 if (para_map == nullptr || sub_graphs == nullptr) {
373 return;
374 }
375
376 for (const auto &nd : nodes) {
377 MS_EXCEPTION_IF_NULL(nd);
378 FuncGraphPtr sub_graph = nd->func_graph();
379 if (sub_graph == nullptr) {
380 MS_LOG(DEBUG) << "Node[" << nd->ToString() << "] belongs to no graph!";
381 continue;
382 }
383 std::shared_ptr<SubGraphIRInfo> gsub = (*sub_graphs)[sub_graph];
384 if (gsub == nullptr) {
385 gsub = std::make_shared<SubGraphIRInfo>();
386 gsub->local_var = 0;
387 (*sub_graphs)[sub_graph] = gsub;
388 }
389 auto ¶m = sub_graph->parameters();
390 for (size_t idx = 0; idx < param.size(); idx++) {
391 MS_EXCEPTION_IF_NULL(param[idx]);
392 if ((*para_map).count(param[idx]) == 0) {
393 (*para_map)[param[idx]] = total_para++;
394 }
395 }
396 if (!nd->isa<Parameter>()) {
397 if (nd->isa<CNode>()) {
398 // print and record output of operator if it is not 'Return'
399 DumpCNode(nd->cast<CNodePtr>(), sub_graph, para_map, gsub, dump_full_name);
400 } else {
401 gsub->dumpbuf << " " << nd->ToString() << std::endl;
402 }
403 }
404 }
405 }
406
DumpSubgraph(const OrderedMap<FuncGraphPtr,std::shared_ptr<SubGraphIRInfo>> * sub_graphs,const FuncGraphPtr & graph,OrderedMap<AnfNodePtr,int32_t> * para_map,std::ofstream & fout)407 void DumpSubgraph(const OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> *sub_graphs,
408 const FuncGraphPtr &graph, OrderedMap<AnfNodePtr, int32_t> *para_map, std::ofstream &fout) {
409 if (sub_graphs == nullptr || graph == nullptr) {
410 return;
411 }
412
413 fout << "#Total subgraph : " << sub_graphs->size() << std::endl;
414 fout << std::endl;
415
416 for (const auto &sg : *sub_graphs) {
417 fout << "subgraph attr:" << std::endl;
418 MS_EXCEPTION_IF_NULL(sg.first);
419 for (const auto &attr : sg.first->attrs()) {
420 fout << attr.first << " : ";
421 if (attr.second->isa<BoolImm>()) {
422 fout << GetValue<bool>(attr.second);
423 } else if (attr.second->isa<StringImm>()) {
424 fout << (GetValue<std::string>(attr.second));
425 }
426 fout << std::endl;
427 }
428 fout << "subgraph @" << sg.first->ToString() << "(";
429 if (sg.first != graph) {
430 std::vector<AnfNodePtr> parameters = sg.first->parameters();
431 if (parameters.size() == 1) {
432 MS_EXCEPTION_IF_NULL(parameters[0]);
433 fout << "%para" << (*para_map)[parameters[0]] << "_" << parameters[0]->ToString();
434 } else if (parameters.size() > 1) {
435 for (size_t idx = 0; idx < parameters.size() - 1; idx++) {
436 MS_EXCEPTION_IF_NULL(parameters[idx]);
437 fout << "%para" << (*para_map)[parameters[idx]] << "_" << parameters[idx]->ToString();
438 fout << ", ";
439 }
440 MS_EXCEPTION_IF_NULL(parameters[parameters.size() - 1]);
441 fout << "%para" << (*para_map)[parameters[parameters.size() - 1]] << "_"
442 << parameters[parameters.size() - 1]->ToString();
443 }
444 }
445 fout << ") {" << std::endl;
446 MS_EXCEPTION_IF_NULL(sg.second);
447 fout << sg.second->dumpbuf.str();
448 fout << "}" << std::endl;
449 fout << std::endl;
450 }
451 }
452
CreatePrefixPath(const std::string & input_path)453 std::optional<std::string> CreatePrefixPath(const std::string &input_path) {
454 std::optional<std::string> prefix_path;
455 std::optional<std::string> file_name;
456 FileUtils::SplitDirAndFileName(input_path, &prefix_path, &file_name);
457 if (!file_name.has_value()) {
458 MS_LOG(ERROR) << "Cannot get file_name from: " << input_path;
459 return std::nullopt;
460 }
461 auto file_name_str = file_name.value();
462 std::string prefix_path_str;
463 if (prefix_path.has_value()) {
464 auto create_prefix_path = FileUtils::CreateNotExistDirs(prefix_path.value(), true);
465 if (!create_prefix_path.has_value()) {
466 return std::nullopt;
467 }
468 prefix_path_str = create_prefix_path.value();
469 } else {
470 auto pwd_path = FileUtils::GetRealPath("./");
471 if (!pwd_path.has_value()) {
472 MS_LOG(ERROR) << "Can not get pwd path";
473 return std::nullopt;
474 }
475 prefix_path_str = pwd_path.value();
476 }
477 return std::string(prefix_path_str + "/" + file_name_str);
478 }
479
DumpIR(const std::string & filename,const FuncGraphPtr & graph,bool dump_full_name)480 void DumpIR(const std::string &filename, const FuncGraphPtr &graph, bool dump_full_name) {
481 if (graph == nullptr) {
482 return;
483 }
484 auto path = "./" + filename;
485 auto realpath = CreatePrefixPath(path);
486 if (!realpath.has_value()) {
487 MS_LOG(ERROR) << "Get real path failed, path=" << path;
488 return;
489 }
490
491 std::ofstream fout(realpath.value());
492 std::ostringstream dumpbuf;
493
494 auto nodes = TopoSort(graph->get_return(), SuccDeeperSimple, AlwaysInclude);
495 OrderedMap<AnfNodePtr, int32_t> para_map;
496 // dump global info
497 DumpGlobalInfoEntry(graph, dumpbuf);
498 int32_t total_para = DumpParams(graph, dumpbuf, ¶_map);
499
500 OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> sub_graphs;
501 // dump ir in each sub graph
502 DumpIRInSubgraph(nodes, ¶_map, &sub_graphs, total_para, dump_full_name);
503
504 // output global info
505 fout << dumpbuf.str() << std::endl;
506
507 // output each sub graph
508 DumpSubgraph(&sub_graphs, graph, ¶_map, fout);
509
510 fout.close();
511 }
512 } // namespace dumpir
513
DumpPassIR(const FuncGraphPtr & func_graph,const std::string & pass_fullname) const514 void GraphKernelPassManagerLite::DumpPassIR(const FuncGraphPtr &func_graph, const std::string &pass_fullname) const {
515 static bool dump_ir = (common::GetEnv("MS_DEV_DUMP_GRAPH_KERNEL_IR") == "on");
516 if (dump_ir) {
517 static std::string rank_id = common::GetEnv("RANK_ID");
518 std::string filename;
519 if (rank_id.empty()) {
520 filename = "verbose_ir_files/" + pass_fullname + ".ir";
521 } else {
522 filename = "rank_" + rank_id + "/verbose_ir_files/" + pass_fullname + ".ir";
523 }
524 dumpir::DumpIR(filename, func_graph, true);
525 }
526 }
527
528 // transplant this function from pass_manager_extends.cc because the implement was moved to PassManagerLite.
RunPass(const FuncGraphPtr & func_graph,size_t pass_id,const PassPtr & pass) const529 bool GraphKernelPassManagerLite::RunPass(const FuncGraphPtr &func_graph, size_t pass_id, const PassPtr &pass) const {
530 bool changed = false;
531 auto begin_time = lite::GetTimeUs();
532 if (pass->Run(func_graph)) {
533 changed = true;
534 }
535 auto end_time = lite::GetTimeUs();
536 MS_LOG(INFO) << "Run pass " << GetPassFullname(pass_id, pass) << " in " << (end_time - begin_time) << " us.";
537 return changed;
538 }
539 } // namespace mindspore::graphkernel
540