diff options
Diffstat (limited to 'lib/megaco/examples/meas/megaco_codec_mstone1.erl')
-rw-r--r-- | lib/megaco/examples/meas/megaco_codec_mstone1.erl | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone1.erl b/lib/megaco/examples/meas/megaco_codec_mstone1.erl new file mode 100644 index 0000000000..9ab7822df8 --- /dev/null +++ b/lib/megaco/examples/meas/megaco_codec_mstone1.erl @@ -0,0 +1,408 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: mstone measurement +%% +%%---------------------------------------------------------------------- + +-module(megaco_codec_mstone1). + + +%% API +-export([ + start/0, start/1, start/2, + start_flex/0, start_flex/1, start_flex/2, + start_no_drv/0, start_no_drv/1, start_no_drv/2, + start_only_drv/0, start_only_drv/1, start_only_drv/2 + ]). + +%% Internal exports +-export([mstone_runner_init/5]). + + +-define(LIB, megaco_codec_mstone_lib). + +-ifndef(MSTONE_TIME). +-define(MSTONE_TIME, 10). +-endif. +-define(MSTONE_RUN_TIME, timer:minutes(?MSTONE_TIME)). + +-ifndef(MSTONE_VERSION3). +-define(MSTONE_VERSION3, v3). +-endif. +-define(VERSION3, ?MSTONE_VERSION3). + +-ifndef(MSTONE_CODECS). +-define(MSTONE_CODECS, megaco_codec_transform:codecs()). +-endif. + +-define(DEFAULT_MESSAGE_PACKAGE, megaco_codec_transform:default_message_package()). +-define(DEFAULT_FACTOR, 1). +-define(DEFAULT_DRV_INCLUDE, ignore). + +%% -define(VERBOSE_STATS,true). + +-ifndef(MSTONE_RUNNER_MIN_HEAP_SZ). +-define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#ffff). +-endif. +-define(MSTONE_RUNNER_OPTS, + [link, {min_heap_size, ?MSTONE_RUNNER_MIN_HEAP_SZ}]). + +-record(mstone, {id, count, codec, econf, heap_size, reds}). + + +start() -> + start(?DEFAULT_FACTOR). + +start([Factor]) -> + start(?DEFAULT_MESSAGE_PACKAGE, Factor); +start([MessagePackage, Factor]) -> + start(MessagePackage, Factor); +start(Factor) -> + start(?DEFAULT_MESSAGE_PACKAGE, Factor). + +start(MessagePackage, Factor) -> + do_start(MessagePackage, Factor, ?DEFAULT_DRV_INCLUDE). + + +start_flex() -> + start_flex(?DEFAULT_FACTOR). + +start_flex([Factor]) -> + start_flex(?DEFAULT_MESSAGE_PACKAGE, Factor); +start_flex([MessagePackage, Factor]) -> + start_flex(MessagePackage, Factor); +start_flex(Factor) -> + start_flex(?DEFAULT_MESSAGE_PACKAGE, Factor). + +start_flex(MessagePackage, Factor) -> + do_start(MessagePackage, Factor, flex). + + +start_only_drv() -> + start_only_drv(?DEFAULT_FACTOR). + +start_only_drv([Factor]) -> + start_only_drv(?DEFAULT_MESSAGE_PACKAGE, Factor); +start_only_drv([MessagePackage, Factor]) -> + start_only_drv(MessagePackage, Factor); +start_only_drv(Factor) -> + start_only_drv(?DEFAULT_MESSAGE_PACKAGE, Factor). + +start_only_drv(MessagePackage, Factor) -> + do_start(MessagePackage, Factor, only_drv). + + +start_no_drv() -> + start_no_drv(?DEFAULT_FACTOR). + +start_no_drv([Factor]) -> + start_no_drv(?DEFAULT_MESSAGE_PACKAGE, Factor); +start_no_drv([MessagePackage, Factor]) -> + start_no_drv(MessagePackage, Factor); +start_no_drv(Factor) -> + start_no_drv(?DEFAULT_MESSAGE_PACKAGE, Factor). + +start_no_drv(MessagePackage, Factor) -> + do_start(MessagePackage, Factor, no_drv). + + +do_start(MessagePackageRaw, FactorRaw, DrvInclude) -> + Factor = parse_factor(FactorRaw), + MessagePackage = parse_message_package(MessagePackageRaw), + mstone_init(MessagePackage, Factor, DrvInclude). + + + +parse_factor(FactorAtom) when is_atom(FactorAtom) -> + case (catch list_to_integer(atom_to_list(FactorAtom))) of + Factor when is_integer(Factor) andalso (Factor > 0) -> + Factor; + _ -> + io:format("ERROR: Bad factor value: ~p~n", [FactorAtom]), + throw({error, {bad_factor, FactorAtom}}) + end; +parse_factor(FactorRaw) when is_list(FactorRaw) -> + case (catch list_to_integer(FactorRaw)) of + Factor when is_integer(Factor) andalso (Factor > 0) -> + Factor; + _ -> + io:format("ERROR: Bad factor value: ~p~n", [FactorRaw]), + throw({error, {bad_factor, FactorRaw}}) + end; +parse_factor(Factor) when is_integer(Factor) andalso (Factor > 0) -> + Factor; +parse_factor(BadFactor) -> + throw({error, {bad_factor, BadFactor}}). + + +parse_message_package(MessagePackageRaw) when is_list(MessagePackageRaw) -> + list_to_atom(MessagePackageRaw); +parse_message_package(MessagePackage) when is_atom(MessagePackage) -> + MessagePackage; +parse_message_package(BadMessagePackage) -> + throw({error, {bad_message_package, BadMessagePackage}}). + + +%% Codecs is a list of megaco codec shortnames: +%% +%% pretty | compact | ber | per | erlang +%% + +mstone_init(MessagePackage, Factor, DrvInclude) -> +%% io:format("mstone_init -> entry with" +%% "~n MessagePackage: ~p" +%% "~n Factor: ~p" +%% "~n DrvInclude: ~p" +%% "~n", [MessagePackage, Factor, DrvInclude]), + Codecs = ?MSTONE_CODECS, + mstone_init(MessagePackage, Factor, Codecs, DrvInclude). + +mstone_init(MessagePackage, Factor, Codecs, DrvInclude) -> + Parent = self(), + Pid = spawn( + fun() -> + process_flag(trap_exit, true), + do_mstone(MessagePackage, Factor, Codecs, DrvInclude), + Parent ! {done, self()} + end), + receive + {done, Pid} -> + ok + end. + +do_mstone(MessagePackage, Factor, Codecs, DrvInclude) -> + io:format("~n", []), + ?LIB:set_default_sched_bind(), + ?LIB:display_os_info(), + ?LIB:display_system_info(), + ?LIB:display_app_info(), + io:format("~n", []), + (catch asn1rt_driver_handler:load_driver()), + {Pid, Conf} = ?LIB:start_flex_scanner(), + put(flex_scanner_conf, Conf), + EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, DrvInclude), + EMsgs = duplicate(Factor, EMessages), + MStone = t1(EMsgs), + ?LIB:stop_flex_scanner(Pid), + io:format("~n", []), + io:format("MStone: ~p~n", [MStone]). + +duplicate(N, Elements) -> + duplicate(N, Elements, []). + +duplicate(_N, [], Acc) -> + lists:flatten(Acc); +duplicate(N, [H|T], Acc) -> + duplicate(N, T, [lists:duplicate(N, H)|Acc]). + +t1(EMsgs) -> + io:format(" * starting runners [~w] ", [length(EMsgs)]), + t1(EMsgs, []). + +t1([], Runners) -> + io:format(" done~n * await runners ready ", []), + await_runners_ready(Runners), + io:format(" done~n * now snooze", []), + receive after 5000 -> ok end, + io:format("~n * release them~n", []), + lists:foreach(fun(P) -> P ! {go, self()} end, Runners), + t2(1, [], Runners); +t1([H|T], Runners) -> + Runner = init_runner(H), + io:format(".", []), + t1(T, [Runner|Runners]). + +await_runners_ready([]) -> + ok; +await_runners_ready(Runners) -> + receive + {ready, Runner} -> + io:format(".", []), + %% i("runner ~w ready", [Runner]), + await_runners_ready(lists:delete(Runner, Runners)); + {'EXIT', Pid, Reason} -> + case lists:member(Pid, Runners) of + true -> + io:format("~nERROR: " + "received (unexpected) exit signal " + "from from runner ~p:" + "~n~p~n", [Pid, Reason]), + exit(Reason); + false -> + await_runners_ready(Runners) + end + end. + +-ifdef(VERBOSE_STATS). +print_runner_stats(RunnerStats) -> + Sorted = lists:keysort(2, RunnerStats), + lists:foreach(fun(#mstone{id = Id, + count = Num, + codec = Codec, + econf = EConf, + heap_size = HeapSz, + reds = Reds}) -> + i("runner: ~w" + "~n Count: ~w" + "~n Codec: ~w" + "~n Encoding config: ~p" + "~n Heap size: ~p" + "~n Reductions: ~p", + [Id, Num, Codec, EConf, HeapSz, Reds]) end, + Sorted), + ok. +-else. +print_runner_stats(_) -> + ok. +-endif. + +t2(_, Acc, []) -> + i("~n~w runners", [length(Acc)]), + print_runner_stats(Acc), + + HeapSzAcc = lists:sort([HS || #mstone{heap_size = HS} <- Acc]), + i("Runner heap size data:" + "~n Min: ~w" + "~n Max: ~w" + "~n Avg: ~w", + [hd(HeapSzAcc), + hd(lists:reverse(HeapSzAcc)), + (lists:sum(HeapSzAcc) div length(HeapSzAcc))]), + + RedsAcc = lists:sort([R || #mstone{reds = R} <- Acc]), + i("Runner reductions data:" + "~n Min: ~w" + "~n Max: ~w" + "~n Avg: ~w", + [hd(RedsAcc), + hd(lists:reverse(RedsAcc)), + (lists:sum(RedsAcc) div length(RedsAcc))]), + + lists:sum([Num || #mstone{count = Num} <- Acc]); +t2(N, Acc, Runners) -> + receive + {'EXIT', Pid, {runner_done, Codec, Conf, Num, Info}} -> + {value, {_, HeapSz}} = lists:keysearch(heap_size, 1, Info), + {value, {_, Reds}} = lists:keysearch(reductions, 1, Info), + MStone = #mstone{id = N, + count = Num, + codec = Codec, + econf = Conf, + heap_size = HeapSz, + reds = Reds}, + t2(N + 1, [MStone|Acc], lists:delete(Pid, Runners)) + end. + +init_runner({Codec, Mod, Conf, Msgs}) -> + Conf1 = runner_conf(Conf), + Conf2 = [{version3,?VERSION3}|Conf1], + Pid = spawn_opt(?MODULE, mstone_runner_init, + [Codec, self(), Mod, Conf2, Msgs], + ?MSTONE_RUNNER_OPTS), + Pid. + +runner_conf([flex_scanner]) -> + get(flex_scanner_conf); +runner_conf(Conf) -> + Conf. + + + +detect_versions(Codec, _Conf, [], []) -> + exit({no_messages_found_for_codec, Codec}); +detect_versions(_Codec, _Conf, [], Acc) -> + lists:reverse(Acc); +detect_versions(Codec, Conf, [{_Name, Bin}|Bins], Acc) -> + Data = ?LIB:detect_version(Codec, Conf, Bin), + detect_versions(Codec, Conf, Bins, [Data|Acc]). + + +mstone_runner_init(_Codec, Parent, Mod, Conf, Msgs0) -> + Msgs = detect_versions(Mod, Conf, Msgs0, []), + warmup(Mod, Conf, Msgs, []), + Parent ! {ready, self()}, + receive + {go, Parent} -> + ok + end, + erlang:send_after(?MSTONE_RUN_TIME, self(), stop), + mstone_runner_loop(Parent, Mod, Conf, 0, Msgs). + +mstone_runner_loop(Parent, Mod, Conf, N, Msgs1) -> + receive + stop -> + exit({runner_done, Mod, Conf, N, mstone_runner_process_info()}) + after 0 -> + {Inc, Msgs2} = mstone_all(Mod, Conf, Msgs1, []), + mstone_runner_loop(Parent, Mod, Conf, N+Inc, Msgs2) + end. + +mstone_runner_process_info() -> + PI = process_info(self()), + FL = [heap_size, stack_size, reductions], + lists:filter(fun({Key, _}) -> lists:member(Key, FL) end, PI). + + +mstone_all(_Codec, _Conf, [], Acc) -> + {length(Acc), lists:reverse(Acc)}; +mstone_all(Codec, Conf, [{V, Bin}|Bins], Acc) when is_binary(Bin) -> + {ok, Msg} = apply(Codec, decode_message, [Conf, V, Bin]), + mstone_all(Codec, Conf, Bins, [{V, Msg}|Acc]); +mstone_all(Codec, Conf, [{V, Msg}|Msgs], Acc) -> + {ok, Bin} = apply(Codec, encode_message, [Conf, V, Msg]), + mstone_all(Codec, Conf, Msgs, [{V, Bin}|Acc]). + +warmup(_Codec, _Conf, [], Acc) -> + lists:reverse(Acc); +warmup(Codec, Conf, [{V, M}|Msgs], Acc) -> +%% io:format("~p warmup -> entry with" +%% "~n Codec: ~p" +%% "~n Conf: ~p" +%% "~n", [self(), Codec, Conf]), + case (catch apply(Codec, decode_message, [Conf, V, M])) of + {ok, Msg} -> + case (catch apply(Codec, encode_message, [Conf, V, Msg])) of + {ok, Bin} -> + warmup(Codec, Conf, Msgs, [Bin|Acc]); + EncodeError -> + emsg("failed encoding message: ~n~p", [EncodeError]) + end; + DecodeError -> + emsg("failed decoding message: " + "~n DecodeError: ~p" + "~n V: ~p" + "~n M: ~p", [DecodeError, V, M]) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +emsg(F, A) -> + error_logger:error_msg(F ++ "~n", A). + +%% i(F) -> +%% i(F, []). +i(F, A) -> + io:format(F ++ "~n", A). + |