FIX: to_json performance + jsx benchmark

This commit is contained in:
Dmitry Kolesnikov 2012-03-22 21:13:20 +02:00
parent da88071cdd
commit 5d12d6262f
4 changed files with 246 additions and 3 deletions

14
Makefile Normal file
View file

@ -0,0 +1,14 @@
all:
test -d ebin || mkdir ebin
erlc -b beam -o ebin src/*.erl
cp src/jsx.app.src ebin/jsx.app
clean:
rm -Rf ebin
test:
erlc -b beam -o ebin priv/b/*.erl
run:
erl -pa ./ebin -pa ./*/ebin

BIN
priv/b/jsx_b.beam Normal file

Binary file not shown.

175
priv/b/jsx_b.erl Normal file
View file

@ -0,0 +1,175 @@
%% The MIT License
%% Copyright (c) 2012 Dmitry Kolesnikov <fogfish@ovi.com>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_b).
-export([run/2, hot/0]).
-define(LEN_KEY, 32). %% upper bound of object attribute
-define(LEN_STR, 256). %% upper bound of string value
-define(LEN_INT, 7). %% upper bound of digits
-define(JSON, 20). %% number of attributes
-define(ALPHA,"qwertyuiopasdfghjklzxcvbnm").
-define(TEXT,"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890\"\\\b\f\n\r\t").
-define(DIGIT,"123456789").
run(Set, Loop) ->
Json = lists:map(fun(_) -> gen_json(?JSON) end, lists:seq(1, Set)),
Term = lists:map(fun(_) -> gen_term(?JSON) end, lists:seq(1, Set)),
[
{
b_jsx_json(Json, Loop)%,
%b_mochi_json(Json, Loop)
},
{
b_jsx_term(Term, Loop)%,
%b_mochi_term(Term, Loop)
}
].
hot() ->
b_jsx_term([gen_term(?JSON)], 100).
b_jsx_json(Set, Loop) ->
{T, _} = timer:tc(
fun() ->
lists:foreach(
fun(_) ->
lists:map(fun(X) -> jsx:to_term(X) end, Set)
end,
lists:seq(1, Loop)
)
end,
[]
),
{jsx, to_term, T / 1000, T / (Loop * length(Set) * 1000)}.
b_jsx_term(Set, Loop) ->
erlang:garbage_collect(),
{T, _} = timer:tc(
fun() ->
lists:foreach(
fun(_) ->
%error_logger:info_report([{mem_jsx, erlang:memory(processes)}]),
lists:map(fun(X) -> jsx:to_json(X) end, Set)
end,
lists:seq(1, Loop)
)
end,
[]
),
{jsx, to_json, T / 1000, T / (Loop * length(Set) * 1000)}.
b_mochi_json(Set, Loop) ->
{T, _} = timer:tc(
fun() ->
lists:foreach(
fun(_) ->
lists:map(fun(X) -> mochijson2:decode(X) end, Set)
end,
lists:seq(1, Loop)
)
end,
[]
),
{mochi, to_term, T / 1000, T / (Loop * length(Set) * 1000)}.
b_mochi_term(Set, Loop) ->
erlang:garbage_collect(),
{T, _} = timer:tc(
fun() ->
lists:foreach(
fun(_) ->
%error_logger:info_report([{mem_mochi, erlang:memory(processes)}]),
lists:map(fun(X) -> mochijson2:encode({struct, X})end, Set)
end,
lists:seq(1, Loop)
)
end,
[]
),
{mochi, to_json, T / 1000, T / (Loop * length(Set) * 1000)}.
%%
%% generates a json object
gen_json(Len) ->
list_to_binary(
io_lib:format("{~s}", [
string:join(
lists:map(
fun(_) ->
case random:uniform(2) of
1 ->
io_lib:format("\"~s\":\"~s\"",
[rstring(?LEN_KEY, ?ALPHA), rstring(?LEN_STR, ?ALPHA)]
);
2 ->
io_lib:format("\"~s\":~s",
[rstring(?LEN_KEY, ?ALPHA), rstring(?LEN_INT, ?DIGIT)]
)
end
end,
lists:seq(1,Len)
),
","
)
])
).
gen_term(Len) ->
lists:map(
fun(_) ->
case random:uniform(2) of
1 -> {
list_to_binary(rstring(?LEN_KEY, ?ALPHA)),
list_to_binary(rstring(?LEN_STR, ?ALPHA))
};
2 -> {
list_to_binary(rstring(?LEN_KEY, ?ALPHA)),
list_to_integer(rstring(?LEN_INT, ?DIGIT))
}
end
end,
lists:seq(1,Len)
).
%%
%%
rstring(Length, Alphabet) ->
ustring(random:uniform(Length), Alphabet).
%%
%% from http://blog.teemu.im/2009/11/07/generating-random-strings-in-erlang/
ustring(Length, AllowedChars) ->
lists:foldl(
fun(_, Acc) ->
[lists:nth(
random:uniform(length(AllowedChars)),
AllowedChars
)] ++ Acc
end,
[],
lists:seq(1, Length)
).

