/* $Id: maxhttp_cps.C,v 1.4 2000/08/29 06:43:58 fubob Exp $ */ /* Use this program to simulate a herd of HTTP clients. Each client connects, asks for "/", reads the page, then closes. You can test the maximum number of sustainable connections per second to a web server. Warning. this is almost as fast as a plain TCP connections. Running longer than a few seconds will likely use up resources. */ /* * * Copyright (C) 2000 Kevin Fu (fubob@mit.edu) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "maxhttp_cps.h" #include "parseopt.h" unsigned long count = 0; unsigned long attempted = 0; u_int64_t bytecount = 0; u_int64_t starttime; char *opt_name = NULL; bool opt_verbose = false; int opt_test = 0; int opt_port = 8080; in_addr addr; static char request1[70] = "GET /symlink.txt HTTP/1.0\r\n\r\n"; int responselen1 = 335; int requestlen1 = strlen (request1); static char request2[70] = "GET /one/two/three/symlink.txt HTTP/1.0\r\n\r\n"; int responselen2 = 335; int requestlen2 = strlen (request2); char bitbucket[2048]; inline u_int64_t gettime () { timeval tv; gettimeofday (&tv, NULL); return tv.tv_sec * INT64(1000000) + tv.tv_usec; } void fail (int err) { warn << "connection failed" << strerror (errno) << "\n"; } void init () { tcpconnect (addr, opt_port, wrap (getsockres)); } void getsockres (int fd) { attempted++; if (fd < 0) { timecb (timenow +1, wrap (init)); } else { tcp_nodelay (fd); int wrlen = write (fd, ((opt_test == 1)?request1:request2), ((opt_test == 1)?requestlen1:requestlen2)); if (wrlen != ((opt_test == 1)?requestlen1:requestlen2)) { warn << "Fuck!\n"; close (fd); } else { shutdown (fd, SHUT_WR); fdcb (fd, selread, wrap (resp, fd)); } } } void resp (int fd) { int rdlen = read (fd, bitbucket, ((opt_test == 1)?responselen1:responselen2)); if (rdlen < 0 && errno != EAGAIN) { fdcb (fd, selread, NULL); fail(errno); } else if (rdlen == ((opt_test == 1)?responselen1:responselen2)) { fdcb (fd, selread, NULL); count++; close (fd); init (); } else { warnx << "Didn't get a proper response. rdlen: " << rdlen << "\n"; close (fd); init (); } } void finish () { u_int64_t elapsed_usec = gettime () - starttime; if (opt_verbose) { printf ("Bytes: %lu\n", ((opt_test == 1)?responselen1:responselen2) * count); printf (" usec: %qd\n", elapsed_usec); printf (" MB/s: %f\n", 0.953674316406 * ((opt_test == 1)?responselen1:responselen2) * count /elapsed_usec); printf ("Successful plays: %lu\n", count); printf ("Attempted plays: %lu\n", attempted); printf ("Successful plays/s: %f\n", count / (elapsed_usec / 1e6F)); printf ("Attempted plays/s: %f\n\n", attempted / (elapsed_usec/ 1e6F)); } else { printf ("%5s %10lu %10qd %10f %6lu %6lu %8.2f %8.2f\n", opt_name?opt_name:"Local", ((opt_test == 1)?responselen1:responselen2) * count, elapsed_usec, 0.953674316406 * ((opt_test == 1)?responselen1:responselen2) * count / elapsed_usec, count, attempted, count / (elapsed_usec / 1e6F), attempted / (elapsed_usec/ 1e6F)); } exit (0); } void usage () { warnx << " Test 1 == Single component\n" << " Test 2 == Multi component\n\n"; fatal << "\nusage: " << progname << " [-p trigger-port] [-n num-clients]\n" << " [-t seconds] [-l label] [-v] -r test-num server port\n\n"; } int main (int argc, char **argv) { setprogname (argv[0]); int opt_triggerport = 0; int opt_nclients = 20; double opt_nseconds = 5.0; int ch; while ((ch = getopt (argc, argv, "p:n:t:r:l:r:v")) != -1) switch (ch) { case 'p': if (!convertint (optarg, &opt_triggerport)) usage (); break; case 'n': if (!convertint (optarg, &opt_nclients)) usage (); break; case 't': opt_nseconds = atof (optarg); if (opt_nseconds <= 0) usage (); break; case 'v': opt_verbose = true; break; case 'l': opt_name = optarg; break; case 'r': if (!convertint (optarg, &opt_test)) usage (); break; default: usage (); break; } if ( (optind + 2 != argc) || ((opt_test != 1) && (opt_test != 2))) usage (); if (!convertint (argv[optind+1], &opt_port)) usage (); hostent *hp = gethostbyname (argv[optind]); if (!hp) fatal << argv[1] << ": no such host\n"; addr = *(in_addr *) hp->h_addr; itimerval itv; bzero (&itv, sizeof (itv)); itv.it_value.tv_sec = long (opt_nseconds); itv.it_value.tv_usec = long (1000000 * (opt_nseconds - itv.it_value.tv_sec)); sigcb (SIGALRM, wrap (finish)); if (opt_verbose) { printf ("Clients Est. Duration (usec) Bytes Act. Duration (usec) MB/s Succ. Plays Attem. Plays Succ. Plays/s Attem. Plays/s\n"); printf ("[ %d clients / %f seconds ]\n", opt_nclients, opt_nseconds); } if (opt_triggerport) { int fd = inetsocket (SOCK_DGRAM, opt_triggerport); if (fd < 0) fatal ("socket: %m\n"); char c; socklen_t l = 0; recvfrom (fd, &c, 1, 0, NULL, &l); } if (setitimer (ITIMER_REAL, &itv, NULL) < 0) fatal ("setitimer: %m\n"); starttime = gettime (); for (int i=0; i< opt_nclients; i++) init(); amain (); }