#include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __i386__ #define rdtscl(low) \ __asm__ __volatile__ ("rdtsc" : "=A" (low)) #else #define rdtscl(val) \ do { \ struct timespec now; \ clock_gettime(CLOCK_REALTIME, &now); \ val = (u_int64_t)now.tv_sec; \ val *= 1000000000LL; \ val += (u_int64_t)now.tv_nsec; \ } while(0) #endif void usage(void) { extern char *__progname; fprintf(stderr, "%s [-n num] [-a [-l lqueue] [IP] port | -b | " "-c [-C bindaddr [-m mask]] [IP] port | -f | -s]\n", __progname); exit(1); } void display(char *msg, int i, u_int64_t a, u_int64_t b) { printf("%s\t%d\t%lld\n", msg, i, b - a); } void socket_ben(int n, int do_bind) { int i, *sockets; struct sockaddr_in sin; u_int64_t a, b; sockets = calloc(n, sizeof(int)); if (sockets == NULL) { fprintf(stderr, "malloc: %s\n", strerror(errno)); exit(1); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = 0; for (i = 0; i < n; i++) { rdtscl(a); if ((sockets[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket %d: %s\n", i, strerror(errno)); n = i; break; } rdtscl(b); display("socket", i, a, b); if (do_bind == 0) continue; rdtscl(a); if (bind(sockets[i], (struct sockaddr *)&sin, sizeof(sin))) { fprintf(stderr, "bind %d: %s\n", i, strerror(errno)); exit(2); } rdtscl(b); display("bind", i, a, b); } } void fork_ben(int n) { int i, quit = 0, pfd[2]; char buf[1]; pid_t *proc; u_int64_t a, b; proc = calloc(n, sizeof(pid_t)); if (proc == NULL) { fprintf(stderr, "malloc: %s\n", strerror(errno)); exit(1); } if (pipe(pfd) < 0) { fprintf(stderr, "pipe: %s\n", strerror(errno)); exit(1); } for (i = 0; i < n; i++) { rdtscl(a); proc[i] = fork(); switch(proc[i]) { case -1: n = i; quit = 1; break; case 0: /* child */ write(pfd[1], "+", 1); close(pfd[1]); sleep(5*60); _exit(0); break; default: break; } if (quit || read(pfd[0], buf, 1) != 1) break; rdtscl(b); display("fork", i, a, b); } for (i = 0; i < n; i++) if (proc[i] > 1) kill(proc[i], SIGTERM); } void accept_ben(int n, struct in_addr addr, u_int16_t port, int lnum) { int i, bindfd, *sockets, sinlen; struct sockaddr_in sin; u_int64_t a, b; sockets = calloc(n, sizeof(int)); if (sockets == NULL) { fprintf(stderr, "malloc: %s\n", strerror(errno)); exit(1); } sin.sin_family = AF_INET; sin.sin_addr = addr; sin.sin_port = port; bindfd = socket(AF_INET, SOCK_STREAM, 0); if (bindfd == -1) { fprintf(stderr, "socket %d: %s\n", i, strerror(errno)); exit(2); } if (bind(bindfd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == -1) { fprintf(stderr, "bind %d: %s\n", i, strerror(errno)); exit(2); } if (listen(bindfd, lnum) == -1) { fprintf(stderr, "listen %d: %s\n", i, strerror(errno)); exit(2); } fprintf(stderr, "accepting connections ..."); for (i = 0; i < n; i++) { sinlen = sizeof(sin); rdtscl(a); sockets[i] = accept(bindfd, (struct sockaddr *)&sin, &sinlen); if (sockets[i] == -1) { fprintf(stderr, "accept %d: %s\n", i, strerror(errno)); exit(2); } rdtscl(b); display("accept", i, a, b); } fprintf(stderr, "done\n"); } void connect_ben(int n, struct in_addr addr, u_int16_t port, struct in_addr base, u_int32_t mask) { int i, *sockets; struct sockaddr_in sbind, sconn; u_int64_t a, b; sockets = calloc(n, sizeof(int)); if (sockets == NULL) { fprintf(stderr, "malloc: %s\n", strerror(errno)); exit(1); } bzero(&sconn, sizeof(sconn)); sconn.sin_len = sizeof(sconn); sconn.sin_family = AF_INET; sconn.sin_port = port; sconn.sin_addr = addr; for (i = 0; i < n; i++) { rdtscl(a); if ((sockets[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket %d: %s\n", i, strerror(errno)); n = i; break; } rdtscl(b); display("socket", i, a, b); if (mask != 0) { sbind.sin_len = sizeof(sbind); sbind.sin_family = AF_INET; sbind.sin_port = 0; sbind.sin_addr.s_addr = htonl( (ntohl(base.s_addr) & mask) | (arc4random() & ~mask)); rdtscl(a); if (bind(sockets[i], (struct sockaddr *)&sbind, sizeof(sbind))) { fprintf(stderr, "bind %d: %s\n", i, strerror(errno)); exit(2); } rdtscl(b); display("bind", i, a, b); } rdtscl(a); if (connect(sockets[i], (struct sockaddr *)&sconn, sizeof(sconn))) { fprintf(stderr, "connect %d: %s [%i]\n", i, strerror(errno), errno); exit(2); } rdtscl(b); display("connect", i, a, b); } } int my_atoi(char *s, int min, int max) { char *ep; long lval; lval = strtol(s, &ep, 0); if (s[0] == '\0' || *ep != '\0') { fprintf(stderr, "argument not a number."); usage(); } if (lval < (long)min || lval > (long)max) { fprintf(stderr, "number out of range (%d - %d).", min, max); usage(); } return lval; } int main(int argc, char **argv) { struct rlimit rl; struct in_addr addr, maddr, base = {0}; int l, n, p, ch, a_flag, b_flag, c_flag, s_flag, f_flag; u_int32_t mask = 0; a_flag = b_flag = c_flag = f_flag = s_flag = 0; n = 100; l = 10; while ((ch = getopt(argc, argv, "abcC:fl:m:n:s")) != -1) { switch (ch) { case 'a': a_flag = 1; break; case 'b': b_flag = 1; break; case 'c': c_flag = 1; break; case 'C': if (inet_aton(optarg, &base) != 1) { fprintf(stderr, "bad network address\n"); usage(); } break; case 'f': f_flag = 1; break; case 'l': if (a_flag == 0) usage(); l = my_atoi(optarg, 1, 128); break; case 'n': n = my_atoi(optarg, 1, INT_MAX); break; case 'm': if (inet_aton(optarg, &maddr) != 1) { fprintf(stderr, "bad network mask\n"); usage(); } mask = ntohl(maddr.s_addr); break; case 's': s_flag = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (c_flag || a_flag) { if (argc == 0 || argc > 2) usage(); if (argc != 2) addr.s_addr = 0; else if (inet_aton(*argv++, &addr) != 1) { fprintf(stderr, "bad network address"); usage(); } p = htons(my_atoi(*argv, 1, 65535)); } rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_NOFILE, &rl); setrlimit(RLIMIT_NPROC, &rl); if (s_flag) socket_ben(n, 0); else if (b_flag) socket_ben(n, 1); else if (f_flag) fork_ben(n); else if (c_flag) connect_ben(n, addr, p, base, mask); else if (a_flag) accept_ben(n, addr, p, l); else fprintf(stderr, "no benchmark\n"); exit(0); }