"Fossies" - the Fresh Open Source Software Archive

Member "httperf-0.9.0/src/gen/wsesspage.c" (7 Apr 2007, 13391 Bytes) of package /linux/www/old/httperf-0.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "wsesspage.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     httperf -- a tool for measuring web server performance
    3     Copyright 2000-2007 Hewlett-Packard Company and Contributors listed in
    4     AUTHORS file. Originally contributed by David Mosberger-Tang
    5 
    6     This file is part of httperf, a web server performance measurment
    7     tool.
    8 
    9     This program is free software; you can redistribute it and/or
   10     modify it under the terms of the GNU General Public License as
   11     published by the Free Software Foundation; either version 2 of the
   12     License, or (at your option) any later version.
   13     
   14     In addition, as a special exception, the copyright holders give
   15     permission to link the code of this work with the OpenSSL project's
   16     "OpenSSL" library (or with modified versions of it that use the same
   17     license as the "OpenSSL" library), and distribute linked combinations
   18     including the two.  You must obey the GNU General Public License in
   19     all respects for all of the code used other than "OpenSSL".  If you
   20     modify this file, you may extend this exception to your version of the
   21     file, but you are not obligated to do so.  If you do not wish to do
   22     so, delete this exception statement from your version.
   23 
   24     This program is distributed in the hope that it will be useful,
   25     but WITHOUT ANY WARRANTY; without even the implied warranty of
   26     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   27     General Public License for more details.
   28 
   29     You should have received a copy of the GNU General Public License
   30     along with this program; if not, write to the Free Software
   31     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
   32     02110-1301, USA
   33 */
   34 
   35 /* Similar to wsess but instead of generating fixed bursts, each
   36    fetched html page is parsed and the embedded objects are fetched in
   37    a burst.
   38 
   39    This is NOT a high performance workload generator!  Use it only for
   40    non-performance critical tests.  */
   41 
   42 #include <assert.h>
   43 #include <ctype.h>
   44 #include <errno.h>
   45 #include <stdio.h>
   46 #include <stdlib.h>
   47 #include <string.h>
   48 
   49 #include <httperf.h>
   50 #include <call.h>
   51 #include <conn.h>
   52 #include <core.h>
   53 #include <event.h>
   54 #include <rate.h>
   55 #include <session.h>
   56 #include <timer.h>
   57 
   58 #define CALL_PRIVATE_DATA(c) \
   59   ((Call_Private_Data *) ((char *)(c) + call_private_data_offset))
   60 #define SESS_PRIVATE_DATA(c) \
   61   ((Sess_Private_Data *) ((char *)(c) + sess_private_data_offset))
   62 
   63 typedef struct Call_Private_Data
   64   {
   65     enum
   66       {
   67     P_INITIAL,
   68     P_HTML,
   69     P_CMD,      /* we saw a `<' and are scanning for the end of CMD */
   70     P_DASH_ONE, /* looking for the first dash of a comment close */
   71     P_DASH_TWO, /* looking for the second dash of a comment close */
   72     P_RANGLE,   /* looking for '>' */
   73     P_SRC,      /* we're looking for "src" */
   74     P_DATA,     /* we're looking for "data" */
   75     P_LQUOTE,   /* we're looking for the left quote of a URI */
   76     P_NAKED_URI,    /* we're looking for an unquoted URI */
   77     P_QUOTED_URI    /* we're looking for a quoted URI */
   78       }
   79     state;
   80     int buf_len;
   81     char buf[1024];
   82     void *to_free;  /* call queue element to free when done */
   83   }
   84 Call_Private_Data;
   85 
   86 typedef struct Sess_Private_Data
   87   {
   88     u_int num_created;      /* # of calls created in this burst */
   89     u_int num_destroyed;    /* # of calls destroyed in this burst */
   90     u_int num_reqs_completed;   /* # of user reqs completed */
   91     Timer *timer;       /* timer for session think time */
   92     struct uri_list
   93       {
   94     struct uri_list *next;
   95     size_t uri_len;
   96     char uri[1];        /* really URI_LEN+1 bytes... */
   97       }
   98     *uri_list;
   99   }
  100 Sess_Private_Data;
  101 
  102 static size_t sess_private_data_offset;
  103 static size_t call_private_data_offset;
  104 
  105 static int num_sessions_generated;
  106 static int num_sessions_destroyed;
  107 static Rate_Generator rg_sess;
  108 
  109 static size_t prefix_len;
  110 static char *prefix;
  111 
  112 static void
  113 issue_calls (Sess *sess, Sess_Private_Data *priv)
  114 {
  115   int i, to_create, retval, embedded = 0;
  116   Call_Private_Data *cpriv;
  117   struct uri_list *el;
  118   Call *call;
  119 
  120   /* Mimic browser behavior of fetching html object, then a couple of
  121      embedded objects: */
  122 
  123   to_create = 1;
  124   if (priv->num_created > 0)
  125     {
  126       to_create = session_max_qlen (sess) - session_current_qlen (sess);
  127       embedded = 1;
  128     }
  129 
  130   for (i = 0; i < to_create && (!embedded || priv->uri_list); ++i)
  131     {
  132       ++priv->num_created;
  133 
  134       call = call_new ();
  135       if (!call)
  136     {
  137       sess_failure (sess);
  138       return;
  139     }
  140       if (embedded)
  141     {
  142       el = priv->uri_list;
  143       priv->uri_list = el->next;
  144 
  145       cpriv = CALL_PRIVATE_DATA (call);
  146       cpriv->to_free = el;
  147       call_set_uri (call, el->uri, el->uri_len);
  148     }
  149 
  150       if (verbose > 1)
  151     printf ("%s: fetching `%s'\n",
  152         prog_name, (char *)call->req.iov[IE_URI].iov_base);
  153 
  154       retval = session_issue_call (sess, call);
  155       call_dec_ref (call);
  156       if (retval < 0)
  157     return;
  158     }
  159 }
  160 
  161 static void
  162 fetch_uri (Sess *sess, Sess_Private_Data *priv, Call_Private_Data *cpriv,
  163        const char *uri, size_t uri_len)
  164 {
  165   struct uri_list *el;
  166   int is_relative;
  167   size_t len;
  168   char *dst;
  169 
  170   if (strchr (uri, ':'))
  171     {
  172       len = strlen (param.server);
  173       if (strncmp (uri, "http://", 7) == 0
  174       && strncmp (uri + 7, param.server, len) == 0
  175       && uri[7 + len] == '/')
  176     {
  177       uri += 7 + len;
  178       uri_len -= 7 + len;
  179     }
  180       else
  181     {
  182       /* Eventually, we may want to create new sessions on the fly,
  183          but for now, we simply punt on non-absolute URIs */
  184       if (verbose > 1)
  185         fprintf (stderr, "%s: ignoring absolute URI `%s'\n",
  186              prog_name, uri);
  187       return;
  188     }
  189     }
  190 
  191   is_relative = (uri[0] != '/');
  192 
  193   /* enqueue the new uri: */
  194   len = uri_len;
  195   if (is_relative)
  196     len += prefix_len;
  197   el = malloc (sizeof (*el) + len);
  198   if (!el)
  199     panic ("%s.fetch_uri: out of memory!\n", prog_name);
  200 
  201   el->uri_len = len;
  202   dst = el->uri;
  203   if (is_relative)
  204     {
  205       memcpy (el->uri, prefix, prefix_len);
  206       dst += prefix_len;
  207     }
  208   memcpy (dst, uri, uri_len + 1);
  209 
  210   el->next = priv->uri_list;
  211   priv->uri_list = el;
  212 
  213   issue_calls (sess, priv);
  214 }
  215 
  216 static void
  217 user_think_time_expired (Timer *t, Any_Type arg)
  218 {
  219   Sess *sess = arg.vp;
  220   Sess_Private_Data *priv;
  221 
  222   assert (object_is_sess (sess));
  223 
  224   priv = SESS_PRIVATE_DATA (sess);
  225   priv->timer = 0;
  226 
  227   issue_calls (sess, priv);
  228 }
  229 
  230 static void
  231 call_recv_hdr (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
  232 {
  233   Call_Private_Data *cpriv;
  234   Sess_Private_Data *priv;
  235   struct iovec *line;
  236   Call *call;
  237   Sess *sess;
  238   char *hdr;
  239 
  240   assert (et == EV_CALL_RECV_HDR && object_is_call (obj));
  241   call = (Call *) obj;
  242   cpriv = CALL_PRIVATE_DATA (call);
  243   sess = session_get_sess_from_call (call);
  244   priv = SESS_PRIVATE_DATA (sess);
  245 
  246   line = callarg.vp;
  247   hdr = line->iov_base;
  248 
  249   switch (tolower (hdr[0]))
  250     {
  251     case 'c':
  252       if (line->iov_len >= 23
  253       && strncasecmp (hdr + 1, "ontent-type: text/html", 22) == 0)
  254     cpriv->state = P_HTML;
  255       break;
  256 
  257     case 'l':
  258       if (line->iov_len > 10
  259       && strncasecmp (hdr + 1, "ocation: ", 9) == 0)
  260     fetch_uri (sess, priv, cpriv, hdr + 10, line->iov_len - 10);
  261       break;
  262     }
  263 
  264 }
  265 
  266 static void
  267 call_recv_data (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
  268 {
  269   Call_Private_Data *cpriv;
  270   Sess_Private_Data *priv;
  271   const char *cp, *end;
  272   struct iovec *line;
  273   Sess *sess;
  274   Call *call;
  275   int ch;
  276 
  277   assert (et == EV_CALL_RECV_DATA && object_is_call (obj));
  278   call = (Call *) obj;
  279   cpriv = CALL_PRIVATE_DATA (call);
  280   sess = session_get_sess_from_call (call);
  281   priv = SESS_PRIVATE_DATA (sess);
  282 
  283   if (cpriv->state == P_INITIAL)
  284     return; /* not an html object */
  285 
  286   line = callarg.vp;
  287   cp = line->iov_base;
  288   end = cp + line->iov_len;
  289   while (cp < end)
  290     {
  291       ch = *cp++;
  292 
  293       switch (cpriv->state)
  294     {
  295     case P_INITIAL:
  296       break;
  297 
  298     case P_HTML:
  299       cpriv->buf_len = 0;
  300       if (ch == '<')
  301         cpriv->state = P_CMD;
  302       break;
  303 
  304     case P_CMD:
  305       if (isspace (ch) || ch == '=')
  306         {
  307           if (cpriv->buf_len > 0)
  308         {
  309           if (DBG > 3)
  310             fprintf (stderr, "found command `%.*s'\n",
  311                  cpriv->buf_len, cpriv->buf);
  312 
  313           if (cpriv->buf_len == 3
  314               && strcmp (cpriv->buf, "!--") == 0)
  315             cpriv->state = P_DASH_ONE;
  316           else if (cpriv->buf_len == 5
  317                && strncasecmp (cpriv->buf, "frame", 5) == 0)
  318             cpriv->state = P_SRC;
  319           else if (cpriv->buf_len == 6
  320                && strncasecmp (cpriv->buf, "iframe", 6) == 0)
  321             cpriv->state = P_SRC;
  322           else if (cpriv->buf_len == 6
  323                && strncasecmp (cpriv->buf, "data", 6) == 0)
  324             cpriv->state = P_DATA;
  325           else if (cpriv->buf_len == 3
  326                && strncasecmp (cpriv->buf, "img", 3) == 0)
  327             cpriv->state = P_SRC;
  328           cpriv->buf_len = 0;
  329         }
  330           else
  331         cpriv->state = P_HTML;
  332         }
  333       else if (ch == '>')
  334         cpriv->state = P_HTML;
  335       else if (cpriv->buf_len < sizeof (cpriv->buf))
  336         cpriv->buf[cpriv->buf_len++] = ch;
  337       break;
  338 
  339     case P_DASH_ONE:
  340       if (ch == '-')
  341         cpriv->state = P_DASH_TWO;
  342       break;
  343 
  344     case P_DASH_TWO:
  345       cpriv->state = (ch == '-') ? P_RANGLE : P_DASH_ONE;
  346       break;
  347 
  348     case P_RANGLE:
  349       if (ch == '>')
  350         cpriv->state = P_HTML;
  351       break;
  352 
  353     case P_SRC:
  354       if (ch == '>')
  355         cpriv->state = P_HTML;
  356       else
  357         {
  358           cpriv->buf[cpriv->buf_len++] = ch;
  359           if (cpriv->buf_len == 4)
  360         {
  361           if (strncasecmp (cpriv->buf, "src=", 4) == 0)
  362             {
  363               cpriv->state = P_LQUOTE;
  364               cpriv->buf_len = 0;
  365             }
  366           else
  367             {
  368               memcpy (cpriv->buf, cpriv->buf + 1, 3);
  369               cpriv->buf_len = 3;
  370             }
  371         }
  372         }
  373       break;
  374 
  375     case P_DATA:
  376       if (ch == '>')
  377         cpriv->state = P_HTML;
  378       else
  379         {
  380           cpriv->buf[cpriv->buf_len++] = ch;
  381           if (cpriv->buf_len == 5)
  382         {
  383           if (strncasecmp (cpriv->buf, "data=", 5) == 0)
  384             {
  385               cpriv->state = P_LQUOTE;
  386               cpriv->buf_len = 0;
  387             }
  388           else
  389             {
  390               memcpy (cpriv->buf, cpriv->buf + 1, 4);
  391               cpriv->buf_len = 4;
  392             }
  393         }
  394         }
  395       break;
  396 
  397     case P_LQUOTE:
  398       if (ch == '"')
  399         cpriv->state = P_QUOTED_URI;
  400       else if (!isspace (ch))
  401         {
  402           cpriv->state = P_NAKED_URI;
  403           cpriv->buf[cpriv->buf_len++] = ch;
  404         }
  405       break;
  406 
  407     case P_NAKED_URI:
  408     case P_QUOTED_URI:
  409       if ((cpriv->state == P_QUOTED_URI && ch == '"')
  410           || (cpriv->state == P_NAKED_URI && isspace (ch)))
  411         {
  412           cpriv->buf[cpriv->buf_len] = '\0';
  413           fetch_uri (sess, priv, cpriv, cpriv->buf, cpriv->buf_len);
  414           cpriv->state = P_HTML;
  415           cpriv->buf_len = 0;
  416         }
  417       else if (cpriv->buf_len < sizeof (cpriv->buf) - 1)
  418         cpriv->buf[cpriv->buf_len++] = ch;
  419       break;
  420     }
  421     }
  422 }
  423 
  424 static void
  425 call_destroyed (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
  426 {
  427   Call_Private_Data *cpriv;
  428   Sess_Private_Data *priv;
  429   Any_Type arg;
  430   Sess *sess;
  431   Call *call;
  432 
  433   assert (et == EV_CALL_DESTROYED && object_is_call (obj));
  434 
  435   call = (Call *) obj;
  436   cpriv = CALL_PRIVATE_DATA (call);
  437   sess = session_get_sess_from_call (call);
  438   priv = SESS_PRIVATE_DATA (sess);
  439 
  440   if (cpriv->to_free)
  441     {
  442       free (cpriv->to_free);
  443       cpriv->to_free = 0;
  444     }
  445   ++priv->num_destroyed;
  446 
  447   if (sess->failed)
  448     return;
  449 
  450   if (priv->uri_list)
  451     /* there are some queued URI's which we may be able to issue now */
  452     issue_calls (sess, priv);
  453   else if (priv->num_destroyed >= priv->num_created)
  454     {
  455       /* we're done with this burst */
  456       if (++priv->num_reqs_completed >= param.wsesspage.num_reqs)
  457     /* we're done with this session */
  458     sess_dec_ref (sess);
  459       else 
  460     {
  461       /* schedule the user-think-time timer */
  462       priv->num_created = 0;
  463       assert (!priv->timer);
  464       arg.vp = sess;
  465       priv->timer = timer_schedule (user_think_time_expired, arg,
  466                     param.wsesspage.think_time);
  467     }
  468     }
  469 }
  470 
  471 /* Create a new session.  */
  472 static int
  473 sess_create (Any_Type arg)
  474 {
  475   Sess_Private_Data *priv;
  476   Sess *sess;
  477 
  478   if (num_sessions_generated++ >= param.wsesspage.num_sessions)
  479     return -1;
  480 
  481   sess = sess_new ();
  482   if (!sess)
  483     return 1;
  484 
  485   priv = SESS_PRIVATE_DATA (sess);
  486 
  487   issue_calls (sess, SESS_PRIVATE_DATA (sess));
  488   return 0;
  489 }
  490 
  491 static void
  492 sess_destroyed (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg)
  493 {
  494   Sess_Private_Data *priv;
  495   Sess *sess;
  496 
  497   assert (et == EV_SESS_DESTROYED && object_is_sess (obj));
  498   sess = (Sess *) obj;
  499 
  500   priv = SESS_PRIVATE_DATA (sess);
  501   if (priv->timer)
  502     {
  503       timer_cancel (priv->timer);
  504       priv->timer = 0;
  505     }
  506 
  507   if (++num_sessions_destroyed >= param.wsesspage.num_sessions)
  508     core_exit ();
  509 }
  510 
  511 static void
  512 init (void)
  513 {
  514   const char *slash;
  515   Any_Type arg;
  516 
  517   slash = strrchr (param.uri, '/');
  518   if (slash)
  519     prefix_len = (slash + 1) - param.uri;
  520   else
  521     panic ("%s: URI specified with --uri must be absolute", prog_name);
  522 
  523   prefix = strdup (param.uri);
  524   prefix[prefix_len] = '\0';
  525 
  526   session_init ();
  527 
  528   call_private_data_offset = object_expand (OBJ_CALL,
  529                         sizeof (Call_Private_Data));
  530   sess_private_data_offset = object_expand (OBJ_SESS,
  531                         sizeof (Sess_Private_Data));
  532   rg_sess.rate = &param.rate;
  533   rg_sess.tick = sess_create;
  534   rg_sess.arg.l = 0;
  535 
  536   arg.l = 0;
  537   event_register_handler (EV_CALL_RECV_HDR, call_recv_hdr, arg);
  538   event_register_handler (EV_CALL_RECV_DATA, call_recv_data, arg);
  539   event_register_handler (EV_SESS_DESTROYED, sess_destroyed, arg);
  540   event_register_handler (EV_CALL_DESTROYED, call_destroyed, arg);
  541 }
  542 
  543 static void
  544 start (void)
  545 {
  546   rate_generator_start (&rg_sess, EV_SESS_DESTROYED);
  547 }
  548 
  549 Load_Generator wsesspage =
  550   {
  551     "creates sessions that fetch html pages and embedded objects",
  552     init,
  553     start,
  554     no_op
  555   };