Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Jan 2000 08:47:03 -0800
From:      "Scott Hess" <scott@avantgo.com>
To:        "Scott Hess" <scott@avantgo.com>, "Matthew Dillon" <dillon@apollo.backplane.com>
Cc:        <freebsd-hackers@FreeBSD.ORG>
Subject:   Re: Performance issue with rfork() and single socketpairs versus multiple socketpairs.
Message-ID:  <0c2101bf6753$cf37f280$1e80000a@avantgo.com>
References:   <01b601bf6696$60701930$1e80000a@avantgo.com> <200001241939.LAA91219@apollo.backplane.com> <0be801bf6715$601423d0$1e80000a@avantgo.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
"Scott Hess" <scott@avantgo.com> wrote:
> "Matthew Dillon" <dillon@apollo.backplane.com> wrote:
> > :Unfortunately, I've found that having a group of processes reading
> > :from  a group of socketpairs has better performance than having
> > :them all read from a single socketpair.  I've been unable to
> > :determine why.
> >
> >  The problem is that when you have N processes waiting on a single
> >  socket and you write to the socket, all N processes will wake up even
> >  though only one will get the data you wrote.
> <snip>
> >  As an alternative to socket pairs, I would consider using SysV shared
> >  memory and SysV semaphores.
>
> OK, so let's say I did spend some time implementing it in terms of
semget()
> and semop().  Would you be totally apalled if the performance turned out
to
> be about the same as using a single socketpair?
<snip>
>Unfortunately, I'll have to wait until tomorrow morning
>to rip things out and make a suitable example program for posting.

Find attached a new version of commtest.c which uses semaphores.  I've also
placed a copy at http://www.doubleu.com/~scott/commtest.c.  The performance
is identical enough that I'm guessing that semaphores must suffer from the
exact same problems as the single socketpair version.

Thanks,
scott


