The MPI background thread loop coordinates all the MPI processes and the tensor reductions. The design of the communicator mechanism is limited by a few considerations: 1. Some MPI implementations require all MPI calls to happen from a single thread. Since TensorFlow may use several threads for graph processing, this means we must have our own dedicated thread for dealing with MPI. 2. We want to
| 572 | // background loop. |
| 573 | // TODO: Use the global mpi_global state variable instead of a local one |
| 574 | void BackgroundThreadLoop() { |
| 575 | #if GOOGLE_CUDA |
| 576 | // Set the device, so that this thread uses the same GPU context as the |
| 577 | // calling thread. |
| 578 | // TODO: Ensure that this is operating correctly. The background thread |
| 579 | // needs to be able to control all GPUs that the rank has access to, and |
| 580 | // might be more than 1 GPU. Tensors could be resident in any of the |
| 581 | // GPUs, so the background thread's accumulate and copy kernels might need |
| 582 | // to correctly set the device and it might be necessary for the background |
| 583 | // thread to manage multiple streams. |
| 584 | cudaSetDevice(mpi_global.device); |
| 585 | cudaStreamCreate(&mpi_global.stream); |
| 586 | #endif |
| 587 | |
| 588 | // Initialize MPI. This must happen on the background thread, since not all |
| 589 | // MPI implementations support being called from multiple threads. |
| 590 | auto init_result = MPI_Init(NULL, NULL); |
| 591 | if (init_result != MPI_SUCCESS) { |
| 592 | mpi_global.init_status = |
| 593 | errors::Unknown("Could not initialize MPI; MPI_Init() failed."); |
| 594 | mpi_global.initialization_done = true; |
| 595 | mpi_global.cv.notify_all(); |
| 596 | return; |
| 597 | } else { |
| 598 | mpi_global.init_status = Status::OK(); |
| 599 | } |
| 600 | |
| 601 | // Get MPI rank to determine if we are rank zero. |
| 602 | int rank; |
| 603 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); |
| 604 | bool is_coordinator = rank == 0; |
| 605 | |
| 606 | // Get MPI size to determine how many tensors to wait for before reducing. |
| 607 | int size; |
| 608 | MPI_Comm_size(MPI_COMM_WORLD, &size); |
| 609 | |
| 610 | // Determine local rank by querying the local communicator. |
| 611 | MPI_Comm local_comm; |
| 612 | MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, |
| 613 | &local_comm); |
| 614 | int local_rank; |
| 615 | MPI_Comm_rank(local_comm, &local_rank); |
| 616 | |
| 617 | mpi_global.rank = rank; |
| 618 | mpi_global.local_rank = local_rank; |
| 619 | mpi_global.size = size; |
| 620 | mpi_global.initialization_done = true; |
| 621 | |
| 622 | // Notify calling thread that initialization is complete |
| 623 | mpi_global.cv.notify_all(); |
| 624 | |
| 625 | // TODO: MOVE MESSAGE TABLE INITIALIZATION TO LIBRARY LOAD! |
| 626 | // Initialize the tensor count table. No tensors are available yet. |
| 627 | if (is_coordinator) { |
| 628 | mpi_global.message_table = |
| 629 | std::unique_ptr<MessageTable>(new MessageTable()); |
| 630 | } |
| 631 |
nothing calls this directly
no test coverage detected