aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/test/ssh_benchmark_SUITE.erl
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2015-12-11 12:01:43 +0100
committerHans Nilsson <[email protected]>2015-12-21 13:59:03 +0100
commitc3135a817f22f76b1ae594dc5821d2d6eab1d25a (patch)
treede534035b9321c778e98512bacee0b8fd3a687bd /lib/ssh/test/ssh_benchmark_SUITE.erl
parent21d6192389a04024f7a41ced9d0911a9cce6f4e8 (diff)
downloadotp-c3135a817f22f76b1ae594dc5821d2d6eab1d25a.tar.gz
otp-c3135a817f22f76b1ae594dc5821d2d6eab1d25a.tar.bz2
otp-c3135a817f22f76b1ae594dc5821d2d6eab1d25a.zip
ssh: Add first version of ssh_benchmark_SUITE
Diffstat (limited to 'lib/ssh/test/ssh_benchmark_SUITE.erl')
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE.erl295
1 files changed, 295 insertions, 0 deletions
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
new file mode 100644
index 0000000000..0d7239c5b5
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -0,0 +1,295 @@
+%%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssh_benchmark_SUITE).
+-compile(export_all).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+-include_lib("ssh/src/ssh.hrl").
+-include_lib("ssh/src/ssh_connect.hrl").
+
+suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
+%%suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() -> [{group, opensshc_erld}
+%% {group, erlc_opensshd}
+ ].
+
+groups() ->
+ [{opensshc_erld, [{repeat, 3}], [openssh_client_shell]},
+ {erlc_opensshd, [{repeat, 3}], [erl_shell]}
+ ].
+
+
+init_per_suite(Config) ->
+ catch ssh:stop(),
+ catch crypto:stop(),
+ try
+ ok = crypto:start(),
+ ok = ssh:start(),
+ {ok,TracerPid} = erlang_trace(),
+ [{tracer_pid,TracerPid} | Config]
+ catch
+ C:E ->
+ {skip, io_lib:format("Couldn't start ~p:~p",[C,E])}
+ end.
+
+end_per_suite(_Config) ->
+ catch ssh:stop(),
+ catch crypto:stop(),
+ ok.
+
+
+
+init_per_group(opensshc_erld, Config) ->
+ case ssh_test_lib:ssh_type() of
+ openSSH ->
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, UserDir),
+ ssh_test_lib:setup_rsa(DataDir, UserDir),
+ ssh_test_lib:setup_ecdsa("256", DataDir, UserDir),
+ [{c_kexs, ssh_test_lib:sshc(kex)},
+ {c_ciphers, ssh_test_lib:sshc(cipher)}
+ | Config];
+ _ ->
+ {skip, "No OpenSsh client found"}
+ end;
+
+init_per_group(erlc_opensshd, _) ->
+ {skip, "Group erlc_opensshd not implemented"};
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+
+init_per_testcase(_Func, Conf) ->
+ Conf.
+
+end_per_testcase(_Func, _Conf) ->
+ ok.
+
+%%%================================================================
+openssh_client_shell(Config) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(UserDir, "known_hosts"),
+
+ {ok, TracerPid} = erlang_trace(),
+ {ServerPid, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SystemDir},
+ {public_key_alg, ssh_dsa},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ct:sleep(500),
+
+ Data = lists:duplicate(100000, $a),
+ Cmd = lists:concat(["ssh -p ",Port,
+ " -o UserKnownHostsFile=", KnownHosts,
+ " -o \"StrictHostKeyChecking no\"",
+ " localhost '\"",Data,"\"'."]),
+%% ct:pal("Cmd ="++Cmd),
+
+ Parent = self(),
+ SlavePid = spawn(fun() ->
+ Parent ! {self(),os:cmd(Cmd)}
+ end),
+ receive
+ {SlavePid, ClientResponse} ->
+%% ct:pal("ClientResponse = ~p",[ClientResponse]),
+ {ok, List} = get_trace_list(TracerPid),
+ Times = find_times(List),
+ Algs = proplists:get_value(algorithms, List, #alg{}),
+ ct:pal("List = ~p~n~nAlgorithms = ~p~n~nTimes = ~p",[List,Algs,Times]),
+ lists:foreach(
+ fun({Tag0,MicroSeconds,Unit}) ->
+ Tag = case Tag0 of
+ {A,B} -> lists:concat([A," ",B]);
+ _ when is_list(Tag0) -> lists:concat(Tag0);
+ _ when is_atom(Tag0) -> Tag0
+ end,
+ DataName =
+ ["Erl server ",Tag,sp(algo(Tag,Algs))," [",Unit,"]"],
+ EventData = [{value, MicroSeconds},
+ {suite, ?MODULE},
+ {name, lists:concat(DataName)}
+ ],
+ ct:pal("ct_event:notify ~p",[EventData]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = EventData})
+ end, Times),
+ ssh:stop_daemon(ServerPid),
+ ok
+ after 10000 ->
+ ssh:stop_daemon(ServerPid),
+ exit(SlavePid, kill),
+ {fail, timeout}
+ end.
+
+
+algo(kex, #alg{kex=Alg} ) -> Alg;
+algo(_, _) -> "".
+
+sp("") -> "";
+sp(A) -> lists:concat([" ",A]).
+
+%%%================================================================
+find_times(L) ->
+ [{accept_to_hello, find_time([tcp_accept,
+ {send,hello}], L, [])/1000,
+ millisec},
+ {kex, find_time([{send,hello},
+ {send,ssh_msg_newkeys}], L, []),
+ microsec},
+ {kex_to_auth, find_time([{send,ssh_msg_newkeys},
+ {recv,ssh_msg_userauth_request}], L, []),
+ microsec},
+ {auth, find_time([{recv,ssh_msg_userauth_request},
+ {send,ssh_msg_userauth_success}], L, []),
+ microsec},
+ {to_prompt, find_time([tcp_accept,
+ {recv,{ssh_msg_channel_request,"env"}}], L, []),
+ microsec}
+
+ | alg_times([encrypt,decrypt], L)
+ ].
+
+
+find_time([Event|Events], [{Event,T}|TraceList], Ts) ->
+ %% Important that the first one found is used!
+ find_time(Events, TraceList, [T|Ts]);
+find_time([], _, [T1,T0]) ->
+ now2micro_sec(now_diff(T1,T0));
+find_time(Events, [_|TraceList], Ts) ->
+ find_time(Events, TraceList, Ts);
+find_time(_, [], _Ts) ->
+ throw({error,not_found}).
+
+
+
+alg_times(Ops, L) ->
+ OpAlgs = lists:usort([{Op,Alg} || Op <- Ops,
+ {{{Op,Alg},_,_},_} <- L]),
+ [begin
+ {[Op,"(",Alg,")"],
+ sum_times(OpAlg, L, 0, 0),
+ "microsec/kbyte"
+ }
+ end || {Op,Alg} = OpAlg <- OpAlgs].
+
+
+sum_times(T, [{{T,start,Id={_,Nbytes}},TS0}|Events], SumBytes, SumMicroSec) ->
+ TS1 = proplists:get_value({T,stop,Id}, Events),
+ sum_times(T, Events, SumBytes+Nbytes, SumMicroSec+now2micro_sec(now_diff(TS1,TS0)));
+sum_times(T, [_|Events], SumBytes, SumMicroSec) ->
+ sum_times(T, Events, SumBytes, SumMicroSec);
+sum_times(T, [], SumBytes, SumMicroSec) ->
+ round(1024*SumMicroSec / SumBytes). % Microseconds per 1k bytes.
+
+%%%----------------------------------------------------------------
+%%%
+%%% API for the traceing
+%%%
+get_trace_list(TracerPid) ->
+ TracerPid ! {get_trace_list,self()},
+ receive
+ {trace_list,L} -> {ok,lists:reverse(L)}
+ after 5000 -> {error,no_reply}
+ end.
+
+erlang_trace() ->
+ TracerPid = spawn(fun trace_loop/0),
+ 0 = erlang:trace(new, true, [call,timestamp,{tracer,TracerPid}]),
+ [init_trace(MFA, TP)
+ || {MFA,TP} <- [{{ssh_acceptor,handle_connection,5}, []},
+ {{ssh_connection_handler,hello,2}, []},
+ {{ssh_message,encode,1}, []},
+ {{ssh_message,decode,1}, [{['_'], [], [{return_trace}]}]},
+ {{ssh_transport,select_algorithm,3}, [{['_','_','_'], [], [{return_trace}]}]},
+ {{ssh_transport,encrypt,2}, [{['_','_'], [], [{return_trace}]}]},
+ {{ssh_transport,decrypt,2}, [{['_','_'], [], [{return_trace}]}]}
+ ]],
+ {ok, TracerPid}.
+
+
+%%%----------------
+init_trace(MFA = {Module,_,_}, TP) ->
+ case code:is_loaded(Module) of
+ false -> code:load_file(Module);
+ _ -> ok
+ end,
+ erlang:trace_pattern(MFA, TP, [local]).
+
+
+trace_loop() ->
+ trace_loop([]).
+
+trace_loop(L) ->
+ receive
+ {trace_ts, Pid, call, {M,F,Args}, TS} = Ev ->
+ cond_pal(Ev),
+ trace_loop(save_event(call, Pid, {M,F,Args}, TS, L));
+ {trace_ts, Pid, return_from, {M,F,Arity}, Ret, TS} = Ev ->
+ cond_pal(Ev),
+ trace_loop(save_event(return_from, Pid, {M,F,Arity,Ret}, TS, L));
+ {get_trace_list, From} ->
+ From ! {trace_list, L},
+ trace_loop(L)
+
+ ; Other -> io:format('~p got ~p~n',[self(),Other]), trace_loop(L)
+ end.
+
+%%cond_pal(Ev) -> ct:pal("~p",[Ev]).
+cond_pal(Ev) -> ok.
+
+
+save_event(_Type, _Pid, MFA, TimeStamp, L) ->
+ try
+ event_name(MFA)
+ of
+ {Tag, 'TS'} -> [{Tag,TimeStamp} | L];
+ Val -> [Val | L]
+ catch
+ _:_ -> L
+ end.
+
+event_name({ssh_acceptor,handle_connection,_}) -> {tcp_accept, 'TS'};
+event_name({ssh_connection_handler,hello,[socket_control|_]}) -> {{send,hello}, 'TS'};
+event_name({ssh_connection_handler,hello,[{version_exchange,_}|_]}) -> {{recv,hello}, 'TS'};
+event_name({ssh_message,encode,[Msg]}) -> {{send,element(1,Msg)}, 'TS'};
+event_name({ssh_message,decode,1,
+ #ssh_msg_channel_request{request_type=ReqType}}) -> {{recv,{ssh_msg_channel_request,ReqType}}, 'TS'};
+event_name({ssh_message,decode,1,Return}) -> {{recv,element(1,Return)}, 'TS'};
+event_name({ssh_transport,select_algorithm,3,{ok,Algs}}) -> {algorithms,Algs};
+event_name({ssh_transport,encrypt,[S,Data]}) -> {{{encrypt,S#ssh.encrypt},start, {S#ssh.send_sequence,size(Data)}}, 'TS'};
+event_name({ssh_transport,encrypt,2,{S,Ret}}) -> {{{encrypt,S#ssh.encrypt},stop, {S#ssh.send_sequence,size(Ret) }}, 'TS'};
+event_name({ssh_transport,decrypt,[S,Data]}) -> {{{decrypt,S#ssh.decrypt},start, {S#ssh.recv_sequence,size(Data)}}, 'TS'};
+event_name({ssh_transport,decrypt,2,{S,Ret}}) -> {{{decrypt,S#ssh.decrypt},stop, {S#ssh.recv_sequence,size(Ret) }}, 'TS'}.
+
+
+now2sec({A,B,C}) -> A*1000000 + B + C/1000000.
+
+now2micro_sec({A,B,C}) -> (A*1000000 + B)*1000000 + C.
+
+now_diff({A1,B1,C1}, {A0,B0,C0}) -> {A1-A0, B1-B0, C1-C0}.
+