View file

@ -29,6 +29,15 @@
-include("jsx_opts.hrl").
-define(ESC(C),
<<H:L/binary, C, T/binary>> ->
B = unicode:characters_to_binary(json_escape_sequence(C)),
json_escape2(
<<H/binary, B/binary, T/binary>>,
Opts, L + size(B), Len + size(B) - 1
);
).
%% parsing of jsx opts
@ -68,11 +77,56 @@ extract_parser_opts([K|Rest], Acc) ->
%% everything else should be a legal json string component
json_escape(String, Opts) when is_binary(String) ->
json_escape(String, Opts, <<>>).
%<< <<(case X of $.->$,; _->X end)>> || <<X>> <= String >>.
%json_escape(String, Opts, <<>>).
json_escape2(String, Opts, 0, size(String)).
json_escape2(Str, Opts, L, Len) when L < Len ->
case Str of
<<H:L/binary, $\", T/binary>> -> %"
json_escape2(<<H/binary, $\\, $\", T/binary>>, Opts, L + 2, Len + 1);%"
<<H:L/binary, $\\, T/binary>> ->
json_escape2(<<H/binary, $\\, $\\, T/binary>>, Opts, L + 2, Len + 1);
<<H:L/binary, $\b, T/binary>> ->
json_escape2(<<H/binary, $\\, $\b, T/binary>>, Opts, L + 2, Len + 1);
<<H:L/binary, $\f, T/binary>> ->
json_escape2(<<H/binary, $\\, $\f, T/binary>>, Opts, L + 2, Len + 1);
<<H:L/binary, $\n, T/binary>> ->
json_escape2(<<H/binary, $\\, $\n, T/binary>>, Opts, L + 2, Len + 1);
<<H:L/binary, $\r, T/binary>> ->
json_escape2(<<H/binary, $\\, $\r, T/binary>>, Opts, L + 2, Len + 1);
<<H:L/binary, $\t, T/binary>> ->
json_escape2(<<H/binary, $\\, $\t, T/binary>>, Opts, L + 2, Len + 1);
% jsonp
<<H:L/binary, 226, 128, 168, T/binary>> ->
B = unicode:characters_to_binary(json_escape_sequence(16#2028)),
json_escape2(
<<H/binary, B/binary, T/binary>>,
Opts, L + size(B), Len + size(B) - 1
);
<<H:L/binary, 226, 128, 169, T/binary>> ->
B = unicode:characters_to_binary(json_escape_sequence(16#2029)),
json_escape2(
<<H/binary, B/binary, T/binary>>,
Opts, L + size(B), Len + size(B) - 1
);
% C >= 0 and C < $\s
?ESC(00) ?ESC(01) ?ESC(02) ?ESC(03) ?ESC(04)
?ESC(05) ?ESC(06) ?ESC(07)
?ESC(11) ?ESC(14)
?ESC(15) ?ESC(16) ?ESC(17) ?ESC(18) ?ESC(19)
?ESC(20) ?ESC(21) ?ESC(22) ?ESC(23) ?ESC(24)
?ESC(25) ?ESC(26) ?ESC(27) ?ESC(28) ?ESC(29)
?ESC(30) ?ESC(31)
_ ->
json_escape2(Str, Opts, L + 1, Len)
end;
json_escape2(Str, _, L, Len) when L =:= Len ->
Str.
%% double quote
json_escape(<<$\", Rest/binary>>, Opts, Acc) ->
json_escape(Rest, Opts, <<Acc/binary, $\\, $\">>);
json_escape(<<$\", Rest/binary>>, Opts, Acc) -> %"
json_escape(Rest, Opts, <<Acc/binary, $\\, $\">>); %"
%% backslash \ reverse solidus
json_escape(<<$\\, Rest/binary>>, Opts, Acc) ->
json_escape(Rest, Opts, <<Acc/binary, $\\, $\\>>);