Maxximiliann

Maxximiliann

defmodule Benchmark do

	def main do
		module_function = Foo.main
		_ = module_function
	end

	def run(params) do
		number_of_trials = Enum.at(params, 0)
		total_warm_up_cycles = Enum.at(params, 1)

		IO.puts("Warming up . . . initiating first trial of #{number_of_trials}.")

		start_time = System.monotonic_time(:millisecond)

		main = main()
		_ = main

		end_time = System.monotonic_time(:millisecond)
		elapsed_time = (end_time - start_time) / 1000

		results = %{time: [elapsed_time], acc: 1}  

		run(results, number_of_trials, totaL_warm_up_cycles)
	end


	def run(results, number_of_trials, total_warm_up_cycles) do
		start_time = System.monotonic_time(:millisecond)

		main = main()
		_ = main

		end_time = System.monotonic_time(:millisecond)
		new_time = (end_time - start_time) / 1000 
		updated_acc = results.acc + 1

		average_time = 
		cond do 
			results.acc == total_warm_up_cycles -> new_time
			results.acc > total_warm_up_cycles -> Enum.sum(results.time) / (updated_acc - (total_warm_up_cycles + 1))
			results.acc < total_warm_up_cycles -> []
		end

		results = 
		if results.acc >= total_warm_up_cycles do
			Enum.map(results, fn _map ->
				%{
					time: List.insert_at(results.time, 0, new_time),
					acc: updated_acc,
					average_time: average_time
				}
			end)
			|> List.first
		else
			Enum.map(results, fn _map ->
				%{
					time: [],
					acc: updated_acc,
					average_time: 0
				}
			end)
			|> List.first
		end

		cond do 
			results.acc < (total_warm_up_cycles + 1) -> IO.puts("Warming up . . . Trial number #{results.acc} of #{number_of_trials}.")	
			run(module_function, results, number_of_trials, total_warm_up_cycles)

			results.acc == (total_warm_up_cycles + 1) -> IO.puts("Average execution time after #{results.acc} trials of #{number_of_trials}: #{Float.floor(results.average_time, 3)} seconds.")
			run(module_function, results, number_of_trials, total_warm_up_cycles)

			results.acc < number_of_trials -> IO.puts("Average execution time after #{results.acc} trials of #{number_of_trials}: #{Float.floor(results.average_time, 3)} seconds.")
			run(module_function, results, number_of_trials, total_warm_up_cycles)

			results.acc == number_of_trials -> IO.puts("Final trial - Average execution time: #{Float.floor(results.average_time, 3)} seconds.")
		end
	end		
	
end

This is designed to accept the following command:
iex(1)> Benchmark.run([20, 5])

Which would then output:

Warming up . . . initiating first trial of 20.
Warming up . . . Trial number 2 of 20.
Warming up . . . Trial number 3 of 20.
Warming up . . . Trial number 4 of 20.
Warming up . . . Trial number 5 of 20.
Average execution time after 6 trials of 20: 0.754 seconds.
Average execution time after 7 trials of 20: 0.754 seconds.
Average execution time after 8 trials of 20: 0.549 seconds.
Average execution time after 9 trials of 20: 0.48 seconds.
Average execution time after 10 trials of 20: 0.448 seconds.
Average execution time after 11 trials of 20: 0.496 seconds.
Average execution time after 12 trials of 20: 0.471 seconds.
Average execution time after 13 trials of 20: 0.499 seconds.
Average execution time after 14 trials of 20: 0.485 seconds.
Average execution time after 15 trials of 20: 0.47 seconds.
Average execution time after 16 trials of 20: 0.457 seconds.
Average execution time after 17 trials of 20: 0.447 seconds.
Average execution time after 18 trials of 20: 0.438 seconds.
Average execution time after 19 trials of 20: 0.431 seconds.
Final trial - Average execution time: 0.427 seconds.
:ok

When attempting to compile this module, however, it triggers the following error:

== Compilation error in file lib/Benchmark.ex ==
** (CompileError) lib/Benchmark.ex:24: undefined function totaL_warm_up_cycles/0

It looks like total_warm_up_cycles = Enum.at(params, 1) is being ignored? If so, why and how is this resolved?

Ideally I’d love to get this to run with something like iex(2)> Benchmark.run([MODULE.FUNCTION, 20, 5]) which would make this more dynamic since the particular module function to be benchmarked wouldn’t have to be hardcoded. After spending dozens of hours searching far and wide, though, I can’t find any resources that cover how exactly this is done. Is this even possible?

Thanks for all your help and opinions! :slight_smile:

Marked As Solved

Nicd

Nicd

totaL_warm_up_cycles has a big L, it’s a typo.

Also Liked

NobbZ

NobbZ

There is an uppercase L in the usage of the variable, but not in it’s definition

kokolegorille

kokolegorille

You put a capital L in the second totaL_warm_up_cycles.

Nicd

Nicd

As for this part, have you tried for example Benchmark.run(&Module.function/n, 20, 5) (substituting module, function, and n for the respective module, function, and arity)? Then you could call the function with function.(args) (note the period).

EDIT: For more information about function capturing, see: https://elixir-lang.org/getting-started/modules-and-functions.html#function-capturing

Last Post!

Maxximiliann

Maxximiliann OP

Got it, thanks so much! :slight_smile:

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews