Changeset 989

Show
Ignore:
Timestamp:
03/01/08 21:34:57 (6 months ago)
Author:
normalperson
Message:

http11: ~6% performance increase in header parsing

Allocate one string object and avoid appending to it causing it
to be resized. Additionally, optimize the string toupper copy
so that it's done in a single pass.

Also, use an inline, locale-independent toupper() implementation
which should be more predictable for users with exotic locales
(HTTP header names are always ASCII).

The following test script was used:
require 'mongrel'
include Mongrel

parser = HttpParser?.new
req = "GET /ruby HTTP/1.1\r\n" \

"User-Agent: curl/7.12.3\r\n" \
"Host: bogomips.org\r\n" \
"Accept: */*\r\n" \
"\r\n".freeze

hash = Hash.new
100000.times do

parser.execute(hash, req, 0)
parser.reset
hash.clear

end

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ext/http11/ext_help.h

    r4 r989  
    55#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name); 
    66#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T); 
     7#define ASCII_UPCASE_CHAR(ch) (ch & ~0x20) 
     8 
    79 
    810#ifdef DEBUG 
  • trunk/ext/http11/http11.c

    r944 r989  
    88#include <string.h> 
    99#include "http11_parser.h" 
    10 #include <ctype.h> 
    1110 
    1211#ifndef RSTRING_PTR 
     
    7069void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen) 
    7170{ 
    72   char *ch, *end; 
     71  char *ch; 
     72  const char *fch; 
    7373  VALUE req = (VALUE)data; 
    7474  VALUE v = Qnil; 
     
    7979 
    8080  v = rb_str_new(value, vlen); 
    81   f = rb_str_dup(global_http_prefix); 
    82   f = rb_str_buf_cat(f, field, flen);  
    83  
    84   for(ch = RSTRING_PTR(f), end = ch + RSTRING_LEN(f); ch < end; ch++) { 
    85     if(*ch == '-') { 
    86       *ch = '_'; 
    87     } else { 
    88       *ch = toupper(*ch); 
    89     } 
     81 
     82  /* 
     83   * using rb_str_new(NULL, len) here is faster than rb_str_buf_new(len) 
     84   * in my testing, because: there's no minimum allocation length (and 
     85   * no check for it, either), RSTRING_LEN(f) does not need to be 
     86   * written twice, and and RSTRING_PTR(f) will already be 
     87   * null-terminated for us. 
     88   */ 
     89  f = rb_str_new(NULL, RSTRING_LEN(global_http_prefix) + flen); 
     90  memcpy(RSTRING_PTR(f), 
     91         RSTRING_PTR(global_http_prefix), 
     92         RSTRING_LEN(global_http_prefix)); 
     93 
     94  ch = RSTRING_PTR(f) + RSTRING_LEN(global_http_prefix); 
     95  for(fch = field; flen-- != 0; ++fch) { 
     96    *ch++ = (*fch >= 'a' && *fch <= 'z') ? 
     97            ASCII_UPCASE_CHAR(*fch) : 
     98            (*fch == '-' ? '_' : *fch); 
    9099  } 
    91100