Current section
Files
Jump to
Current section
Files
lib/benchee/benchmark/function_call_overhead.ex
defmodule Benchee.Benchmark.FunctionCallOverhead do
@moduledoc false
alias Benchee.Benchmark.Collect.Time
alias Benchee.Conversion
@overhead_determination_time Conversion.Duration.convert_value({0.01, :second}, :nanosecond)
# Compute the function call overhead on the current system
#
# You might wonder why this isn't done simply through using our existing infrastructure
# and just run it with Scenario, Context etc. - in fact that's how it used to be,
# but it meant that we'd pass half-baked scenarios to functions causing dialyzer to complain,
# as well as running for a lot more code than we strictly need to like the
# `determine_n_times` code that we should rather not go through as it changes
# what this function does.
# This also gives us a way to make sure we definitely take at least one measurement.
@spec measure() :: non_neg_integer()
def measure do
# just the fastest function one can think of...
overhead_function = fn -> nil end
_ = warmup(overhead_function)
run_times = run(overhead_function)
Statistex.minimum(run_times)
end
defp warmup(function) do
run_for(function, @overhead_determination_time / 2)
end
defp run(function) do
run_for(function, @overhead_determination_time)
end
defp run_for(function, run_time) do
end_time = current_time() + run_time
do_run(function, [], end_time)
end
@spec do_run((() -> any), [number], number) :: [number, ...]
defp do_run(function, durations, end_time) do
{duration, _} = Time.collect(function)
if current_time() < end_time do
do_run(function, [duration | durations], end_time)
else
durations
end
end
defp current_time, do: :erlang.system_time(:nano_seconds)
end