* PROBLEM: INET TCP socket communication through loopback
@ 2005-05-09 13:07 Hans Henrik Happe
0 siblings, 0 replies; only message in thread
From: Hans Henrik Happe @ 2005-05-09 13:07 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: text/plain, Size: 1594 bytes --]
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
[-- Attachment #2: random-inet.c --]
[-- Type: text/x-csrc, Size: 3941 bytes --]
/*
* usage: random-inet <# processes> <# messages>
*/
#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <netdb.h>
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<cnt; i++) {
pid = fork();
if (pid == 0) {
rank=cnt-i;
break;
}
}
/* Setup connections */
lsock = start_listen(port+rank);
for (i=0; i<rank; i++) {
socks[i] = do_accept(lsock);
pfds[i].fd = socks[i];
pfds[i].events = POLLIN;
}
for (i=rank; i<cnt-1; i++) {
socks[i] = do_connect(port+i+1);
pfds[i].fd = socks[i];
pfds[i].events = POLLIN;
}
srandom(rank);
/* Write startup messages */
if (rank < n) {
dest = random()%(cnt-1);
write(socks[dest], &data, 1);
}
/* Receive and forward messages to random destinations */
while (1) {
poll(pfds, cnt-1, -1);
j = 0;
for (i=0; i<cnt-1; i++) {
if (pfds[i].revents != 0) {
read(pfds[i].fd, &data, 1);
j++;
}
}
for (i=0; i<j; i++) {
dest = random()%(cnt-1);
write(socks[dest], &data, 1);
}
}
}
return 0;
}
[-- Attachment #3: ver_linux.2.4.24 --]
[-- Type: text/plain, Size: 1018 bytes --]
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
Linux n24 2.4.24 #2 Mon Jan 26 15:59:45 CET 2004 i686 GNU/Linux
Gnu C 3.3.3
Gnu make 3.80
binutils 2.14.90.0.6
util-linux 2.12
mount 2.11x
module-init-tools 0.9.15-pre2
e2fsprogs 1.35-WIP
jfsutils 1.1.2
reiserfsprogs 3.6.11
reiser4progs line
xfsprogs 2.5.11
pcmcia-cs 3.2.5
PPP 2.4.2b3
nfs-utils 1.0.5
Linux C Library 2.3.2
Dynamic linker (ldd) 2.3.2
Procps 3.1.12
Net-tools 1.60
Console-tools 0.2.3
Sh-utils 5.0
Modules Loaded e1000 ehci-hcd pcmcia_core nls_iso8859-1 ntfs msdos reiserfs ext3 jbd agpgart autofs4 i810_audio ac97_codec soundcore i810_rng serial usb-uhci usbcore rtc e100 crc32 nfs lockd sunrpc af_packet
[-- Attachment #4: ver_linux.2.6.11-gentoo-r6 --]
[-- Type: text/plain, Size: 1137 bytes --]
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
Linux haptop 2.6.11-gentoo-r6 #7 Sat May 7 18:07:07 CEST 2005 i686 Mobile Intel(R) Celeron(R) CPU 1.60GHz GenuineIntel GNU/Linux
Gnu C 3.3.5-20050130
Gnu make 3.80
binutils 2.15.92.0.2
util-linux 2.12i
mount 2.12i
module-init-tools 3.0
e2fsprogs 1.35
reiserfsprogs 3.6.19
reiser4progs line
PPP 2.4.2
Linux C Library 2.3.4
Dynamic linker (ldd) 2.3.4
Procps 3.2.4
Net-tools 1.60
Kbd 1.12
Sh-utils 5.2.1
udev 045
Modules Loaded usb_storage radeon ohci_hcd e100 orinoco_pci orinoco hermes yenta_socket rsrc_nonstatic pcmcia_core radeonfb i2c_algo_bit snd_intel8x0m i2c_i801 i2c_core snd_pcm_oss snd_mixer_oss snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_intel8x0 snd_ac97_codec snd_pcm snd_timer snd soundcore snd_page_alloc ehci_hcd uhci_hcd intel_agp rtc
[-- Attachment #5: ver_linux.2.6.3-7mdk --]
[-- Type: text/plain, Size: 1158 bytes --]
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
Linux mimi.imada.sdu.dk 2.6.3-7mdk #1 Wed Mar 17 15:56:42 CET 2004 i686 Intel(R) Celeron(R) CPU 2.40GHz unknown GNU/Linux
Gnu C 3.4.1
Gnu make 3.80
binutils 2.15.90.0.3
util-linux 2.12a
mount 2.12a
module-init-tools 3.0
e2fsprogs 1.35
reiserfsprogs line
reiser4progs line
nfs-utils 1.0.6
Linux C Library 2.3.3
Dynamic linker (ldd) 2.3.3
Procps 3.2.3
Net-tools 1.60
Console-tools 0.2.3
Sh-utils 5.2.1
Modules Loaded nls_iso8859-1 nls_cp850 vfat fat usb-storage ircomm-tty ircomm irda floppy raw sg st sr_mod sd_mod scsi_mod snd-seq-oss snd-seq-midi-event snd-seq snd-pcm-oss snd-mixer-oss snd-intel8x0 snd-ac97-codec snd-pcm snd-timer gameport snd-page-alloc snd-mpu401-uart snd-rawmidi snd-seq-device snd soundcore md5 ipv6 af_packet 8139too mii ide-cd cdrom loop intel-agp agpgart ehci-hcd uhci-hcd usbcore rtc ext3 jbd
[-- Attachment #6: random-mpi.c --]
[-- Type: text/x-csrc, Size: 908 bytes --]
#include <stdio.h>
#include <mpi.h>
/*
* Sends 'n' messages between processes. When a process
* receives a message it chooses a new destination at random.
*
* usage: random-mpi <n>
*/
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();
}
[-- Attachment #7: random-spair.c --]
[-- Type: text/x-csrc, Size: 2310 bytes --]
/*
* usage: random-spair <# processes> <# messages>
*/
#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <netdb.h>
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<cnt; i++) {
pid = fork();
if (pid == 0) {
rank=cnt-i;
break;
}
}
/* Assign sockets */
j=0;
for (i=0; i<cnt; i++) {
if (i != rank) {
if (i < rank) {
socks[j] = spairs[2*(i*cnt+rank)];
} else {
socks[j] = spairs[2*(rank*cnt+i)+1];
}
pfds[j].fd = socks[j];
pfds[j].events = POLLIN;
j++;
}
}
srandom(rank);
/* Write startup messages */
if (rank < n) {
dest = random()%(cnt-1);
if (write(socks[dest], &data, 1) == -1) {
perror("write 1");
}
}
/* Receive and forward messages to random destinations */
while (1) {
poll(pfds, cnt-1, -1);
j = 0;
for (i=0; i<cnt-1; i++) {
if (pfds[i].revents != 0) {
if (read(pfds[i].fd, &data, 1) == -1) {
perror("read");
}
j++;
}
}
for (i=0; i<j; i++) {
dest = random()%(cnt-1);
if (write(socks[dest], &data, 1) == -1) {
perror("write 2");
}
}
}
}
return 0;
}
[-- Attachment #8: ring-mpi.c --]
[-- Type: text/x-csrc, Size: 712 bytes --]
#include <stdio.h>
#include <mpi.h>
/*
* Sends 'n' messages in a ring of processes.
*
* usage: ring-mpi <n>
*/
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();
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-05-09 13:07 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-09 13:07 PROBLEM: INET TCP socket communication through loopback Hans Henrik Happe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox