aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/examples/meas/megaco_codec_mstone2.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/examples/meas/megaco_codec_mstone2.erl')
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone2.erl400
1 files changed, 400 insertions, 0 deletions
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone2.erl b/lib/megaco/examples/meas/megaco_codec_mstone2.erl
new file mode 100644
index 0000000000..f3588f2e3d
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_mstone2.erl
@@ -0,0 +1,400 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%
+%% megaco_codec_mstone2:start().
+%% megaco_codec_mstone2:start_no_drv().
+%% megaco_codec_mstone2:start_only_drv().
+%%
+%%----------------------------------------------------------------------
+%% Purpose: mstone 2 measurement
+%% This module implement a simple performence measurment case.
+%% The architecture is as followes:
+%% - One loader process:
+%% It keeps a list of all codec combinations, including
+%% all the messages (in a list) for each codec.
+%% Initially it creates a timer (finished) (circa 10 minutes).
+%% It spawns a worker process for each codec config (it also
+%% creates a monitor to each process so it knows when they
+%% exit). When the result comes in from a process (in the
+%% form of a DOWN message), spawns a new worker process for
+%% this codec config and update's the statistics.
+%% When the finished timer expires, it will stop respawing
+%% the worker processes, and instead just wait for them all
+%% to finish.
+%% The test is finished by printing the statistics.
+%% - A worker process for each codec combination.
+%% This process is spawned by the loader process. It receives
+%% at start a list of messages. It shall decode and then
+%% encode each message. When all messages has been processed
+%% it exits (normally).
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_mstone2).
+
+
+%% Exports
+-export([
+ start/0, start/1,
+ start_flex/0, start_flex/1,
+ start_no_drv/0, start_no_drv/1,
+ start_only_drv/0, start_only_drv/1
+ ]).
+
+
+%%%----------------------------------------------------------------------
+%%% Macros
+%%%----------------------------------------------------------------------
+
+-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).
+
+-ifndef(MSTONE_RUNNER_MIN_HEAP_SZ).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#7fff).
+-define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#ffff).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#17ffe).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#1ffff).
+%% -define(MSTONE_RUNNER_OPTS, [link]).
+-endif.
+-define(MSTONE_RUNNER_OPTS,
+ [link, {min_heap_size, ?MSTONE_RUNNER_MIN_HEAP_SZ}]).
+
+
+%%%----------------------------------------------------------------------
+%%% Records
+%%%----------------------------------------------------------------------
+
+-record(codec_data, {ref, mod, config = [], msgs = []}).
+
+-record(state, {timer, running = [], idle = [], flex_handler, flex_conf}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start() ->
+ start(?DEFAULT_MESSAGE_PACKAGE).
+
+start([MessagePackage]) ->
+ do_start(MessagePackage, ?DEFAULT_DRV_INCLUDE);
+start(MessagePackage) ->
+ do_start(MessagePackage, ?DEFAULT_DRV_INCLUDE).
+
+
+start_flex() ->
+ start_flex(?DEFAULT_MESSAGE_PACKAGE).
+
+start_flex([MessagePackage]) ->
+ do_start(MessagePackage, flex);
+start_flex(MessagePackage) ->
+ do_start(MessagePackage, flex).
+
+
+start_no_drv() ->
+ start_no_drv(?DEFAULT_MESSAGE_PACKAGE).
+
+start_no_drv([MessagePackage]) ->
+ do_start(MessagePackage, no_drv);
+start_no_drv(MessagePackage) ->
+ do_start(MessagePackage, no_drv).
+
+
+start_only_drv() ->
+ start_only_drv(?DEFAULT_MESSAGE_PACKAGE).
+
+start_only_drv([MessagePackage]) ->
+ do_start(MessagePackage, only_drv);
+start_only_drv(MessagePackage) ->
+ do_start(MessagePackage, only_drv).
+
+
+do_start(MessagePackageRaw, DrvInclude) ->
+%% io:format("do_start -> entry with"
+%% "~n MessagePackageRaw: ~p"
+%% "~n DrvInclude: ~p"
+%% "~n", [MessagePackageRaw, DrvInclude]),
+ MessagePackage = parse_message_package(MessagePackageRaw),
+ mstone_init(MessagePackage, DrvInclude).
+
+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}}).
+
+
+mstone_init(MessagePackage, DrvInclude) ->
+ io:format("~n", []),
+ ?LIB:set_default_sched_bind(),
+ ?LIB:display_os_info(),
+ ?LIB:display_system_info(),
+ ?LIB:display_app_info(),
+ io:format("~n", []),
+ Ref = erlang:monitor(process,
+ spawn(fun() ->
+ loader(MessagePackage, DrvInclude)
+ end)),
+ receive
+ {'DOWN', Ref, process, _Pid, {done, Result}} ->
+ display_result(Result);
+ {'DOWN', Ref, process, _Pid, Result} ->
+ io:format("Unexpected result:~n~p~n", [Result]),
+ ok
+ end.
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+display_result(Result) ->
+ {value, {worker_cnt, WC}} = lists:keysearch(worker_cnt, 1, Result),
+ CodecStat =
+ [{Mod, Conf, Cnt} || {{codec_cnt, Mod, Conf}, Cnt} <- Result],
+ MStone = lists:sum([Cnt || {_, _, Cnt} <- CodecStat]),
+ io:format("Number of procs spawned: ~w~n"
+ "MStone: ~w~n"
+ "~n", [WC, MStone]),
+ display_worker_result(lists:keysort(3, CodecStat)),
+ ok.
+
+display_worker_result([]) ->
+ io:format("~n", []);
+display_worker_result([{Mod, Conf, Cnt}|Res]) ->
+ io:format("~s: ~w~n", [image_of(Mod, Conf), Cnt]),
+ display_worker_result(Res).
+
+image_of(megaco_per_bin_encoder, Conf) ->
+ bin_image("per_bin", Conf);
+image_of(megaco_ber_bin_encoder, Conf) ->
+ bin_image("ber_bin", Conf);
+image_of(megaco_pretty_text_encoder, Conf) ->
+ text_image("pretty", Conf);
+image_of(megaco_compact_text_encoder, Conf) ->
+ text_image("compact", Conf);
+image_of(megaco_erl_dist_encoder, Conf) ->
+ erl_image("erl_dist", Conf).
+
+bin_image(Bin, Conf) ->
+ Drv =
+ case lists:member(driver, Conf) of
+ true ->
+ [driver];
+ false ->
+ []
+ end,
+ Nat =
+ case lists:member(native, Conf) of
+ true ->
+ [native];
+ false ->
+ []
+ end,
+ io_lib:format("~s ~w", [Bin, Drv ++ Nat]).
+
+text_image(Txt, Conf) ->
+ Flex =
+ case lists:keysearch(flex, 1, Conf) of
+ false ->
+ [];
+ _ ->
+ [flex]
+ end,
+ io_lib:format("~s ~w", [Txt, Flex]).
+
+erl_image(Erl, Conf) ->
+ MC =
+ case lists:member(megaco_compressed, Conf) of
+ true ->
+ [megaco_compressed];
+ false ->
+ []
+ end,
+ C =
+ case lists:member(compressed, Conf) of
+ true ->
+ [compressed];
+ false ->
+ []
+ end,
+ io_lib:format("~s ~w", [Erl, MC ++ C]).
+
+
+%%%----------------------------------------------------------------------
+
+loader(MessagePackage, DrvInclude) ->
+ loader(?MSTONE_CODECS, MessagePackage, DrvInclude).
+
+
+%% Codecs is a list of megaco codec shortnames:
+%%
+%% pretty | compact | ber | per | erlang
+%%
+
+loader(Codecs, MessagePackage, DrvInclude) ->
+ process_flag(trap_exit, true),
+ case (catch init(Codecs, MessagePackage, DrvInclude)) of
+ {ok, State} ->
+ loader_loop(running, State);
+ Error ->
+ exit(Error)
+ end.
+
+init(Codecs, MessagePackage, DrvInclude) ->
+ ets:new(mstone, [set, private, named_table, {keypos, 1}]),
+ ets:insert(mstone, {worker_cnt, 0}),
+ {Pid, FlexConf} = ?LIB:start_flex_scanner(),
+ io:format("prepare messages", []),
+ EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, DrvInclude),
+ io:format("~ninit codec data", []),
+ CodecData = init_codec_data(EMessages, FlexConf),
+ Timer = erlang:send_after(?MSTONE_RUN_TIME, self(), mstone_finished),
+ io:format("~n", []),
+ {ok, #state{timer = Timer,
+ idle = CodecData,
+ flex_handler = Pid,
+ flex_conf = FlexConf}}.
+
+init_codec_data(EMsgs, FlexConf) ->
+ [init_codec_data(Codec, Mod, Conf, Msgs, FlexConf) ||
+ {Codec, Mod, Conf, Msgs} <- EMsgs].
+
+init_codec_data(Codec, Mod, Conf0, Msgs0, FlexConf)
+ when is_atom(Codec) andalso
+ is_atom(Mod) andalso
+ is_list(Conf0) andalso
+ is_list(Msgs0) ->
+ io:format(".", []),
+ Conf = [{version3,?VERSION3}|init_codec_conf(FlexConf, Conf0)],
+ Msgs = [?LIB:detect_version(Mod, Conf, Bin) || {_, Bin} <- Msgs0],
+ ets:insert(mstone, {{codec_cnt, Mod, Conf}, 0}),
+ #codec_data{mod = Mod, config = Conf, msgs = Msgs}.
+
+
+init_codec_conf(FlexConf, [flex_scanner]) ->
+ FlexConf;
+init_codec_conf(_, Conf) ->
+ Conf.
+
+
+%% -- Main loop --
+
+loader_loop(finishing, #state{flex_handler = Pid, running = []}) ->
+ %% we are done
+ io:format("~n", []),
+ ?LIB:stop_flex_scanner(Pid),
+ exit({done, lists:sort(ets:tab2list(mstone))});
+
+loader_loop(finishing, State) ->
+ receive
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ loader_loop(finishing, done_worker(Ref, Codec, Conf, Cnt, State))
+ end;
+
+loader_loop(running, #state{idle = []} = State) ->
+ receive
+ mstone_finished ->
+ loader_loop(finishing, State);
+
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ loader_loop(running, done_worker(Ref, Codec, Conf, Cnt, State))
+ end;
+
+loader_loop(running, State) ->
+ receive
+ mstone_finished ->
+ loader_loop(finishing, State);
+
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ State2 = done_worker(Ref, Codec, Conf, Cnt, State),
+ loader_loop(running, State2)
+
+ after 0 ->
+ loader_loop(running, start_worker(State))
+ end.
+
+done_worker(Ref, Codec, Conf, Cnt,
+ #state{running = Running, idle = Idle} = State) ->
+ %% io:format("worker ~w ~w done with ~w~n", [Codec, Conf, Cnt]),
+ ets:update_counter(mstone, worker_cnt, 1),
+ ets:update_counter(mstone, {codec_cnt, Codec, Conf}, Cnt),
+ Running2 = lists:keydelete(Ref, #codec_data.ref, Running),
+ CD = Running -- Running2,
+ State#state{running = Running2, idle = lists:append(Idle, CD)}.
+
+start_worker(#state{running = Running, idle = [H|T]} = State) ->
+ #codec_data{mod = Codec, config = Conf, msgs = Msgs} = H,
+ Worker = fun() -> worker(Codec, Conf, Msgs, 0) end,
+ Ref = erlang:monitor(process, spawn(Worker)),
+ CD = H#codec_data{ref = Ref},
+ State#state{running = [CD | Running], idle = T}.
+
+
+%%%----------------------------------------------------------------------
+
+worker(Codec, Conf, [], Cnt) ->
+ exit({mstone_done, Codec, Conf, Cnt});
+worker(Codec, Conf, [{V, Msg}|Msgs], Cnt) ->
+ work(Codec, Conf, V, Msg),
+ worker(Codec, Conf, Msgs, Cnt + 1).
+
+work(Codec, Conf, V, M) ->
+ case (catch apply(Codec, decode_message, [Conf, V, M])) of
+ {ok, Msg} ->
+ case (catch apply(Codec, encode_message, [Conf, V, Msg])) of
+ {ok, Bin} when is_binary(Bin) ->
+ ok;
+ EncodeError ->
+ emsg("failed encoding message: ~n~p", [EncodeError]),
+ exit({mstone_worker_encode_failure, EncodeError})
+ end;
+ DecodeError ->
+ emsg("failed decoding message: ~n~p", [DecodeError]),
+ exit({mstone_worker_decode_failure, DecodeError})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+emsg(F, A) ->
+ error_logger:error_msg(F ++ "~n", A).
+
+