From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hans Henrik Happe Subject: PROBLEM: INET TCP socket communication through loopback Date: Mon, 9 May 2005 15:07:50 +0200 Message-ID: <200505091507.50387.hhh@imada.sdu.dk> Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_mC2fCmC2MLhfCfd" Return-path: To: netdev@oss.sgi.com Sender: netdev-bounce@oss.sgi.com Errors-to: netdev-bounce@oss.sgi.com List-Id: netdev.vger.kernel.org --Boundary-00=_mC2fCmC2MLhfCfd Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline I have experienced some odd behavior when communicating between multiple processes through the loopback device using poll() to wait for input. Attachment 'random-inet.c' is a program that shows the problem. Basically it starts a number of processes. Each process makes a connection to the each of the other processes (resembling MPI implementations such as lam-mpi). Now a given number of messages are sent to a pseudo-random destination. When a process receives one of the messages it forwards it to another randomly chosen destination. The program is run as follows: ./random-inet <# processes> <# messages> Problem: One would expect that this program would use up all the available CPU-time, but this is not the case. Allready with 3 processes and 1 message there is still some idle CPU-time and it becomes worse when more process are added. As a sanity check i created the same program using UNIX socket created by socketpair() (random-spair.c). This makes the problem go away. I have also attached the MPI program 'random-mpi.c' showing the same problem with lam-mpi 7.0.6. Another MPI program that does NOT have the problem is 'ring-mpi.c'. This sends the messages around in a ring of processes. The controlled communication pattern somehow makes the problem go away. I have attached the 'ver-linux' of the systems that I have tested. I know these are not mainline kernels but I have not found any mention of such a problem in the latest changelogs. I will gladly try it on the mainline if that would help. I'm not on the list so please CC. Hans Henrik Happe --Boundary-00=_mC2fCmC2MLhfCfd Content-Type: text/x-csrc; charset="us-ascii"; name="random-inet.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="random-inet.c" /* * usage: random-inet <# processes> <# messages> */ #include #include #include #include #include #include #include int do_connect(int port) { int n, sock, on=1; struct addrinfo hints, *res; char str[6]; void *adr; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; sprintf(str, "%d", port); n = getaddrinfo("localhost", str, &hints, &res); if (n != 0) { fprintf(stderr, "getaddrinfo error: [%s]\n", gai_strerror(n)); return -1; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { perror("socket"); return -1; } if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) == -1) { perror("setsockopt"); return -1; } if (connect(sock, (struct sockaddr *)res->ai_addr, sizeof(*res->ai_addr)) == -1) { perror("connect"); return -1; } freeaddrinfo(res); return sock; } int start_listen(int port) { int n, on=1; int sock; struct sockaddr_in name; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { perror("socket"); return -1; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { perror("setsockopt"); return -1; } name.sin_family = AF_INET; name.sin_port = htons (port); name.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (sock, (struct sockaddr *) &name, sizeof (name)) == -1) { perror("bind"); return -1; } if (listen(sock, 10) == -1) { perror("listen"); return -1; } return sock; } int do_accept(int lsock) { struct sockaddr addr; socklen_t len = sizeof(addr); int sock, on=1; if ((sock = accept(lsock, &addr, &len)) == -1) { perror("accept"); return -1; } if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) == -1) { perror("setsockopt"); return -1; } return sock; } int main(int argc, char *argv[]) { int i, j, n, cnt, pid, rank, dest; int lsock; char data = 'h'; int port = 11100; /* # processes */ cnt = atoi(argv[1]); /* # messages */ n = atoi(argv[2]); { int socks[cnt-1]; struct pollfd pfds[cnt-1]; /* Create processes */ rank = 0; for (i=1; i #include /* * Sends 'n' messages between processes. When a process * receives a message it chooses a new destination at random. * * usage: random-mpi */ main(int argc, char **argv) { int n, i, data[1]; int dest, size, rank; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); n = atoi(argv[1]); srandom(rank); /* Send 'n' startup messages. */ if (rank < n) { while ((dest = (random()%size)) == rank); MPI_Send(data, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); } while (1) { MPI_Recv(data, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); /* Don't send to self. */ while ((dest = (random()%size)) == rank); MPI_Send(data, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); } MPI_Finalize(); } --Boundary-00=_mC2fCmC2MLhfCfd Content-Type: text/x-csrc; charset="us-ascii"; name="random-spair.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="random-spair.c" /* * usage: random-spair <# processes> <# messages> */ #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int i, j, n, cnt, pid, rank, dest; int lsock; char data; int port = 11100; cnt = atoi(argv[1]); n = atoi(argv[2]); { int socks[cnt-1]; struct pollfd pfds[cnt-1]; int spairs[2*cnt*cnt]; for (i=0; i<2*cnt*cnt; i+=2) { socketpair(AF_UNIX, SOCK_STREAM, 0, spairs+i); } /* Create processes */ rank = 0; for (i=1; i #include /* * Sends 'n' messages in a ring of processes. * * usage: ring-mpi */ main(int argc, char **argv) { int n, i, data[1]; int size, rank, dest; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); n = atoi(argv[1]); dest = (rank+1)%size; /* Send 'n' startup messages. */ if (rank%(size/n) == 0) { MPI_Send(data, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); } while (1) { MPI_Recv(data, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Send(data, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); } MPI_Finalize(); } --Boundary-00=_mC2fCmC2MLhfCfd--