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