There's a note in ab that strstr is a performance drain. The diff
attached tries to remove strstr from a few places and changes the way
that we check things. It works and is as fast, if not slightly faster,
that the current code but I'm sure it can be improved on. anyway, it's
here should it be of interest. I won't commit it unless I get some
positive agreement.
I've tried at avoid using str* functions where possible.
david
Index: ab.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/support/ab.c,v
retrieving revision 1.29
diff -u -u -r1.29 ab.c
--- ab.c 2000/10/15 11:46:22 1.29
+++ ab.c 2000/10/15 13:35:14
@@ -566,6 +566,7 @@
/* --------------------------------------------------------- */
/* read data from connection */
+#define ASCII_LF '\012'
static void read_connection(struct connection *c)
{
@@ -590,7 +591,9 @@
totalread += r;
if (!c->gotheader) {
- char *s;
+ char *s, *pos, *temppos;
+ apr_size_t len;
+ int loops = 0;
int l = 4;
int space = CBUFFSIZE - c->cbx - 1; /* -1 to allow for 0
terminator */
int tocopy = (space < r) ? space : r;
@@ -613,15 +616,46 @@
if (verbosity >= 4) {
printf("LOG: header received:\n%s\n", c->cbuff);
}
- 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;
- }
+
+ temppos = c->cbuff;
+ len = c->cbx;
+ while (pos = memchr(temppos, ASCII_LF, len)){
+ /* Get the response code... */
+ if (*temppos == 'H' && *(temppos+1) == 'T' && *(temppos+2)
== 'T'
+ && *(temppos+3) == 'P'){
+ respcode[0] = *(temppos + 9);
+ respcode[1] = *(temppos + 10);
+ respcode[2] = *(temppos + 11);
+ respcode[3] = '\0';
+ }
+ /* Do we need the servername ? */
+ if (!good && *temppos == 'S' && *(temppos+1) == 'e'
+ && *(temppos+2) == 'r' && *(temppos+3) == 'v'){
+ char *q;
+ q = servername;
+ temppos += 8;
+
+ while (*temppos > 32)
+ *q++ = *temppos++;
+ *q = 0;
+ }
+
+ /* Have we reached the end of the headers? */
+ if ((*(pos + 1)) == '\r' && (*(pos + 2)) == '\n'){
+ s = pos;
+ break;
+ } else if ((*(pos + 1)) == '\n'){
+ s=pos;
+ l = 2;
+ break;
+ }
+ len -= (pos - temppos);
+ if (len <= 0)
+ break;
+ temppos = ++pos;
+ }
+
if (!s) {
/* read rest next time */
if (space) {
@@ -640,28 +674,6 @@
}
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;
- }
-
- /* XXX: this parsing isn't even remotely HTTP compliant...
- * but in the interest of speed it doesn't totally have to
be,
- * it just needs to be extended to handle whatever servers
- * folks want to test against. -djg */
-
- /* check response code */
- part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */
- strncpy(respcode, (part + strlen("HTTP/1.x_")), 3);
- respcode[3] = '\0';
if (respcode[0] != '2') {
err_response++;
if (verbosity >= 2)
@@ -711,10 +723,10 @@
}
if (done < requests) {
struct data s;
- c->done = apr_now();
+ c->done = apr_now();
s.read = c->read;
- s.ctime = (c->connect - c->start) / 1000;
- s.time = (c->done - c->start) / 1000;
+ s.ctime = (c->connect - c->start) / 1000;
+ s.time = (c->done - c->start) / 1000;
stats[done++] = s;
}
c->keepalive = 0;
|