diff --git a/bench/decode.exs b/bench/decode.exs index 553e1cb..ffe3783 100644 --- a/bench/decode.exs +++ b/bench/decode.exs @@ -1,13 +1,16 @@ -decode_jobs = %{ - "Jason" => fn {json, _} -> Jason.decode!(json) end, - "Poison" => fn {json, _} -> Poison.decode!(json) end, - "JSX" => fn {json, _} -> JSX.decode!(json, [:strict]) end, - "Tiny" => fn {json, _} -> Tiny.decode!(json) end, - "jsone" => fn {json, _} -> :jsone.decode(json) end, - "jiffy" => fn {json, _} -> :jiffy.decode(json, [:return_maps, :use_nil]) end, - "JSON" => fn {json, _} -> JSON.decode!(json) end, - # "binary_to_term/1" => fn {_, etf} -> :erlang.binary_to_term(etf) end, -} +decode_jobs = + %{ + "Jason" => &Jason.decode!/1, + "Poison" => &Poison.decode!/1, + "JSX" => &JSX.decode!(&1, [:strict]), + "Tiny" => &Tiny.decode!/1, + "jsone" => &:jsone.decode/1, + "jiffy" => &:jiffy.decode(&1, [:return_maps, :use_nil]), + "Jsonrs" => &Jsonrs.decode!/1 + # "binary_to_term/1" => fn {_, etf} -> :erlang.binary_to_term(etf) end, + } + |> Bench.Helpers.put_job_if_loaded(:json, &:json.decode/1) + |> Bench.Helpers.put_job_if_loaded(Elixir.JSON, &Elixir.JSON.decode!/1) decode_inputs = [ "GitHub", @@ -19,41 +22,22 @@ decode_inputs = [ "JSON Generator (Pretty)", "UTF-8 escaped", "UTF-8 unescaped", - "Issue 90", + "Issue 90" ] -read_data = fn (name) -> - file = - name - |> String.downcase - |> String.replace(~r/([^\w]|-|_)+/, "-") - |> String.trim("-") - - json = File.read!(Path.expand("data/#{file}.json", __DIR__)) - etf = :erlang.term_to_binary(Jason.decode!(json)) - - {json, etf} -end - -inputs = for name <- decode_inputs, into: %{}, do: {name, read_data.(name)} - -IO.puts("Checking jobs don't crash") -for {name, input} <- inputs, {job, decode_job} <- decode_jobs do - IO.puts("Testing #{job} #{name}") - decode_job.(input) -end -IO.puts("\n") +inputs = for name <- decode_inputs, into: %{}, do: {name, Bench.Helpers.read_data!(name)} Benchee.run(decode_jobs, -# parallel: 4, + # parallel: 4, warmup: 5, time: 30, memory_time: 1, + pre_check: true, inputs: inputs, save: %{path: "output/runs/#{DateTime.utc_now()}.benchee"}, load: "output/runs/*.benchee", formatters: [ {Benchee.Formatters.HTML, file: Path.expand("output/decode.html", __DIR__)}, - Benchee.Formatters.Console, + Benchee.Formatters.Console ] ) diff --git a/bench/encode.exs b/bench/encode.exs index dfaefd3..fe444a3 100644 --- a/bench/encode.exs +++ b/bench/encode.exs @@ -1,15 +1,19 @@ -encode_jobs = %{ - "Jason" => &Jason.encode_to_iodata!(&1, escape: :elixir_json), - "Jason native" => &Jason.encode_to_iodata!(&1, escape: :native_json), - # "Jason strict" => &Jason.encode_to_iodata!(&1, maps: :strict, escape: :elixir_json), - "Poison" => &Poison.encode!/1, - # "JSX" => &JSX.encode!/1, - # "Tiny" => &Tiny.encode!/1, - # "jsone" => &:jsone.encode/1, - "jiffy" => &:jiffy.encode/1, - # "JSON" => &JSON.encode!/1, - # "term_to_binary" => &:erlang.term_to_binary/1, -} +encode_jobs = + %{ + "Jason" => &Jason.encode_to_iodata!(&1, escape: :elixir_json), + "Jason native" => &Jason.encode_to_iodata!(&1, escape: :native_json), + # "Jason strict" => &Jason.encode_to_iodata!(&1, maps: :strict, escape: :elixir_json), + "Poison" => &Poison.encode!/1, + # "JSX" => &JSX.encode!/1, + # "Tiny" => &Tiny.encode!/1, + # "jsone" => &:jsone.encode/1, + "jiffy" => &:jiffy.encode/1, + "Jsonrs" => &Jsonrs.encode_to_iodata!/1, + "Jsonrs (lean)" => &Jsonrs.encode_to_iodata!(&1, lean: true) + # "term_to_binary" => &:erlang.term_to_binary/1, + } + |> Bench.Helpers.put_job_if_loaded(:json, &:json.encode/1) + |> Bench.Helpers.put_job_if_loaded(Elixir.JSON, &Elixir.JSON.encode!/1) encode_inputs = [ "GitHub", @@ -20,32 +24,23 @@ encode_inputs = [ "JSON Generator", "UTF-8 unescaped", "Issue 90", - "Canada", + "Canada" ] -read_data = fn (name) -> - name - |> String.downcase - |> String.replace(~r/([^\w]|-|_)+/, "-") - |> String.trim("-") - |> (&"data/#{&1}.json").() - |> Path.expand(__DIR__) - |> File.read! -end - - Benchee.run(encode_jobs, -# parallel: 4, + # parallel: 4, warmup: 2, time: 15, memory_time: 0.01, reduction_time: 0.01, - inputs: for name <- encode_inputs, into: %{} do - name - |> read_data.() - |> Jason.decode!() - |> (&{name, &1}).() - end, + pre_check: true, + inputs: + for name <- encode_inputs, into: %{} do + name + |> Bench.Helpers.read_data!() + |> Jason.decode!() + |> (&{name, &1}).() + end, formatters: [ {Benchee.Formatters.HTML, file: Path.expand("output/encode.html", __DIR__)}, Benchee.Formatters.Console diff --git a/bench/lib/helpers.ex b/bench/lib/helpers.ex new file mode 100644 index 0000000..69bf2e7 --- /dev/null +++ b/bench/lib/helpers.ex @@ -0,0 +1,19 @@ +defmodule Bench.Helpers do + def put_job_if_loaded(jobs, mod, fun) do + if Code.ensure_loaded?(mod) do + Map.put(jobs, Atom.to_string(mod), fun) + else + jobs + end + end + + def read_data!(name) do + name + |> String.downcase() + |> String.replace(~r/([^\w]|-|_)+/, "-") + |> String.trim("-") + |> (&"data/#{&1}.json").() + |> Path.expand(Path.dirname(Mix.Project.project_file())) + |> File.read!() + end +end diff --git a/bench/mix.exs b/bench/mix.exs index d4927da..3e32eb6 100644 --- a/bench/mix.exs +++ b/bench/mix.exs @@ -6,6 +6,7 @@ defmodule JasonBench.MixProject do app: :jason_bench, version: "0.1.0", elixir: "~> 1.6", + elixirc_path: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps(), aliases: aliases() @@ -31,7 +32,9 @@ defmodule JasonBench.MixProject do {:tiny, "~> 1.0"}, {:jsone, "~> 1.4"}, {:jiffy, "~> 1.0"}, - {:json, "~> 1.0"}, + {:jsonrs, "~> 0.3"} ] end + + defp elixirc_paths(_), do: ["lib"] end diff --git a/bench/mix.lock b/bench/mix.lock index 57213a2..96dd031 100644 --- a/bench/mix.lock +++ b/bench/mix.lock @@ -2,15 +2,17 @@ "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, "benchee_html": {:hex, :benchee_html, "1.0.0", "5b4d24effebd060f466fb460ec06576e7b34a00fc26b234fe4f12c4f05c95947", [:mix], [{:benchee, ">= 0.99.0 and < 2.0.0", [hex: :benchee, repo: "hexpm", optional: false]}, {:benchee_json, "~> 1.0", [hex: :benchee_json, repo: "hexpm", optional: false]}], "hexpm", "5280af9aac432ff5ca4216d03e8a93f32209510e925b60e7f27c33796f69e699"}, "benchee_json": {:hex, :benchee_json, "1.0.0", "cc661f4454d5995c08fe10dd1f2f72f229c8f0fb1c96f6b327a8c8fc96a91fe5", [:mix], [{:benchee, ">= 0.99.0 and < 2.0.0", [hex: :benchee, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "da05d813f9123505f870344d68fb7c86a4f0f9074df7d7b7e2bb011a63ec231c"}, + "castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, "jason_native": {:hex, :jason_native, "0.1.0", "03003746213ba6da181ad9e488461969aaa6b212a48e9a57ce74ada4c71cbc1f", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "6dd4c067da7d9296425604968536f91927dbb3fa538131cdef19ad2a3a0d1ee1"}, "jiffy": {:hex, :jiffy, "1.1.1", "aca10f47aa91697bf24ab9582c74e00e8e95474c7ef9f76d4f1a338d0f5de21b", [:rebar3], [], "hexpm", "62e1f0581c3c19c33a725c781dfa88410d8bff1bbafc3885a2552286b4785c4c"}, - "json": {:hex, :json, "1.4.1", "8648f04a9439765ad449bc56a3ff7d8b11dd44ff08ffcdefc4329f7c93843dfa", [:mix], [], "hexpm", "9abf218dbe4ea4fcb875e087d5f904ef263d012ee5ed21d46e9dbca63f053d16"}, "jsone": {:hex, :jsone, "1.7.0", "1e3bd7d5dd44bb2eb0797dddea1cbf2ddab8d9f29e499a467ca171c23f5984ea", [:rebar3], [], "hexpm", "a3a33712ee6bc8be10cfa21c7c425a299de4c5a8533f9f931e577a6d0e8f5dbd"}, + "jsonrs": {:hex, :jsonrs, "0.3.3", "f610dc571807687de9c2924442b2f7e69accdca261fee0cf66538d8fc61c65ab", [:mix], [{:rustler, "~> 0.30.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.7.0", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "eb3294294c337e8a369c82a102b6e8c2346b1cb264e6b7c662d962effcb14576"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"}, "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, + "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.3", "42cb9449785cd86c87453e39afdd27a0bdfa5c77a4ec5dc5ce45112e06b9f89b", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "cbc4b3777682e5f6f43ed39b0e0b4a42dccde8053aba91b4514e8f5ff9a5ac6d"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "tiny": {:hex, :tiny, "1.0.1", "535ea7e600cb1c6ba17b53029266d9d7ec54ce29bfb05d906c433907acfa01ca", [:mix], [], "hexpm", "1278a457deb8d99135c378b71f66f21e283d8adea426252a3f8f5e003c536a7b"}, }