SlideShare ist ein Scribd-Unternehmen logo
1 von 139
Downloaden Sie, um offline zu lesen
The other day
array = (1..1_000).to_a
array.sort do |item, other|
other <=> item
end
Reverse Sort
$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
$ time ruby scripts/sort.rb
real 0m0.151s
user 0m0.052s
sys 0m0.016s
$ asdf local ruby jruby-9.1.8.0
$ ruby -v
jruby 9.1.8.0 (2.3.1) 2017-03-06 90fc7ab OpenJDK 64-Bit
Server VM 25.121-b13 on 1.8.0_121-8u121-b13-
0ubuntu1.16.04.2-b13 +jit [linux-x86_64]
$ time ruby scripts/sort.rb
real 0m3.468s
user 0m8.384s
sys 0m0.232s
CRuby vs JRuby
Success!
The End?
● Way too few samples
● Realistic data/multiple inputs?
● No warmup
● Non production environment
● Does creating the array matter?
● Is reverse sorting really the bottle neck?
● Setup information
● Running on battery
● Lots of applications running
Numerous Failures!
What’s important for you?
Startup
What’s important for you?
Startup Warmup
What’s important for you?
Startup Warmup Runtime
What’s important for you?
MJIT
Awesome?
Disclaimer
Focus
Truffle: 33.58 seconds
vs
MJIT: 9.34 seconds
time ruby pent.rb
Truffle: 33.58 seconds
vs
MJIT: 9.34 seconds
MJIT 3.5+ times faster!
Startup
Startup
Truffle: 3.68 seconds
vs
MJIT: 0.00 seconds
time ruby empty.rb
Startup Warmup
Warmup
Benchmark.avg do |benchmark|
benchmark.config time: 60, warmup: 95
benchmark.report "pent" do
mkpieces
mkboard
$p[4] = [$p[4][0]]
$pnum = (0...$p.length).to_a
setpiece([],0)
end
end
Proper Benchmark
28s → 2s
Warmup
Startup Warmup Runtime
Runtime
Truffle 3.7+ times faster!
We just went from Truffle is
3.5 times slower all the way
to Truffle is 3.7 times faster
RUN
YOUR
OWN
BENCHMARKS
Stop Guessing and Start
Measuring
Benchmarking in Practice
Tobias Pfeiffer
@PragTob
pragtob.info
Concept vs Tool Usage
A Poly-journey
Benchmarking vs. Profiling
Profiling
Application Performance Monitoring
● (Ruby versions mentioned when used)
● OpenJDK 8
● GraalVM 25
● MJIT master as of July 6th (last commit mid of June)
● Elixir 1.3.4
● Erlang 19.1
● i5-7200U – 2 x 2.5GHz (Up to 3.10GHz)
● 8GB RAM
● Linux Mint 18.1 - 64 bit (Ubuntu 16.04 base)
● Linux Kernel 4.8.0
● Firefox 54.0
System Specification
What to benchmark?
● Runtime?
● Memory?
● Throughput?
● Custom?
What to measure?
Amount of socket connection
What to measure?
● Runtime!
● Memory?
● Throughput?
● Custom?
Did we make it faster?
“Isn’t that the root of all evil?”
“More likely, not reading the sources is the
source of all evil”
Me, just now
“We should forget about small efficiencies, say
about 97% of the time: premature optimization
is the root of all evil.”
Donald Knuth, 1974
(Computing Surveys, Vol 6, No 4, December 1974)
“Yet we should not pass up our opportunities in
that critical 3%”
Donald Knuth, 1974
(Computing Surveys, Vol 6, No 4, December 1974)
The very next sentence
“(...) a 12 % improvement, easily obtained, is
never considered marginal.”
Donald Knuth, 1974
(Computing Surveys, Vol 6, No 4, December 1974)
Prior Paragraph
Go-Bots
Neighbours?
Neighbours?
Neighbours?
Neighbours?
getColor = function(x, y, board) {
if (isOutOfBounds(x, y, board)) {
return NEUTRAL;
} else {
return board[y][x];
}
};
isOutOfBounds = function(x, y, board) {
var board_size = board.length;
if ((x < 0) || (y < 0) ||
(x >= board_size) || (y >= board_size)) {
return true;
} else {
return false;
}
};
Checks...
getColor = function(x, y, board) {
if (isOutOfBounds(x, y, board)) {
return NEUTRAL;
} else {
return board[y][x];
}
};
isOutOfBounds = function(x, y, board) {
var board_size = board.length;
if ((x < 0) || (y < 0) ||
(x >= board_size) || (y >= board_size)) {
return true;
} else {
return false;
}
};
Checks...
getColor = function(x, y, board) {
if (isOutOfBounds(x, y, board)) {
return NEUTRAL;
} else {
return board[y][x];
}
};
isOutOfBounds = function(x, y, board) {
var board_size = board.length;
if ((x < 0) || (y < 0) ||
(x >= board_size) || (y >= board_size)) {
return true;
} else {
return false;
}
};
Checks...
getColor = function(x, y, board) {
if (isOutOfBounds(x, y, board)) {
return NEUTRAL;
} else {
return board[y][x];
}
};
isOutOfBounds = function(x, y, board) {
var board_size = board.length;
if ((x < 0) || (y < 0) ||
(x >= board_size) || (y >= board_size)) {
return true;
} else {
return false;
}
};
Checks...
What if...
Layer
Neutral
Checks
Checks
getColor = function(x, y, board) {
return board[y + 1][x + 1];
};
BEST CODE EVER!
Benchmark.js
var board = initBoard(3);
var suite = new Benchmark.Suite;
suite.add('getColor', function() {
getColor(1, 2, board);
}).on('cycle', function(event) {
// log result
}).on('complete', function() {
// done
}).run({
async: true
});
Benchmark function
var board = initBoard(3);
var suite = new Benchmark.Suite;
suite.add('getColor', function() {
getColor(1, 2, board);
}).on('cycle', function(event) {
// log result
}).on('complete', function() {
// done
}).run({
async: true
});
getColor x 278,959,094 ops/sec ±0.39%
(98 runs sampled)
getColor x 1,816,254,291 ops/sec ±0.17%
(94 runs sampled)
Run it!
New
Old
getColor x ~279 Million ops/sec ±0.39%
(98 runs sampled)
getColor x ~1 816 Million ops/sec ±0.17%
(94 runs sampled)
Run it!
New
Old
getColor x ~279 Million ops/sec ±0.39%
(98 runs sampled)
getColor x ~1 816 Million ops/sec ±0.17%
(94 runs sampled)
Over 6 times faster!!!
New
Old
Success!
Does it even matter?
var suite = new Benchmark.Suite;
suite.add('playing a random 9x9 game', function() {
playoutForBoard(initBoard(9));
}).add('playing a random 13x13 game', function() {
playoutForBoard(initBoard(13));
}).add('playing a random 19x19 game', function() {
playoutForBoard(initBoard(19));
}).on('cycle', function(event) {
// log result here
}).on('complete', function() {
// done
}).run({
async: true
});
A bigger benchmark
var suite = new Benchmark.Suite;
suite.add('playing a random 9x9 game', function() {
playoutForBoard(initBoard(9));
}).add('playing a random 13x13 game', function() {
playoutForBoard(initBoard(13));
}).add('playing a random 19x19 game', function() {
playoutForBoard(initBoard(19));
}).on('cycle', function(event) {
// log result here
}).on('complete', function() {
// done
}).run({
async: true
});
A bigger benchmark
9x9 game x 252 ops/sec ±2.44%
13x13 game x 80.50 ops/sec ±4.14%
19x19 game x 25.19 ops/sec ±6.33%
9x9 game x 199 ops/sec ±18.09%
13x13 game x 67.11 ops/sec ±3.24%
19x19 game x 20.97 ops/sec ±7.56%
Run it!
New
Old
9x9 game x 252 ops/sec ±2.44%
13x13 game x 80.50 ops/sec ±4.14%
19x19 game x 25.19 ops/sec ±6.33%
9x9 game x 199 ops/sec ±18.09%
13x13 game x 67.11 ops/sec ±3.24%
19x19 game x 20.97 ops/sec ±7.56%
New
Old
~20% slower?!?!
9x9 game x 252 ops/sec ±2.44%
13x13 game x 80.50 ops/sec ±4.14%
19x19 game x 25.19 ops/sec ±6.33%
9x9 game x 199 ops/sec ±18.09%
13x13 game x 67.11 ops/sec ±3.24%
19x19 game x 20.97 ops/sec ±7.56%
New
Old
Initializing & Copying Boards
What are you measuring?
Does it matter?
Types of benchmarks
Feature
Integration
Unit
Testing Pyramid
Application
Macro
Micro
Benchmarking Pyramid
Benchmark.ips do |benchmark|
game_19 = playout_for(19).game_state.game
scorer = Rubykon::GameScorer.new
benchmark.report '19x19 scoring' do
scorer.score game_19
end
end
micro: scoring
Benchmark.ips do |benchmark|
benchmark.report '19x19 playout' do
game = Rubykon::Game.new(19)
game_state = Rubykon::GameState.new(game)
mcts = MCTS::Playout.new(game_state)
mcts.playout
end
end
macro: playout
Benchmark.avg do |benchmark|
game_19 = Rubykon::Game.new(19)
game_state_19 = Rubykon::GameState.new game_19
mcts = MCTS::MCTS.new
benchmark.config warmup: 180, time: 180
benchmark.report "19x19 1_000 iterations" do
mcts.start game_state_19, 1_000
end
end
Application: tree search
Micro Macro Application
Micro Macro
Components involved
Application
Micro Macro
Setup Complexity
Components involved
Application
Micro Macro
Setup Complexity
Execution Time
Components involved
Application
Micro Macro
Setup Complexity
Execution Time
Confidence of Real Impact
Components involved
Application
Micro Macro
Setup Complexity
Execution Time
Confidence of Real Impact
Components involved
Chance of Interference
Application
Micro Macro
Setup Complexity
Execution Time
Confidence of Real Impact
Components involved
Chance of Interference
Golden Middle
Application
Benchmark.avg do |benchmark|
game_19 = Rubykon::Game.new(19)
game_state_19 = Rubykon::GameState.new game_19
mcts = MCTS::MCTS.new
benchmark.config warmup: 180, time: 180
benchmark.report "19x19 1_000 iterations" do
mcts.start game_state_19, 1_000
end
end
Application: tree search
Great ruby rumble
Speedup relative to 2.0
A little help...
Story Time
Boom
Boom
Elixir.DBConnection.ConnectionError
Benchee.run %{
"Using LatestCourierLocation" => fn(courier_id) ->
LatestCourierLocation
|> CourierLocation.with_courier_ids(courier_id)
|> Repo.one
end,
"with_courier_ids + order" => fn(courier_id) ->
CourierLocation.with_courier_ids(courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end,
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}
A real case
Benchee.run %{
"Using LatestCourierLocation" => fn(courier_id) ->
LatestCourierLocation
|> CourierLocation.with_courier_ids(courier_id)
|> Repo.one
end,
"with_courier_ids + order" => fn(courier_id) ->
CourierLocation.with_courier_ids(courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end,
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}
Database View
Benchee.run %{
"Using LatestCourierLocation" => fn(courier_id) ->
LatestCourierLocation
|> CourierLocation.with_courier_ids(courier_id)
|> Repo.one
end,
"with_courier_ids + order" => fn(courier_id) ->
CourierLocation.with_courier_ids(courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end,
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}
Only difference
Name ips average deviation median
with_courier_ids + order 1.19 K 841.44 μs ±67.64% 675.00 μs
full custom 1.16 K 862.36 μs ±56.06% 737.00 μs
Using LatestCourierLocation 0.00603 K 165897.47 μs ±2.33% 165570.00 μs
Comparison:
with_courier_ids + order 1.19 K
full custom 1.16 K - 1.02x slower
Using LatestCourierLocation 0.00603 K - 197.16x slower
Another job well done?
Boom
Boom
Elixir.DBConnection.ConnectionError
Boom
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Boom
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
Elixir.DBConnection.ConnectionError
inputs = %{
"Big 2.3 Million locations" => 3799,
"No locations" => 8901,
"~200k locations" => 4238,
"~20k locations" => 4201
}
Benchee.run %{
...
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}, inputs: inputs, time: 25, warmup: 5
Inputs to the rescue!
inputs = %{
"Big 2.3 Million locations" => 3799,
"No locations" => 8901,
"~200k locations" => 4238,
"~20k locations" => 4201
}
Benchee.run %{
...
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}, inputs: inputs, time: 25, warmup: 5
Inputs to the rescue!
inputs = %{
"Big 2.3 Million locations" => 3799,
"No locations" => 8901,
"~200k locations" => 4238,
"~20k locations" => 4201
}
Benchee.run %{
...
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}, inputs: inputs, time: 25, warmup: 5
Inputs to the rescue!
inputs = %{
"Big 2.3 Million locations" => 3799,
"No locations" => 8901,
"~200k locations" => 4238,
"~20k locations" => 4201
}
Benchee.run %{
...
"full custom" => fn(courier_id) ->
CourierLocation
|> Ecto.Query.where(courier_id: ^courier_id)
|> Ecto.Query.order_by(desc: :time)
|> Ecto.Query.limit(1)
|> Repo.one
end
}, inputs: inputs, time: 25, warmup: 5
Inputs to the rescue!
##### With input Big 2.3 Million locations #####
Comparison:
with_courier_ids + order 1.19 K
full custom 1.16 K - 1.02x slower
Using LatestCourierLocation 0.00603 K - 197.16x slower
##### With input ~200k locations #####
Comparison:
Using LatestCourierLocation 3.66
full custom 0.133 - 27.57x slower
with_courier_ids + order 0.132 - 27.63x slower
##### With input ~20k locations #####
Comparison:
Using LatestCourierLocation 38.12
full custom 0.122 - 312.44x slower
with_courier_ids + order 0.122 - 313.33x slower
##### With input No locations #####
Comparison:
Using LatestCourierLocation 2967.48
full custom 0.114 - 25970.57x slower
with_courier_ids + order 0.114 - 26046.06x slower
Old
##### With input Big 2.3 Million locations #####
Comparison:
with_courier_ids + order 1.19 K
full custom 1.16 K - 1.02x slower
Using LatestCourierLocation 0.00603 K - 197.16x slower
##### With input ~200k locations #####
Comparison:
Using LatestCourierLocation 3.66
full custom 0.133 - 27.57x slower
with_courier_ids + order 0.132 - 27.63x slower
##### With input ~20k locations #####
Comparison:
Using LatestCourierLocation 38.12
full custom 0.122 - 312.44x slower
with_courier_ids + order 0.122 - 313.33x slower
##### With input No locations #####
Comparison:
Using LatestCourierLocation 2967.48
full custom 0.114 - 25970.57x slower
with_courier_ids + order 0.114 - 26046.06x slower
Old
##### With input Big 2.3 Million locations #####
Comparison:
with_courier_ids + order 1.19 K
full custom 1.16 K - 1.02x slower
Using LatestCourierLocation 0.00603 K - 197.16x slower
##### With input ~200k locations #####
Comparison:
Using LatestCourierLocation 3.66
full custom 0.133 - 27.57x slower
with_courier_ids + order 0.132 - 27.63x slower
##### With input ~20k locations #####
Comparison:
Using LatestCourierLocation 38.12
full custom 0.122 - 312.44x slower
with_courier_ids + order 0.122 - 313.33x slower
##### With input No locations #####
Comparison:
Using LatestCourierLocation 2967.48
full custom 0.114 - 25970.57x slower
with_courier_ids + order 0.114 - 26046.06x slower
Old
Combined Indexes
##### With input Big 2.3 Million locations #####
Comparison:
full custom 3921.12
with_courier_ids + order 23.05 - 170.09x slower
Using LatestCourierLocation 5.98 - 655.74x slower
##### With input ~200k locations #####
Comparison:
full custom 4272.84
with_courier_ids + order 14.20 - 300.91x slower
Using LatestCourierLocation 3.80 - 1125.59x slower
##### With input ~20k locations #####
Comparison:
full custom 3792.97
with_courier_ids + order 78.93 - 48.06x slower
Using LatestCourierLocation 35.62 - 106.47x slower
##### With input No locations #####
Comparison:
full custom 5.14 K
with_courier_ids + order 3.87 K - 1.33x slower
Using LatestCourierLocation 3.29 K - 1.56x slower
Combined Index
##### With input Big 2.3 Million locations #####
Comparison:
full custom 3921.12
with_courier_ids + order 23.05 - 170.09x slower
Using LatestCourierLocation 5.98 - 655.74x slower
##### With input ~200k locations #####
Comparison:
full custom 4272.84
with_courier_ids + order 14.20 - 300.91x slower
Using LatestCourierLocation 3.80 - 1125.59x slower
##### With input ~20k locations #####
Comparison:
full custom 3792.97
with_courier_ids + order 78.93 - 48.06x slower
Using LatestCourierLocation 35.62 - 106.47x slower
##### With input No locations #####
Comparison:
full custom 5.14 K
with_courier_ids + order 3.87 K - 1.33x slower
Using LatestCourierLocation 3.29 K - 1.56x slower
Combined Index
# with an index on courier_id and one on time
Name ips average deviation median
Updating a location 366.90 2.73 ms ±36.35% 2.29 ms
# with a combined index on courier_id and time
Name ips average deviation median
Updating a location 283.41 3.53 ms ±52.18% 2.77 ms
Insertion Time
Inputs matter!
Interference free Environment
Correct & Meaningful Setup
RAILS_ENV=performance
[info] GET /
[debug] Processing by Rumbl.PageController.index/2
Parameters: %{}
Pipelines: [:browser]
[info] Sent 200 in 46ms
[info] GET /sessions/new
[debug] Processing by Rumbl.SessionController.new/2
Parameters: %{}
Pipelines: [:browser]
[info] Sent 200 in 5ms
[info] GET /users/new
[debug] Processing by Rumbl.UserController.new/2
Parameters: %{}
Pipelines: [:browser]
[info] Sent 200 in 7ms
[info] POST /users
[debug] Processing by Rumbl.UserController.create/2
Parameters: %{"_csrf_token" =>
"NUEUdRMNAiBfIHEeNwZkfA05PgAOJgAAf0ACXJqCjl7YojW+trdjdg==", "_utf8" => " ", "user" =>✓
%{"name" => "asdasd", "password" => "[FILTERED]", "username" => "Homer"}}
Pipelines: [:browser]
[debug] QUERY OK db=0.1ms
begin []
[debug] QUERY OK db=0.9ms
INSERT INTO "users" ("name","password_hash","username","inserted_at","updated_at") VALUES
($1,$2,$3,$4,$5) RETURNING "id" ["asdasd",
"$2b$12$.qY/kpo0Dec7vMK1ClJoC.Lw77c3oGllX7uieZILMlFh2hFpJ3F.C", "Homer", {{2016, 12,
2}, {14, 10, 28, 0}}, {{2016, 12, 2}, {14, 10, 28, 0}}]
Logging & Friends
Tail Call Optimization
defmodule MyMap do
def map_tco(list, function) do
Enum.reverse do_map_tco([], list, function)
end
defp do_map_tco(acc, [], _function) do
acc
end
defp do_map_tco(acc, [head | tail], func) do
do_map_tco([func.(head) | acc], tail, func)
end
def map_body([], _func), do: []
def map_body([head | tail], func) do
[func.(head) | map_body(tail, func)]
end
end
TCO
defmodule MyMap do
def map_tco(list, function) do
Enum.reverse do_map_tco([], list, function)
end
defp do_map_tco(acc, [], _function) do
acc
end
defp do_map_tco(acc, [head | tail], func) do
do_map_tco([func.(head) | acc], tail, func)
end
def map_body([], _func), do: []
def map_body([head | tail], func) do
[func.(head) | map_body(tail, func)]
end
end
TCO
defmodule MyMap do
def map_tco(list, function) do
Enum.reverse do_map_tco([], list, function)
end
defp do_map_tco(acc, [], _function) do
acc
end
defp do_map_tco(acc, [head | tail], func) do
do_map_tco([func.(head) | acc], tail, func)
end
def map_body([], _func), do: []
def map_body([head | tail], func) do
[func.(head) | map_body(tail, func)]
end
end
TCO
map_fun = fn(i) -> i + 1 end
inputs = %{
"Small (10 Thousand)" => Enum.to_list(1..10_000),
"Middle (100 Thousand)" => Enum.to_list(1..100_000),
"Big (1 Million)" => Enum.to_list(1..1_000_000),
"Bigger (5 Million)" => Enum.to_list(1..5_000_000)
}
Benchee.run %{
"tail-recursive" =>
fn(list) -> MyMap.map_tco(list, map_fun) end,
"stdlib map" =>
fn(list) -> Enum.map(list, map_fun) end,
"body-recursive" =>
fn(list) -> MyMap.map_body(list, map_fun) end
}, inputs: inputs
TCO
map_fun = fn(i) -> i + 1 end
inputs = %{
"Small (10 Thousand)" => Enum.to_list(1..10_000),
"Middle (100 Thousand)" => Enum.to_list(1..100_000),
"Big (1 Million)" => Enum.to_list(1..1_000_000),
"Bigger (5 Million)" => Enum.to_list(1..5_000_000)
}
Benchee.run %{
"tail-recursive" =>
fn(list) -> MyMap.map_tco(list, map_fun) end,
"stdlib map" =>
fn(list) -> Enum.map(list, map_fun) end,
"body-recursive" =>
fn(list) -> MyMap.map_body(list, map_fun) end
}, inputs: inputs
TCO
map_fun = fn(i) -> i + 1 end
inputs = %{
"Small (10 Thousand)" => Enum.to_list(1..10_000),
"Middle (100 Thousand)" => Enum.to_list(1..100_000),
"Big (1 Million)" => Enum.to_list(1..1_000_000),
"Bigger (5 Million)" => Enum.to_list(1..5_000_000)
}
Benchee.run %{
"tail-recursive" =>
fn(list) -> MyMap.map_tco(list, map_fun) end,
"stdlib map" =>
fn(list) -> Enum.map(list, map_fun) end,
"body-recursive" =>
fn(list) -> MyMap.map_body(list, map_fun) end
}, inputs: inputs
TCO
##### With input Small (10 Thousand) #####
Comparison:
body-recursive 5.12 K
stdlib map 5.07 K - 1.01x slower
tail-recursive 4.38 K - 1.17x slower
##### With input Middle (100 Thousand) #####
Comparison:
body-recursive 491.16
stdlib map 488.45 - 1.01x slower
tail-recursive 399.08 - 1.23x slower
##### With input Big (1 Million) #####
Comparison:
tail-recursive 35.36
body-recursive 25.69 - 1.38x slower
stdlib map 24.85 - 1.42x slower
##### With input Bigger (5 Million) #####
Comparison:
tail-recursive 6.93
body-recursive 4.92 - 1.41x slower
stdlib map 4.87 - 1.42x slower
TCO
##### With input Small (10 Thousand) #####
Comparison:
body-recursive 5.12 K
stdlib map 5.07 K - 1.01x slower
tail-recursive 4.38 K - 1.17x slower
##### With input Middle (100 Thousand) #####
Comparison:
body-recursive 491.16
stdlib map 488.45 - 1.01x slower
tail-recursive 399.08 - 1.23x slower
##### With input Big (1 Million) #####
Comparison:
tail-recursive 35.36
body-recursive 25.69 - 1.38x slower
stdlib map 24.85 - 1.42x slower
##### With input Bigger (5 Million) #####
Comparison:
tail-recursive 6.93
body-recursive 4.92 - 1.41x slower
stdlib map 4.87 - 1.42x slower
TCO
TCO
What even is a benchmark?
config
|> Benchee.init
|> Benchee.system
|> Benchee.benchmark("job", fn -> magic end)
|> Benchee.measure
|> Benchee.statistics
|> Benchee.Formatters.Console.output
|> Benchee.Formatters.HTML.output
A transformation of inputs
Enjoy Benchmarking! ❤
Tobias Pfeiffer
@PragTob
pragtob.info
github.com/evanphx/benchmark-ips
github.com/PragTob/benchee
benchmarkjs.com/

Weitere ähnliche Inhalte

Was ist angesagt?

Building a turn-based game prototype using ECS - Unite Copenhagen 2019
Building a turn-based game prototype using ECS - Unite Copenhagen 2019Building a turn-based game prototype using ECS - Unite Copenhagen 2019
Building a turn-based game prototype using ECS - Unite Copenhagen 2019Unity Technologies
 
Basically Redux - Android Listeners
Basically Redux - Android ListenersBasically Redux - Android Listeners
Basically Redux - Android ListenersCody Engel
 
The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180Mahmoud Samir Fayed
 
Cross-scene references: A shock to the system - Unite Copenhagen 2019
Cross-scene references: A shock to the system - Unite Copenhagen 2019Cross-scene references: A shock to the system - Unite Copenhagen 2019
Cross-scene references: A shock to the system - Unite Copenhagen 2019Unity Technologies
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsBaruch Sadogursky
 
Psycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python ScriptPsycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python ScriptSurvey Department
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Ben Lesh
 
Kubernetes Tutorial
Kubernetes TutorialKubernetes Tutorial
Kubernetes TutorialCi Jie Li
 
1eu introduction
1eu introduction1eu introduction
1eu introductionJames Wang
 
Zabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensZabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensNETWAYS
 
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak   CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak PROIDEA
 
Programming with Python and PostgreSQL
Programming with Python and PostgreSQLProgramming with Python and PostgreSQL
Programming with Python and PostgreSQLPeter Eisentraut
 
Understanding Autovacuum
Understanding AutovacuumUnderstanding Autovacuum
Understanding AutovacuumDan Robinson
 
[Ultracode Munich #4] Demo on Animatron by Anton Kotenko
[Ultracode Munich #4] Demo on Animatron by Anton Kotenko[Ultracode Munich #4] Demo on Animatron by Anton Kotenko
[Ultracode Munich #4] Demo on Animatron by Anton KotenkoBeMyApp
 
Make Sure Your Applications Crash
Make Sure Your  Applications CrashMake Sure Your  Applications Crash
Make Sure Your Applications CrashMoshe Zadka
 
The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189Mahmoud Samir Fayed
 

Was ist angesagt? (20)

Building a turn-based game prototype using ECS - Unite Copenhagen 2019
Building a turn-based game prototype using ECS - Unite Copenhagen 2019Building a turn-based game prototype using ECS - Unite Copenhagen 2019
Building a turn-based game prototype using ECS - Unite Copenhagen 2019
 
Ruby 1.9
Ruby 1.9Ruby 1.9
Ruby 1.9
 
Basically Redux - Android Listeners
Basically Redux - Android ListenersBasically Redux - Android Listeners
Basically Redux - Android Listeners
 
The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180
 
Cross-scene references: A shock to the system - Unite Copenhagen 2019
Cross-scene references: A shock to the system - Unite Copenhagen 2019Cross-scene references: A shock to the system - Unite Copenhagen 2019
Cross-scene references: A shock to the system - Unite Copenhagen 2019
 
Five
FiveFive
Five
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 Seasons
 
Corona sdk
Corona sdkCorona sdk
Corona sdk
 
Psycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python ScriptPsycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python Script
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
Kubernetes Tutorial
Kubernetes TutorialKubernetes Tutorial
Kubernetes Tutorial
 
1eu introduction
1eu introduction1eu introduction
1eu introduction
 
Zabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensZabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet Mens
 
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak   CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
 
Programming with Python and PostgreSQL
Programming with Python and PostgreSQLProgramming with Python and PostgreSQL
Programming with Python and PostgreSQL
 
Understanding Autovacuum
Understanding AutovacuumUnderstanding Autovacuum
Understanding Autovacuum
 
Text adventure
Text adventureText adventure
Text adventure
 
[Ultracode Munich #4] Demo on Animatron by Anton Kotenko
[Ultracode Munich #4] Demo on Animatron by Anton Kotenko[Ultracode Munich #4] Demo on Animatron by Anton Kotenko
[Ultracode Munich #4] Demo on Animatron by Anton Kotenko
 
Make Sure Your Applications Crash
Make Sure Your  Applications CrashMake Sure Your  Applications Crash
Make Sure Your Applications Crash
 
The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189
 

Ähnlich wie Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)

Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJSstefanmayer13
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Dirkjan Bussink
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsMike Hagedorn
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot CampTroy Miles
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
Let’s talk about microbenchmarking
Let’s talk about microbenchmarkingLet’s talk about microbenchmarking
Let’s talk about microbenchmarkingAndrey Akinshin
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptVisual Engineering
 
Performance is a Feature! at DDD 11
Performance is a Feature! at DDD 11Performance is a Feature! at DDD 11
Performance is a Feature! at DDD 11Matt Warren
 
Functional Reactive Programming in JavaScript
Functional Reactive Programming in JavaScriptFunctional Reactive Programming in JavaScript
Functional Reactive Programming in JavaScriptzupzup.org
 
Yevhen Tatarynov "From POC to High-Performance .NET applications"
Yevhen Tatarynov "From POC to High-Performance .NET applications"Yevhen Tatarynov "From POC to High-Performance .NET applications"
Yevhen Tatarynov "From POC to High-Performance .NET applications"LogeekNightUkraine
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJSKyung Yeol Kim
 
Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowBusiness Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowRomain Dorgueil
 
The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31Mahmoud Samir Fayed
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisFastly
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fpAlexander Granin
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseAlex Derkach
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: ServersidenessWebExpo
 

Ähnlich wie Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version) (20)

Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot Camp
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Let’s talk about microbenchmarking
Let’s talk about microbenchmarkingLet’s talk about microbenchmarking
Let’s talk about microbenchmarking
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
Performance tests - it's a trap
Performance tests - it's a trapPerformance tests - it's a trap
Performance tests - it's a trap
 
Performance is a Feature!
Performance is a Feature!Performance is a Feature!
Performance is a Feature!
 
Performance is a Feature! at DDD 11
Performance is a Feature! at DDD 11Performance is a Feature! at DDD 11
Performance is a Feature! at DDD 11
 
Functional Reactive Programming in JavaScript
Functional Reactive Programming in JavaScriptFunctional Reactive Programming in JavaScript
Functional Reactive Programming in JavaScript
 
Yevhen Tatarynov "From POC to High-Performance .NET applications"
Yevhen Tatarynov "From POC to High-Performance .NET applications"Yevhen Tatarynov "From POC to High-Performance .NET applications"
Yevhen Tatarynov "From POC to High-Performance .NET applications"
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowBusiness Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
 
The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: Serversideness
 

Mehr von Tobias Pfeiffer

Metaphors are everywhere: Ideas to Improve Software Development
 Metaphors are everywhere: Ideas to Improve Software Development  Metaphors are everywhere: Ideas to Improve Software Development
Metaphors are everywhere: Ideas to Improve Software Development Tobias Pfeiffer
 
Elixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitElixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitTobias Pfeiffer
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among HumansTobias Pfeiffer
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among HumansTobias Pfeiffer
 
Do You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItDo You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItTobias Pfeiffer
 
Elixir, your Monolith and You
Elixir, your Monolith and YouElixir, your Monolith and You
Elixir, your Monolith and YouTobias Pfeiffer
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Tobias Pfeiffer
 
It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)Tobias Pfeiffer
 
Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Tobias Pfeiffer
 
Introducing Elixir the easy way
Introducing Elixir the easy wayIntroducing Elixir the easy way
Introducing Elixir the easy wayTobias Pfeiffer
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitTobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?Tobias Pfeiffer
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitTobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?Tobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...Tobias Pfeiffer
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missTobias Pfeiffer
 

Mehr von Tobias Pfeiffer (20)

Going Staff
Going StaffGoing Staff
Going Staff
 
Stories in Open SOurce
Stories in Open SOurceStories in Open SOurce
Stories in Open SOurce
 
Metaphors are everywhere: Ideas to Improve Software Development
 Metaphors are everywhere: Ideas to Improve Software Development  Metaphors are everywhere: Ideas to Improve Software Development
Metaphors are everywhere: Ideas to Improve Software Development
 
Stories in Open Source
Stories in Open SourceStories in Open Source
Stories in Open Source
 
Elixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitElixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and Explicit
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among Humans
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among Humans
 
Do You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItDo You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About It
 
Elixir, your Monolith and You
Elixir, your Monolith and YouElixir, your Monolith and You
Elixir, your Monolith and You
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
 
Where do Rubyists go?
 Where do Rubyists go?  Where do Rubyists go?
Where do Rubyists go?
 
It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)
 
Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?
 
Introducing Elixir the easy way
Introducing Elixir the easy wayIntroducing Elixir the easy way
Introducing Elixir the easy way
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
 
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might miss
 

Kürzlich hochgeladen

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 

Kürzlich hochgeladen (20)

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 

Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)

  • 2. array = (1..1_000).to_a array.sort do |item, other| other <=> item end Reverse Sort
  • 3. $ ruby -v ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux] $ time ruby scripts/sort.rb real 0m0.151s user 0m0.052s sys 0m0.016s $ asdf local ruby jruby-9.1.8.0 $ ruby -v jruby 9.1.8.0 (2.3.1) 2017-03-06 90fc7ab OpenJDK 64-Bit Server VM 25.121-b13 on 1.8.0_121-8u121-b13- 0ubuntu1.16.04.2-b13 +jit [linux-x86_64] $ time ruby scripts/sort.rb real 0m3.468s user 0m8.384s sys 0m0.232s CRuby vs JRuby
  • 6.
  • 7. ● Way too few samples ● Realistic data/multiple inputs? ● No warmup ● Non production environment ● Does creating the array matter? ● Is reverse sorting really the bottle neck? ● Setup information ● Running on battery ● Lots of applications running Numerous Failures!
  • 11. Startup Warmup Runtime What’s important for you?
  • 12. MJIT
  • 15. Focus
  • 16. Truffle: 33.58 seconds vs MJIT: 9.34 seconds time ruby pent.rb
  • 17. Truffle: 33.58 seconds vs MJIT: 9.34 seconds MJIT 3.5+ times faster!
  • 18.
  • 20. Truffle: 3.68 seconds vs MJIT: 0.00 seconds time ruby empty.rb
  • 22. Benchmark.avg do |benchmark| benchmark.config time: 60, warmup: 95 benchmark.report "pent" do mkpieces mkboard $p[4] = [$p[4][0]] $pnum = (0...$p.length).to_a setpiece([],0) end end Proper Benchmark
  • 27. We just went from Truffle is 3.5 times slower all the way to Truffle is 3.7 times faster
  • 29. Stop Guessing and Start Measuring Benchmarking in Practice Tobias Pfeiffer @PragTob pragtob.info
  • 30.
  • 36. ● (Ruby versions mentioned when used) ● OpenJDK 8 ● GraalVM 25 ● MJIT master as of July 6th (last commit mid of June) ● Elixir 1.3.4 ● Erlang 19.1 ● i5-7200U – 2 x 2.5GHz (Up to 3.10GHz) ● 8GB RAM ● Linux Mint 18.1 - 64 bit (Ubuntu 16.04 base) ● Linux Kernel 4.8.0 ● Firefox 54.0 System Specification
  • 38. ● Runtime? ● Memory? ● Throughput? ● Custom? What to measure?
  • 39. Amount of socket connection
  • 40. What to measure? ● Runtime! ● Memory? ● Throughput? ● Custom?
  • 41. Did we make it faster?
  • 42. “Isn’t that the root of all evil?”
  • 43. “More likely, not reading the sources is the source of all evil” Me, just now
  • 44. “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.” Donald Knuth, 1974 (Computing Surveys, Vol 6, No 4, December 1974)
  • 45. “Yet we should not pass up our opportunities in that critical 3%” Donald Knuth, 1974 (Computing Surveys, Vol 6, No 4, December 1974) The very next sentence
  • 46. “(...) a 12 % improvement, easily obtained, is never considered marginal.” Donald Knuth, 1974 (Computing Surveys, Vol 6, No 4, December 1974) Prior Paragraph
  • 47.
  • 49.
  • 54. getColor = function(x, y, board) { if (isOutOfBounds(x, y, board)) { return NEUTRAL; } else { return board[y][x]; } }; isOutOfBounds = function(x, y, board) { var board_size = board.length; if ((x < 0) || (y < 0) || (x >= board_size) || (y >= board_size)) { return true; } else { return false; } }; Checks...
  • 55. getColor = function(x, y, board) { if (isOutOfBounds(x, y, board)) { return NEUTRAL; } else { return board[y][x]; } }; isOutOfBounds = function(x, y, board) { var board_size = board.length; if ((x < 0) || (y < 0) || (x >= board_size) || (y >= board_size)) { return true; } else { return false; } }; Checks...
  • 56. getColor = function(x, y, board) { if (isOutOfBounds(x, y, board)) { return NEUTRAL; } else { return board[y][x]; } }; isOutOfBounds = function(x, y, board) { var board_size = board.length; if ((x < 0) || (y < 0) || (x >= board_size) || (y >= board_size)) { return true; } else { return false; } }; Checks...
  • 57. getColor = function(x, y, board) { if (isOutOfBounds(x, y, board)) { return NEUTRAL; } else { return board[y][x]; } }; isOutOfBounds = function(x, y, board) { var board_size = board.length; if ((x < 0) || (y < 0) || (x >= board_size) || (y >= board_size)) { return true; } else { return false; } }; Checks...
  • 59. Layer
  • 63. getColor = function(x, y, board) { return board[y + 1][x + 1]; }; BEST CODE EVER!
  • 64. Benchmark.js var board = initBoard(3); var suite = new Benchmark.Suite; suite.add('getColor', function() { getColor(1, 2, board); }).on('cycle', function(event) { // log result }).on('complete', function() { // done }).run({ async: true });
  • 65. Benchmark function var board = initBoard(3); var suite = new Benchmark.Suite; suite.add('getColor', function() { getColor(1, 2, board); }).on('cycle', function(event) { // log result }).on('complete', function() { // done }).run({ async: true });
  • 66. getColor x 278,959,094 ops/sec ±0.39% (98 runs sampled) getColor x 1,816,254,291 ops/sec ±0.17% (94 runs sampled) Run it! New Old
  • 67. getColor x ~279 Million ops/sec ±0.39% (98 runs sampled) getColor x ~1 816 Million ops/sec ±0.17% (94 runs sampled) Run it! New Old
  • 68. getColor x ~279 Million ops/sec ±0.39% (98 runs sampled) getColor x ~1 816 Million ops/sec ±0.17% (94 runs sampled) Over 6 times faster!!! New Old
  • 70. Does it even matter?
  • 71. var suite = new Benchmark.Suite; suite.add('playing a random 9x9 game', function() { playoutForBoard(initBoard(9)); }).add('playing a random 13x13 game', function() { playoutForBoard(initBoard(13)); }).add('playing a random 19x19 game', function() { playoutForBoard(initBoard(19)); }).on('cycle', function(event) { // log result here }).on('complete', function() { // done }).run({ async: true }); A bigger benchmark
  • 72. var suite = new Benchmark.Suite; suite.add('playing a random 9x9 game', function() { playoutForBoard(initBoard(9)); }).add('playing a random 13x13 game', function() { playoutForBoard(initBoard(13)); }).add('playing a random 19x19 game', function() { playoutForBoard(initBoard(19)); }).on('cycle', function(event) { // log result here }).on('complete', function() { // done }).run({ async: true }); A bigger benchmark
  • 73. 9x9 game x 252 ops/sec ±2.44% 13x13 game x 80.50 ops/sec ±4.14% 19x19 game x 25.19 ops/sec ±6.33% 9x9 game x 199 ops/sec ±18.09% 13x13 game x 67.11 ops/sec ±3.24% 19x19 game x 20.97 ops/sec ±7.56% Run it! New Old
  • 74. 9x9 game x 252 ops/sec ±2.44% 13x13 game x 80.50 ops/sec ±4.14% 19x19 game x 25.19 ops/sec ±6.33% 9x9 game x 199 ops/sec ±18.09% 13x13 game x 67.11 ops/sec ±3.24% 19x19 game x 20.97 ops/sec ±7.56% New Old ~20% slower?!?!
  • 75.
  • 76. 9x9 game x 252 ops/sec ±2.44% 13x13 game x 80.50 ops/sec ±4.14% 19x19 game x 25.19 ops/sec ±6.33% 9x9 game x 199 ops/sec ±18.09% 13x13 game x 67.11 ops/sec ±3.24% 19x19 game x 20.97 ops/sec ±7.56% New Old Initializing & Copying Boards
  • 77. What are you measuring? Does it matter?
  • 78.
  • 82.
  • 83. Benchmark.ips do |benchmark| game_19 = playout_for(19).game_state.game scorer = Rubykon::GameScorer.new benchmark.report '19x19 scoring' do scorer.score game_19 end end micro: scoring
  • 84. Benchmark.ips do |benchmark| benchmark.report '19x19 playout' do game = Rubykon::Game.new(19) game_state = Rubykon::GameState.new(game) mcts = MCTS::Playout.new(game_state) mcts.playout end end macro: playout
  • 85. Benchmark.avg do |benchmark| game_19 = Rubykon::Game.new(19) game_state_19 = Rubykon::GameState.new game_19 mcts = MCTS::MCTS.new benchmark.config warmup: 180, time: 180 benchmark.report "19x19 1_000 iterations" do mcts.start game_state_19, 1_000 end end Application: tree search
  • 89. Micro Macro Setup Complexity Execution Time Components involved Application
  • 90. Micro Macro Setup Complexity Execution Time Confidence of Real Impact Components involved Application
  • 91. Micro Macro Setup Complexity Execution Time Confidence of Real Impact Components involved Chance of Interference Application
  • 92. Micro Macro Setup Complexity Execution Time Confidence of Real Impact Components involved Chance of Interference Golden Middle Application
  • 93. Benchmark.avg do |benchmark| game_19 = Rubykon::Game.new(19) game_state_19 = Rubykon::GameState.new game_19 mcts = MCTS::MCTS.new benchmark.config warmup: 180, time: 180 benchmark.report "19x19 1_000 iterations" do mcts.start game_state_19, 1_000 end end Application: tree search
  • 96.
  • 99. Boom
  • 101.
  • 102. Benchee.run %{ "Using LatestCourierLocation" => fn(courier_id) -> LatestCourierLocation |> CourierLocation.with_courier_ids(courier_id) |> Repo.one end, "with_courier_ids + order" => fn(courier_id) -> CourierLocation.with_courier_ids(courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end, "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end } A real case
  • 103. Benchee.run %{ "Using LatestCourierLocation" => fn(courier_id) -> LatestCourierLocation |> CourierLocation.with_courier_ids(courier_id) |> Repo.one end, "with_courier_ids + order" => fn(courier_id) -> CourierLocation.with_courier_ids(courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end, "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end } Database View
  • 104. Benchee.run %{ "Using LatestCourierLocation" => fn(courier_id) -> LatestCourierLocation |> CourierLocation.with_courier_ids(courier_id) |> Repo.one end, "with_courier_ids + order" => fn(courier_id) -> CourierLocation.with_courier_ids(courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end, "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end } Only difference
  • 105. Name ips average deviation median with_courier_ids + order 1.19 K 841.44 μs ±67.64% 675.00 μs full custom 1.16 K 862.36 μs ±56.06% 737.00 μs Using LatestCourierLocation 0.00603 K 165897.47 μs ±2.33% 165570.00 μs Comparison: with_courier_ids + order 1.19 K full custom 1.16 K - 1.02x slower Using LatestCourierLocation 0.00603 K - 197.16x slower Another job well done?
  • 106. Boom
  • 110. inputs = %{ "Big 2.3 Million locations" => 3799, "No locations" => 8901, "~200k locations" => 4238, "~20k locations" => 4201 } Benchee.run %{ ... "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end }, inputs: inputs, time: 25, warmup: 5 Inputs to the rescue!
  • 111. inputs = %{ "Big 2.3 Million locations" => 3799, "No locations" => 8901, "~200k locations" => 4238, "~20k locations" => 4201 } Benchee.run %{ ... "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end }, inputs: inputs, time: 25, warmup: 5 Inputs to the rescue!
  • 112. inputs = %{ "Big 2.3 Million locations" => 3799, "No locations" => 8901, "~200k locations" => 4238, "~20k locations" => 4201 } Benchee.run %{ ... "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end }, inputs: inputs, time: 25, warmup: 5 Inputs to the rescue!
  • 113. inputs = %{ "Big 2.3 Million locations" => 3799, "No locations" => 8901, "~200k locations" => 4238, "~20k locations" => 4201 } Benchee.run %{ ... "full custom" => fn(courier_id) -> CourierLocation |> Ecto.Query.where(courier_id: ^courier_id) |> Ecto.Query.order_by(desc: :time) |> Ecto.Query.limit(1) |> Repo.one end }, inputs: inputs, time: 25, warmup: 5 Inputs to the rescue!
  • 114. ##### With input Big 2.3 Million locations ##### Comparison: with_courier_ids + order 1.19 K full custom 1.16 K - 1.02x slower Using LatestCourierLocation 0.00603 K - 197.16x slower ##### With input ~200k locations ##### Comparison: Using LatestCourierLocation 3.66 full custom 0.133 - 27.57x slower with_courier_ids + order 0.132 - 27.63x slower ##### With input ~20k locations ##### Comparison: Using LatestCourierLocation 38.12 full custom 0.122 - 312.44x slower with_courier_ids + order 0.122 - 313.33x slower ##### With input No locations ##### Comparison: Using LatestCourierLocation 2967.48 full custom 0.114 - 25970.57x slower with_courier_ids + order 0.114 - 26046.06x slower Old
  • 115. ##### With input Big 2.3 Million locations ##### Comparison: with_courier_ids + order 1.19 K full custom 1.16 K - 1.02x slower Using LatestCourierLocation 0.00603 K - 197.16x slower ##### With input ~200k locations ##### Comparison: Using LatestCourierLocation 3.66 full custom 0.133 - 27.57x slower with_courier_ids + order 0.132 - 27.63x slower ##### With input ~20k locations ##### Comparison: Using LatestCourierLocation 38.12 full custom 0.122 - 312.44x slower with_courier_ids + order 0.122 - 313.33x slower ##### With input No locations ##### Comparison: Using LatestCourierLocation 2967.48 full custom 0.114 - 25970.57x slower with_courier_ids + order 0.114 - 26046.06x slower Old
  • 116. ##### With input Big 2.3 Million locations ##### Comparison: with_courier_ids + order 1.19 K full custom 1.16 K - 1.02x slower Using LatestCourierLocation 0.00603 K - 197.16x slower ##### With input ~200k locations ##### Comparison: Using LatestCourierLocation 3.66 full custom 0.133 - 27.57x slower with_courier_ids + order 0.132 - 27.63x slower ##### With input ~20k locations ##### Comparison: Using LatestCourierLocation 38.12 full custom 0.122 - 312.44x slower with_courier_ids + order 0.122 - 313.33x slower ##### With input No locations ##### Comparison: Using LatestCourierLocation 2967.48 full custom 0.114 - 25970.57x slower with_courier_ids + order 0.114 - 26046.06x slower Old
  • 118. ##### With input Big 2.3 Million locations ##### Comparison: full custom 3921.12 with_courier_ids + order 23.05 - 170.09x slower Using LatestCourierLocation 5.98 - 655.74x slower ##### With input ~200k locations ##### Comparison: full custom 4272.84 with_courier_ids + order 14.20 - 300.91x slower Using LatestCourierLocation 3.80 - 1125.59x slower ##### With input ~20k locations ##### Comparison: full custom 3792.97 with_courier_ids + order 78.93 - 48.06x slower Using LatestCourierLocation 35.62 - 106.47x slower ##### With input No locations ##### Comparison: full custom 5.14 K with_courier_ids + order 3.87 K - 1.33x slower Using LatestCourierLocation 3.29 K - 1.56x slower Combined Index
  • 119. ##### With input Big 2.3 Million locations ##### Comparison: full custom 3921.12 with_courier_ids + order 23.05 - 170.09x slower Using LatestCourierLocation 5.98 - 655.74x slower ##### With input ~200k locations ##### Comparison: full custom 4272.84 with_courier_ids + order 14.20 - 300.91x slower Using LatestCourierLocation 3.80 - 1125.59x slower ##### With input ~20k locations ##### Comparison: full custom 3792.97 with_courier_ids + order 78.93 - 48.06x slower Using LatestCourierLocation 35.62 - 106.47x slower ##### With input No locations ##### Comparison: full custom 5.14 K with_courier_ids + order 3.87 K - 1.33x slower Using LatestCourierLocation 3.29 K - 1.56x slower Combined Index
  • 120. # with an index on courier_id and one on time Name ips average deviation median Updating a location 366.90 2.73 ms ±36.35% 2.29 ms # with a combined index on courier_id and time Name ips average deviation median Updating a location 283.41 3.53 ms ±52.18% 2.77 ms Insertion Time
  • 125. [info] GET / [debug] Processing by Rumbl.PageController.index/2 Parameters: %{} Pipelines: [:browser] [info] Sent 200 in 46ms [info] GET /sessions/new [debug] Processing by Rumbl.SessionController.new/2 Parameters: %{} Pipelines: [:browser] [info] Sent 200 in 5ms [info] GET /users/new [debug] Processing by Rumbl.UserController.new/2 Parameters: %{} Pipelines: [:browser] [info] Sent 200 in 7ms [info] POST /users [debug] Processing by Rumbl.UserController.create/2 Parameters: %{"_csrf_token" => "NUEUdRMNAiBfIHEeNwZkfA05PgAOJgAAf0ACXJqCjl7YojW+trdjdg==", "_utf8" => " ", "user" =>✓ %{"name" => "asdasd", "password" => "[FILTERED]", "username" => "Homer"}} Pipelines: [:browser] [debug] QUERY OK db=0.1ms begin [] [debug] QUERY OK db=0.9ms INSERT INTO "users" ("name","password_hash","username","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["asdasd", "$2b$12$.qY/kpo0Dec7vMK1ClJoC.Lw77c3oGllX7uieZILMlFh2hFpJ3F.C", "Homer", {{2016, 12, 2}, {14, 10, 28, 0}}, {{2016, 12, 2}, {14, 10, 28, 0}}] Logging & Friends
  • 126.
  • 128. defmodule MyMap do def map_tco(list, function) do Enum.reverse do_map_tco([], list, function) end defp do_map_tco(acc, [], _function) do acc end defp do_map_tco(acc, [head | tail], func) do do_map_tco([func.(head) | acc], tail, func) end def map_body([], _func), do: [] def map_body([head | tail], func) do [func.(head) | map_body(tail, func)] end end TCO
  • 129. defmodule MyMap do def map_tco(list, function) do Enum.reverse do_map_tco([], list, function) end defp do_map_tco(acc, [], _function) do acc end defp do_map_tco(acc, [head | tail], func) do do_map_tco([func.(head) | acc], tail, func) end def map_body([], _func), do: [] def map_body([head | tail], func) do [func.(head) | map_body(tail, func)] end end TCO
  • 130. defmodule MyMap do def map_tco(list, function) do Enum.reverse do_map_tco([], list, function) end defp do_map_tco(acc, [], _function) do acc end defp do_map_tco(acc, [head | tail], func) do do_map_tco([func.(head) | acc], tail, func) end def map_body([], _func), do: [] def map_body([head | tail], func) do [func.(head) | map_body(tail, func)] end end TCO
  • 131. map_fun = fn(i) -> i + 1 end inputs = %{ "Small (10 Thousand)" => Enum.to_list(1..10_000), "Middle (100 Thousand)" => Enum.to_list(1..100_000), "Big (1 Million)" => Enum.to_list(1..1_000_000), "Bigger (5 Million)" => Enum.to_list(1..5_000_000) } Benchee.run %{ "tail-recursive" => fn(list) -> MyMap.map_tco(list, map_fun) end, "stdlib map" => fn(list) -> Enum.map(list, map_fun) end, "body-recursive" => fn(list) -> MyMap.map_body(list, map_fun) end }, inputs: inputs TCO
  • 132. map_fun = fn(i) -> i + 1 end inputs = %{ "Small (10 Thousand)" => Enum.to_list(1..10_000), "Middle (100 Thousand)" => Enum.to_list(1..100_000), "Big (1 Million)" => Enum.to_list(1..1_000_000), "Bigger (5 Million)" => Enum.to_list(1..5_000_000) } Benchee.run %{ "tail-recursive" => fn(list) -> MyMap.map_tco(list, map_fun) end, "stdlib map" => fn(list) -> Enum.map(list, map_fun) end, "body-recursive" => fn(list) -> MyMap.map_body(list, map_fun) end }, inputs: inputs TCO
  • 133. map_fun = fn(i) -> i + 1 end inputs = %{ "Small (10 Thousand)" => Enum.to_list(1..10_000), "Middle (100 Thousand)" => Enum.to_list(1..100_000), "Big (1 Million)" => Enum.to_list(1..1_000_000), "Bigger (5 Million)" => Enum.to_list(1..5_000_000) } Benchee.run %{ "tail-recursive" => fn(list) -> MyMap.map_tco(list, map_fun) end, "stdlib map" => fn(list) -> Enum.map(list, map_fun) end, "body-recursive" => fn(list) -> MyMap.map_body(list, map_fun) end }, inputs: inputs TCO
  • 134. ##### With input Small (10 Thousand) ##### Comparison: body-recursive 5.12 K stdlib map 5.07 K - 1.01x slower tail-recursive 4.38 K - 1.17x slower ##### With input Middle (100 Thousand) ##### Comparison: body-recursive 491.16 stdlib map 488.45 - 1.01x slower tail-recursive 399.08 - 1.23x slower ##### With input Big (1 Million) ##### Comparison: tail-recursive 35.36 body-recursive 25.69 - 1.38x slower stdlib map 24.85 - 1.42x slower ##### With input Bigger (5 Million) ##### Comparison: tail-recursive 6.93 body-recursive 4.92 - 1.41x slower stdlib map 4.87 - 1.42x slower TCO
  • 135. ##### With input Small (10 Thousand) ##### Comparison: body-recursive 5.12 K stdlib map 5.07 K - 1.01x slower tail-recursive 4.38 K - 1.17x slower ##### With input Middle (100 Thousand) ##### Comparison: body-recursive 491.16 stdlib map 488.45 - 1.01x slower tail-recursive 399.08 - 1.23x slower ##### With input Big (1 Million) ##### Comparison: tail-recursive 35.36 body-recursive 25.69 - 1.38x slower stdlib map 24.85 - 1.42x slower ##### With input Bigger (5 Million) ##### Comparison: tail-recursive 6.93 body-recursive 4.92 - 1.41x slower stdlib map 4.87 - 1.42x slower TCO
  • 136. TCO
  • 137. What even is a benchmark?
  • 138. config |> Benchee.init |> Benchee.system |> Benchee.benchmark("job", fn -> magic end) |> Benchee.measure |> Benchee.statistics |> Benchee.Formatters.Console.output |> Benchee.Formatters.HTML.output A transformation of inputs
  • 139. Enjoy Benchmarking! ❤ Tobias Pfeiffer @PragTob pragtob.info github.com/evanphx/benchmark-ips github.com/PragTob/benchee benchmarkjs.com/