diff --git a/rebar.config b/rebar.config index f0830dc..7787817 100644 --- a/rebar.config +++ b/rebar.config @@ -8,7 +8,9 @@ {lager, "3.6.3"}, {erlang_psq, "1.0.0"} ]}. -{plugins, [rebar3_proper]}. +{plugins, [rebar3_proper, + rebar3_bench] +}. {xref_checks, [undefined_function_calls, diff --git a/test/bench_codec_decode.erl b/test/bench_codec_decode.erl new file mode 100644 index 0000000..d946145 --- /dev/null +++ b/test/bench_codec_decode.erl @@ -0,0 +1,194 @@ +%%% @author Sergey +%%% @copyright (C) 2019, Sergey +%%% @doc +%%% Decoding benchmarks for codecs +%%% @end +%%% Created : 7 Sep 2019 by Sergey + +-module(bench_codec_decode). + +-export([fake_tls/1, bench_fake_tls/2, + intermediate/1, bench_intermediate/2, + secure/1, bench_secure/2, + full/1, bench_full/2, + aes_cbc/1, bench_aes_cbc/2, + obfuscated/1, bench_obfuscated/2, + fold_dd_codec/1, bench_fold_dd_codec/2, + fold_tls_codec/1, bench_fold_tls_codec/2, + fold_backend_codec/1, bench_fold_backend_codec/2]). + + +%% @doc bench mtp_fake_tls decoding +fake_tls(init) -> + mtp_fake_tls:new(); +fake_tls({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_fake_tls, Codec). + +bench_fake_tls(Stream, Codec) -> + mtp_fake_tls:decode_all(Stream, Codec). + + +%% @doc bench mtp_intermediate decoding +intermediate(init) -> + mtp_intermediate:new(); +intermediate({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_intermediate, Codec). + +bench_intermediate(Stream, Codec) -> + decode_all_intermediate(Stream, Codec). + +decode_all_intermediate(Stream0, Codec0) -> + case mtp_intermediate:try_decode_packet(Stream0, Codec0) of + {ok, Pkt, Stream1, Codec1} -> + [Pkt | decode_all_intermediate(Stream1, Codec1)]; + {incomplete, _} -> + [] + end. + + +%% @doc bench mtp_secure decoding +secure(init) -> + mtp_secure:new(); +secure({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_secure, Codec). + +bench_secure(Stream, Codec) -> + decode_all_secure(Stream, Codec). + +decode_all_secure(Stream0, Codec0) -> + case mtp_secure:try_decode_packet(Stream0, Codec0) of + {ok, Pkt, Stream1, Codec1} -> + [Pkt | decode_all_secure(Stream1, Codec1)]; + {incomplete, _} -> + [] + end. + + +%% @doc bench mtp_full decoding +full(init) -> + mtp_full:new(); +full({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_full, Codec). + +bench_full(Stream, Codec) -> + decode_all_full(Stream, Codec). + +decode_all_full(Stream0, Codec0) -> + case mtp_full:try_decode_packet(Stream0, Codec0) of + {ok, Pkt, Stream1, Codec1} -> + [Pkt | decode_all_full(Stream1, Codec1)]; + {incomplete, _} -> + [] + end. + + +%% @doc bench aes_cbc decryption +aes_cbc(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + BlockSize = 16, + mtp_aes_cbc:new(Key, IV, Key, IV, BlockSize); +aes_cbc({input, Codec}) -> + Packets = mk_front_packets(), + {Stream, _} = mtp_aes_cbc:encrypt(Packets, Codec), + Stream. + +bench_aes_cbc(Stream, Codec) -> + {Dec, <<>>, _} = mtp_aes_cbc:decrypt(Stream, Codec), + Dec. + + +%% @doc decrypt mtp_obfuscated +obfuscated(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + mtp_obfuscated:new(Key, IV, Key, IV); +obfuscated({input, Codec}) -> + Packets = mk_front_packets(), + {Stream, _} = mtp_obfuscated:encrypt(Packets, Codec), + Stream. + +bench_obfuscated(Stream, Codec) -> + {Dec, <<>>, _} = mtp_obfuscated:decrypt(Stream, Codec), + Dec. + +%% @doc "codec" that is used for "dd" secrets +fold_dd_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + CryptoSt = mtp_obfuscated:new(Key, IV, Key, IV), + PacketSt = mtp_secure:new(), + mtp_codec:new(mtp_obfuscated, CryptoSt, + mtp_secure, PacketSt); +fold_dd_codec({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_codec, Codec). + +bench_fold_dd_codec(Stream, Codec) -> + codec_fold(Stream, Codec). + + +%% @doc "codec" that is used for "fake-tls" connections +fold_tls_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + CryptoSt = mtp_obfuscated:new(Key, IV, Key, IV), + PacketSt = mtp_secure:new(), + TlsSt = mtp_fake_tls:new(), + mtp_codec:new(mtp_obfuscated, CryptoSt, + mtp_secure, PacketSt, + true, TlsSt, + 10 * 1024 * 1024); +fold_tls_codec({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_codec, Codec). + +bench_fold_tls_codec(Stream, Codec) -> + codec_fold(Stream, Codec). + + +%% @doc codec that is used for connections to telegram datacenter +fold_backend_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + BlockSize = 16, + CryptoSt = mtp_aes_cbc:new(Key, IV, Key, IV, BlockSize), + PacketSt = mtp_full:new(), + mtp_codec:new(mtp_aes_cbc, CryptoSt, + mtp_full, PacketSt); +fold_backend_codec({input, Codec}) -> + Packets = mk_front_packets(), + encode_all(Packets, mtp_codec, Codec). + +bench_fold_backend_codec(Stream, Codec) -> + codec_fold(Stream, Codec). + + +%% +%% Helpers + +mk_front_packets() -> + %% Histogram from live server shows that majority of Telegram protocol packets from client to + %% proxy are between 128 to 512 bytes. + %% Network (tcp) data chunk size depends on sock buffewr, but is usually between 128b to 2kb. + Packet = binary:copy(<<0>>, 256), + lists:duplicate(8, Packet). + +encode_all(Pkts, Codec, St0) -> + {Stream, _} = + lists:foldl( + fun(Pkt, {Acc, St}) -> + {Enc, St1} = Codec:encode_packet(Pkt, St), + {<>, St1} + end, {<<>>, St0}, Pkts), + Stream. + +codec_fold(Stream, Codec) -> + mtp_codec:fold_packets( + fun(Pkt, Acc, Codec1) -> + {[Pkt | Acc], Codec1} + end, [], Stream, Codec). diff --git a/test/bench_codec_encode.erl b/test/bench_codec_encode.erl new file mode 100644 index 0000000..c3ff1ef --- /dev/null +++ b/test/bench_codec_encode.erl @@ -0,0 +1,164 @@ +%%% @author Sergey +%%% @copyright (C) 2019, Sergey +%%% @doc +%%% Encoding benchmark for codecs +%%% @end +%%% Created : 15 Sep 2019 by Sergey + +-module(bench_codec_encode). + +-export([fake_tls/1, bench_fake_tls/2, + intermediate/1, bench_intermediate/2, + secure/1, bench_secure/2, + full/1, bench_full/2, + aes_cbc/1, bench_aes_cbc/2, + obfuscated/1, bench_obfuscated/2, + dd_codec/1, bench_dd_codec/2, + fake_tls_codec/1, bench_fake_tls_codec/2, + backend_codec/1, bench_backend_codec/2 + ]). + + +fake_tls({input, _}) -> + mk_back_packets(). + +bench_fake_tls(Packets, _) -> + Codec0 = mtp_fake_tls:new(), + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_fake_tls:encode_packet(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +intermediate({input, _}) -> + mk_back_packets(). + +bench_intermediate(Packets, _) -> + Codec0 = mtp_intermediate:new(), + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_intermediate:encode_packet(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +secure({input, _}) -> + mk_back_packets(). + +bench_secure(Packets, _) -> + Codec0 = mtp_secure:new(), + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_secure:encode_packet(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +full({input, _}) -> + mk_back_packets(). + +bench_full(Packets, _) -> + Codec0 = mtp_full:new(), + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_full:encode_packet(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +aes_cbc(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + BlockSize = 16, + mtp_aes_cbc:new(Key, IV, Key, IV, BlockSize); +aes_cbc({input, _}) -> + mk_back_packets(). + +bench_aes_cbc(Packets, Codec0) -> + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_aes_cbc:encrypt(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +obfuscated(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + mtp_obfuscated:new(Key, IV, Key, IV); +obfuscated({input, _}) -> + mk_back_packets(). + +bench_obfuscated(Packets, Codec0) -> + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_obfuscated:encrypt(Pkt, Codec1), + Codec2 + end, Codec0, Packets). + + +dd_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + CryptoSt = mtp_obfuscated:new(Key, IV, Key, IV), + PacketSt = mtp_secure:new(), + mtp_codec:new(mtp_obfuscated, CryptoSt, + mtp_secure, PacketSt); +dd_codec({input, _}) -> + mk_back_packets(). + +bench_dd_codec(Packets, Codec) -> + codec_encode(Packets, Codec). + + +fake_tls_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + CryptoSt = mtp_obfuscated:new(Key, IV, Key, IV), + PacketSt = mtp_secure:new(), + TlsSt = mtp_fake_tls:new(), + mtp_codec:new(mtp_obfuscated, CryptoSt, + mtp_secure, PacketSt, + true, TlsSt, + 10 * 1024 * 1024); +fake_tls_codec({input, _}) -> + mk_back_packets(). + +bench_fake_tls_codec(Packets, Codec) -> + codec_encode(Packets, Codec). + + +backend_codec(init) -> + Key = binary:copy(<<0>>, 32), + IV = binary:copy(<<1>>, 16), + BlockSize = 16, + CryptoSt = mtp_aes_cbc:new(Key, IV, Key, IV, BlockSize), + PacketSt = mtp_full:new(), + mtp_codec:new(mtp_aes_cbc, CryptoSt, + mtp_full, PacketSt); +backend_codec({input, _}) -> + mk_back_packets(). + +bench_backend_codec(Packets, Codec) -> + codec_encode(Packets, Codec). + + +%% +%% Helpers + +mk_back_packets() -> + %% Histogram from live server shows that majority of Telegram protocol packets from server to + %% proxy are between 32b to 2kb. + %% Network (tcp) data chunk size depends on sock buffewr, but is usually distributed + %% evenly in logarithmic scale: 32b - 128b - 512b - 2kb - 8kb - 33kb + %% Majority is from 128b to 512b + Packet = binary:copy(<<0>>, 512), + lists:duplicate(4, Packet). + +codec_encode(Packets, Codec0) -> + lists:foldl( + fun(Pkt, Codec1) -> + {_Enc, Codec2} = mtp_codec:encode_packet(Pkt, Codec1), + Codec2 + end, Codec0, Packets).