11.2.2. TCP

11.2.2.1. Using the TCP BTL for MPI messages

Open MPI generally uses the tcp BTL automatically when:

  1. The tcp BTL is available at run time (which it should be on most POSIX-like systems), and

  2. A higher-performance network is not available.

When the tcp BTL is used, it is typically also used (automatically) with the self and sm BTLs for process-loopback and node-loopback communication, respectively.

To guarantee that the tcp, sm, and self BTLs are used, you can specify them explicitly on the mpirun command line:

shell$ mpirun --mca pml ob1 --mca btl tcp,sm,self ...

Warning

Failure to specify the sm BTL will likely result in lower performance when Open MPI uses the TCP network stack to send to peers on the same host.

Warning

Failure to specify the self BTL may result in Open MPI being unable to complete send-to-self scenarios (meaning that your program will run fine until a process tries to send to itself).

11.2.2.2. Coexisting with a high-speed network

If you have both an IP network and at least one high-speed network (such as InfiniBand), you do not need to disable the TCP BTL. Following the so-called “Law of Least Astonishment,” Open MPI assumes that you will likely want to use only the high-speed network(s) for MPI message passing, so the tcp BTL component senses this and automatically deactivates itself.

That said, Open MPI may still use TCP for setup and teardown information, so you will see traffic across your IP network during startup and shutdown of your MPI job. This is normal and does not affect the MPI message-passing channels.

11.2.2.3. Listing tunable parameters

The ompi_info command can display all the parameters available for the tcp BTL component (that is, the component that uses TCP for MPI communication):

shell$ ompi_info --param btl tcp --level 9

11.2.2.4. The IP loopback interface

Open MPI usually does not use the operating system IP loopback interface. In general message-passing usage, there are two scenarios in which the IP loopback interface could be used:

  1. Sending a message from one process to itself, and

  2. Sending a message from one process to another process on the same machine.

The tcp BTL does not handle send-to-self scenarios; instead, the self BTL is used for all send-to-self MPI communication. This lets all Open MPI BTL components avoid special-case code for send-to-self and also avoids using less efficient loopback network stacks (such as the IP loopback device). The self component uses its own mechanisms and does not use operating system network interfaces such as the IP loopback interface.

When sending to other processes on the same machine, Open MPI defaults to using a shared-memory BTL (sm). If the shared-memory BTL has been deactivated, then — depending on what other BTL components are available — it is possible that the tcp BTL will be chosen for on-node message passing, in which case the IP loopback device will likely be used. This is not the default, however: either shared memory must fail to start up properly, or the user must specifically request not to use the shared-memory BTL. If you do need to use the IP loopback device, the tcp BTL can be configured to use it by setting the btl_tcp_if_include MCA parameter to lo or 127.0.0.0/32 (or whatever the local naming scheme is on your system). For example:

shell$ mpirun --mca btl_tcp_if_include lo ...

11.2.2.6. Selecting which IP interfaces to use

In some HPC environments, it is not uncommon to have multiple IP interfaces on each node — for example, one “slow” IP network used for control information (such as a batch scheduler, a networked filesystem, and/or interactive logins) and another “fast” IP network (or networks) intended for parallel applications to use during their runs. Some operating systems may also have virtual interfaces for communicating with virtual machines.

Unless otherwise specified, Open MPI greedily uses all “up” IP networks that it can find, per its reachability computations, and tries to connect to all peers on demand (Open MPI does not open sockets to all of its MPI peers during MPI_Init — see sockets opened during MPI_Init). If you want MPI jobs to not use specific IP networks — or not use any IP networks at all — then you must tell Open MPI.

Warning

Aggressively using all “up” interfaces can cause problems in some cases. For example, if you have a machine with a local-only interface (such as the loopback device, or a virtual-machine bridge device that can only be used on that machine and cannot be used to communicate with MPI processes on other machines), you will likely need to tell Open MPI to ignore these networks.

Open MPI usually ignores loopback devices by default, but other local-only devices must be manually ignored. Users have reported cases where RHEL6 automatically installed a virbr0 device for Xen virtualization. This interface was automatically given an IP address in the 192.168.1.0/24 subnet and marked as “up”. Since Open MPI saw this 192.168.1.0/24 “up” interface in all MPI processes on all nodes, it assumed that network was usable for MPI communication. This is obviously incorrect, and it led to MPI applications hanging when they tried to send or receive MPI messages.

