This is an automated email from the ASF dual-hosted git repository. jaydoane pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/couchdb-b64url.git
commit 75336f1390720c94abc94d94801b81c0f55aab20 Author: Paul J. Davis <paul.joseph.da...@gmail.com> AuthorDate: Tue Dec 3 12:28:57 2013 -0600 A simplistic benchmark This is a rather simple benchmark that just looks at how much data can be passed through the NIF vs the current implementation in CouchDB. --- test/benchmark.escript | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/test/benchmark.escript b/test/benchmark.escript new file mode 100755 index 0000000..5c2bdd5 --- /dev/null +++ b/test/benchmark.escript @@ -0,0 +1,168 @@ +#!/usr/bin/env escript + +-mode(compile). + + +-export([ + encode/1, + decode/1, + run_worker/1 +]). + + +-record(st, { + parent, + module, + workers, + minsize, + maxsize, + duration, + total_bytes +}). + + +main([Workers0, MinSize0, MaxSize0, Duration0]) -> + code:add_path("./ebin"), + code:add_path("../ebin"), + Workers = to_int(Workers0), + MinSize = to_int(MinSize0), + MaxSize = to_int(MaxSize0), + Duration = to_int(Duration0), + if Workers > 0 -> ok; true -> + die("Worker count must be positive~n") + end, + if MinSize > 0 -> ok; true -> + die("Minimum size must be positive.~n") + end, + if MaxSize > 0 -> ok; true -> + die("Maximum size must be positive.~n") + end, + if MinSize < MaxSize -> ok; true -> + die("Minimum size must be less than maximum size.~n") + end, + if Duration > 0 -> ok; true -> + die("Duration must be positive.~n") + end, + St = #st{ + parent = self(), + workers = Workers, + minsize = MinSize, + maxsize = MaxSize, + duration = Duration + }, + lists:foreach(fun(M) -> + run_test(St#st{module=M}) + end, randomize([b64url, ?MODULE])); + +main(_) -> + Args = [escript:script_name()], + die("usage: ~s num_workers min_size max_size time_per_test~n", Args). + + +run_test(St) -> + Workers = spawn_workers(St#st.workers, St), + start_workers(Workers), + Results = wait_for_workers(Workers), + report(St#st.module, St#st.duration, Results). + + +start_workers(Pids) -> + lists:foreach(fun(P) -> + P ! start + end, Pids). + + +wait_for_workers(Pids) -> + lists:map(fun(P) -> + receive + {P, TotalBytes} -> TotalBytes + end + end, Pids). + + +report(Module, Duration, TotalByteList) -> + ModDesc = case Module of + ?MODULE -> "erl"; + b64url -> "nif" + end, + TotalBytes = lists:sum(TotalByteList), + io:format("~s : ~14b bytes / ~3b seconds = ~14.2f bps~n", [ + ModDesc, TotalBytes, Duration, TotalBytes / Duration]). + + +spawn_workers(NumWorkers, St) -> + lists:map(fun(_) -> + spawn_link(?MODULE, run_worker, [St]) + end, lists:seq(1, NumWorkers)). + + +run_worker(St) -> + random:seed(erlang:now()), + receive + start -> ok + end, + run_worker(St#st{total_bytes=0}, os:timestamp()). + + +run_worker(St, Started) -> + HasRun = timer:now_diff(os:timestamp(), Started), + case HasRun div 1000000 > St#st.duration of + true -> + St#st.parent ! {self(), St#st.total_bytes}; + false -> + NewSt = do_round_trip(St), + run_worker(NewSt, Started) + end. + + +do_round_trip(St) -> + Size = St#st.minsize + random:uniform(St#st.maxsize - St#st.minsize), + Data = crypto:rand_bytes(Size), + Encoded = (St#st.module):encode(Data), + Data = (St#st.module):decode(Encoded), + St#st{total_bytes=St#st.total_bytes+Size}. + + +encode(Url) -> + Url1 = iolist_to_binary(re:replace(base64:encode(Url), "=+$", "")), + Url2 = iolist_to_binary(re:replace(Url1, "/", "_", [global])), + iolist_to_binary(re:replace(Url2, "\\+", "-", [global])). + + +decode(Url64) -> + Url1 = re:replace(iolist_to_binary(Url64), "-", "+", [global]), + Url2 = iolist_to_binary( + re:replace(iolist_to_binary(Url1), "_", "/", [global]) + ), + Padding = list_to_binary(lists:duplicate((4 - size(Url2) rem 4) rem 4, $=)), + base64:decode(<<Url2/binary, Padding/binary>>). + + +randomize(List) -> + random:seed(erlang:now()), + List0 = [{random:uniform(), L} || L <- List], + List1 = lists:sort(List0), + [L || {_, L} <- List1]. + + +to_int(Val) when is_integer(Val) -> + Val; +to_int(Val) when is_binary(Val) -> + to_int(binary_to_list(Val)); +to_int(Val) when is_list(Val) -> + try + list_to_integer(Val) + catch _:_ -> + die("Invalid integer: ~w~n", [Val]) + end; +to_int(Val) -> + die("Invalid integer: ~w~n", [Val]). + + +die(Message) -> + die(Message, []). + +die(Format, Args) -> + io:format(Format, Args), + init:stop(). +