You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by "Ralf S. Engelschall" <rs...@apache.org> on 1998/03/17 13:46:43 UTC

cvs commit: apache-1.3/src/support ab.c ab.1 Makefile.tmpl

rse         98/03/17 04:46:42

  Modified:    .        STATUS
               src      CHANGES
               src/support Makefile.tmpl
  Added:       src/support ab.c ab.1
  Log:
  Include of the new "ApacheBench" support program:
  
    o base is ZeusBench 1.0 from Adam Twiss, Zeus Technology Ltd.
  
    o includes enhancements by Dean from November 1997 for keepalive, SunOS4,
      etc. pp. which were already committed to src/test/zb.c
  
    o cleanups and enhancements by Ralf from March 1998: command line
      parsing, new options, URL-like target specification, manual page,
      Apache-style code indentation, etc.
  
    o !!IMPORTANT!! personal license agreement from March 1998 with Adam Twiss
      from Zeus Technology (see message
      <19...@en1.engelschall.com> in apache-core mailing list
      for reference) to include this version into the Apache distribution the
      way it currently is. So, don't change copyright messages or other
      license stuff there, please. The program itself can now be enhanced or
      changed in any way.
  
  Revision  Changes    Path
  1.194     +1 -0      apache-1.3/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/STATUS,v
  retrieving revision 1.193
  retrieving revision 1.194
  diff -u -r1.193 -r1.194
  --- STATUS	1998/03/17 09:59:30	1.193
  +++ STATUS	1998/03/17 12:46:36	1.194
  @@ -93,6 +93,7 @@
       * Ralf's Various cleanups to the command line interface and manual pages
       * Marc's mod_proxy was not clearing the Proxy-Connection header
       * Dean's API_EXPORT and CORE_EXPORT cleanup for core functions
  +    * Ralf's new ApacheBench support program (src/support/ab.c)
   
   Available Patches:
   
  
  
  
  1.719     +7 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.718
  retrieving revision 1.719
  diff -u -r1.718 -r1.719
  --- CHANGES	1998/03/17 08:31:00	1.718
  +++ CHANGES	1998/03/17 12:46:38	1.719
  @@ -1,5 +1,12 @@
   Changes with Apache 1.3b6
   
  +  *) Add the new ApacheBench program "ab" to src/support/: This is derived
  +     from the ZeusBench benchmarking program and can be used to determine the
  +     response performance of an Apache installation. This version is
  +     officially licensed with Zeus Technology, Ltd. See the license agreement
  +     statements in <19...@en1.engelschall.com> in apache-core.
  +     [Ralf S. Engelschall]
  +
     *) API: Various core functions that are definately not part of the API
        have been made static, and a few have been marked API_EXPORT.  Still
        more have been marked CORE_EXPORT and are not intended for general
  
  
  
  1.11      +5 -2      apache-1.3/src/support/Makefile.tmpl
  
  Index: Makefile.tmpl
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/support/Makefile.tmpl,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- Makefile.tmpl	1998/03/13 08:15:26	1.10
  +++ Makefile.tmpl	1998/03/17 12:46:41	1.11
  @@ -9,9 +9,9 @@
   LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) -L../ap
   INCDIR=../include
   
  -TARGETS=htpasswd htdigest rotatelogs logresolve
  +TARGETS=htpasswd htdigest rotatelogs logresolve ab
   
  -OBJS=htpasswd.o htdigest.o rotatelogs.o logresolve.o
  +OBJS=htpasswd.o htdigest.o rotatelogs.o logresolve.o ab.o
   
   .c.o: 
   	$(CC) -c $(CFLAGS) $(INCLUDES) $<
  @@ -29,6 +29,9 @@
   
   logresolve: logresolve.o
   	$(CC) $(INCLUDES) $(CFLAGS) logresolve.o -o logresolve $(LDFLAGS) $(LIBS)
  +
  +ab: ab.o
  +	$(CC) $(INCLUDES) $(CFLAGS) ab.o -o ab $(LDFLAGS) $(LIBS)
   
   clean:
   	rm -f $(TARGETS) *.o
  
  
  
  1.1                  apache-1.3/src/support/ab.c
  
  Index: ab.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1998 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  /* 
  ** This program is based on ZeusBench V1.0 written by Adam Twiss 
  ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/
  **
  ** This software is provided "as is" and any express or implied waranties, 
  ** including but not limited to, the implied warranties of merchantability and
  ** fitness for a particular purpose are disclaimed.  In no event shall 
  ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special, 
  ** exemplary, or consequential damaged (including, but not limited to, 
  ** procurement of substitute good or services; loss of use, data, or profits;
  ** or business interruption) however caused and on theory of liability.  Whether
  ** in contract, strict liability or tort (including negligence or otherwise) 
  ** arising in any way out of the use of this software, even if advised of the
  ** possibility of such damage.
  **
  */
  
  /*
  ** HISTORY: 
  **    - Originally written by Adam Twiss <ad...@zeus.co.uk>, March 1996
  **      with input from Mike Belshe <mb...@netscape.com> and 
  **      Michael Campanella <ca...@stevms.enet.dec.com>
  **    - Enhanced by Dean Gaudet <dg...@apache.org>, November 1997
  **    - Cleaned up by Ralf S. Engelschall <rs...@apache.org>, March 1998 
  **
  */
  
  #define VERSION "1.1"
  
  /*  -------------------------------------------------------------------- */
  
  /* affects include files on Solaris */
  #define BSD_COMP
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <netdb.h>
  #include <sys/time.h>
  #include <sys/ioctl.h>
  #include <sys/socket.h>
  #include <sys/ioctl.h>
  #include <netinet/in.h>
  
  /* ------------------- DEFINITIONS -------------------------- */
  
  /* maximum number of requests on a time limited test */
  #define MAX_REQUESTS 50000
  
  /* good old state hostname */
  #define STATE_UNCONNECTED 0
  #define STATE_CONNECTING  1
  #define STATE_READ        2
  
  #define CBUFFSIZE       512
  
  struct connection {
      int fd;
      int state;
      int read;                   /* amount of bytes read */
      int bread;                  /* amount of body read */
      int length;                 /* Content-Length value used for keep-alive */
      char cbuff[CBUFFSIZE];      /* a buffer to store server response header */
      int cbx;                    /* offset in cbuffer */
      int keepalive;              /* non-zero if a keep-alive request */
      int gotheader;              /* non-zero if we have the entire header in cbuff */
      struct timeval start, connect, done;
  };
  
  struct data {
      int read;                   /* number of bytes read */
      int ctime;                  /* time in ms to connect */
      int time;                   /* time in ms for connection */
  };
  
  #define min(a,b) ((a)<(b))?(a):(b)
  #define max(a,b) ((a)>(b))?(a):(b)
  
  /* --------------------- GLOBALS ---------------------------- */
  
  int requests = 1;               /* Number of requests to make */
  int concurrency = 1;            /* Number of multiple requests to make */
  int tlimit = 0;                 /* time limit in cs */
  int keepalive = 0;              /* try and do keepalive connections */
  char servername[1024];          /* name that server reports */
  char hostname[1024];            /* host name */
  char path[1024];                /* path name */
  int port = 80;                  /* port number */
  
  int doclen = 0;                 /* the length the document should be */
  int totalread = 0;              /* total number of bytes read */
  int totalbread = 0;             /* totoal amount of entity body read */
  int done = 0;                   /* number of requests we have done */
  int doneka = 0;                 /* number of keep alive connections done */
  int good = 0, bad = 0;          /* number of good and bad requests */
  
  /* store error cases */
  int err_length = 0, err_conn = 0, err_except = 0;
  
  struct timeval start, endtime;
  
  /* global request (and its length) */
  char request[512];
  int reqlen;
  
  /* one global throw-away buffer to read stuff into */
  char buffer[4096];
  
  struct connection *con;         /* connection array */
  struct data *stats;             /* date for each request */
  
  fd_set readbits, writebits;     /* bits for select */
  struct sockaddr_in server;      /* server addr structure */
  
  /* --------------------------------------------------------- */
  
  /* simple little function to perror and exit */
  
  static void err(char *s)
  {
      perror(s);
      exit(errno);
  }
  
  /* --------------------------------------------------------- */
  
  /* write out request to a connection - assumes we can write 
     (small) request out in one go into our new socket buffer  */
  
  void write_request(struct connection *c)
  {
      gettimeofday(&c->connect, 0);
      write(c->fd, request, reqlen);
      c->state = STATE_READ;
      FD_SET(c->fd, &readbits);
      FD_CLR(c->fd, &writebits);
  }
  
  /* --------------------------------------------------------- */
  
  /* make an fd non blocking */
  
  void nonblock(int fd)
  {
      int i = 1;
      ioctl(fd, FIONBIO, &i);
  }
  
  /* --------------------------------------------------------- */
  
  /* returns the time in ms between two timevals */
  
  int timedif(struct timeval a, struct timeval b)
  {
      register int us, s;
  
      us = a.tv_usec - b.tv_usec;
      us /= 1000;
      s = a.tv_sec - b.tv_sec;
      s *= 1000;
      return s + us;
  }
  
  /* --------------------------------------------------------- */
  
  /* calculate and output results and exit */
  
  void output_results()
  {
      int timetaken;
  
      gettimeofday(&endtime, 0);
      timetaken = timedif(endtime, start);
  
      printf("\r                                                                           \r");
      printf("Server Software:        %s\n", servername);
      printf("Server Hostname:        %s\n", hostname);
      printf("Server Port:            %d\n", port);
      printf("\n");
      printf("Document Path:          %s\n", path);
      printf("Document Length:        %d bytes\n", doclen);
      printf("\n");
      printf("Concurency Level:       %d\n", concurrency);
      printf("Time taken for tests:   %d.%03d seconds\n",
             timetaken / 1000, timetaken % 1000);
      printf("Complete requests:      %d\n", done);
      printf("Failed requests:        %d\n", bad);
      if (bad)
          printf("   (Connect: %d, Length: %d, Exceptions: %d)\n",
                 err_conn, err_length, err_except);
      if (keepalive)
          printf("Keep-Alive requests:    %d\n", doneka);
      printf("Total transfered:       %d bytes\n", totalread);
      printf("HTML transfered:        %d bytes\n", totalbread);
  
      /* avoid divide by zero */
      if (timetaken) {
          printf("Requests per seconds:   %.2f\n", 1000 * (float) (done) / timetaken);
          printf("Transfer rate:          %.2f kb/s\n",
                 (float) (totalread) / timetaken);
      }
  
      {
          /* work out connection times */
          int i;
          int totalcon = 0, total = 0;
          int mincon = 9999999, mintot = 999999;
          int maxcon = 0, maxtot = 0;
  
          for (i = 0; i < requests; i++) {
              struct data s = stats[i];
              mincon = min(mincon, s.ctime);
              mintot = min(mintot, s.time);
              maxcon = max(maxcon, s.ctime);
              maxtot = max(maxtot, s.time);
              totalcon += s.ctime;
              total += s.time;
          }
          printf("\nConnnection Times (ms)\n");
          printf("           min   avg   max\n");
          printf("Connect: %5d %5d %5d\n", mincon, totalcon / requests, maxcon);
          printf("Total:   %5d %5d %5d\n", mintot, total / requests, maxtot);
      }
  
      exit(0);
  }
  
  /* --------------------------------------------------------- */
  
  /* start asnchronous non-blocking connection */
  
  void start_connect(struct connection *c)
  {
      c->read = 0;
      c->bread = 0;
      c->keepalive = 0;
      c->cbx = 0;
      c->gotheader = 0;
  
      c->fd = socket(AF_INET, SOCK_STREAM, 0);
      if (c->fd < 0)
          err("socket");
  
      nonblock(c->fd);
      gettimeofday(&c->start, 0);
  
      if (connect(c->fd, (struct sockaddr *) &server, sizeof(server)) < 0) {
          if (errno == EINPROGRESS) {
              c->state = STATE_CONNECTING;
              FD_SET(c->fd, &writebits);
              return;
          }
          else {
              close(c->fd);
              err_conn++;
              if (bad++ > 10) {
                  printf("\nTest aborted after 10 failures\n\n");
                  exit(1);
              }
              start_connect(c);
          }
      }
  
      /* connected first time */
      write_request(c);
  }
  
  /* --------------------------------------------------------- */
  
  /* close down connection and save stats */
  
  void close_connection(struct connection *c)
  {
      if (c->read == 0 && c->keepalive) {
          /* server has legitiamately shut down an idle keep alive request */
          good--;                 /* connection never happend */
      }
      else {
          if (good == 1) {
              /* first time here */
              doclen = c->bread;
          }
          else if (c->bread != doclen) {
              bad++;
              err_length++;
          }
  
          /* save out time */
          if (done < requests) {
              struct data s;
              gettimeofday(&c->done, 0);
              s.read = c->read;
              s.ctime = timedif(c->connect, c->start);
              s.time = timedif(c->done, c->start);
              stats[done++] = s;
          }
      }
  
      close(c->fd);
      FD_CLR(c->fd, &readbits);
      FD_CLR(c->fd, &writebits);
  
      /* connect again */
      start_connect(c);
      return;
  }
  
  /* --------------------------------------------------------- */
  
  /* read data from connection */
  
  void read_connection(struct connection *c)
  {
      int r;
  
      r = read(c->fd, buffer, sizeof(buffer));
      if (r == 0 || (r < 0 && errno != EAGAIN)) {
          good++;
          close_connection(c);
          return;
      }
  
      if (r < 0 && errno == EAGAIN)
          return;
  
      c->read += r;
      totalread += r;
  
      if (!c->gotheader) {
          char *s;
          int l = 4;
          int space = CBUFFSIZE - c->cbx - 1;     /* -1 to allow for 0 terminator */
          int tocopy = (space < r) ? space : r;
          memcpy(c->cbuff + c->cbx, buffer, space);
          c->cbx += tocopy;
          space -= tocopy;
          c->cbuff[c->cbx] = 0;   /* terminate for benefit of strstr */
          s = strstr(c->cbuff, "\r\n\r\n");
          /* this next line is so that we talk to NCSA 1.5 which blatantly breaks 
             the http specifaction */
          if (!s) {
              s = strstr(c->cbuff, "\n\n");
              l = 2;
          }
  
          if (!s) {
              /* read rest next time */
              if (space)
                  return;
              else {
                  /* header is in invalid or too big - close connection */
                  close(c->fd);
                  if (bad++ > 10) {
                      printf("\nTest aborted after 10 failures\n\n");
                      exit(1);
                  }
                  FD_CLR(c->fd, &writebits);
                  start_connect(c);
              }
          }
          else {
              /* have full header */
              if (!good) {
                  /* this is first time, extract some interesting info */
                  char *p, *q;
                  p = strstr(c->cbuff, "Server:");
                  q = servername;
                  if (p) {
                      p += 8;
                      while (*p > 32)
                          *q++ = *p++;
                  }
                  *q = 0;
              }
  
              c->gotheader = 1;
              *s = 0;             /* terminate at end of header */
              if (keepalive &&
                  (strstr(c->cbuff, "Keep-Alive")
                   || strstr(c->cbuff, "keep-alive"))) {  /* for benefit of MSIIS */
                  char *cl;
                  cl = strstr(c->cbuff, "Content-Length:");
                  /* for cacky servers like NCSA which break the spec and send a 
                     lower case 'l' */
                  if (!cl)
                      cl = strstr(c->cbuff, "Content-length:");
                  if (cl) {
                      c->keepalive = 1;
                      c->length = atoi(cl + 16);
                  }
              }
              c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy;
              totalbread += c->bread;
          }
      }
      else {
          /* outside header, everything we have read is entity body */
          c->bread += r;
          totalbread += r;
      }
  
      if (c->keepalive && (c->bread >= c->length)) {
          /* finished a keep-alive connection */
          good++;
          doneka++;
          /* save out time */
          if (good == 1) {
              /* first time here */
              doclen = c->bread;
          }
          else if (c->bread != doclen) {
              bad++;
              err_length++;
          }
          if (done < requests) {
              struct data s;
              gettimeofday(&c->done, 0);
              s.read = c->read;
              s.ctime = timedif(c->connect, c->start);
              s.time = timedif(c->done, c->start);
              stats[done++] = s;
          }
          c->keepalive = 0;
          c->length = 0;
          c->gotheader = 0;
          c->cbx = 0;
          c->read = c->bread = 0;
          write_request(c);
          c->start = c->connect;  /* zero connect time with keep-alive */
      }
  }
  
  /* --------------------------------------------------------- */
  
  /* run the tests */
  
  int test()
  {
      struct timeval timeout, now;
      fd_set sel_read, sel_except, sel_write;
      int i;
  
      printf("Benchmarking %s (be patient)...", hostname);
      fflush(stdout);
  
      {
          /* get server information */
          struct hostent *he;
          he = gethostbyname(hostname);
          if (!he)
              err("gethostbyname");
          server.sin_family = he->h_addrtype;
          server.sin_port = htons(port);
          server.sin_addr.s_addr = ((unsigned long *) (he->h_addr_list[0]))[0];
      }
  
      con = malloc(concurrency * sizeof(struct connection));
      memset(con, 0, concurrency * sizeof(struct connection));
  
      stats = malloc(requests * sizeof(struct data));
  
      FD_ZERO(&readbits);
      FD_ZERO(&writebits);
  
      /* setup request */
      sprintf(request, "GET %s HTTP/1.0\r\n"
                       "User-Agent: ApacheBench/%s\r\n"
                       "%s"
                       "Host: %s\r\n"
                       "Accept: */*\r\n"
                       "\r\n", 
                       path, 
                       VERSION,
                       keepalive ? "Connection: Keep-Alive\r\n" : "", 
                       hostname);
  
      reqlen = strlen(request);
  
      /* ok - lets start */
      gettimeofday(&start, 0);
  
      /* initialise lots of requests */
      for (i = 0; i < concurrency; i++)
          start_connect(&con[i]);
  
      while (done < requests) {
          int n;
          /* setup bit arrays */
          memcpy(&sel_except, &readbits, sizeof(readbits));
          memcpy(&sel_read, &readbits, sizeof(readbits));
          memcpy(&sel_write, &writebits, sizeof(readbits));
  
          /* check for time limit expiry */
          gettimeofday(&now, 0);
          if (tlimit && timedif(now, start) > (tlimit * 1000)) {
              requests = done;    /* so stats are correct */
              output_results();
          }
  
          /* Timeout of 30 seconds. */
          timeout.tv_sec = 30;
          timeout.tv_usec = 0;
          n = select(256, &sel_read, &sel_write, &sel_except, &timeout);
          if (!n) {
              printf("\nServer timed out\n\n");
              exit(1);
          }
          if (n < 1)
              err("select");
  
          for (i = 0; i < concurrency; i++) {
              int s = con[i].fd;
              if (FD_ISSET(s, &sel_except)) {
                  bad++;
                  err_except++;
                  start_connect(&con[i]);
                  continue;
              }
              if (FD_ISSET(s, &sel_read))
                  read_connection(&con[i]);
              if (FD_ISSET(s, &sel_write))
                  write_request(&con[i]);
          }
          if (done >= requests)
              output_results();
      }
      return 0;
  }
  
  /* ------------------------------------------------------- */
  
  /* display copyright information */
  void copyright(void) 
  {
      printf("This is ApacheBench, Version %s\n", VERSION);
      printf("Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\n");
      printf("Copyright (c) 1998 The Apache Group, http://www.apache.org/\n");
      printf("\n");
  }
  
  /* display usage information */
  void usage(char *progname)
  {
      fprintf(stderr, "Usage: %s [options] [http://]hostname[:port]/path\n", progname);
      fprintf(stderr, "Options are:\n");
      fprintf(stderr, "    -n requests     Number of requests to perform\n");
      fprintf(stderr, "    -c concurrency  Number of multiple requests to make\n");
      fprintf(stderr, "    -t timelimit    Seconds to max. wait for responses\n");
      fprintf(stderr, "    -k              Use HTTP KeepAlive feature\n");
      fprintf(stderr, "    -v              Display version and copyright information\n");
      fprintf(stderr, "    -h              Display usage information (this message)\n");
      exit(EINVAL);
  }
  
  /* ------------------------------------------------------- */
  
  /* split URL into parts */
  
  int parse_url(char *url)
  {
      char *cp;
      char *h;
      char *p = NULL;
  
      if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) 
          url += 7;
      h = url;
      if ((cp = strchr(url, ':')) != NULL) {
          *cp++ = '\0';
          p = cp;
          url = cp;
      }
      if ((cp = strchr(url, '/')) == NULL)
          return 1;
      strcpy(path, cp);
      *cp = '\0';
      strcpy(hostname, h);
      if (p != NULL)
          port = atoi(p);
      return 0;
  }
  
  /* ------------------------------------------------------- */
  
  extern char *optarg;
  extern int optind, opterr, optopt;
  
  /* sort out command-line args and call test */
  int main(int argc, char **argv)
  {
      int c;
      optind = 1;
      while ((c = getopt(argc, argv, "n:c:t:kvh")) > 0) {
          switch (c) {
          case 'n':
              requests = atoi(optarg);
              if (!requests) {
                  printf("Invalid number of requests\n");
                  exit(1);
              }
              break;
          case 'k':
              keepalive = 1;
              break;
          case 'c':
              concurrency = atoi(optarg);
              break;
              break;
          case 't':
              tlimit = atoi(optarg);
              requests = MAX_REQUESTS;    /* need to size data array on something */
              break;
          case 'v':
              copyright();
              exit(0);
              break;
          case 'h':
              usage(argv[0]);
              break;
          default:
              fprintf(stderr, "%s: invalid option `%c'\n", argv[0], c);
              usage(argv[0]);
              break;
          }
      }
      if (optind != argc-1) {
          fprintf(stderr, "%s: wrong number of arguments\n", argv[0]);
          usage(argv[0]);
      }
  
      if (parse_url(argv[optind++])) {
          fprintf(stderr, "%s: invalid URL\n", argv[0]);
          usage(argv[0]);
      }
  
      copyright();
      test();
      exit(0);
  }
  
  
  
  
  1.1                  apache-1.3/src/support/ab.1
  
  Index: ab.1
  ===================================================================
  .TH ab 1 "March 1998"
  .\" Copyright (c) 1998 The Apache Group. All rights reserved.
  .\"
  .\" Redistribution and use in source and binary forms, with or without
  .\" modification, are permitted provided that the following conditions
  .\" are met:
  .\"
  .\" 1. Redistributions of source code must retain the above copyright
  .\"    notice, this list of conditions and the following disclaimer. 
  .\"
  .\" 2. Redistributions in binary form must reproduce the above copyright
  .\"    notice, this list of conditions and the following disclaimer in
  .\"    the documentation and/or other materials provided with the
  .\"    distribution.
  .\"
  .\" 3. All advertising materials mentioning features or use of this
  .\"    software must display the following acknowledgment:
  .\"    "This product includes software developed by the Apache Group
  .\"    for use in the Apache HTTP server project (http://www.apache.org/)."
  .\"
  .\" 4. The names "Apache Server" and "Apache Group" must not be used to
  .\"    endorse or promote products derived from this software without
  .\"    prior written permission.
  .\"
  .\" 5. Redistributions of any form whatsoever must retain the following
  .\"    acknowledgment:
  .\"    "This product includes software developed by the Apache Group
  .\"    for use in the Apache HTTP server project (http://www.apache.org/)."
  .\"
  .\" THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  .\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  .\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  .\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  .\" OF THE POSSIBILITY OF SUCH DAMAGE.
  .\" ====================================================================
  .\"
  .\" This software consists of voluntary contributions made by many
  .\" individuals on behalf of the Apache Group and was originally based
  .\" on public domain software written at the National Center for
  .\" Supercomputing Applications, University of Illinois, Urbana-Champaign.
  .\" For more information on the Apache Group and the Apache HTTP server
  .\" project, please see <http://www.apache.org/>.
  .SH NAME
  ab \- Apache HTTP server benchmarking tool
  .SH SYNOPSIS
  .B ab 
  [
  .B \-k
  ] [
  .BI \-n " requests"
  ] [
  .BI \-t " timelimit"
  ] [
  .BI \-c " concurrency"
  ]
  .I [http://]hostname[:port]/path 
  
  .B ab
  [
  .B \-v 
  ] [
  .B \-h 
  ]
  .PP
  .SH DESCRIPTION
  .B ab
  is a tool for benchmarking your Apache HyperText Transfer Protocol (HTTP)
  server. It is designed to give you an impression on how performant is your
  current Apache installation.  This especially shows you how much requests per
  time your Apache installation is capable to serve. 
  .PP
  .SH OPTIONS
  .TP 12
  .B \-k 
  Enable the HTTP KeepAlive feature, i.e. perform multiple requests within one
  HTTP session instead. Default is no KeepAlive.
  .TP 12
  .BI \-n " requests"
  Number of requests to perform for the benchmarking session.  The default is to
  just perform one single request which usually leads to not very representative
  benchmarking results.
  .TP 12
  .BI \-t " timelimit"
  Seconds to max. spend for benchmarking. This implies
  a 
  .B \-n 
  .B 50000
  internally. Use this to benchmark the server within a fixed total amount of
  time.  Per default there is no timelimit. 
  .TP 12
  .BI \-c " concurrency"
  Number of multiple requests per time to perform. 
  Default is one request per time.
  .TP 12
  .B \-v 
  Display version and copyright information.
  .TP 12
  .B \-h 
  Display usage information.
  .PD
  .SH SEE ALSO
  .BR httpd(8)
  .
  
  
  

Re: cvs commit: apache-1.3/src/support ab.c ab.1 Makefile.tmpl

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 17 Mar 1998, Ralf S. Engelschall wrote:

>     o includes enhancements by Dean from November 1997 for keepalive, SunOS4,
>       etc. pp. which were already committed to src/test/zb.c

Those were from the original author via marc... I just happened to commit
them.  I'm not sure renaming this is such a good idea.  I'd rather just
have a subversion or something.  There are other changes I'd like to make.

Dean