<commit_before>defmodule Benchfella do
  @bench_tab __MODULE__
  @results_tab :"#{__MODULE__}:results"
  @bench_sec 1

  defmacro __using__(_) do
    quote do
      import unquote(__MODULE__), only: :macros
    end
  end

  def start(opts \\ []) do
    cli_opts = Process.get(:"benchfella cli options")
    opts = Keyword.merge(opts, cli_opts)

    :ets.new(@bench_tab, [:public, :named_table, :set])

    {collect_mem_stats, sys_mem_stats} =
      case Keyword.fetch(opts, :mem_stats) do
        {:ok, :include_sys} -> {true, true}
        {:ok, true}         -> {true, false}
        {:ok, false}        -> {false, false}
        :error              -> {false, false}
      end

    format = case Keyword.fetch(opts, :format) do
      {:ok, f} when f in [:default, :machine] -> f
      :error -> :default
    end

    verbose = case Keyword.fetch(opts, :verbose) do
      {:ok, flag} when flag in [false, true] -> flag
      :error -> format == :default
    end

    output = case Keyword.fetch(opts, :output) do
      {:ok, path} when is_binary(path) -> path
      :error -> :default
    end

    System.at_exit(fn _ ->
      run(Keyword.get(opts, :duration, @bench_sec) |> sec2musec,
                    verbose, format, output, collect_mem_stats, sys_mem_stats)
    end)
  end

  defp sec2musec(sec), do: trunc(sec * 1_000_000)
  defp musec2sec(musec), do: Float.round(musec/1_000_000, 2)

  def run(bench_time, verbose, format, output, mem_stats, sys_mem_stats) do
    cond do
      format == :machine ->
        IO.puts "duration:#{musec2sec(bench_time)};"
                 <> "mem stats:#{mem_stats};"
                 <> "sys mem stats:#{sys_mem_stats}"
      verbose ->
        IO.puts "Settings:"
        IO.puts "  duration:      #{musec2sec(bench_time)} s"
        IO.puts "  mem stats:     #{mem_stats}"
        IO.puts "  sys mem stats: #{sys_mem_stats}"
        IO.puts ""

      true -> nil
    end

    :ets.new(@results_tab, [:named_table, :set])
    bench_count = :ets.info(@bench_tab, :size)
    bench_config = {bench_time, mem_stats}
    {total_time, _, _} =
      :ets.foldl(&run_bench(&1, &2, verbose, bench_config), {0, 1, bench_count}, @bench_tab)
    {results, max_len} = :ets.foldl(&collect_results/2, {[], 0}, @results_tab)

    if verbose do
      sec = Float.round(total_time / 1_000_000, 2)
      IO.puts :stderr, "Finished in #{sec} seconds"
      IO.puts :stderr, ""
    end

    #:io.format('~*.s ~10s   time~n', [-max_len, "benchmark", "iterations"])
    #IO.puts ""
    print_results(results, max_len, format, mem_stats, sys_mem_stats)
  end

  defp print_results(results, max_len, format, collect_mem_stats, sys_mem_stats) do
    results
    |> Enum.sort(fn {_, n1, elapsed1, _}, {_, n2, elapsed2, _} ->
      elapsed1/n1 < elapsed2/n2<commit_msg>Tweak formatting<commit_after>defmodule Benchfella do
  @bench_tab __MODULE__
  @results_tab :"#{__MODULE__}:results"
  @bench_sec 1

  defmacro __using__(_) do
    quote do
      import unquote(__MODULE__), only: :macros
    end
  end

  def start(opts \\ []) do
    cli_opts = Process.get(:"benchfella cli options")
    opts = Keyword.merge(opts, cli_opts)

    :ets.new(@bench_tab, [:public, :named_table, :set])

    {collect_mem_stats, sys_mem_stats} =
      case Keyword.fetch(opts, :mem_stats) do
        {:ok, :include_sys} -> {true, true}
        {:ok, true}         -> {true, false}
        {:ok, false}        -> {false, false}
        :error              -> {false, false}
      end

    format = case Keyword.fetch(opts, :format) do
      {:ok, f} when f in [:default, :machine] -> f
      :error -> :default
    end

    verbose = case Keyword.fetch(opts, :verbose) do
      {:ok, flag} when flag in [false, true] -> flag
      :error -> format == :default
    end

    # output = case Keyword.fetch(opts, :output) do
    #   {:ok, path} when is_binary(path) -> path
    #   :error -> :default
    # end

    System.at_exit(fn _ ->
      run(Keyword.get(opts, :duration, @bench_sec) |> sec2musec,
                    verbose, format, collect_mem_stats, sys_mem_stats)
    end)
  end

  defp sec2musec(sec), do: trunc(sec * 1_000_000)
  defp musec2sec(musec), do: Float.round(musec/1_000_000, 2)

  def run(bench_time, verbose, format, mem_stats, sys_mem_stats) do
    if format == :machine do
      IO.puts "duration:#{musec2sec(bench_time)};"
               <> "mem stats:#{mem_stats};"
               <> "sys mem stats:#{sys_mem_stats}"
    end

    if verbose do
      IO.puts :stderr, "Settings:"
      IO.puts :stderr, "  duration:      #{musec2sec(bench_time)} s"
      IO.puts :stderr, "  mem stats:     #{mem_stats}"
      IO.puts :stderr, "  sys mem stats: #{sys_mem_stats}"
      IO.puts :stderr, ""
    end

    :ets.new(@results_tab, [:named_table, :set])
    bench_count = :ets.info(@bench_tab, :size)
    bench_config = {bench_time, mem_stats}
    {total_time, _, _} =
      :ets.foldl(&run_bench(&1, &2, verbose, bench_config), {0, 1, bench_count}, @bench_tab)
    {results, max_len} = :ets.foldl(&collect_results/2, {[], 0}, @results_tab)

    if verbose do
      sec = Float.round(total_time / 1_000_000, 2)
      IO.puts :stderr, "Finished in #{sec} seconds"
      IO.puts :stderr, ""
    end

    #:io.format('~*.s ~10s   time~n', [-max_len, "benchmark", "iterations"])
    #IO.puts ""
    print_results(results, max_len, format, mem_stats, sys_mem_stats)
  end

  defp print_results(results, max_len, format, collect_mem_stats, sys_mem_stats) do
    results
    |> Enum.sort(fn {_, n1, elapsed1, _}, {_, n2, elapsed2, _} ->
      elapsed1/n1 < elapsed2/n2
{'fraction_non_alphanumeric': 0.14675278076785073, 'fraction_numerical': 0.016146393972012917, 'mean_word_length': 2.696949602122016, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4465967', 'n_tokens_mistral': 2117, 'n_tokens_neox': 2005, 'n_words': 464}