Assemble copy cost
| 322 | |
| 323 | // Assemble copy cost |
| 324 | void SbpEdge::InitCopyAndMemoryCost(const std::string& ibn, bool use_sbp_collector, |
| 325 | bool nccl_not_use_compute_stream) { |
| 326 | std::vector<int64_t> consumer_nd_sbp_sig2memory; |
| 327 | if (nccl_not_use_compute_stream) { |
| 328 | in_memory_support_ = true; |
| 329 | // Compute and store the memory for consumer |
| 330 | const auto& consumer_operator = end_node_->op_node_->op(); |
| 331 | const auto& end_sbp_sig_list = end_node_->sbp_sig_list_; |
| 332 | consumer_nd_sbp_sig2memory.resize(end_sbp_sig_list.size(), 0); |
| 333 | const auto& lbi = consumer_operator.BnInOp2Lbi(ibn); |
| 334 | const auto& consumer_hierarchy = |
| 335 | *CHECK_JUST(consumer_operator.GetParallelDesc4BnInOp(ibn))->hierarchy(); |
| 336 | const auto& logical_blob_desc = start_node_->op_node_->LogicalBlobDesc4Lbi(lbi); |
| 337 | HashMap<NdSbp, int64_t> consumer_nd_sbp2memory; |
| 338 | for (int32_t sbp_sig_id = 0; sbp_sig_id < end_sbp_sig_list.size(); sbp_sig_id++) { |
| 339 | const NdSbp& nd_sbp = end_sbp_sig_list[sbp_sig_id].bn_in_op2nd_sbp().at(ibn); |
| 340 | auto it = consumer_nd_sbp2memory.find(nd_sbp); |
| 341 | if (it == consumer_nd_sbp2memory.end()) { |
| 342 | // This compute the memory at rank 0, the largest one. |
| 343 | // We could be faster if we just compute the average memory. |
| 344 | it = consumer_nd_sbp2memory |
| 345 | .insert({nd_sbp, |
| 346 | MaxByteSize4BlobDescSbp(logical_blob_desc, nd_sbp, consumer_hierarchy)}) |
| 347 | .first; |
| 348 | } |
| 349 | consumer_nd_sbp_sig2memory[sbp_sig_id] += it->second; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | // In this part, we assemble the cost from nodes to nodes. |
| 354 | if (start_node_->op_node_ && end_node_->op_node_) { |
| 355 | OpNode* consumer = end_node_->op_node_; |
| 356 | |
| 357 | // Add copy cost for each blob |
| 358 | const LogicalBlobId& lbi = consumer->op().BnInOp2Lbi(ibn); |
| 359 | |
| 360 | // Check whether lbi is transferred by this edge |
| 361 | if (use_sbp_collector && !SearchLbi(lbi)) { return; } |
| 362 | |
| 363 | OpNode* producer = start_node_->op_node_; |
| 364 | const std::string& producer_lbn = *CHECK_JUST(producer->op().obn4lbi(lbi)); |
| 365 | const ParallelDesc& producer_parallel_desc = |
| 366 | *CHECK_JUST(producer->op().GetParallelDesc4BnInOp(producer_lbn)); |
| 367 | const ParallelDesc& consumer_parallel_desc = |
| 368 | *CHECK_JUST(consumer->op().GetParallelDesc4BnInOp(ibn)); |
| 369 | |
| 370 | // Need to be careful, the logical blob description should be independent to current |
| 371 | // SbpParallel. Use producer or op_node? |
| 372 | const BlobDesc& logical_blob_desc = producer->LogicalBlobDesc4Lbi(lbi); |
| 373 | const std::string& obn = *CHECK_JUST(producer->op().obn4lbi(lbi)); |
| 374 | // If we are deciding whether we need the wait time, then make require_same_sbp true. |
| 375 | // B->S cause cudaEventSynchronize in current implementation. |
| 376 | bool require_same_sbp = RequireSameSbp(consumer, ibn); |
| 377 | int32_t consumer_sbp_size = end_node_->sbp_sig_list_.size(); |
| 378 | LazyMode::Guard enable_lazy_mode(true); |
| 379 | |
| 380 | // look through sbp signature in producer |
| 381 | for (int32_t sbp_id_producer = 0; sbp_id_producer < start_node_->sbp_sig_list_.size(); |
nothing calls this directly
no test coverage detected