There are several ways to control which interfaces Open MPI uses:

  1. To prevent Open MPI from using TCP for MPI communication at all, set the btl MCA parameter accordingly. You can either exclude the TCP component or include only other components:

    # Exclude the TCP BTL component (implicitly including all others)
    shell$ mpirun --mca btl ^tcp ...
    
    # Include only the listed BTL components
    # (tcp is not listed, and therefore will not be used)
    shell$ mpirun --mca btl self,sm ...
    
  2. To use TCP for MPI communication but restrict it to (or from) certain networks, use the btl_tcp_if_include or btl_tcp_if_exclude MCA parameter (only one of the two should be set). The value can be a comma-delimited list of network interfaces. For example:

    # Do not use the lo and eth0 interfaces (and implicitly use the
    # rest).  Per the description above, IP loopback and all
    # local-only devices *must* be included in an exclude list.
    shell$ mpirun --mca btl_tcp_if_exclude lo,eth0 ...
    
    # Use only the eth1 and eth2 interfaces (and implicitly ignore
    # the rest)
    shell$ mpirun --mca btl_tcp_if_include eth1,eth2 ...
    
  3. You can also specify subnets in the include or exclude lists in CIDR notation. For example:

    # Only use the 192.168.1.0/24 and 10.10.0.0/16 subnets for MPI
    # communication
    shell$ mpirun --mca btl_tcp_if_include 192.168.1.0/24,10.10.0.0/16 ...
    

    Note

    You must specify the CIDR notation for a given network precisely. For example, if you have two IP networks 10.10.0.0/24 and 10.10.1.0/24, Open MPI will not recognize either of them if you specify “10.10.0.0/16”.

Warning

If you use the btl_tcp_if_include and btl_tcp_if_exclude MCA parameters to shape the behavior of the TCP BTL for MPI communication, you may also need/want to investigate the corresponding PRRTE parameters that control use of network interfaces by the runtime (for example, communication setup and coordination during MPI_Init and MPI_Finalize), using the prte_info(1) and pmix_info(1) commands.

Note that the Open MPI runtime uses TCP for control messages — such as data exchange between mpirun(1) and the MPI processes, rendezvous information during MPI_Init, and so on — even if the tcp BTL component is disabled.

11.2.2.7. Sockets opened during MPI_Init

Although Open MPI is likely to open multiple TCP sockets during MPI_Init, the tcp BTL component does not open one socket per MPI peer process during MPI_Init. Open MPI opens sockets as they are required, so the first time a process sends a message to a peer and there is no TCP connection between the two, Open MPI automatically opens a new socket.

As a result, you should not have scalability issues (such as running out of per-process file descriptors) when running large numbers of processes, provided your parallel application is sparse in its communication with peers.

11.2.2.9. How Open MPI determines routability

Open MPI assumes that all interfaces are routable as long as they have the same address family (IPv4 or IPv6). It uses graph theory, giving each possible connection a weight depending on the quality of the connection, which allows the library to select the best connections between nodes. This method also supports striping, but prevents more than one connection to any interface.

The quality of a connection is defined as follows, with a higher number meaning a better connection. Note that a connection consisting of a private address and a public address is given the weight PRIVATE_DIFFERENT_NETWORK.

            NO_CONNECTION = 0
PRIVATE_DIFFERENT_NETWORK = 1
PRIVATE_SAME_NETWORK      = 2
PUBLIC_DIFFERENT_NETWORK  = 3
PUBLIC_SAME_NETWORK       = 4

An example best illustrates how two processes on two different nodes would connect. Here we have two nodes with a variety of interfaces:

       Node A                Node B
 ----------------       ----------------
|      lo0       |     |      lo0       |
| 127.0.0.1/8    |     | 127.0.0.1/8    |
|                |     |                |
|      eth0      |     |      eth0      |
| 10.8.47.1/24   |     | 10.8.47.2/24   |
|                |     |                |
|      eth1      |     |      eth1      |
| 192.168.1.1/24 |     | 192.168.1.2/24 |
|                |     |                |
|      eth2      |     |                |
| 192.168.2.2/24 |     |                |
 ----------------      ------------------

From these two nodes, the software builds a bipartite graph that shows all the possible connections with all the possible weights. The lo0 interfaces are excluded because the btl_tcp_if_exclude MCA parameter is set to lo by default. Here is what all the possible connections with their weights look like:

      Node A       Node B
eth0 --------- 2 -------- eth0
       ------- 1 -------- eth1

eth1 --------- 1 -------- eth0
       ------- 2 -------- eth1

eth2 --------- 1 -------- eth0
       ------- 1 -------- eth1

The library then examines all the connections and picks the optimal ones. This leaves two connections established between the two nodes.

