Created
June 19, 2023 16:50
-
-
Save cr0t/299280930808b67b6db7742d6900d368 to your computer and use it in GitHub Desktop.
An Elixir benchmark idea of which born during discussion with one of my mentees on Exercism.io
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Mix.install([:benchee]) | |
defmodule Proteins do | |
@stop "STOP" | |
@err_msg "invalid codon" | |
@codons %{ | |
"UGU" => "Cysteine", | |
"UGG" => "Tryptophan", | |
"UUU" => "Phenylalanine", | |
"UAA" => @stop | |
} | |
def rna_normal(rna) do | |
rna | |
|> parse() | |
|> Stream.map(&of_codon/1) | |
|> Stream.take_while(&(elem(&1, 1) not in [@stop, @err_msg])) | |
|> Enum.to_list() | |
end | |
def rna_throw(rna) do | |
try do | |
rna | |
|> parse() | |
|> Stream.transform([], fn codon, acc -> | |
case of_codon(codon) do | |
{:ok, @stop} -> throw(acc) | |
{:error, _} -> throw(acc) | |
protein -> {[protein], [protein | acc]} | |
end | |
end) | |
|> Enum.to_list() | |
catch | |
results -> results | |
end | |
end | |
# Helpers | |
defp parse(rna), do: Regex.scan(~r/.{3}/, rna) |> List.flatten() | |
defp of_codon(codon) when is_map_key(@codons, codon), do: {:ok, @codons[codon]} | |
defp of_codon(_), do: {:error, @err_msg} | |
end | |
# Preparations | |
# A long and correct strand of codons can be made by diplication | |
long_strand = String.duplicate("UGUUGGUUU", 33_000) | |
short_strand = String.duplicate("UGUUGGUUU", 1) | |
long_mid = "#{long_strand}UAA#{long_strand}" | |
long_err = "#{long_strand}ERR#{long_strand}" | |
short_mid = "#{short_strand}UAA#{short_strand}" | |
short_err = "#{short_strand}ERR#{short_strand}" | |
IO.puts(""" | |
Length of the short strand is #{String.length(short_mid)} chars, it contains #{div(String.length(short_mid), 3)} codons | |
Length of the long strand is #{String.length(long_mid)} chars, it contains #{div(String.length(long_mid), 3)} codons | |
""") | |
# Just to check that our functions return the same output, we can compare it: | |
IO.inspect( | |
{ | |
Proteins.rna_normal(long_mid) == Proteins.rna_throw(long_mid), | |
Proteins.rna_normal(long_err) == Proteins.rna_throw(long_err), | |
Proteins.rna_normal(short_mid) == Proteins.rna_throw(short_mid), | |
Proteins.rna_normal(short_err) == Proteins.rna_throw(short_err) | |
}, | |
label: "rna_normal/1 == rna_throw/2" | |
) | |
# Benchmarks | |
Benchee.run( | |
%{ | |
"mid_short_normal" => fn -> Proteins.rna_normal(short_mid) end, | |
"mid_short_throw" => fn -> Proteins.rna_throw(short_mid) end | |
}, | |
memory_time: 2 | |
) | |
# Benchmarking mid_short_normal ... | |
# Benchmarking mid_short_throw ... | |
# Name ips average deviation median 99th % | |
# mid_short_normal 133.82 K 7.47 μs ±161.36% 6.94 μs 14.33 μs | |
# mid_short_throw 130.04 K 7.69 μs ±208.18% 7.11 μs 18.98 μs | |
# Comparison: | |
# mid_short_normal 133.82 K | |
# mid_short_throw 130.04 K - 1.03x slower +0.22 μs | |
# Memory usage statistics: | |
# Name Memory usage | |
# mid_short_normal 3.24 KB | |
# mid_short_throw 3.86 KB - 1.19x memory usage +0.62 KB | |
Benchee.run( | |
%{ | |
"mid_long_normal" => fn -> Proteins.rna_normal(long_mid) end, | |
"mid_long_throw" => fn -> Proteins.rna_throw(long_mid) end | |
}, | |
memory_time: 2 | |
) | |
# Benchmarking mid_long_normal ... | |
# Benchmarking mid_long_throw ... | |
# Name ips average deviation median 99th % | |
# mid_long_normal 4.56 219.16 ms ±14.19% 213.24 ms 332.82 ms | |
# mid_long_throw 3.44 291.10 ms ±12.84% 284.57 ms 356.07 ms | |
# Comparison: | |
# mid_long_normal 4.56 | |
# mid_long_throw 3.44 - 1.33x slower +71.95 ms | |
# Memory usage statistics: | |
# Name Memory usage | |
# mid_long_normal 59.67 MB | |
# mid_long_throw 81.57 MB - 1.37x memory usage +21.90 MB | |
Benchee.run( | |
%{ | |
"err_short_normal" => fn -> Proteins.rna_normal(short_err) end, | |
"err_short_throw" => fn -> Proteins.rna_throw(short_err) end | |
}, | |
memory_time: 2 | |
) | |
# Benchmarking err_short_normal ... | |
# Benchmarking err_short_throw ... | |
# Name ips average deviation median 99th % | |
# err_short_normal 131.65 K 7.60 μs ±377.34% 7.06 μs 13.76 μs | |
# err_short_throw 129.20 K 7.74 μs ±148.64% 7.21 μs 15.04 μs | |
# Comparison: | |
# err_short_normal 131.65 K | |
# err_short_throw 129.20 K - 1.02x slower +0.144 μs | |
# Memory usage statistics: | |
# Name Memory usage | |
# err_short_normal 3.23 KB | |
# err_short_throw 3.84 KB - 1.19x memory usage +0.60 KB | |
Benchee.run( | |
%{ | |
"err_long_normal" => fn -> Proteins.rna_normal(long_err) end, | |
"err_long_throw" => fn -> Proteins.rna_throw(long_err) end | |
}, | |
memory_time: 2 | |
) | |
# Benchmarking err_long_normal ... | |
# Benchmarking err_long_throw ... | |
# Name ips average deviation median 99th % | |
# err_long_normal 4.48 223.34 ms ±13.81% 218.28 ms 337.31 ms | |
# err_long_throw 3.34 299.57 ms ±12.38% 303.89 ms 349.05 ms | |
# Comparison: | |
# err_long_normal 4.48 | |
# err_long_throw 3.34 - 1.34x slower +76.23 ms | |
# Memory usage statistics: | |
# Name Memory usage | |
# err_long_normal 59.67 MB | |
# err_long_throw 81.57 MB - 1.37x memory usage +21.90 MB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment