From e02fd12d3da5c02cf6e0495350d13088285c10e5 Mon Sep 17 00:00:00 2001 From: Tobias Pfeiffer Date: Fri, 11 May 2018 14:58:35 +0200 Subject: [PATCH] Test Repetition code even on platforms that don't trigger it/unit --- lib/benchee/benchmark/repeated_measurement.ex | 7 +- lib/benchee/benchmark/runner.ex | 8 +- .../benchmark/repeated_measurement_test.exs | 115 ++++++++++++++++++ 3 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 test/benchee/benchmark/repeated_measurement_test.exs diff --git a/lib/benchee/benchmark/repeated_measurement.ex b/lib/benchee/benchmark/repeated_measurement.ex index 94fd7912..750d700e 100644 --- a/lib/benchee/benchmark/repeated_measurement.ex +++ b/lib/benchee/benchmark/repeated_measurement.ex @@ -31,9 +31,10 @@ defmodule Benchee.Benchmark.RepeatedMeasurement do num_iterations: num_iterations, printer: printer }, - fast_warning + fast_warning, + measurer \\ Measure.NativeTime ) do - run_time = measure_iteration(scenario, scenario_context, Measure.NativeTime) + run_time = measure_iteration(scenario, scenario_context, measurer) if run_time >= @minimum_execution_time do {num_iterations, adjust_for_iterations(run_time, num_iterations)} @@ -45,7 +46,7 @@ defmodule Benchee.Benchmark.RepeatedMeasurement do | num_iterations: num_iterations * @times_multiplier } - determine_n_times(scenario, new_context, false) + determine_n_times(scenario, new_context, false, measurer) end end diff --git a/lib/benchee/benchmark/runner.ex b/lib/benchee/benchmark/runner.ex index 42474851..397a6ec4 100644 --- a/lib/benchee/benchmark/runner.ex +++ b/lib/benchee/benchmark/runner.ex @@ -1,8 +1,8 @@ defmodule Benchee.Benchmark.Runner do - @moduledoc """ - This module actually runs our benchmark scenarios, adding information about - run time and memory usage to each scenario. - """ + @moduledoc false + + # This module actually runs our benchmark scenarios, adding information about + # run time and memory usage to each scenario. alias Benchee.Benchmark alias Benchee.Benchmark.{Scenario, ScenarioContext, Measure, Hooks, RepeatedMeasurement} diff --git a/test/benchee/benchmark/repeated_measurement_test.exs b/test/benchee/benchmark/repeated_measurement_test.exs new file mode 100644 index 00000000..ded93497 --- /dev/null +++ b/test/benchee/benchmark/repeated_measurement_test.exs @@ -0,0 +1,115 @@ +defmodule Bencheee.Benchmark.RepeatedMeasurementTest.FakeMeasurer do + @behaviour Benchee.Benchmark.Measure + + def measure(function) do + value = function.() + time = Process.get(:test_measurement_time, 5) + next_value = time * 10 + + Process.put(:test_measurement_time, next_value) + + {time, value} + end +end + +defmodule Bencheee.Benchmark.RepeatedMeasurementTest do + use ExUnit.Case + + import Benchee.Benchmark.RepeatedMeasurement + alias Benchee.Benchmark.{Scenario, ScenarioContext} + alias Benchee.Test.FakeBenchmarkPrinter + alias Bencheee.Benchmark.RepeatedMeasurementTest.FakeMeasurer + + @no_input Benchee.Benchmark.no_input() + @scenario_context %ScenarioContext{ + num_iterations: 1, + printer: FakeBenchmarkPrinter, + config: %Benchee.Configuration{}, + scenario_input: @no_input + } + + describe ".determine_n_times/4" do + test "it repeats the function calls until a suitable time is reached" do + function = fn -> send(self(), :called) end + scenario = %Scenario{function: function} + {num_iterations, time} = determine_n_times(scenario, @scenario_context, false, FakeMeasurer) + + assert num_iterations == 10 + assert time == 5 # 50 adjusted by the 10 iteration factor + + assert_received_exactly_n_times(:called, 11) # 1 initial + 10 more after repeat + end + + test "doesn't do repetitions if the time is small enough from the get go" do + function = fn -> send(self(), :called) end + scenario = %Scenario{function: function} + Process.put(:test_measurement_time, 10) + + {num_iterations, time} = determine_n_times(scenario, @scenario_context, false, FakeMeasurer) + + assert num_iterations == 1 + assert time == 10 + + assert_received_exactly_n_times(:called, 1) # 1 initial + 10 more after repeat + end + end + + describe ".measure" do + test "scales reported times approproately" do + scenario_context = %ScenarioContext{ + @scenario_context + | num_iterations: 10, + } + scenario = %Scenario{ + input: @no_input, + function: fn -> 42 end + } + Process.put(:test_measurement_time, 50) + + time = measure(scenario, scenario_context, FakeMeasurer) + + assert time == 5 + end + + test "calls hooks appropriately even with multiple iterations" do + num_iterations = 10 + scenario_context = %ScenarioContext{ + @scenario_context + | num_iterations: num_iterations, + config: %Benchee.Configuration{ + before_each: fn _ -> + send self(), :global_before + @no_input + end, + after_each: fn _ -> send self(), :global_after end + } + } + scenario = %Scenario{ + input: @no_input, + function: fn -> send(self(), :called) end, + before_each: fn _ -> + send self(), :local_before + @no_input + end, + after_each: fn _ -> send self(), :local_after end + } + Process.put(:test_measurement_time, 50) + + time = measure(scenario, scenario_context, FakeMeasurer) + + assert time == 5 + + expected_messages = [:global_before, :local_before, :called, :local_after, :global_after] + + Enum.each(expected_messages, fn message -> + assert_received_exactly_n_times(message, num_iterations) + end) + end + end + + defp assert_received_exactly_n_times(message, count) do + Enum.each(1..count, fn _ -> assert_received ^message end) + + refute_received ^message + end +end