If you are curious about the actual connect() calls being made by the processes, run with --mca btl_base_verbose 30. This can be useful if you notice your job hanging and believe it may be the library trying to make connections to unreachable hosts:

# Here is an example with some of the output deleted for clarity.
# One can see the connections that are attempted.
shell$ mpirun --mca btl self,sm,tcp --mca btl_base_verbose 30 -n 2 -host NodeA,NodeB a.out
[...snip...]
[NodeA:18003] btl: tcp: attempting to connect() to address 10.8.47.2 on port 59822
[NodeA:18003] btl: tcp: attempting to connect() to address 192.168.1.2 on port 59822
[NodeB:16842] btl: tcp: attempting to connect() to address 192.168.1.1 on port 44500
[...snip...]

If you want more details about the theory behind the connection code, you can find the background story in this IEEE paper.

11.2.2.10. When Open MPI closes TCP sockets

In general, Open MPI does not close TCP sockets; however, there are some exceptions. Although TCP sockets are opened lazily (MPI connections / TCP sockets are only opened on demand, as opposed to opening all possible sockets between MPI peer processes during MPI_Init), they are never closed unless the MPI world or MPI sessions are explicitly finalized or disconnected. For example, if the MPI world is finalized, all TCP sockets are closed. If a spawned MPI process is disconnected, all TCP sockets to any parent MPI process are closed. Similarly, if an MPI session is disconnected, all TCP sockets to any child MPI processes are closed.

11.2.2.11. Interfaces with multiple IP addresses

In general, Open MPI does not support an IP interface that has more than one IP address. For example, if the output from your ifconfig has a single IP device with multiple IP addresses like this:

0: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
   link/ether 00:18:ae:f4:d2:29 brd ff:ff:ff:ff:ff:ff
   inet 192.168.0.3/24 brd 192.168.0.255 scope global eth0:1
   inet 10.10.0.3/24 brd 10.10.0.255 scope global eth0
   inet6 fe80::218:aef2:29b4:2c4/64 scope link
      valid_lft forever preferred_lft forever

(note the two inet lines), then Open MPI will be unable to use this device.

11.2.2.12. Virtual IP interfaces

Open MPI does not support virtual IP interfaces. For example, if the output of your ifconfig has both eth0 and eth0:0, Open MPI will get confused if you use the TCP BTL, and may hang or otherwise act unpredictably. Note that using btl_tcp_if_include or btl_tcp_if_exclude to avoid using the virtual interface will not solve the issue.

11.2.2.13. Using multiple TCP connections

Open MPI can use multiple TCP connections between any pair of MPI processes, striping large messages across the connections. The btl_tcp_links parameter sets how many TCP connections are established between MPI processes.

Note that this may not improve application performance for common use cases of nearest-neighbor exchanges when there are many MPI processes on each host. In those cases, there are already many TCP connections between any two hosts (because of the many processes all communicating), so the extra TCP connections are likely just consuming extra resources and adding work to the MPI implementation.

However, for highly multi-threaded applications where there are only one or two MPI processes per host, the btl_tcp_links option may improve TCP throughput considerably.

11.2.2.14. Limiting the time spent establishing TCP connections

You can set the btl_tcp_recv_timeout and btl_tcp_handshake_timeout MCA parameters to limit the time spent establishing TCP connections. The difference between the two is subtle but important: btl_tcp_recv_timeout is the timeout for one receive operation, while btl_tcp_handshake_timeout is the timeout for the entire handshake (that is, the exchange of the correct magic string and process GUID). These parameters can be used to avoid deadlocks in adversarial situations where external processes (for example, processes that are not part of any MPI job) try to connect to the Open MPI process and hold the connection socket open without sending the proper handshake information.

The default values are 250,000 usec for btl_tcp_recv_timeout and 1,000,000 usec for btl_tcp_handshake_timeout. For example:

shell$ mpirun --mca btl_tcp_recv_timeout 1000000 ...
shell$ mpirun --mca btl_tcp_handshake_timeout 1000000 ...

11.2.2.15. Nagle’s algorithm and TCP_NODELAY

By default, the TCP BTL disables Nagle’s algorithm — that is, it sets the TCP_NODELAY socket option — which favors low latency for applications driven by waves of small messages. Using Nagle’s algorithm can increase short-message latency.

This behavior is controlled by the btl_tcp_use_nagle MCA parameter, which defaults to 0 (Nagle’s algorithm disabled, TCP_NODELAY set). Set it to 1 to use Nagle’s algorithm (clearing TCP_NODELAY); this is rarely desirable for latency-sensitive workloads.