couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject [12/15] git commit: A simplistic benchmark
Date Mon, 04 Aug 2014 18:06:50 GMT
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.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-b64url/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-b64url/commit/75336f13
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-b64url/tree/75336f13
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-b64url/diff/75336f13

Branch: refs/heads/windsor-merge
Commit: 75336f1390720c94abc94d94801b81c0f55aab20
Parents: 504cbd0
Author: Paul J. Davis <paul.joseph.davis@gmail.com>
Authored: Tue Dec 3 12:28:57 2013 -0600
Committer: Paul J. Davis <paul.joseph.davis@gmail.com>
Committed: Tue Dec 3 12:28:57 2013 -0600

----------------------------------------------------------------------
 test/benchmark.escript | 168 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-b64url/blob/75336f13/test/benchmark.escript
----------------------------------------------------------------------
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().
+


Mime
View raw message