Use two function
| 391 | |
| 392 | // Use two function |
| 393 | void InitMemory(const OpGraph& op_graph, SbpGraph* sbp_graph, bool nccl_use_compute_stream) { |
| 394 | // Generate topological data structure for each sbp node |
| 395 | HashMap<const OpNode*, TopoStruct> op_node2topo_struct; |
| 396 | std::vector<TopoStruct*> topo_structs; |
| 397 | std::vector<TopoStruct*> ordered_topo_structs; |
| 398 | |
| 399 | // Traverse all the nodes in the sbp graph |
| 400 | for (const auto& sbp_node : sbp_graph->GetNodeList()) { |
| 401 | auto* op_node = sbp_node->GetOperatorNode(); |
| 402 | CHECK(op_node != nullptr) |
| 403 | << "No proxy node allow at this status. InitMemory() should be run before sbp collector!"; |
| 404 | op_node2topo_struct.insert({op_node, TopoStruct(sbp_node)}); |
| 405 | topo_structs.push_back(&op_node2topo_struct.at(op_node)); |
| 406 | } |
| 407 | |
| 408 | // Construct the map from a lbi to its id, consumers, blob size |
| 409 | HashMap<LogicalBlobId, int32_t> lbi2id; |
| 410 | std::vector<std::vector<TopoStruct*>> id2consumer_topo_structs; |
| 411 | std::vector<int64_t> id2blob_size; |
| 412 | |
| 413 | StraightenOpNodes(op_node2topo_struct, &topo_structs, &lbi2id, &id2consumer_topo_structs, |
| 414 | &id2blob_size, &ordered_topo_structs); |
| 415 | |
| 416 | // Mark the memory support, which contains two part: |
| 417 | // All the non-reusable memory and those blobs which is a part of the maximum reusable memory |
| 418 | int64_t max_reusable_memory = 0; |
| 419 | int64_t curr_reusable_memory = 0; |
| 420 | std::vector<int32_t> id2count(id2blob_size.size(), -1); |
| 421 | // Blobs born, increase count and memory |
| 422 | auto GenerateBlobs = [&](TopoStruct* topo_struct) { |
| 423 | const auto& curr_operator = topo_struct->op_node->op(); |
| 424 | if (topo_struct->is_reusable) { |
| 425 | for (const auto& obn : curr_operator.output_bns()) { |
| 426 | const LogicalBlobId& lbi = curr_operator.BnInOp2Lbi(obn); |
| 427 | int32_t index = lbi2id.at(lbi); |
| 428 | // Reusable blobs born |
| 429 | curr_reusable_memory += id2blob_size[index]; |
| 430 | id2count[index] = id2consumer_topo_structs[index].size(); |
| 431 | } |
| 432 | } |
| 433 | }; |
| 434 | // Blobs die, decrease count and memory |
| 435 | auto KillBlobs = [&](TopoStruct* topo_struct) { |
| 436 | const auto& curr_operator = topo_struct->op_node->op(); |
| 437 | // Those reusable blobs who do not have a consumer would die immediately |
| 438 | // For example: |
| 439 | // register_num: 1, op_name: |
| 440 | // "model.cls_head.loss_func.lm_loss-sparse_softmax_cross_entropy_ms-231-split_softmax_reduce_max_device_stage", |
| 441 | // blob_name: "mask_0", shape { dim: 2048 dim: 21248 }, |
| 442 | // data_type: kBool, time_shape { dim: 1 dim: 1 }, enable_reuse_mem: true, |
| 443 | // alloc_before_actor: 369, free_after_actor: 369 |
| 444 | if (topo_struct->is_reusable) { |
| 445 | for (const auto& obn : curr_operator.output_bns()) { |
| 446 | const LogicalBlobId& lbi = curr_operator.BnInOp2Lbi(obn); |
| 447 | int32_t index = lbi2id.at(lbi); |
| 448 | // Do not have consumer |
| 449 | if (id2count[index] == 0) { |
| 450 | // Reusable blobs die |
no test coverage detected