[-- Attachment #2 --]
// commtest.c
// gcc -Wall -g -o commtest commtest.c
//
// Test performance differences for multiple socketpairs versus a
// single shared socketpair versus SYSV semaphores.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <sys/sem.h>
#include <sys/ipc.h>

typedef unsigned char request_t;

#define CLIENT_EXIT ((request_t)(~0))
#define CLIENT_COUNT 32
#define REQUEST_TARGET 10000

int client_fd_count=0;
int client_fds[ CLIENT_COUNT];
int server_fds[ CLIENT_COUNT];

/* Reflect requests. */
void socket_client( int fd)
{
    request_t request;
    int rc;
    
    while( 1) {
        if( (rc=read( fd, &request, sizeof( request)))==-1) {
            perror( "client read");
            _exit( 1);
        } else if( rc<sizeof( request)) {
            _exit( 0);
        } else if( (rc=write( fd, &request, sizeof( request)))==-1) {
            perror( "client write");
            _exit( 1);
        } else if( rc<sizeof( request)) {
            _exit( 0);
        }
    }
}
void sem_client( int sem, int sem_id, int fd, request_t rid)
{
    struct sembuf sem_req={ sem_id, -1, 0};
    int rc;
    
    while( 1) {
	if( (rc=semop( sem, &sem_req, 1))==-1) {
            perror( "client semop");
            _exit( 1);
        } else if( (rc=write( fd, &rid, sizeof( rid)))==-1) {
            perror( "client write");
            _exit( 1);
        } else if( rc<sizeof( rid)) {
            _exit( 0);
        }
    }
}

void main( int argc, char **argv)
{
    int ii, jj, flags, maxfd, rc;
    int pair[ 2];
    fd_set default_fdset, fdset;
    pid_t cpid;
    request_t request[32];
    int request_count=0;
    int sem=-1;
    int sem_count=-1;
    
    client_fd_count=1;
    if( argc==2 && !strcmp( argv[ 1], "--multi")) {
        client_fd_count=CLIENT_COUNT;
    } else if( argc==2 && !strcmp( argv[ 1], "--single")) {
        client_fd_count=1;
    } else if( argc==2 && !strcmp( argv[ 1], "--handful")) {
        client_fd_count=4;
    } else if( argc==2 && !strcmp( argv[ 1], "--sem")) {
	sem_count=1;
    } else if( argc==2 && !strcmp( argv[ 1], "--semulti")) {
	sem_count=CLIENT_COUNT;
    }
    
    if( sem_count>-1) {
	sem=semget( IPC_PRIVATE, sem_count, SEM_R|SEM_A);
	if( sem==-1) {
	    perror( "semget");
	    exit( 1);
	}
    }
    
    maxfd=0;
    FD_ZERO( &default_fdset);
    for( ii=0; ii<client_fd_count; ii++) {
        if( socketpair(AF_UNIX,SOCK_STREAM,0,pair)==-1) {
            perror( "creating socketpair");
            goto err_exit;
        } else if( (flags=fcntl( pair[ 0], F_GETFL, NULL))==-1) {
            perror( "getting flags");
            goto err_exit;
        } else if( fcntl( pair[ 0], F_SETFL, flags|O_NONBLOCK)==-1) {
            perror( "setting flags");
            goto err_exit;
        }
        
        client_fds[ ii]=pair[ 0];
        server_fds[ ii]=pair[ 1];
        
        FD_SET( client_fds[ ii], &default_fdset);
        if( client_fds[ ii]>maxfd) {
            maxfd=client_fds[ ii];
        }
    }
    
    /* Spin off children to process requests. */
    for( ii=0; ii<CLIENT_COUNT; ii++) {
        if( (cpid=rfork(RFPROC))==-1) {
            perror( "rfork");
            goto err_exit;
        } else if( cpid==0) {
	    if( sem!=-1) {
		sem_client( sem, ii%sem_count, server_fds[ ii%client_fd_count], ii);
	    } else {
		socket_client( server_fds[ ii%client_fd_count]);
	    }
        } else {
            request[0]=ii;
	    if( sem!=-1) {
		struct sembuf sem_req={ ii%sem_count, 1, 0};
		if( semop( sem, &sem_req, 1)==-1) {
		    perror( "semop");
		    goto err_exit;
		}
            } else if( write( client_fds[ ii%client_fd_count], &(request[0]), sizeof( request[0]))==-1) {
                perror( "writing initial request");
                goto err_exit;
            }
        }
    }

    while( request_count<REQUEST_TARGET) {
        fdset=default_fdset;
        select( maxfd+1, &fdset, NULL, &fdset, NULL);
        
        for( ii=0; ii<client_fd_count && request_count<REQUEST_TARGET; ii++) {
            if( (rc=read( client_fds[ ii], request, sizeof( request)))==-1) {
		if( rc==-1 && errno!=EAGAIN && errno!=EWOULDBLOCK) {
		    perror( "reading response");
		    goto err_exit;
		}
	    } else {
		jj=rc/sizeof( request[ 0]);
		while( jj--) {
		    if( sem!=-1) {
			struct sembuf sem_req={ request[jj]%sem_count, 1, 0};
			if( semop( sem, &sem_req, 1)==-1) {
			    perror( "semop");
			    goto err_exit;
			}
		    } else if( write( client_fds[ ii], &(request[jj]), sizeof( request[jj]))==-1) {
			perror( "writing request");
			goto err_exit;
		    }
		    request_count++;
		}
            }
        }
    }
    
    if( sem!=-1) {
	semctl( sem, 0, IPC_RMID);
    }
    for( ii=0; ii<client_fd_count; ii++) {
        close( client_fds[ ii]);
    }
    exit( 0);

err_exit:
    if( sem!=-1) {
	semctl( sem, 0, IPC_RMID);
    }
    for( ii=0; ii<client_fd_count; ii++) {
        close( client_fds[ ii]);
    }
    exit( 1);
}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?0c2101bf6753$cf37f280$1e80000a>