-
Notifications
You must be signed in to change notification settings - Fork 39
/
io_lists_vs_concatenation.exs
98 lines (86 loc) · 2.49 KB
/
io_lists_vs_concatenation.exs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# To make this a fair test and to use varying numbers of arguments as inputs, I needed to write
# the actual modules in a very macro-heavy way. Both of these modules are essentially doing the
# following:
#
# defmodule Output.Fast do
# def output(a, b, c, d, e) do
# [e | [d | [c | [a | b]]]]
# end
#
# # and so on for the 50 and 100 argument versions of that function.
# end
#
# defmodule Output.Slow do
# def output(a, b, c, d, e) do
# "#{e}#{d}#{c}#{a}#{e}"
# end
#
# # and so on for the 50 and 100 argument versions of that function.
# end
defmodule Output.Fast do
Enum.each([5, 50, 100], fn count ->
[first, second | rest] = vars = Macro.generate_arguments(count, __MODULE__)
starting =
quote do
[unquote(first) | unquote(second)]
end
cons_expr =
Enum.reduce(rest, starting, fn var, acc ->
quote do
[unquote(var) | unquote(acc)]
end
end)
def output(unquote_splicing(vars)) do
unquote(cons_expr)
end
end)
end
defmodule Output.Slow do
Enum.each([5, 50, 100], fn count ->
[first | rest] = vars = Macro.generate_arguments(count, __MODULE__)
starting = [
{:"::", [], [{{:., [], [Kernel, :to_string]}, [], [first]}, {:binary, [], Output.Slow}]}
]
interpolation_expr =
Enum.reduce(rest, starting, fn var, acc ->
[
{:"::", [], [{{:., [], [Kernel, :to_string]}, [], [var]}, {:binary, [], Output.Slow}]}
| acc
]
end)
def output(unquote_splicing(vars)) do
unquote({:<<>>, [], interpolation_expr})
end
end)
end
defmodule Output.Benchmark do
def inputs do
%{
"100 3-character strings" => generate_chunks(3, 100),
"100 300-character strings" => generate_chunks(300, 100),
"50 3-character strings" => generate_chunks(3, 50),
"50 300-character strings" => generate_chunks(300, 50),
"5 3-character_strings" => generate_chunks(3, 5),
"5 300-character_strings" => generate_chunks(300, 5)
}
end
def generate_chunks(chunk_size, count) do
?a..?z
|> Stream.cycle()
|> Stream.chunk_every(chunk_size)
|> Stream.map(&to_string/1)
|> Enum.take(count)
end
def benchmark do
Benchee.run(
%{
"IO List" => fn input -> apply(Output.Fast, :output, input) end,
"Interpolation" => fn input -> apply(Output.Slow, :output, input) end
},
inputs: inputs(),
time: 10,
print: [fast_warning: false]
)
end
end
Output.Benchmark.benchmark()