-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Project benchmarks #312
Project benchmarks #312
Changes from all commits
56f7f67
003ee51
94979ee
3143ca7
238b978
b38d7cf
349f7d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ doc | |
docs | ||
/test/tmp | ||
save.benchee | ||
/.elixir_ls/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
defmodule Clickhouse.Benchmark.Performance do | ||
use Benchee.Benchmark | ||
|
||
# Since it's a module, any other constructs may be used, | ||
# such as defs, defmacro, etc. | ||
def map_fun(i) do | ||
[i] | ||
end | ||
|
||
# Global benchmark setup. Optional. | ||
# | ||
# Called before any benchmark in the module. | ||
# | ||
# If defined, must return {:ok, state} for benchmarks to run | ||
before_all do | ||
{:ok, nil} | ||
end | ||
|
||
# Global benchmark teardown. Optional. | ||
# | ||
# Called after all benchmarks have finished | ||
# (and their possible local teardowns had been called). | ||
# | ||
# Can return anything. | ||
after_all do | ||
:anything | ||
end | ||
|
||
# Benchmarks. Module may have many of them. | ||
benchmark "Flattening list from map", # Name. Mandatory. | ||
warmup: 0, time: 1 # Opts (see Benchee.run). Optional. | ||
jrogov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
do # Do block. Mandatory. | ||
|
||
# Benchmark setup. Optional | ||
# | ||
# If global setup is defined, | ||
# implicit variable "state" is bound to it's result | ||
# | ||
# If defined, must return {:ok, state} for benchmarks to run | ||
before_benchmark do | ||
{:ok, fn x -> [x] end} | ||
end | ||
|
||
# Benchmark teardown. Optional | ||
# | ||
# Implicit variable: state, as it is returned from local setup | ||
# (or from global setup, if no local setup is defined) | ||
# | ||
# Can return anything | ||
after_benchmark do | ||
:anything | ||
end | ||
|
||
# Inputs: the same as passing inputs via :input option | ||
# | ||
# Accepts either an expression or a do block as a 2nd argument | ||
input "Small", Enum.to_list(1..100) | ||
input "Medium" do | ||
n = 10_000 | ||
Enum.to_list(1..n) | ||
end | ||
input "Bigger", Enum.to_list(1..100_000) | ||
jrogov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
# Benchmark scenarios | ||
# | ||
# Each scenario has an implicit variables: | ||
# - state: state returned from local or global setup | ||
# And if any input is passed (either with option or as input directive): | ||
# - input: data for benchmark | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I like the idea of implicit variables. I'd like it to be more explicit. How about doing it like Not sure what to do about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I was gritting my teeth when wrote this part. Although I somewhat despise magic forced implicits and implicit variables, I must admit that with implicits benchmark code looks cleaner. Nonetheless, if you can give me examples of parameters/variables that we might be adding in the future, I will happily change implicits to map. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the map I just meant how you can reuse what setup returned in the tests: https://hexdocs.pm/ex_unit/ExUnit.Callbacks.html#setup_all/1-examples Note sure what we'd need the examples for, overall, this would give people the possibility to put in there whatever data they need. Not sure if that's the best. In "normal" benchee it's solved through just giving the function an argument where those values can be accomulated was the solution. Not certain one could do to give |
||
scenario "Enum.flat_map", # Name. Mandatory | ||
before_scenario: | ||
fn i -> # Scenario options, e.g. local hooks. Optional. | ||
IO.inspect(length(i), label: "Input length"); | ||
i | ||
end | ||
do # Do block. Mandatory | ||
map_fun = state | ||
Enum.flat_map(input, map_fun) | ||
end | ||
|
||
scenario "Enum.map |> List.flatten" do | ||
map_fun = state | ||
input |> Enum.map(map_fun) |> List.flatten() | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need
{:ok, state}
? I know ExUnit does it, but why can't we just returnstate
? If something goes wrong it can justraise
or what am I missing?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's rather a matter of convention.
raise
means some serious runtime error that should have never happened if the code were write.Surely, we can, just
throw
things, but it will be more implicit I think: if you just look on the result type of the setup, you already know what it should return to work correctly. To tell programmers to just throw their error would be less obvious IMO than that.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just never quite understood it. In what scenario will my setup not work? Usually the code I call will already raise at some point. It might just be me, I've never seen
setup
implementation that returns anything but{:ok, state}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the code that returns ok/error pair usually should never throw (although might raise), at least with any other reason then MatchError, but that's on the caller side, so not function's problem, but programmer that's calling it :)
Surely it might be easier to write happy-path-code all the way, just a matter of taste I guess.
Share your final thoughts on this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with it for ExUnits sake 🤷♂️