From da88071cdd37a3b11cc4b6e8670d978c5b509574 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Wed, 21 Mar 2012 05:49:19 -0700 Subject: [PATCH 1/2] remove older emulator versions from travis ci --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7265c2..25a09e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,4 @@ language: erlang script: rebar compile && rebar skip_deps=true eunit otp_release: - - R15B - - R14B02 - - R14B03 - - R14B04 \ No newline at end of file + - R15B \ No newline at end of file From 5d12d6262f8523884e38fdc613012b9b803d7621 Mon Sep 17 00:00:00 2001 From: Dmitry Kolesnikov Date: Thu, 22 Mar 2012 21:13:20 +0200 Subject: [PATCH 2/2] FIX: to_json performance + jsx benchmark --- Makefile | 14 ++++ priv/b/jsx_b.beam | Bin 0 -> 1512 bytes priv/b/jsx_b.erl | 175 ++++++++++++++++++++++++++++++++++++++++++++++ src/jsx_utils.erl | 60 +++++++++++++++- 4 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 Makefile create mode 100644 priv/b/jsx_b.beam create mode 100644 priv/b/jsx_b.erl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e719fcc --- /dev/null +++ b/Makefile @@ -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 diff --git a/priv/b/jsx_b.beam b/priv/b/jsx_b.beam new file mode 100644 index 0000000000000000000000000000000000000000..cf970ddf11069b74cff639046039032606694ce5 GIT binary patch literal 1512 zcmY*ZO>7%Q6rS;}cXtvy8SmOj4jeWOhqj4hCrzpXmkCvxgoZYP_Rvz~pLp%8v)*;Q z>yQHysZdc`2`OBV7IEmcTnHDCIJM;x3X~q`2@VnBfH+0r|A54M&L)_ZKD}?g`QDrN zc1L^R@+%XB#P?pDoq2gC@EU}WF9AdGy1!8<({kLg{lJ%eYfWmDnp(|r3w7Uf6+dX% zZcVOxwyW4)!LiFq)oV3Mfm(G+L14LR>(HXKN^Zq#sBPCqgW5in<5kb8IK2(8(srzZ z?N&X-YB?ph)?c%NLYJJ%Mj5%uY_;uX^I65Q+*+_AxxtE_J!&X75$*P7%f}oBIqy|0 zLg?Q>IRKv!FaThbhdidA;M7cTE+n}|gft>#L!=}zB8R4Gf?x<)3Qf)AoaV!POfPdP zB0J=C*~PJai<59kHMy80Mp#r$lbd{2iWy>#OJP$r^Wmn(1))pfc1(Y0(qe*}!jQwe zDqn)*y(@GnB$s%T z?i@;--p5fos<}y@gnM92=jmP_bhH0vJik4HGYcaf?jLrs#d)Z4)x6tjUY2xj(EU(L zLEa#z8t>yo3`?P=gFTxxq!*;5F(`(UsZ>&@T1w2BhF~Tb4B51Bg1NjQ)}l2R_(G&v z8G4!%Af`1l4^{R5(lSSBQ0Ei@3kv_sTLN+5FwcNKUXrMm4o&E92r6X+OG^rz0w4O- zpmhZTS!gsdZUK4$xFrK(5syb)g{VcGLF|b*`Z13Jl7PO5qmFkAqYf|t=sDt8A9*Iy z(TDdhHoMX3=Ol2{QUJ_LL>$8L*{H`Zv|a3f5rF<70P0w`^T^uAKLZ&AppHFZB$1v5 zih0;K_C!%%v;(ZU3E1BFaJg74A{vjY#qa3kxy{7;zkL4Vb@O|+`|0S| zXFF5mgNMCSw~X;vdQa)u8GV`=z4kQo#ZM1za7voP&pM0V^3iMx^wK?B_dMM*^n(xQ zz;A``3_0c^aBg`f2wD(NzU`p05~~nt-FG_+my>5c*?sG;`FEdt@6J05NNw~bNzZ}v2L||SgjIiYWy53a$q;C6{Spw`a?-74U~AvD5Y>m@x69y z*;*xMa#wvw%dL8j<-7K3u41iQPR`m0td?7Ha`2nYHCy(2u8g!$9*4hR9h#Ua`vC;9 zXuI(LA_95zm=N*)5O#u%uv6@LmStmXl$~Z**j09omDzRn8hf4HVB;*u&a!DX$tL~< DIn^iu literal 0 HcmV?d00001 diff --git a/priv/b/jsx_b.erl b/priv/b/jsx_b.erl new file mode 100644 index 0000000..15865ab --- /dev/null +++ b/priv/b/jsx_b.erl @@ -0,0 +1,175 @@ +%% The MIT License + +%% Copyright (c) 2012 Dmitry Kolesnikov + +%% 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) + ). \ No newline at end of file diff --git a/src/jsx_utils.erl b/src/jsx_utils.erl index 814092c..37a3fcd 100644 --- a/src/jsx_utils.erl +++ b/src/jsx_utils.erl @@ -29,6 +29,15 @@ -include("jsx_opts.hrl"). +-define(ESC(C), + <> -> + B = unicode:characters_to_binary(json_escape_sequence(C)), + json_escape2( + <>, + 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)>> || <> <= String >>. + %json_escape(String, Opts, <<>>). + json_escape2(String, Opts, 0, size(String)). + +json_escape2(Str, Opts, L, Len) when L < Len -> + case Str of + <> -> %" + json_escape2(<>, Opts, L + 2, Len + 1);%" + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + <> -> + json_escape2(<>, Opts, L + 2, Len + 1); + % jsonp + <> -> + B = unicode:characters_to_binary(json_escape_sequence(16#2028)), + json_escape2( + <>, + Opts, L + size(B), Len + size(B) - 1 + ); + <> -> + B = unicode:characters_to_binary(json_escape_sequence(16#2029)), + json_escape2( + <>, + 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, <>); +json_escape(<<$\", Rest/binary>>, Opts, Acc) -> %" + json_escape(Rest, Opts, <>); %" %% backslash \ reverse solidus json_escape(<<$\\, Rest/binary>>, Opts, Acc) -> json_escape(Rest, Opts, <>);