extend/cowboy — pull request #145 by ostinelli (2012-02-21 04:19:56+00:00)
Title: Custom function instead of proplists:get_value/2,3

`proplists:get_value/2,3` is considerably slower than `lists:keyfind/3` and 'lists:member/2' which are both implemented in C.

This is not important at load time when reading from options, however it is critical when performing some parsing tasks like the one that are available in the `cowboy_cookies.erl` module.

run this to perform a benchmark on your machine.

```erlang

-module(test).
-define(LIST_SIZES, [10000, 100000, 1000000]).
-define(RETRIES, 1000).
-compile(export_all).

start() ->
% test for different list sizes
lists:foreach(fun(N) -> test_list(N) end, ?LIST_SIZES).

test_list(ListSize) ->
% generate a list of size ListSize of {Key, Val} entries
KeyList = [{K, K} || K <- lists:seq(1, ListSize)],
% test this list against both functions
lists:foreach(fun(Type) -> get_val(Type, now(), KeyList, ListSize, ?RETRIES) end,
[proplists, lists]).

% test getting values, compute necessary time and output print results
get_val(Type, Start, _KeyList, ListSize, 0) ->
T = timer:now_diff(now(), Start),
io:format("computed ~p random key searches on a ~p-sized list in ~p ms using ~p~n",
[?RETRIES, ListSize, T/1000, Type]);
get_val(proplists, Start, KeyList, ListSize, Tries) ->
proplists:get_value(random:uniform(ListSize), KeyList),
get_val(proplists, Start, KeyList, ListSize, Tries - 1);
get_val(lists, Start, KeyList, ListSize, Tries) ->
get_value(random:uniform(ListSize), KeyList),
get_val(lists, Start, KeyList, ListSize, Tries - 1).

% custom implementation
get_value(Key, List) ->
get_value(Key, List, undefined).
get_value(Key, List, Default) ->
case lists:keyfind(Key, 1, List) of
false->
case lists:member(Key, List) of
true -> true;
false -> Default
end;
{Key, Value}-> Value
end.

```

a typical output would be something like

```
1> test:start().
computed 1000 random key searches on a 10000-sized list in 337.345 ms using proplists
computed 1000 random key searches on a 10000-sized list in 12.991 ms using lists
computed 1000 random key searches on a 100000-sized list in 3354.291 ms using proplists
computed 1000 random key searches on a 100000-sized list in 128.217 ms using lists
computed 1000 random key searches on a 1000000-sized list in 33745.847 ms using proplists
computed 1000 random key searches on a 1000000-sized list in 2129.49 ms using lists
ok
```

i've therefore substituted all calls to `proplists:get_value/2,3` with a newly added function `cowboy_utilities:get_value/2,3`.

all tests, including added ones for this specific function, pass.