• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020 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 
17 #include "backend/optimizer/mem_reuse/mem_reuse_checker.h"
18 #include <fstream>
19 
20 namespace mindspore {
21 namespace memreuse {
GetInstance()22 MemReuseChecker &MemReuseChecker::GetInstance() {
23   static MemReuseChecker instance{};
24   return instance;
25 }
26 
CheckSignalOps(const CNodePtr & c_node)27 void MemReuseChecker::CheckSignalOps(const CNodePtr &c_node) {
28   std::string node_name = AnfAlgo::GetCNodeName(c_node);
29   if (node_name == kSendOpName || node_name == kRecvOpName) {
30     MS_LOG(INFO) << "MemReuseChecker check op_name of  Send or Send";
31     // get op's info && check
32     MS_LOG(INFO) << "op: " << node_name << " in_num: " << AnfAlgo::GetInputTensorNum(c_node)
33                  << " out_num: " << AnfAlgo::GetOutputTensorNum(c_node);
34   }
35 }
36 
CheckWorkSpace(const std::vector<size_t> & max_list)37 void MemReuseChecker::CheckWorkSpace(const std::vector<size_t> &max_list) {
38   for (auto &ma : max_list) {
39     total_re_wkspe_size_checker_ += ma;
40   }
41 }
42 
CheckOutRef(const KernelRefs & kernel_refs,const CNodePtr & c_node,size_t output_idx)43 void MemReuseChecker::CheckOutRef(const KernelRefs &kernel_refs, const CNodePtr &c_node, size_t output_idx) {
44   auto key = c_node.get();
45   auto iter = kernel_refs.find(key);
46   auto node_name = AnfAlgo::GetCNodeName(c_node);
47   if (iter == kernel_refs.end()) {
48     MS_LOG(EXCEPTION) << "kernel [" << node_name << "] has no output tensor, node: " << c_node->DebugString()
49                       << " output index: " << output_idx;
50   }
51   if (output_idx >= iter->second.size()) {
52     MS_LOG(INFO) << "invalid cnode: " << c_node->fullname_with_scope().c_str();
53     MS_LOG(EXCEPTION) << "The index: " << output_idx
54                       << " is out of the size of kernel_output_refs_:" << iter->second.size();
55   }
56 }
57 
CalculOriInput(const KernelGraph * graph) const58 int64_t MemReuseChecker::CalculOriInput(const KernelGraph *graph) const {
59   MS_EXCEPTION_IF_NULL(graph);
60   int64_t static_input_size = 0;
61   for (auto &item : graph->inputs()) {
62     if (!item->isa<Parameter>()) {
63       continue;
64     }
65     auto output_size = AnfAlgo::GetOutputTensorNum(item);
66     for (size_t index = 0; index < output_size; index++) {
67       TypeId ou_type = AnfAlgo::GetOutputDeviceDataType(item, index);
68       // parameter has not init by a cnode
69       if (ou_type == kTypeUnknown) {
70         ou_type = AnfAlgo::GetOutputInferDataType(item, index);
71       }
72       size_t type_size = GetTypeByte(TypeIdToType(ou_type));
73       std::vector<size_t> shape = AnfAlgo::GetOutputDeviceShape(item, index);
74       size_t tensor_size =
75         shape.empty() ? type_size : std::accumulate(shape.begin(), shape.end(), type_size, std::multiplies<size_t>());
76       auto checker_size = SizeToLong(tensor_size);
77       static_input_size += checker_size;
78     }
79   }
80   return static_input_size;
81 }
82 
CalculOriValue(const KernelGraph * graph) const83 int64_t MemReuseChecker::CalculOriValue(const KernelGraph *graph) const {
84   MS_EXCEPTION_IF_NULL(graph);
85   int64_t static_value_size = 0;
86   for (auto &value_node : graph->graph_value_nodes()) {
87     MS_EXCEPTION_IF_NULL(value_node);
88     auto &node_value = value_node->value();
89     MS_EXCEPTION_IF_NULL(node_value);
90     auto tensor = node_value->cast<tensor::TensorPtr>();
91     if (tensor == nullptr) {
92       continue;
93     }
94     int64_t checker_size = tensor->data().nbytes();
95     static_value_size += checker_size;
96   }
97   return static_value_size;
98 }
99 
CalculOriStatic(const KernelGraph * graph) const100 int64_t MemReuseChecker::CalculOriStatic(const KernelGraph *graph) const {
101   // cal static inputs
102   auto static_input_size = CalculOriInput(graph);
103   // do not calcul outpput size
104   auto statica_value_size = CalculOriValue(graph);
105   auto total_ori_static_size = static_input_size + statica_value_size;
106   return total_ori_static_size;
107 }
108 
CalculOriDy(const KernelGraph * graph) const109 int64_t MemReuseChecker::CalculOriDy(const KernelGraph *graph) const {
110   MS_EXCEPTION_IF_NULL(graph);
111   int64_t ori_dy_size = 0;
112   auto kerenls = graph->execution_order();
113   for (auto &kernel : kerenls) {
114     auto kernel_mod = AnfAlgo::GetKernelMod(kernel);
115     MS_EXCEPTION_IF_NULL(kernel_mod);
116     for (auto &dy_size : kernel_mod->GetOutputSizeList()) {
117       auto checker_size = SizeToLong(dy_size);
118       ori_dy_size += checker_size;
119     }
120   }
121   return ori_dy_size;
122 }
123 
CalculOriWk(const KernelGraph * graph) const124 int64_t MemReuseChecker::CalculOriWk(const KernelGraph *graph) const {
125   MS_EXCEPTION_IF_NULL(graph);
126   int64_t ori_wk_size = 0;
127   auto kerenls = graph->execution_order();
128   for (auto &kernel : kerenls) {
129     auto kernel_mod = AnfAlgo::GetKernelMod(kernel);
130     MS_EXCEPTION_IF_NULL(kernel_mod);
131     for (auto &wk_size : kernel_mod->GetWorkspaceSizeList()) {
132       auto checker_size = SizeToLong(wk_size);
133       ori_wk_size += checker_size;
134     }
135   }
136   return ori_wk_size;
137 }
138 
GetSplitName(const std::string & scope_name) const139 std::string MemReuseChecker::GetSplitName(const std::string &scope_name) const {
140   auto indx = scope_name.rfind(kSplitC);
141   if (indx == std::string::npos) {
142     return scope_name;
143   } else {
144     if (indx < scope_name.size() - 1) {
145       auto split_name = scope_name.substr(indx + 1);
146       return split_name;
147     }
148     return scope_name;
149   }
150 }
151 
CheckMemReuseIR(const KernelRefCountPtrList & total_refs_list,const KernelDefPtrMaps & kernel_def_ptr_list,const KernelGraph * graph)152 void MemReuseChecker::CheckMemReuseIR(const KernelRefCountPtrList &total_refs_list,
153                                       const KernelDefPtrMaps &kernel_def_ptr_list, const KernelGraph *graph) {
154   total_ori_static_size_ = CalculOriStatic(graph);
155   total_ori_input_size_ = CalculOriInput(graph);
156   total_ori_value_size_ = CalculOriValue(graph);
157   total_ori_dy_size_ = CalculOriDy(graph);
158   total_ori_wkspace_size_ = CalculOriWk(graph);
159   std::string graph_id = std::to_string(graph->graph_id());
160   std::string filename = "./memreuse_" + graph_id + ".ir";
161   std::ofstream ofs(filename);
162   if (!ofs.is_open()) {
163     MS_LOG(ERROR) << "Open file [" << filename << "] failed!";
164     return;
165   }
166   ofs << "all_tensor_refs:\n";
167   ofs << "index:"
168       << "\tsize:"
169       << "\trefcount:"
170       << "\ttype:\n";
171   for (auto &ref : total_refs_list) {
172     ofs << "%" << ref->index_ << "T"
173         << "\t"
174         << "#" << ref->size_ << "S"
175         << "\t" << ref->ref_count_ << "C"
176         << "\t" << ref->type_ << "t"
177         << "\n";
178   }
179   ofs << "kernel_def exc_order:\n";
180   int def_idx = 0;
181   for (auto &def : kernel_def_ptr_list) {
182     ExportMemOpIr(def.get(), ofs, def_idx);
183     def_idx++;
184   }
185   ofs.close();
186 }
187 
ExportKernelDependence()188 void MemReuseChecker::ExportKernelDependence() {
189   std::string filename = "./memreuse_dependence.ir";
190   std::ofstream ofs(filename);
191   if (!ofs.is_open()) {
192     MS_LOG(ERROR) << "Open file [" << filename << "] failed!";
193     return;
194   }
195   size_t i = 0;
196   for (const auto &kernel_front : kernel_front_map_) {
197     auto kernel = kernel_front.first;
198     auto front = kernel_front.second;
199     ofs << "[" << i++ << "] " << kernel->scope_full_name() << "\n";
200     for (const auto &node : front) {
201       ofs << node->scope_full_name() << "\n";
202     }
203     ofs << "\n\n";
204   }
205 
206   ofs.close();
207 }
208 
CheckGraphOutputAssigned(const session::KernelGraph * graph)209 bool MemReuseChecker::CheckGraphOutputAssigned(const session::KernelGraph *graph) {
210   // set real graph output node to be special who's refcount equal kMaxRefCount
211   for (const auto &output : graph->outputs()) {
212     MS_EXCEPTION_IF_NULL(output);
213     size_t input_num = AnfAlgo::GetInputTensorNum(output);
214     for (size_t i = 0; i < input_num; ++i) {
215       if (output->isa<CNode>()) {
216         auto cnode = output->cast<CNodePtr>();
217         auto input_node = cnode->input(i + 1);
218         auto kernel_input_with_idx = AnfAlgo::VisitKernel(input_node, 0);
219         auto kernel_input = kernel_input_with_idx.first;
220         MS_EXCEPTION_IF_NULL(kernel_input);
221         auto kernel_mod = AnfAlgo::GetKernelMod(kernel_input);
222         if (kernel_mod == nullptr) {
223           continue;
224         }
225         auto output_sizes = kernel_mod->GetOutputSizeList();
226         if (output_sizes.empty()) {
227           continue;
228         }
229         for (size_t j = 0; j < output_sizes.size(); ++j) {
230           if (!AnfAlgo::OutputAddrExist(kernel_input, j)) {
231             return false;
232           }
233         }
234       }
235     }
236   }
237   return true;
238 }
239 
ExportMemOpIr(const KernelDef * def,std::ofstream & ofs,int def_idx)240 void MemReuseChecker::ExportMemOpIr(const KernelDef *def, std::ofstream &ofs, int def_idx) {
241   auto scope_name = def->scope_full_name();
242   std::string split_name = GetSplitName(scope_name);
243   ofs << "$" << def_idx << "\t" << split_name << "\t" << static_cast<int>(def->type_) << "\t";
244   ofs << "inputs[";
245   for (auto &in : def->inputs_) {
246     for (auto &in_ref : in.second) {
247       ofs << "%" << in_ref->index_ << "T"
248           << ",";
249     }
250   }
251   ofs << "]";
252   ofs << "\toutpus[";
253   for (auto &ou : def->outputs_) {
254     for (auto &ou_ref : ou.second) {
255       ofs << "%" << ou_ref->index_ << "T"
256           << ",";
257     }
258   }
259   ofs << "]";
260   ofs << "\tstreamID["
261       << "@" << def->stream_id() << "]\n";
262 }
263 
ExportNormalTensorIR(std::ofstream & ofs)264 void MemReuseChecker::ExportNormalTensorIR(std::ofstream &ofs) {
265   ofs << "all_tensor_refs:\n";
266   ofs << "index:"
267       << "\tsize:"
268       << "\trefcount:\n";
269   size_t ou_idx = 0;
270   for (auto &ou : nor_output_tensors_) {
271     ofs << "%" << ou_idx << "T"
272         << "\t"
273         << "#" << nor_tensor_sizes_[ou_idx] << "S"
274         << "\t";
275     auto iter_ref = ptr_refs_.find(ou);
276     if (iter_ref != ptr_refs_.end()) {
277       ofs << iter_ref->second << "C"
278           << "\n";
279     } else {
280       MS_LOG(EXCEPTION) << "can not find refs for output";
281     }
282     ou_idx++;
283   }
284   ofs << "kernel_def exc_order:\n";
285 }
286 
GetTensorIdx(const void * in) const287 int MemReuseChecker::GetTensorIdx(const void *in) const {
288   auto iter = ptr_idx_.find(in);
289   if (iter == ptr_idx_.end()) {
290     return kInvalidIndex;
291   } else {
292     return SizeToInt(iter->second);
293   }
294 }
295 
ExportNormalOpIr(const std::vector<CNodePtr> & cnodes)296 void MemReuseChecker::ExportNormalOpIr(const std::vector<CNodePtr> &cnodes) {
297   std::ofstream ofs("./normal_mem.ir");
298   if (!ofs.is_open()) {
299     MS_LOG(ERROR) << "Open file failed!";
300     return;
301   }
302   ExportNormalTensorIR(ofs);
303   size_t node_idx = 0;
304   for (const auto &node : cnodes) {
305     MS_EXCEPTION_IF_NULL(node);
306     ofs << "$" << node_idx << "\t" << GetSplitName(node->fullname_with_scope()) << "\t";
307     std::vector<int> in_idx;
308     auto iter = node_ins_.find(node.get());
309     if (iter != node_ins_.end()) {
310       for (auto &in : iter->second) {
311         if (GetTensorIdx(in) != kInvalidIndex) {
312           in_idx.push_back(GetTensorIdx(in));
313         }
314       }
315     }
316     std::vector<int> ou_idx;
317     iter = node_ous_.find(node.get());
318     if (iter != node_ous_.end()) {
319       for (auto &ou : iter->second) {
320         if (GetTensorIdx(ou) != kInvalidIndex) {
321           ou_idx.push_back(GetTensorIdx(ou));
322         }
323       }
324     }
325     ofs << "inputs[";
326     for (auto idx : in_idx) {
327       bool has_in_ou = std::any_of(ou_idx.begin(), ou_idx.end(), [idx](int odx) { return idx == odx; });
328       if (!has_in_ou) {
329         ofs << "%" << idx << "T,";
330       }
331     }
332     ofs << "]\toutpus[";
333     for (auto odx : ou_idx) {
334       ofs << "%" << odx << "T,";
335     }
336     ofs << "]\tstreamID[@" << AnfAlgo::GetStreamId(node) << "]\n";
337     node_idx++;
338   }
339   ofs.close();
340 }
341 
SetTesnorFromAndToInfo(const KernelDef * op_def)342 void MemReuseChecker::SetTesnorFromAndToInfo(const KernelDef *op_def) {
343   auto split_name = GetSplitName(op_def->scope_full_name());
344   for (auto &in : op_def->inputs_) {
345     auto in_tensors = in.second;
346     for (auto &tensor : in_tensors) {
347       auto indx = tensor->index_;
348       tensor_to_[indx].push_back(split_name);
349     }
350   }
351   for (auto &ou : op_def->outputs_) {
352     auto ou_tensors = ou.second;
353     for (auto &tensor : ou_tensors) {
354       auto indx = tensor->index_;
355       tensor_from_[indx].push_back(split_name);
356     }
357   }
358 }
359 
CheckNormalIR(const session::KernelGraph * graph)360 void MemReuseChecker::CheckNormalIR(const session::KernelGraph *graph) {
361   const auto &cnodes = graph->execution_order();
362   for (const auto &node : cnodes) {
363     std::vector<const void *> curr_ous;
364     size_t output_num = AnfAlgo::GetOutputTensorNum(node);
365     for (size_t i = 0; i < output_num; ++i) {
366       auto it = AnfAlgo::GetOutputAddr(node, i);
367       MS_EXCEPTION_IF_NULL(it);
368       auto ptr = it->GetPtr();
369       nor_output_tensors_.push_back(ptr);
370       nor_tensor_sizes_.push_back(it->GetSize());
371       curr_ous.push_back(it->GetPtr());
372     }
373     (void)node_ous_.insert(std::make_pair(node.get(), curr_ous));
374     std::vector<const void *> curr_ins;
375     size_t input_num = AnfAlgo::GetInputTensorNum(node);
376     for (size_t i = 0; i < input_num; ++i) {
377       if (i + 1 >= node->inputs().size()) {
378         MS_LOG(EXCEPTION) << "Input index: " << i
379                           << " is larger than input number: " << AnfAlgo::GetInputTensorNum(node);
380       }
381       auto real_input_index = AnfAlgo::GetRealInputIndex(node, i);
382       auto input = node->input(real_input_index + 1);
383       MS_EXCEPTION_IF_NULL(input);
384       auto kernel_with_index = AnfAlgo::VisitKernel(input, 0);
385       if (kernel_with_index.first->isa<Parameter>()) {
386         continue;
387       }
388       auto device_address = AnfAlgo::GetPrevNodeOutputAddr(node, real_input_index);
389       MS_EXCEPTION_IF_NULL(device_address);
390       nor_input_tensors_.push_back(device_address->GetPtr());
391       curr_ins.push_back(device_address->GetPtr());
392     }
393     (void)node_ins_.insert(std::make_pair(node.get(), curr_ins));
394   }
395   size_t ou_idx = 0;
396   for (const auto &ou : nor_output_tensors_) {
397     (void)ptr_idx_.insert(std::make_pair(ou, ou_idx));
398     (void)ptr_refs_.insert(std::make_pair(ou, 0));
399     ou_idx++;
400   }
401   for (const auto &in : nor_input_tensors_) {
402     if (ptr_idx_.find(in) != ptr_idx_.end()) {
403       if (ptr_refs_.find(in) != ptr_refs_.end()) {
404         auto iter = ptr_refs_.find(in);
405         (iter->second)++;
406       } else {
407         MS_LOG(EXCEPTION) << "ptr_refs is not equal to ptr_idx";
408       }
409     }
410   }
411   ExportNormalOpIr(cnodes);
412 }
413 
SetMembuInfos(const KernelDef * op_def,const std::vector<MembufPtr> & membuf_ptr_list)414 void MemReuseChecker::SetMembuInfos(const KernelDef *op_def, const std::vector<MembufPtr> &membuf_ptr_list) {
415   std::vector<MembufPtr> curr_mem_infos;
416   for (const auto &mem : membuf_ptr_list) {
417     auto mem_checker =
418       std::make_shared<Membuf>(mem->status_, mem->size_, mem->offset_, mem->index_, mem->type_, mem->used_kernel_);
419     curr_mem_infos.push_back(mem_checker);
420   }
421   membuf_all_infos_.push_back(curr_mem_infos);
422   auto split_name = GetSplitName(op_def->scope_full_name());
423   all_split_names_.push_back(split_name);
424   SetTesnorFromAndToInfo(op_def);
425 }
426 
SetAddNewMembuInfos(const KernelDef * op_def,const std::vector<MembufPtr> & membuf_ptr_list,size_t op_idx)427 void MemReuseChecker::SetAddNewMembuInfos(const KernelDef *op_def, const std::vector<MembufPtr> &membuf_ptr_list,
428                                           size_t op_idx) {
429   std::vector<MembufPtr> add_new_curr_mem;
430 
431   for (const auto &mem : membuf_ptr_list) {
432     auto mem_checker =
433       std::make_shared<Membuf>(mem->status_, mem->size_, mem->offset_, mem->index_, mem->type_, mem->used_kernel_);
434     add_new_curr_mem.push_back(mem_checker);
435   }
436   add_new_mem_infos_.push_back(add_new_curr_mem);
437   auto split_name = GetSplitName(op_def->scope_full_name());
438   add_new_names_.push_back(split_name);
439   add_new_op_indxs_.push_back(op_idx);
440   add_new_stream_ids_.push_back(op_def->stream_id());
441 }
442 
ExportEachMembufInfo(std::ofstream & ofs)443 void MemReuseChecker::ExportEachMembufInfo(std::ofstream &ofs) {
444   size_t i = 0;
445   std::vector<size_t> each_node_used_size;
446   std::vector<size_t> each_node_allocated_size;
447   for (const auto &curr_membuf_list : membuf_all_infos_) {
448     ofs << all_split_names_.at(i) << "\n";
449     ++i;
450     ofs << "mem_num\t"
451         << "stream_id\t"
452         << "status\t"
453         << "tensor_idex\t"
454         << "mem_size\t"
455         << "mem_head\t"
456         << "mem_tail\t"
457         << "mem_type\t"
458         << "used_kernel\n";
459     size_t curr_used = 0;
460     size_t curr_allocated = 0;
461     for (size_t j = 0; j < curr_membuf_list.size(); ++j) {
462       auto membuf = curr_membuf_list.at(j);
463       auto used_kernel = membuf->used_kernel_->scope_full_name();
464       ofs << "&" << j << "\t"
465           << "streamID[@" << membuf->used_kernel_->stream_id() << "]"
466           << "\t"
467           << "#" << static_cast<int>(membuf->status_) << "\t%" << membuf->index_ << "T"
468           << "\t" << membuf->size_ << "\t" << membuf->offset_ << "\t\t" << membuf->offset_ + membuf->size_ << "\t"
469           << "\t" << static_cast<int>(membuf->type_) << "\t" << GetSplitName(used_kernel) << "\n";
470       if (membuf->status_ == kReused) {
471         curr_used += membuf->size_;
472       }
473     }
474     if (!curr_membuf_list.empty()) {
475       curr_allocated = curr_membuf_list.back()->offset_ + curr_membuf_list.back()->size_;
476     }
477     each_node_used_size.push_back(curr_used);
478     each_node_allocated_size.push_back(curr_allocated);
479     ofs << "curr real used size: \t" << curr_used << "\n";
480     ofs << "curr allocated size: \t" << curr_allocated << "\n";
481     ofs << "\n\n";
482   }
483   auto optimal_iter = std::max_element(each_node_used_size.begin(), each_node_used_size.end());
484   ofs << "theoretical optimal size: " << *optimal_iter << "\n";
485   ofs << "each node used size: \n";
486   for (auto size : each_node_used_size) {
487     ofs << size << "\t";
488   }
489   ofs << "\n\n";
490   ofs << "each node allocated size: \n";
491   for (auto size : each_node_allocated_size) {
492     ofs << size << "\t";
493   }
494   ofs << "\n\n";
495 }
496 
ExportMembufInfoIR()497 void MemReuseChecker::ExportMembufInfoIR() {
498   std::string ir_file_name = "./mem_buf_info.ir";
499   std::ofstream ofs(ir_file_name);
500   int64_t total_reuse_size = 0;
501   if (!ofs.is_open()) {
502     MS_LOG(ERROR) << "Open file [" << ir_file_name << "] failed!";
503   }
504   ofs << "Total static size:\t" << total_ori_static_size_ << "\n";
505   ofs << "Graph inputs size:\t" << total_ori_input_size_ << "\n";
506   ofs << "Value nodes size:\t" << total_ori_value_size_ << "\n";
507   ofs << "Total dynamic size:\t" << total_ori_dy_size_ << "\n";
508   ofs << "Total workspace size:\t" << total_ori_wkspace_size_ << "\n";
509   // get last membuf_list
510   if (membuf_all_infos_.empty()) {
511     return;
512   }
513   auto last_membuf_list = membuf_all_infos_.back();
514   for (const auto &membuf : last_membuf_list) {
515     auto checker_size = SizeToLong(membuf->size_);
516     total_reuse_size += checker_size;
517   }
518   ofs << "After reuse size:\t" << total_reuse_size << "\n\n";
519   ExportEachMembufInfo(ofs);
520   ofs.close();
521 }
522 
ExportAddNewMmebufIR()523 void MemReuseChecker::ExportAddNewMmebufIR() {
524   std::string ir_file_name = "./AddNewMembuf.ir";
525   std::ofstream ofs(ir_file_name);
526   if (!ofs.is_open()) {
527     MS_LOG(ERROR) << "Open file [" << ir_file_name << "] failed!";
528   }
529   auto check_idx = add_new_mem_infos_.size();
530   if (check_idx == add_new_op_indxs_.size() && check_idx == add_new_names_.size() &&
531       check_idx == add_new_stream_ids_.size()) {
532     size_t i = 0;
533     for (const auto &curr_membuf_list : add_new_mem_infos_) {
534       ofs << "op_idx:$" << add_new_op_indxs_.at(i) << "\t" << add_new_names_.at(i) << "\t";
535       ofs << "streamID[@" << add_new_stream_ids_.at(i) << "]"
536           << "\n";
537       i++;
538       ofs << "mem_num\t"
539           << "status\t"
540           << "tensor_idex\t"
541           << "mem_size\t"
542           << "mem_head\t"
543           << "mem_tail\t"
544           << "FromOp\t"
545           << "ToOp\n";
546       for (size_t j = 0; j < curr_membuf_list.size(); ++j) {
547         auto membuf = curr_membuf_list.at(j);
548         ofs << "&" << j << "\t"
549             << "\t"
550             << "#" << static_cast<int>(membuf->status_) << "\t%" << membuf->index_ << "T"
551             << "\t" << membuf->size_ << "\t" << membuf->offset_ << "\t" << membuf->offset_ + membuf->size_ << "\t";
552         auto in_idx_iter = tensor_from_.find(membuf->index_);
553         if (in_idx_iter != tensor_from_.end()) {
554           for (auto &in_name : in_idx_iter->second) {
555             ofs << in_name << ",";
556           }
557           ofs << "\t";
558         }
559         auto ou_idx_iter = tensor_to_.find(membuf->index_);
560         if (ou_idx_iter != tensor_to_.end()) {
561           for (auto &ou_name : ou_idx_iter->second) {
562             ofs << ou_name << ",";
563           }
564           ofs << "\n";
565         }
566       }
567       ofs << "\n";
568     }
569   }
570   ofs.close();
571 }
572 }  // namespace memreuse
573 }  // namespace mindspore
574