Skip to content

Commit

Permalink
Use a more efficient variant of string:to_lower to improve performance.
Browse files Browse the repository at this point in the history
After much testing and experimentation of all kinds I find lists to be both
faster and using less memory than binaries for request-line and headers
handling. This is more than likely due to the fact that headers are very
short and thus do not benefit from the advantages of refc binaries, meaning
they're copied, just like lists. The memory usage discrepancy is still a
mystery for the most part, although the hoops needed to perform operations
on the binaries are probably responsible for the extra memory use.

I'm thus giving up on trying to use binaries for request-line and headers.
Instead, this commit improves performances even more to the lists code,
making lists 5% faster than binaries. Lists are easier to work with too,
so I guess it's all a big win for everyone.

Of course the request body is still read as a binary, we're using the
binary type where it performs best.
  • Loading branch information
Loïc Hoguin committed Mar 27, 2011
1 parent 5726aa3 commit d0d9b0e
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions src/cowboy_http_protocol.erl
Expand Up @@ -97,7 +97,7 @@ wait_header(Req, State=#state{socket=Socket,
Value::string()} | http_eoh, Req::#http_req{}, State::#state{}) -> ok.
header({http_header, _I, 'Host', _R, RawHost}, Req=#http_req{path=Path,
host=undefined}, State=#state{dispatch=Dispatch}) ->
RawHost2 = string:to_lower(RawHost),
RawHost2 = string_to_lower(RawHost),
Host = cowboy_dispatcher:split_host(RawHost2),
%% @todo We probably want to filter the Host and Path here to allow
%% things like url rewriting.
Expand Down Expand Up @@ -220,7 +220,43 @@ connection_to_atom("keep-alive") ->
connection_to_atom("close") ->
close;
connection_to_atom(Connection) ->
case string:to_lower(Connection) of
case string_to_lower(Connection) of
"close" -> close;
_Any -> keepalive
end.

%% More efficient implementation of string:to_lower.
%% We are excluding a few characters on purpose.
-spec string_to_lower(string()) -> string().
string_to_lower(L) ->
[char_to_lower(C) || C <- L].

%% We gain noticeable speed by matching each value directly.
-spec char_to_lower(char()) -> char().
char_to_lower($A) -> $a;
char_to_lower($B) -> $b;
char_to_lower($C) -> $c;
char_to_lower($D) -> $d;
char_to_lower($E) -> $e;
char_to_lower($F) -> $f;
char_to_lower($G) -> $g;
char_to_lower($H) -> $h;
char_to_lower($I) -> $i;
char_to_lower($J) -> $j;
char_to_lower($K) -> $k;
char_to_lower($L) -> $l;
char_to_lower($M) -> $m;
char_to_lower($N) -> $n;
char_to_lower($O) -> $o;
char_to_lower($P) -> $p;
char_to_lower($Q) -> $q;
char_to_lower($R) -> $r;
char_to_lower($S) -> $s;
char_to_lower($T) -> $t;
char_to_lower($U) -> $u;
char_to_lower($V) -> $v;
char_to_lower($W) -> $w;
char_to_lower($X) -> $x;
char_to_lower($Y) -> $y;
char_to_lower($Z) -> $z;
char_to_lower(Ch) -> Ch.

0 comments on commit d0d9b0e

Please sign in to comment.