lib/test1.ex

defmodule Test1 do
#  import ExProf.Macro
  import Xpeg

  def time(what, f) do
    #Task.start(fn -> 
    {t1, _} = :erlang.statistics(:runtime)
    r = f.()
    {t2, _} = :erlang.statistics(:runtime)
    IO.puts("#{what} #{(t2-t1)/1000}")
    r
    #end)
  end

  def do_prof(lines, pid) do
    i = :erlang.process_info(pid, :current_stacktrace)
    #{_, {_, _, _, line}} = i
    line = i
    lines = Map.update(lines, line, 1, &(&1+1))
    receive do
      :stop -> 
        Enum.sort(lines, fn {_, a}, {_, b} -> a > b end)
        |> Enum.take(20)
        |> IO.inspect()
    after
      0 -> do_prof(lines, pid)
    end
  end

  def prof(f) do
    pid = self()
    {:ok, tracer_pid} = Task.start(fn -> do_prof(%{}, pid) end)
    f.()
    send(tracer_pid, :stop)
  end

  #"""
  def performance do
    p =
      Xpeg.peg Json, dump_code: false, trace: false, dump_ir: false, dump_graph: true do
        # White space
        S <- star({' ', '\t', '\r', '\n'})

        # Basic atoms
        True <- "true" * fn cs -> [true | cs] end
        False <- "false" * fn cs -> [false | cs] end
        Null <- "null" * fn cs -> [nil | cs] end

        # Parse strings - needs proper escaping for the capture
        Xdigit <- {'0'..'9', 'a'..'f', 'A'..'F'}
        Unicode_escape <- 'u' * Xdigit[4]
        Escape <- '\\' * ({'"', '\\', '/', 'b', 'f', 'n', 'r', 't'} | Unicode_escape)
        String_body <- star(Escape) * star(+({'\x20'..'\x7f'} - {'"'} - {'\\'}) * star(Escape))
        String <- '"' * str(String_body) * '"'

        # Numbers are converted to Elixir float
        Minus <- '-'
        Int_part <- '0' | {'1'..'9'} * star({'0'..'9'})
        Fract_part <- "." * +{'0'..'9'}
        Exp_part <- {'e', 'E'} * opt({'+', '-'}) * +{'0'..'9'}

        Number <- float(opt(Minus) * Int_part * opt(Fract_part) * opt(Exp_part)) 

        # Objects are represented by an Elixir map
        Obj_pair <-
          S * String * S * ":" * Value *
            fn [v, k, obj | cs] -> [Map.put(obj, k, v) | cs] end

        Object <- '{' * fn cs -> [%{} | cs] end * (Obj_pair * star("," * Obj_pair) | S) * "}"

        # Arrays are represented by an Elixir list
        Array_elem <- Value * fn [v, a | cs] -> [[v | a] | cs] end

        Array <- "[" * fn cs -> [[] | cs] end * (Array_elem * star("," * Array_elem) | S) * "]" *
            fn [a | cs] -> [Enum.reverse(a) | cs] end

        # All possible JSON values
        Value <- S * (Number | String | Object | Array | True | False | Null) * S

        # The toplevel json document is a value with no other trailing characters
        Json <- Value * !1
      end
      
    #Module.create(Koe, p, Macro.Env.location(__ENV__))

    s = File.read!("/tmp/json-32M.bzip2.out")
    s2 = to_charlist(s)

    Poison.decode!(s)
    Poison.decode!(s)
    
    time("poison", fn ->
      Poison.decode!(s)
    end)
    
    time("jason", fn ->
      Jason.decode!(s)
    end)

    time("xpeg", fn ->
      #prof("xpeg", fn ->
      Xpeg.match(p, s2)
      #end)
    end)

    :nop


    #nil

  end

  #"""

  def run() do
    p =
      peg Line, trace: true, dump_ir: true do
         Space <- ' '
         Line <- Word * star(Space * Word)
         Word <- +{'a'..'z'}
      end

    Xpeg.match(p, "one two")

  end

end