lmbench_select_tcp.c [plain text]
#ifdef __sun
#pragma ident "@(#)socket.c 1.3 05/08/04 Apple Inc."
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include "../libmicro.h"
int open_file(void* tsd);
void server(void* tsd);
int tcp_accept(int sock, int rdwr);
void sock_optimize(int sock, int flags);
int sockport(int s);
int tcp_server(int prog, int rdwr);
int tcp_connect(char *host, int prog, int rdwr);
int open_socket(void *tsd);
typedef int (*open_f)(void* tsd);
typedef struct {
char fname[L_tmpnam];
open_f fid_f;
pid_t pid;
int sock;
int fid;
int num;
int max;
fd_set set;
} tsd_t;
static int optt = 1;
static int optn = -1;
static int optp = 1;
static int optw = 0;
void
morefds(void)
{
#ifdef RLIMIT_NOFILE
struct rlimit r;
getrlimit(RLIMIT_NOFILE, &r);
r.rlim_cur = r.rlim_max;
setrlimit(RLIMIT_NOFILE, &r);
#endif
}
int
open_file(void* tsd)
{
tsd_t* ts = (tsd_t*)tsd;
return (int) open(ts->fname, O_RDONLY);
}
int
open_socket(void* tsd)
{
return tcp_connect("localhost", TCP_SELECT, SOCKOPT_NONE);
}
void
server(void* tsd)
{
int pid;
tsd_t *ts = (tsd_t *)tsd;
pid = getpid();
ts->pid = 0;
if (ts->fid_f == open_file) {
sprintf(ts->fname, "lat_selectXXXXXX");
ts->fid = mkstemp(ts->fname);
if (ts->fid <= 0) {
char buf[L_tmpnam+128];
sprintf(buf, "lat_select: Could not create temp file %s", ts->fname);
perror(buf);
exit(1);
}
close(ts->fid);
return;
}
ts->sock = tcp_server(TCP_SELECT, SOCKOPT_REUSE);
if (ts->sock <= 0) {
perror("lat_select: Could not open tcp server socket");
exit(1);
}
switch(ts->pid = fork()) {
case 0:
while (pid == getppid()) {
int newsock = tcp_accept(ts->sock, SOCKOPT_NONE);
read(newsock, &ts->fid, 1);
close(newsock);
}
exit(0);
case -1:
perror("lat_select::server(): fork() failed");
exit(1);
default:
break;
}
}
int
tcp_accept(int sock, int rdwr)
{
struct sockaddr_in s;
int newsock;
socklen_t namelen;
namelen = sizeof(s);
bzero((void*)&s, namelen);
retry:
if ((newsock = accept(sock, (struct sockaddr*)&s, &namelen)) < 0) {
if (errno == EINTR)
goto retry;
perror("accept");
exit(6);
}
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "Server newsock port %d\n", sockport(newsock));
#endif
sock_optimize(newsock, rdwr);
return (newsock);
}
void
sock_optimize(int sock, int flags)
{
if (flags & SOCKOPT_READ) {
int sockbuf = SOCKBUF;
while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sockbuf,
sizeof(int))) {
sockbuf >>= 1;
}
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "sockopt %d: RCV: %dK\n", sock, sockbuf>>10);
#endif
}
if (flags & SOCKOPT_WRITE) {
int sockbuf = SOCKBUF;
while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sockbuf,
sizeof(int))) {
sockbuf >>= 1;
}
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "sockopt %d: SND: %dK\n", sock, sockbuf>>10);
#endif
}
if (flags & SOCKOPT_REUSE) {
int val = 1;
if (setsockopt(sock, SOL_SOCKET,
SO_REUSEADDR, &val, sizeof(val)) == -1) {
perror("SO_REUSEADDR");
}
}
}
int
sockport(int s)
{
socklen_t namelen;
struct sockaddr_in sin;
namelen = sizeof(sin);
if (getsockname(s, (struct sockaddr *)&sin, &namelen) < 0) {
perror("getsockname");
return(-1);
}
return ((int)ntohs(sin.sin_port));
}
int
tcp_server(int prog, int rdwr)
{
int sock;
struct sockaddr_in s;
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "tcp_server(%u, %u)\n", prog, rdwr);
#endif
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
exit(1);
}
sock_optimize(sock, rdwr);
bzero((void*)&s, sizeof(s));
s.sin_family = AF_INET;
if (prog < 0) {
s.sin_port = htons(-prog);
}
if (bind(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
perror("bind");
exit(2);
}
if (listen(sock, 100) < 0) {
perror("listen");
exit(4);
}
if (prog > 0) {
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "Server port %d\n", sockport(sock));
#endif
(void)pmap_unset((u_long)prog, (u_long)1);
if (!pmap_set((u_long)prog, (u_long)1, (u_long)IPPROTO_TCP,
(unsigned short)sockport(sock))) {
perror("pmap_set");
exit(5);
}
}
return (sock);
}
int
tcp_connect(char *host, int prog, int rdwr)
{
static struct hostent *h;
static struct sockaddr_in s;
static u_short save_port;
static u_long save_prog;
static char *save_host;
int sock;
static int tries = 0;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
exit(1);
}
if (rdwr & SOCKOPT_PID) {
static unsigned short port;
struct sockaddr_in sin;
if (!port) {
port = (unsigned short)(getpid() << 4);
if (port < 1024) {
port += 1024;
}
}
do {
port++;
bzero((void*)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
} while (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1);
}
#ifdef LIBTCP_VERBOSE
else {
struct sockaddr_in sin;
bzero((void*)&sin, sizeof(sin));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
perror("bind");
exit(2);
}
}
fprintf(stderr, "Client port %d\n", sockport(sock));
#endif
sock_optimize(sock, rdwr);
if (!h || host != save_host || prog != save_prog) {
save_host = host;
save_prog = prog;
if (!(h = gethostbyname(host))) {
perror(host);
exit(2);
}
bzero((void *) &s, sizeof(s));
s.sin_family = AF_INET;
bcopy((void*)h->h_addr, (void *)&s.sin_addr, h->h_length);
if (prog > 0) {
save_port = pmap_getport(&s, prog,
(u_long)1, IPPROTO_TCP);
if (!save_port) {
perror("lib TCP: No port found");
exit(3);
}
#ifdef LIBTCP_VERBOSE
fprintf(stderr, "Server port %d\n", save_port);
#endif
s.sin_port = htons(save_port);
} else {
s.sin_port = htons(-prog);
}
}
if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
if (errno == ECONNRESET
|| errno == ECONNREFUSED
|| errno == EAGAIN) {
close(sock);
if (++tries > 10) return(-1);
return (tcp_connect(host, prog, rdwr));
}
perror("connect");
exit(4);
}
tries = 0;
return (sock);
}
int
benchmark_initbatch(void *tsd)
{
return (0);
}
int
benchmark_finirun()
{
return (0);
}
int
benchmark_init()
{
(void) sprintf(lm_optstr, "p:w:n:t:");
lm_tsdsize = sizeof (tsd_t);
(void) sprintf(lm_usage,
" [-p parallelism (default 1)]\n"
" [-w warmup (default 0)]\n"
" [-n number of descriptors (default 1)]\n"
" [-t int (default 1)]\n"
"notes: measures lmbench_select_file\n");
lm_defB = 1;
return (0);
}
int
benchmark_fini()
{
return (0);
}
int
benchmark_finibatch(void *tsd)
{
return (0);
}
char *
benchmark_result()
{
static char result = '\0';
return (&result);
}
int
benchmark_finiworker(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
int i;
for (i = 0; i <= ts->max; ++i) {
if (FD_ISSET(i, &(ts->set)))
close(i);
}
FD_ZERO(&(ts->set));
unlink(ts->fname);
return (0);
}
int
benchmark_optswitch(int opt, char *optarg)
{
switch (opt) {
case 't':
optt = sizetoint(optarg);
break;
case 'n':
optn = sizetoint(optarg);
break;
case 'p':
optp = sizetoint(optarg);
break;
case 'w':
optw = sizetoint(optarg);
break;
default:
return (-1);
}
return (0);
}
int
benchmark_initworker(void *tsd)
{
int n = 0;
tsd_t *ts = (tsd_t *)tsd;
int N, fid, fd;
ts->num = 200;
if (optn > 0) {
ts->num = optn;
}
N = ts->num;
morefds();
ts->fid_f = open_socket;
server(ts);
fid = (*ts->fid_f)(ts);
if (fid <= 0) {
perror("Could not open device");
exit(1);
}
ts->max = 0;
FD_ZERO(&(ts->set));
for (n = 0; n < N; n++) {
fd = dup(fid);
if (fd == -1) break;
if (fd > ts->max)
ts->max = fd;
FD_SET(fd, &(ts->set));
}
ts->max++;
close(fid);
if (n != N)
exit(1);
return (0);
}
int
benchmark_initrun()
{
return (0);
}
int
benchmark(void *tsd, result_t *res)
{
tsd_t *ts = (tsd_t *)tsd;
fd_set nosave;
static struct timeval tv;
int i;
tv.tv_sec = 0;
tv.tv_usec = 0;
for (i = 0; i < lm_optB; i++) {
nosave = ts->set;
select(ts->num, 0, &nosave, 0, &tv);
}
res->re_count = i;
return (0);
}