From 483aceacd063d0a9b787bf468e795617d52e0507 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 14 Jun 2017 16:53:01 +0200 Subject: Exercise example RFC 4005 dictionary in traffic suite Only exercising the standard dictionaries has missed some problems in the past. --- lib/diameter/test/diameter_traffic_SUITE.erl | 269 ++++++++++++++++++++------- 1 file changed, 202 insertions(+), 67 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 84b41f14b7..0a93033d83 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -35,7 +35,8 @@ end_per_testcase/2]). %% testcases --export([start/1, +-export([rfc4005/1, + start/1, start_services/1, add_transports/1, result_codes/1, @@ -125,7 +126,7 @@ -define(L, atom_to_list). %% Don't use is_record/2 since dictionary hrl's aren't included. -%% (Since they define conflicting reqcords with the same names.) +%% (Since they define conflicting records with the same names.) -define(is_record(Rec, Name), (Name == element(1, Rec))). -define(ADDR, {127,0,0,1}). @@ -144,8 +145,8 @@ %% How to send answers, in a diameter_packet or not. -define(CONTAINERS, [pkt, msg]). -%% Which common dictionary to use in the clients. --define(RFCS, [rfc3588, rfc6733]). +%% Which dictionary to use in the clients. +-define(RFCS, [rfc3588, rfc6733, rfc4005]). %% Whether to decode stringish Diameter types to strings, or leave %% them as binary. @@ -165,7 +166,7 @@ strings, client_service, client_encoding, - client_dict0, + client_dict, client_sender, server_service, server_encoding, @@ -198,8 +199,8 @@ {'Host-IP-Address', [?ADDR]}, {'Vendor-Id', 12345}, {'Product-Name', "OTP/diameter"}, - {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, - {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}, + {'Auth-Application-Id', [0]}, %% common messages + {'Acct-Application-Id', [3]}, %% base accounting {restrict_connections, false}, {string_decode, Decode}, {incoming_maxlen, 1 bsl 21} @@ -209,7 +210,9 @@ || D <- [diameter_gen_base_rfc3588, diameter_gen_base_accounting, diameter_gen_base_rfc6733, - diameter_gen_acct_rfc6733]]]). + diameter_gen_acct_rfc6733, + nas4005], + D /= nas4005 orelse have_nas()]]). -define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_SUCCESS'). @@ -254,7 +257,7 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [start, result_codes, {group, traffic}, empty, stop]. + [rfc4005, start, result_codes, {group, traffic}, empty, stop]. groups() -> [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] @@ -300,9 +303,11 @@ tc(L) -> %% -------------------- init_per_suite(Config) -> - [{sctp, ?util:have_sctp()} | Config]. + [{rfc4005, compile_and_load()}, {sctp, ?util:have_sctp()} | Config]. end_per_suite(_Config) -> + code:delete(nas4005), + code:purge(nas4005), ok. %% -------------------- @@ -322,13 +327,16 @@ init_per_group(sctp = Name, Config) -> end; init_per_group(Name, Config) -> + Nas = proplists:get_value(rfc4005, Config, false), case ?util:name(Name) of + [_,_,D,_,_,_, _, _, _] when D == rfc4005, true /= Nas -> + {skip, rfc4005}; [T,R,D,A,C,S,SS,ST,CS] -> G = #group{transport = T, strings = S, client_service = [$C|?util:unique_string()], client_encoding = R, - client_dict0 = dict0(D), + client_dict = appdict(D), client_sender = CS, server_service = [$S|?util:unique_string()], server_encoding = A, @@ -463,26 +471,45 @@ add_transports(Config) -> | [{packet, hd(?util:scramble([false, raw]))} || T == sctp andalso CS]], [{capabilities_cb, fun capx/2}, - {pool_size, 8}, - {applications, apps(rfc3588)}] + {pool_size, 8} + | server_apps()] ++ [{spawn_opt, {erlang, spawn, []}} || CS]), Cs = [?util:connect(CN, [T, {sender, CS}], LRef, - [{id, Id}, - {capabilities, [{'Origin-State-Id', origin(Id)}]}, - {applications, apps(D)}]) + [{id, Id} + | client_apps(D, [{'Origin-State-Id', origin(Id)}])]) || A <- ?ENCODINGS, C <- ?CONTAINERS, D <- ?RFCS, + D /= rfc4005 orelse have_nas(), Id <- [{A,C}]], %% The server uses the client's Origin-State-Id to decide how to %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). -apps(D0) -> - D = dict0(D0), - [acct(D), D]. +server_apps() -> + B = have_nas(), + [{applications, [diameter_gen_base_rfc3588, + diameter_gen_base_accounting] + ++ [nas4005 || B]}, + {capabilities, [{'Auth-Application-Id', [0] ++ [1 || B]}, %% common, NAS + {'Acct-Application-Id', [3]}]}]. %% accounting + +client_apps(D, Caps) -> + if D == rfc4005 -> + [{applications, [nas4005]}, + {capabilities, [{'Auth-Application-Id', [1]}, %% NAS + {'Acct-Application-Id', []} + | Caps]}]; + true -> + D0 = dict0(D), + [{applications, [acct(D0), D0]}, + {capabilities, Caps}] + end. + +have_nas() -> + false /= code:is_loaded(nas4005). remove_transports(Config) -> #group{client_service = CN, @@ -515,6 +542,11 @@ capx(_, #diameter_caps{origin_host = {OH,DH}}) -> %% =========================================================================== +%% Fail only this testcase if the RFC 4005 dictionary hasn't been +%% successfully compiled and loaded. +rfc4005(Config) -> + true = proplists:get_value(rfc4005, Config). + %% Ensure that result codes have the expected values. result_codes(_Config) -> {2001, 3001, 3002, 3003, 3004, 3007, 3008, 3009, 5001, 5011, 5014} @@ -615,12 +647,10 @@ send_unknown_short(Config, M, RC) -> data = <<17>>}]}], ['ASA', {'Session-Id', _}, {'Result-Code', RC} | Avps] = call(Config, Req), - [#'diameter_base_Failed-AVP'{'AVP' = As}] - = proplists:get_value('Failed-AVP', Avps), - [#diameter_avp{code = 999, - is_mandatory = M, - data = <<17, _/binary>>}] %% extra bits from padding - = As. + [[#diameter_avp{code = 999, + is_mandatory = M, + data = <<17, _/binary>>}]] %% extra bits from padding + = failed_avps(Avps, Config). %% Ditto but set the M flag. send_unknown_mandatory(Config) -> @@ -629,12 +659,10 @@ send_unknown_mandatory(Config) -> data = <<17>>}]}], ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps] = call(Config, Req), - [#'diameter_base_Failed-AVP'{'AVP' = As}] - = proplists:get_value('Failed-AVP', Avps), - [#diameter_avp{code = 999, - is_mandatory = true, - data = <<17>>}] - = As. + [[#diameter_avp{code = 999, + is_mandatory = true, + data = <<17>>}]] + = failed_avps(Avps, Config). %% Ditto, and point the AVP length past the end of the message. Expect %% 5014 instead of 5001. @@ -649,13 +677,11 @@ send_unexpected_mandatory_decode(Config) -> data = <<12:32>>}]}], ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps] = call(Config, Req), - [#'diameter_base_Failed-AVP'{'AVP' = As}] - = proplists:get_value('Failed-AVP', Avps), - [#diameter_avp{code = 27, - is_mandatory = true, - value = 12, - data = <<12:32>>}] - = As. + [[#diameter_avp{code = 27, + is_mandatory = true, + value = 12, + data = <<12:32>>}]] + = failed_avps(Avps, Config). %% Send an containing a faulty Grouped AVP (empty Proxy-Host in %% Proxy-Info) and expect that only the faulty AVP is sent in @@ -667,13 +693,9 @@ send_grouped_error(Config) -> {'Proxy-State', ""}]]}], ['ASA', {'Session-Id', _}, {'Result-Code', ?INVALID_AVP_LENGTH} | Avps] = call(Config, Req), - [#'diameter_base_Failed-AVP'{'AVP' = As}] - = proplists:get_value('Failed-AVP', Avps), - [#diameter_avp{name = 'Proxy-Info', - value = #'diameter_base_Proxy-Info' - {'Proxy-Host' = Empty, - 'Proxy-State' = undefined}}] - = As, + [[#diameter_avp{name = 'Proxy-Info', value = V}]] + = failed_avps(Avps, Config), + {Empty, undefined, []} = proxy_info(V, Config), <<0>> = iolist_to_binary(Empty). %% Send an STR that the server ignores. @@ -729,10 +751,10 @@ send_invalid_avp_length(Config) -> {'User-Name', _}, {'Class', _}, {'Error-Message', _}, - {'Error-Reporting-Host', _}, - {'Failed-AVP', [#'diameter_base_Failed-AVP'{'AVP' = [_]}]} - | _] - = call(Config, Req). + {'Error-Reporting-Host', _} + | Avps] + = call(Config, Req), + [[_]] = failed_avps(Avps, Config). %% Send a request containing 5xxx errors that the server rejects with %% 3xxx. @@ -935,6 +957,29 @@ send_anything(Config) -> %% =========================================================================== +failed_avps(Avps, Config) -> + #group{client_dict = D} = proplists:get_value(group, Config), + [failed_avp(D, T) || T <- proplists:get_value('Failed-AVP', Avps)]. + +failed_avp(nas4005, {'nas_Failed-AVP', As}) -> + As; +failed_avp(_, #'diameter_base_Failed-AVP'{'AVP' = As}) -> + As. + +proxy_info(Rec, Config) -> + #group{client_dict = D} = proplists:get_value(group, Config), + if D == nas4005 -> + {'nas_Proxy-Info', H, S, As} + = Rec, + {H,S,As}; + true -> + #'diameter_base_Proxy-Info'{'Proxy-Host' = H, + 'Proxy-State' = S, + 'AVP' = As} + = Rec, + {H,S,As} + end. + group(Config) -> #group{} = proplists:get_value(group, Config). @@ -956,7 +1001,7 @@ call(Config, Req, Opts) -> Name = proplists:get_value(testcase, Config), #group{client_service = CN, client_encoding = ReqEncoding, - client_dict0 = Dict0} + client_dict = Dict0} = Group = group(Config), diameter:call(CN, @@ -996,9 +1041,21 @@ msg([H|T], record, Dict) -> msg(Msg, _, _) -> Msg. +appdict(rfc4005) -> + nas4005; +appdict(D) -> + dict0(D). + dict0(D) -> ?A("diameter_gen_base_" ++ ?L(D)). +dict(Msg, nas4005 = D) -> + if 'answer-message' == hd(Msg); + ?is_record(Msg, 'diameter_base_answer-message') -> + diameter_gen_base_rfc3588; + true -> + D + end; dict(Msg, Dict0) when 'ACR' == hd(Msg); 'ACA' == hd(Msg); @@ -1016,7 +1073,7 @@ acct(diameter_gen_base_rfc6733) -> %% Set only values that aren't already. set(_, [H|T], Vs) -> [H | Vs ++ T]; -set(#group{client_dict0 = Dict0} = _Group, Rec, Vs) -> +set(#group{client_dict = Dict0} = _Group, Rec, Vs) -> Dict = dict(Rec, Dict0), lists:foldl(fun({F,_} = FV, A) -> set(Dict, Dict:'#get-'(F, A), FV, A) @@ -1086,7 +1143,7 @@ log(#diameter_packet{bin = Bin} = P, T) %% prepare/4 -prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) +prepare(Pkt, Caps, N, #group{client_dict = Dict0} = Group) when N == send_unknown_short_mandatory; N == send_unknown_short -> Req = prepare(Pkt, Caps, Group), @@ -1106,7 +1163,7 @@ prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) <> = Bin, E#diameter_packet{bin = <>}; -prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) +prepare(Pkt, Caps, N, #group{client_dict = Dict0} = Group) when N == send_long_avp_length; N == send_short_avp_length; N == send_zero_avp_length -> @@ -1132,7 +1189,7 @@ prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) T/binary, Hdr/binary, AL:24, Data/binary>>}; -prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) +prepare(Pkt, Caps, N, #group{client_dict = Dict0} = Group) when N == send_invalid_avp_length; N == send_invalid_reject -> Req = prepare(Pkt, Caps, Group), @@ -1147,7 +1204,7 @@ prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group) <> = H0, %% assert E#diameter_packet{bin = <>}; -prepare(Pkt, Caps, send_unexpected_mandatory, #group{client_dict0 = Dict0} +prepare(Pkt, Caps, send_unexpected_mandatory, #group{client_dict = Dict0} = Group) -> Req = prepare(Pkt, Caps, Group), #diameter_packet{bin = <>} @@ -1157,7 +1214,7 @@ prepare(Pkt, Caps, send_unexpected_mandatory, #group{client_dict0 = Dict0} Avp = <>, E#diameter_packet{bin = <>}; -prepare(Pkt, Caps, send_grouped_error, #group{client_dict0 = Dict0} +prepare(Pkt, Caps, send_grouped_error, #group{client_dict = Dict0} = Group) -> Req = prepare(Pkt, Caps, Group), #diameter_packet{bin = Bin} @@ -1189,14 +1246,14 @@ prepare(Pkt, Caps, send_grouped_error, #group{client_dict0 = Dict0} Payload/binary, T/binary>>}; -prepare(Pkt, Caps, send_unsupported, #group{client_dict0 = Dict0} = Group) -> +prepare(Pkt, Caps, send_unsupported, #group{client_dict = Dict0} = Group) -> Req = prepare(Pkt, Caps, Group), #diameter_packet{bin = <>} = E = diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}), E#diameter_packet{bin = <>}; -prepare(Pkt, Caps, send_unsupported_app, #group{client_dict0 = Dict0} +prepare(Pkt, Caps, send_unsupported_app, #group{client_dict = Dict0} = Group) -> Req = prepare(Pkt, Caps, Group), #diameter_packet{bin = <>} @@ -1225,6 +1282,7 @@ prepare(Pkt, Caps, _Name, Group) -> prepare(#diameter_packet{msg = Req}, Caps, Group) when ?is_record(Req, diameter_base_accounting_ACR); + ?is_record(Req, nas_ACR); 'ACR' == hd(Req) -> #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} @@ -1237,6 +1295,7 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) prepare(#diameter_packet{msg = Req}, Caps, Group) when ?is_record(Req, diameter_base_ASR); + ?is_record(Req, nas_ASR); 'ASR' == hd(Req) -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} @@ -1250,6 +1309,7 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) prepare(#diameter_packet{msg = Req}, Caps, Group) when ?is_record(Req, diameter_base_STR); + ?is_record(Req, nas_STR); 'STR' == hd(Req) -> #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} @@ -1262,6 +1322,7 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) prepare(#diameter_packet{msg = Req}, Caps, Group) when ?is_record(Req, diameter_base_RAR); + ?is_record(Req, nas_RAR); 'RAR' == hd(Req) -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} @@ -1287,7 +1348,7 @@ handle_answer(Pkt, Req, [$C|_], Peer, {send_detach = Name, Group}, _, X) -> {Pid, Ref} = X, Pid ! {Ref, answer(Pkt, Req, Peer, Name, Group)}. -answer(Pkt, Req, _Peer, Name, #group{client_dict0 = Dict0}) -> +answer(Pkt, Req, _Peer, Name, #group{client_dict = Dict0}) -> #diameter_packet{header = H, msg = Ans, errors = Es} = Pkt, ApplId = app(Req, Name, Dict0), #diameter_header{application_id = ApplId} = H, %% assert @@ -1343,20 +1404,68 @@ handle_request(#diameter_packet{header = H, msg = M, avps = As}, V = EI bsr B, %% assert V = HI bsr B, %% #diameter_caps{origin_state_id = {_,[Id]}} = Caps, - answer(origin(Id), request(M, [H|As], Caps)). + wrap(origin(Id), H, request(nas_to_base(M, H), [H|As], Caps)). -answer(T, {Tag, Action, Post}) -> - {Tag, answer(T, Action), Post}; -answer(_, {reply, [#diameter_header{} | _]} = T) -> +wrap(T, H, {Tag, Action, Post}) -> + {Tag, wrap(T, H, Action), Post}; +wrap(_, _, {reply, [#diameter_header{} | _]} = T) -> T; -answer({A,C}, {reply, Ans}) -> - answer(C, {reply, msg(Ans, A, diameter_gen_base_rfc3588)}); -answer(pkt, {reply, Ans}) +wrap({A,C}, H, {reply, Ans}) -> + Msg = msg(Ans, A, diameter_gen_base_rfc3588), + wrap(C, H, {reply, base_to_nas(Msg, H)}); +wrap(pkt, _, {reply, Ans}) when not is_record(Ans, diameter_packet) -> {reply, #diameter_packet{msg = Ans}}; -answer(_, T) -> +wrap(_, _, T) -> T. +%% nas_to_base/1 +%% +%% Map an RFC 4005 message to RFC 3588, to return the same answer in +%% both cases. + +nas_to_base(Rec, #diameter_header{application_id = 1}) -> + [R | Values] = nas4005:'#get-'(Rec), + "nas_" ++ Name = ?L(R), + {D, RN} = case Name of + "ACR" -> + {diameter_gen_base_accounting, + diameter_base_accounting_ACR}; + _ -> + {diameter_gen_base_rfc3588, + ?A("diameter_base_" ++ Name)} + end, + Fs = D:'#info-'(RN), + D:'#new-'([RN | [T || {F,_} = T <- Values, lists:member(F, Fs)]]); + +nas_to_base(Rec, _) -> + Rec. + +%% base_to_nas/2 + +base_to_nas(#diameter_packet{msg = Msg} = Pkt, H) -> + Pkt#diameter_packet{msg = base_to_nas(Msg, H)}; + +base_to_nas(Rec, #diameter_header{application_id = 1}) + when is_tuple(Rec), not ?is_record(Rec, 'diameter_base_answer-message') -> + D = case element(1, Rec) of + diameter_base_accounting_ACA -> + diameter_gen_base_accounting; + _ -> + diameter_gen_base_rfc3588 + end, + [R | Values] = D:'#get-'(Rec), + "diameter_base_" ++ N = ?L(R), + Name = ?A("nas_" ++ if N == "accounting_ACA" -> + "ACA"; + true -> + N + end), + nas4005:'#new-'([Name | Values]); + +base_to_nas(Msg, _) -> + Msg. + %% request/3 %% send_experimental_result @@ -1523,3 +1632,29 @@ message(ack, <<_:32, 1, _/bits>>, _) -> %% sent answer or discarded request message(ack, _, N) -> [0 =< N, fun ?MODULE:message/3, N+1]. + +%% ------------------------------------------------------------------------ + +compile_and_load() -> + try + Path = hd([P || H <- [[here(), ".."], [code:lib_dir(diameter)]], + P <- [filename:join(H ++ ["examples", + "dict", + "rfc4005_nas.dia"])], + {ok, _} <- [file:read_file_info(P)]]), + {ok, [Forms]} + = diameter_make:codec(Path, [return, + forms, + {name, "nas4005"}, + {prefix, "nas"}, + {inherits, "common/diameter_gen_base_rfc3588"}]), + {ok, nas4005, Bin, []} = compile:forms(Forms, [debug_info, return]), + {module, nas4005} = code:load_binary(nas4005, "nas4005", Bin), + true + catch + E:R -> + {E, R, erlang:get_stacktrace()} + end. + +here() -> + filename:dirname(code:which(?MODULE)). -- cgit v1.2.3 From c63f31deeff7eea054ff3b84b73c1b5b03d5aec6 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 26 Jul 2017 14:17:37 +0200 Subject: Fix message_cb in traffic suite Matched a byte instead of a bit, and increment/decrement wasn't symmetric. Allow more requests since some requests timeout. Bungled in commit 09089872. --- lib/diameter/test/diameter_traffic_SUITE.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 0a93033d83..dd0dfc776d 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -467,7 +467,7 @@ add_transports(Config) -> LRef = ?util:listen(SN, [T, {sender, SS}, - {message_cb, ST andalso {?MODULE, message, [4]}} + {message_cb, ST andalso {?MODULE, message, [0]}} | [{packet, hd(?util:scramble([false, raw]))} || T == sctp andalso CS]], [{capabilities_cb, fun capx/2}, @@ -1614,8 +1614,8 @@ message(Dir, #diameter_packet{bin = Bin}, N) -> message(Dir, Bin, N); %% incoming request -message(recv, <<_:32, 1, _/bits>> = Bin, N) -> - [Bin, 1 < N, fun ?MODULE:message/3, N-1]; +message(recv, <<_:32, 1:1, _/bits>> = Bin, N) -> + [Bin, N < 16, fun ?MODULE:message/3, N+1]; %% incoming answer message(recv, Bin, _) -> @@ -1626,12 +1626,12 @@ message(send, Bin, _) -> [Bin]; %% sent request -message(ack, <<_:32, 1, _/bits>>, _) -> +message(ack, <<_:32, 1:1, _/bits>>, _) -> []; %% sent answer or discarded request message(ack, _, N) -> - [0 =< N, fun ?MODULE:message/3, N+1]. + [N =< 16, fun ?MODULE:message/3, N-1]. %% ------------------------------------------------------------------------ -- cgit v1.2.3 From b9f2d5a867806563c11f8b13e7977f8d03b64a54 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 3 Jul 2017 11:49:23 +0200 Subject: Fix obsolete diameter_gen.hrl comments Most of the contents were moved to module diameter_gen in commit 205521d3. --- lib/diameter/src/base/diameter_codec.erl | 2 +- lib/diameter/src/compiler/diameter_codegen.erl | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 82fa796e69..93c1b28f4c 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -29,7 +29,7 @@ msg_name/2, msg_id/1]). -%% Towards generated encoders (from diameter_gen.hrl). +%% towards diameter_gen -export([pack_data/2, pack_avp/2]). diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index f56e4a5249..4e6fe32d69 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -21,15 +21,14 @@ -module(diameter_codegen). %% -%% This module generates erl/hrl files for encode/decode modules -%% from the orddict parsed from a dictionary file (.dia) by -%% diameter_dict_util. The generated code is simple (one-liners), -%% the generated functions being called by code included iin the -%% generated modules from diameter_gen.hrl. The orddict itself is -%% returned by dict/0 in the generated module and diameter_dict_util -%% calls this function when importing dictionaries as a consequence -%% of @inherits sections. That is, @inherits introduces a dependency -%% on the beam file of another dictionary. +%% This module generates erl/hrl files for encode/decode modules from +%% the orddict parsed from a dictionary file by diameter_dict_util. +%% The generated code is simple (one-liners), and is called from +%% diameter_gen. The orddict itself is returned by dict/0 in the +%% generated module and diameter_dict_util calls this function when +%% importing dictionaries as a consequence of @inherits sections. That +%% is, @inherits introduces a dependency on the beam file of another +%% dictionary. %% -export([from_dict/4, -- cgit v1.2.3 From e30c38a44bbe2872e5b9b0ad46774c19b6af5292 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 3 Jul 2017 16:40:51 +0200 Subject: Count AVP arities during decode Instead of after, during the check that AVPs have sufficient arity. This makes the arity checks independent of the record decode, which will allow the latter to be made optional. --- lib/diameter/src/base/diameter_gen.erl | 246 ++++++++++++++++++--------------- 1 file changed, 132 insertions(+), 114 deletions(-) diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index e832832876..6f11583868 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -172,14 +172,17 @@ enc_AVP(_Name, {_Dict, _AvpName, _Data} = T, Opts, _) -> when Failed :: [{5000..5999, #diameter_avp{}}]. decode_avps(Name, Recs, #{module := Mod} = Opts) -> - {Avps, {Rec, Failed}} + {Avps, {Rec, AM, Failed}} = mapfoldl(fun(T,A) -> decode(Name, Opts, Mod, T, A) end, - {newrec(Mod, Name), []}, + {newrec(Mod, Name), #{}, []}, Recs), - {Rec, Avps, Failed ++ missing(Rec, Name, Failed, Opts, Mod)}. + %% AM counts the number of top-level AVPs, which missing/4 then + %% uses when adding 5005 errors. + {Rec, Avps, Failed ++ missing(Name, Opts, Mod, AM)}. + %% Append 5005 errors so that errors are reported in the order %% encountered. Failed-AVP should typically contain the first -%% encountered error accordg to the RFC. +%% error encountered. %% mapfoldl/3 %% @@ -194,6 +197,8 @@ mapfoldl(F, Acc0, [T|Rest], List) -> mapfoldl(_, Acc, [], List) -> {List, Acc}. +%% missing/4 + %% 3588: %% %% DIAMETER_MISSING_AVP 5005 @@ -204,57 +209,41 @@ mapfoldl(_, Acc, [], List) -> %% Vendor-Id if applicable. The value field of the missing AVP %% should be of correct minimum length and contain zeros. -missing(Rec, Name, Failed, Opts, Mod) -> - Avps = lists:foldl(fun({_, #diameter_avp{code = C, vendor_id = V}}, A) -> - maps:put({C,V}, true, A) - end, - maps:new(), - Failed), - missing(Mod:avp_arity(Name), tl(tuple_to_list(Rec)), Avps, Opts, Mod, []). - -missing([{Name, Arity} | As], [Value | Vs], Avps, Opts, Mod, Acc) -> - missing(As, - Vs, - Avps, - Opts, - Mod, - case - [H || missing_arity(Arity, Value), - {C,_,V} = H <- [Mod:avp_header(Name)], - not maps:is_key({C,V}, Avps)] - of - [H] -> - [{5005, empty_avp(Name, H, Opts, Mod)} | Acc]; - [] -> - Acc - end); - -missing([], [], _, _, _, Acc) -> - Acc. - -%% Maximum arities have already been checked in building the record. - -missing_arity(1, V) -> - V == undefined; -missing_arity({0, _}, _) -> - false; -missing_arity({1, _}, L) -> - [] == L; -missing_arity({Min, _}, L) -> - not has_prefix(Min, L). - -%% Compare a non-negative integer and the length of a list without -%% computing the length. -has_prefix(0, _) -> - true; -has_prefix(_, []) -> +missing(Name, Opts, Mod, AM) -> + lists:foldl(fun(T,A) -> missing(T, AM, Opts, Mod, A) end, + [], + Mod:avp_arity(Name)). + +%% missing/5 + +missing({Name, Arity}, AM, Opts, Mod, Acc) -> + case missing(Name, Arity, AM) of + true -> [{5005, empty_avp(Name, Opts, Mod)} | Acc]; + false -> Acc + end. + +%% missing/3 + +missing(Name, Arity, AM) -> + 'AVP' /= Name andalso too_few(Name, Arity, AM). + +%% too_few/3 +%% +%% Maximum arities have already been checked during the decode. + +too_few(_, {0, _}, _) -> false; -has_prefix(N, [_|L]) -> - has_prefix(N-1, L). -%% empty_avp/4 +too_few(FieldName, 1, AM) -> + not maps:is_key(FieldName, AM); + +too_few(FieldName, {M, _}, AM) -> + maps:get(FieldName, AM, 0) < M. -empty_avp(Name, {Code, Flags, VId}, Opts, Mod) -> +%% empty_avp/3 + +empty_avp(Name, Opts, Mod) -> + {Code, Flags, VId} = Mod:avp_header(Name), {Name, Type} = Mod:avp_name(Code, VId), #diameter_avp{name = Name, code = Code, @@ -280,8 +269,27 @@ decode(Name, Mod, #diameter_avp{code = Code, vendor_id = Vid} = Avp, - Acc) -> - decode(Name, Opts, Mod, Mod:avp_name(Code, Vid), Avp, Acc). + {Rec, AM, Failed}) -> + T = Mod:avp_name(Code, Vid), + decode(Name, Opts, Mod, T, Avp, {Rec, incr(field(T), AM), Failed}). + +%% field/1 + +field({AvpName, _Type}) -> + AvpName; + +field('AVP' = A) -> + A. + +%% incr/2 + +incr(Key, Map) -> + maps:update_with(Key, fun incr/1, 1, Map). + +%% incr/1 + +incr(N) -> + N + 1. %% decode/6 @@ -352,15 +360,13 @@ decode(Name, Opts0, Mod, {AvpName, Type}, Avp, Acc) -> %% decode is packed into 'AVP'. %% Reset the dictionary for best-effort decode of Failed-AVP. - DecMod = if Failed -> - AppMod; - true -> - Mod + DecMod = if Failed -> AppMod; + true -> Mod end, - %% On decode, a Grouped AVP is represented as a #diameter_avp{} - %% list with AVP as head and component AVPs as tail. On encode, - %% data can be a list of component AVPs. + %% A Grouped AVP is represented as a #diameter_avp{} list with AVP + %% as head and component AVPs as tail. On encode, data can be a + %% list of component AVPs. try avp_decode(Data, AvpName, Opts, DecMod, Mod) of {Rec, As} when Type == 'Grouped' -> @@ -425,7 +431,7 @@ trim(Avp) -> %% decode_error/7 -decode_error(Name, [_ | Rec], _, #{failed_avp := true} = Opts, Mod, Avp, Acc) -> +decode_error(Name, [_|Rec], _, #{failed_avp := true} = Opts, Mod, Avp, Acc) -> decode_AVP(Name, Avp#diameter_avp{value = Rec}, Opts, Mod, Acc); decode_error(Name, _, _, #{failed_avp := true} = Opts, Mod, Avp, Acc) -> @@ -437,24 +443,25 @@ decode_error(_, [Error | _], ComponentAvps, _, _, Avp, Acc) -> decode_error(_, Error, ComponentAvps, _, _, Avp, Acc) -> decode_error(Error, Avp, Acc, ComponentAvps). -%% decode_error/5 +%% decode_error/6 decode_error(Name, _Reason, #{failed_avp := true} = Opts, Mod, Avp, Acc) -> decode_AVP(Name, Avp, Opts, Mod, Acc); -decode_error(Name, Reason, Opts, Mod, Avp, {Rec, Failed}) -> +decode_error(Name, Reason, Opts, Mod, Avp, {Rec, AM, Failed}) -> Stack = diameter_lib:get_stacktrace(), + AvpName = Avp#diameter_avp.name, diameter_lib:log(decode_error, ?MODULE, ?LINE, - {Reason, Name, Avp#diameter_avp.name, Mod, Stack}), - {Avp, {Rec, [rc(Reason, Avp, Opts, Mod) | Failed]}}. + {Reason, Name, AvpName, Mod, Stack}), + {Avp, {Rec, AM, [rc(Reason, Avp, Opts, Mod) | Failed]}}. %% decode_error/4 -decode_error({RC, ErrorData}, Avp, {Rec, Failed}, ComponentAvps) -> +decode_error({RC, ErrorData}, Avp, {Rec, AM, Failed}, ComponentAvps) -> E = Avp#diameter_avp{data = [ErrorData]}, - {[Avp | trim(ComponentAvps)], {Rec, [{RC, E} | Failed]}}. + {[Avp | trim(ComponentAvps)], {Rec, AM, [{RC, E} | Failed]}}. %% set_strict/3 @@ -490,8 +497,8 @@ decode_AVP(Name, Avp, Opts, Mod, Acc) -> %% DIAMETER_INVALID_AVP_LENGTH (5014). A module specified to a %% @custom_types tag in a dictionary file can also raise an error of %% this form. -rc({'DIAMETER', 5014 = RC, _}, #diameter_avp{name = AvpName} = Avp, Opts, Mod) -> - {RC, Avp#diameter_avp{data = Mod:empty_value(AvpName, Opts)}}; +rc({'DIAMETER', 5014 = RC, _}, #diameter_avp{name = AvpName} = A, Opts, Mod) -> + {RC, A#diameter_avp{data = Mod:empty_value(AvpName, Opts)}}; %% 3588: %% @@ -531,20 +538,33 @@ pack_avp(_, Arity, #diameter_avp{name = AvpName} = Avp, _Opts, Mod, Acc) -> %% type. pack_AVP(_, #diameter_avp{data = {5014 = RC, Data}} = Avp, _, _, Acc) -> - {Rec, Failed} = Acc, - {Rec, [{RC, Avp#diameter_avp{data = Data}} | Failed]}; + {Rec, AM, Failed} = Acc, + {Rec, AM, [{RC, Avp#diameter_avp{data = Data}} | Failed]}; pack_AVP(Name, Avp, Opts, Mod, Acc) -> - pack_arity(Name, pack_arity(Name, Opts, Mod, Avp), Avp, Mod, Acc). - -%% pack_arity/5 + Arity = pack_arity(Name, Opts, Mod, Avp), + if 0 == Arity -> + M = Avp#diameter_avp.is_mandatory, + {Rec, AM, Failed} = Acc, + {Rec, AM, [{if M -> 5001; true -> 5008 end, Avp} | Failed]}; + true -> + pack(Arity, 'AVP', Avp, Mod, Acc) + end. -pack_arity(_, 0, #diameter_avp{is_mandatory = M} = Avp, _, Acc) -> - {Rec, Failed} = Acc, - {Rec, [{if M -> 5001; true -> 5008 end, Avp} | Failed]}; +%% 3588: +%% +%% DIAMETER_AVP_UNSUPPORTED 5001 +%% The peer received a message that contained an AVP that is not +%% recognized or supported and was marked with the Mandatory bit. A +%% Diameter message with this error MUST contain one or more Failed- +%% AVP AVP containing the AVPs that caused the failure. +%% +%% DIAMETER_AVP_NOT_ALLOWED 5008 +%% A message was received with an AVP that MUST NOT be present. The +%% Failed-AVP AVP MUST be included and contain a copy of the +%% offending AVP. -pack_arity(_, Arity, Avp, Mod, Acc) -> - pack(Arity, 'AVP', Avp, Mod, Acc). +%% pack_arity/4 %% Give Failed-AVP special treatment since (1) it'll contain any %% unrecognized mandatory AVP's and (2) the RFC 3588 grammar failed to @@ -573,31 +593,13 @@ pack_arity(Name, 0 end. -%% 3588: -%% -%% DIAMETER_AVP_UNSUPPORTED 5001 -%% The peer received a message that contained an AVP that is not -%% recognized or supported and was marked with the Mandatory bit. A -%% Diameter message with this error MUST contain one or more Failed- -%% AVP AVP containing the AVPs that caused the failure. -%% -%% DIAMETER_AVP_NOT_ALLOWED 5008 -%% A message was received with an AVP that MUST NOT be present. The -%% Failed-AVP AVP MUST be included and contain a copy of the -%% offending AVP. - %% pack/5 -pack(Arity, FieldName, Avp, Mod, {Rec, _} = Acc) -> - pack(Mod:'#get-'(FieldName, Rec), Arity, FieldName, Avp, Mod, Acc). - -%% pack/6 - -pack(undefined, 1, 'AVP' = F, Avp, Mod, {Rec, Failed}) -> %% unlikely - {Mod:'#set-'({F, Avp}, Rec), Failed}; - -pack(undefined, 1, F, #diameter_avp{value = V}, Mod, {Rec, Failed}) -> - {Mod:'#set-'({F, V}, Rec), Failed}; +pack(Arity, F, Avp, Mod, {Rec, AM, Failed}) -> + case too_many(F, Arity, AM) of + true -> {Rec, AM, [{5009, Avp} | Failed]}; + false -> {set(Arity, F, value(F, Avp), Mod, Rec), AM, Failed} + end. %% 3588: %% @@ -608,18 +610,34 @@ pack(undefined, 1, F, #diameter_avp{value = V}, Mod, {Rec, Failed}) -> %% the offending AVP that exceeded the maximum number of occurrences %% -pack(_, 1, _, Avp, _, {Rec, Failed}) -> - {Rec, [{5009, Avp} | Failed]}; +%% too_many/3 -pack(L, {_, Max}, F, Avp, Mod, {Rec, Failed}) -> - case '*' /= Max andalso has_prefix(Max+1, L) of - true -> - {Rec, [{5009, Avp} | Failed]}; - false when F == 'AVP' -> - {Mod:'#set-'({F, [Avp | L]}, Rec), Failed}; - false -> - {Mod:'#set-'({F, [Avp#diameter_avp.value | L]}, Rec), Failed} - end. +too_many(_, {_, '*'}, _) -> + false; + +too_many(FieldName, {_, M}, Map) -> + too_many(FieldName, M, Map); + +too_many(FieldName, M, Map) -> + #{FieldName := N} = Map, + M < N. + +%% set/5 + +set(1, F, Value, Mod, Rec) -> + Mod:'#set-'({F, Value}, Rec); + +set(_, F, V, Mod, Rec) -> + Vs = Mod:'#get-'(F, Rec), + Mod:'#set-'({F, [V|Vs]}, Rec). + +%% value/2 + +value('AVP', Avp) -> + Avp; + +value(_, #diameter_avp{value = V}) -> + V. %% --------------------------------------------------------------------------- %% # grouped_avp/3 -- cgit v1.2.3 From 722fa41564381dff0b7aa2b465193db30bb2f02f Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Jul 2017 09:58:07 +0200 Subject: Add service_opt() record_decode To control whether or not messages and grouped AVPs are decoded to records, in #diameter_packet.msg and #diameter_avp.value respectively. The decode became unnecessary for diameter's needs in parent commit, which decoupled it from the checking of AVP arities. --- lib/diameter/doc/src/diameter.xml | 23 ++++++++++++++++++++++ lib/diameter/src/base/diameter.erl | 1 + lib/diameter/src/base/diameter_codec.erl | 3 ++- lib/diameter/src/base/diameter_config.erl | 3 +++ lib/diameter/src/base/diameter_gen.erl | 15 +++++++++++++- lib/diameter/src/base/diameter_peer_fsm.erl | 9 ++++++--- lib/diameter/src/base/diameter_service.erl | 1 + lib/diameter/src/base/diameter_traffic.erl | 9 ++++++--- lib/diameter/src/base/diameter_watchdog.erl | 9 ++++++--- lib/diameter/test/diameter_codec_SUITE.erl | 1 + .../diameter_test_unknown.erl | 1 + lib/diameter/test/diameter_codec_test.erl | 3 ++- 12 files changed, 66 insertions(+), 12 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 2cbe48ecce..663c9cc785 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -969,6 +969,29 @@ occur in the message in question.

+ +{record_decode, boolean()} + +

+Whether or not to decode message and grouped AVPs to records in the +msg field of diameter_packet records and value field of +diameter_avp records respectively. +If false then the fields are set to the same value.

+ +

+Defaults to true.

+ + +

+Disabling the record is useful for applications in which the records +aren't used/needed. +AVP values are available in the avps field of +diameter_packet records regardless of whether or not there is a record +decode.

+
+ +
+ {string_decode, boolean()} diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index bd92e16fba..f411656e90 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -338,6 +338,7 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} + | {record_decode, boolean()} | {string_decode, boolean()} | {strict_mbit, boolean()} | {incoming_maxlen, message_length()} diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 93c1b28f4c..5e4c6e6d8f 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -287,7 +287,8 @@ rec2msg(Mod, Rec) -> %% longer *the* decode. decode(Mod, Pkt) -> - Opts = #{string_decode => true, + Opts = #{record_decode => true, + string_decode => true, strict_mbit => true, rfc => 6733}, decode(Mod, Opts, Pkt). diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 34018ae6d3..46a3e362ac 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -713,6 +713,7 @@ make_config(SvcName, Opts) -> {nodes, restrict_connections}, {16#FFFFFF, incoming_maxlen}, {true, strict_mbit}, + {true, record_decode}, {true, string_decode}, {[], spawn_opt}]), @@ -756,6 +757,7 @@ opt(K, false = B) K == monitor; K == restrict_connections; K == strict_mbit; + K == record_decode; K == string_decode -> B; @@ -763,6 +765,7 @@ opt(K, true = B) when K == share_peers; K == use_shared_peers; K == strict_mbit; + K == record_decode; K == string_decode -> B; diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 6f11583868..4879ad8f6c 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -174,7 +174,7 @@ enc_AVP(_Name, {_Dict, _AvpName, _Data} = T, Opts, _) -> decode_avps(Name, Recs, #{module := Mod} = Opts) -> {Avps, {Rec, AM, Failed}} = mapfoldl(fun(T,A) -> decode(Name, Opts, Mod, T, A) end, - {newrec(Mod, Name), #{}, []}, + {newrec(Mod, Name, Opts), #{}, []}, Recs), %% AM counts the number of top-level AVPs, which missing/4 then %% uses when adding 5005 errors. @@ -624,6 +624,9 @@ too_many(FieldName, M, Map) -> %% set/5 +set(_, _, _, _, undefined = No) -> + No; + set(1, F, Value, Mod, Rec) -> Mod:'#set-'({F, Value}, Rec); @@ -723,5 +726,15 @@ empty(Name, #{module := Mod} = Opts) -> %% ------------------------------------------------------------------------------ +%% newrec/3 + +newrec(_, _, #{record_decode := false}) -> + undefined; + +newrec(Mod, Name, _) -> + newrec(Mod, Name). + +%% newrec/2 + newrec(Mod, Name) -> Mod:'#new-'(Mod:name2rec(Name)). diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index 1b0dc417e5..f2fbb70270 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -128,7 +128,8 @@ %% outgoing DPR; boolean says whether or not %% the request was sent explicitly with %% diameter:call/4. - codec :: #{string_decode := boolean(), + codec :: #{record_decode := true, + string_decode := boolean(), strict_mbit := boolean(), rfc := 3588 | 6733, ordered_encode := false}, @@ -253,11 +254,13 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) -> length_errors = LengthErr, strict = Strictness, incoming_maxlen = Maxlen, - codec = maps:with([string_decode, + codec = maps:with([record_decode, + string_decode, strict_mbit, rfc, ordered_encode], - SvcOpts#{ordered_encode => false})}. + SvcOpts#{ordered_encode => false, + record_decode => true})}. %% The transport returns its local ip addresses so that different %% transports on the same service can use different local addresses. %% The local addresses are put into Host-IP-Address avps here when diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index a976a8b998..6dc4889c82 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -113,6 +113,7 @@ restrict_connections := diameter:restriction(), incoming_maxlen := diameter:message_length(), strict_mbit := boolean(), + record_decode := boolean(), string_decode := boolean(), spawn_opt := list() | {module(), atom(), list()}}}). diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 85378babea..228d9802ad 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -76,7 +76,8 @@ service_name :: diameter:service_name(), apps :: [#diameter_app{}], sequence :: diameter:sequence(), - codec :: #{string_decode := boolean(), + codec :: #{record_decode := boolean(), + string_decode := boolean(), strict_mbit := boolean(), incoming_maxlen := diameter:message_length()}}). %% Note that incoming_maxlen is currently handled in diameter_peer_fsm, @@ -102,7 +103,8 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) -> peerT = PeerT, apps = Apps, sequence = Mask, - codec = maps:with([string_decode, + codec = maps:with([record_decode, + string_decode, strict_mbit, ordered_encode, incoming_maxlen], @@ -1933,7 +1935,8 @@ choose(false, _, X) -> X. %% Decode options sufficient for AVP extraction. decode_opts(Dict) -> - #{string_decode => false, + #{record_decode => true, + string_decode => false, strict_mbit => false, failed_avp => false, dictionary => Dict}. diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index a63425d92a..c3dc8c3bf0 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -72,7 +72,8 @@ restrict := boolean(), suspect := non_neg_integer(), %% OKAY -> SUSPECT okay := non_neg_integer()}, %% REOPEN -> OKAY - codec :: #{string_decode := false, + codec :: #{record_decode := false, + string_decode := false, strict_mbit := boolean(), failed_avp := false, rfc := 3588 | 6733, @@ -135,7 +136,8 @@ i({Ack, T, Pid, {Opts, putr(restart, {T, Opts, Svc, SvcOpts}), %% save seeing it in trace putr(dwr, dwr(Caps)), %% Nodes = restrict_nodes(Restrict), - CodecKeys = [string_decode, + CodecKeys = [record_decode, + string_decode, strict_mbit, incoming_maxlen, spawn_opt, @@ -155,7 +157,8 @@ i({Ack, T, Pid, {Opts, suspect => 1, okay => 3}, Opts)), - codec = maps:with(CodecKeys, SvcOpts#{string_decode := false, + codec = maps:with(CodecKeys, SvcOpts#{record_decode := false, + string_decode := false, ordered_encode => false})}. wait(Ref, Pid) -> diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 9f08f49f9f..31332537e9 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -292,6 +292,7 @@ recode(Msg, Dict) -> opts(Mod) -> #{dictionary => Mod, + record_decode => true, string_decode => false, strict_mbit => true, rfc => 6733, diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl index 700910878c..fe602c9ee5 100644 --- a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl +++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl @@ -78,6 +78,7 @@ dec('BR', #diameter_packet opts(Mod) -> #{dictionary => Mod, + record_decode => true, string_decode => true, strict_mbit => true, rfc => 6733, diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl index b548f85cb8..7595e7edfc 100644 --- a/lib/diameter/test/diameter_codec_test.erl +++ b/lib/diameter/test/diameter_codec_test.erl @@ -219,7 +219,8 @@ opts(Mod) -> dictionary => Mod}. opts() -> - #{string_decode => true, + #{record_decode => true, + string_decode => true, strict_mbit => true, rfc => 6733, failed_avp => false}. -- cgit v1.2.3 From 1b3b64af3d9a5441b6da37cf4e97b59cb043f33b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Jul 2017 11:02:31 +0200 Subject: Let messages and grouped AVPs be encoded/decoded from/to maps With {record_decode, map}. The option name is arguably a bit misleading now, but not too objectionable given that the encode/decode in question has historically only been of records. One advantage of the map decode is that the map only contains values for those AVPs existing in the message or grouped AVP in question. The name of the message or grouped AVP is stored in with key ':name', the leading colon ensuring that the key isn't a diameter-name. Decoding to maps makes the hrl files generated from dictionary files largely irrelevant. There are value defines generated into these, but they're typically so long as to be unusable. --- lib/diameter/doc/src/diameter.xml | 9 ++-- lib/diameter/doc/src/diameter_codec.xml | 9 +++- lib/diameter/src/base/diameter.erl | 2 +- lib/diameter/src/base/diameter_codec.erl | 3 ++ lib/diameter/src/base/diameter_config.erl | 3 ++ lib/diameter/src/base/diameter_gen.erl | 28 +++++++++- lib/diameter/src/base/diameter_service.erl | 2 +- lib/diameter/src/base/diameter_traffic.erl | 87 ++++++++++++++++++++++-------- 8 files changed, 111 insertions(+), 32 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 663c9cc785..bfb6da41b5 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -539,7 +539,7 @@ that matches no peer.

The host and realm filters cause the Destination-Host and Destination-Realm AVPs to be extracted from the -outgoing request, assuming it to be a record- or list-valued +outgoing request, assuming it to be a record-, list- or map-valued &codec_message;, and assuming at most one of each AVP. If this is not the case then the {host|realm, &dict_DiameterIdentity;} filters must be used to achieve the desired result. @@ -970,13 +970,14 @@ occur in the message in question.

-{record_decode, boolean()} +{record_decode, boolean() | map}

Whether or not to decode message and grouped AVPs to records in the msg field of diameter_packet records and value field of -diameter_avp records respectively. -If false then the fields are set to the same value.

+diameter_avp records respectively, or to an alternate format. +If false then the fields are set to the same value. +See also &codec_message;.

Defaults to true.

diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml index 0117c1c88a..6262dbf00d 100644 --- a/lib/diameter/doc/src/diameter_codec.xml +++ b/lib/diameter/doc/src/diameter_codec.xml @@ -230,7 +230,7 @@ header.

-message() = record() | list() +message() = record() | list() | map()

The representation of a Diameter message as passed to @@ -240,7 +240,12 @@ a message as defined in a dictionary file is encoded as a record with one field for each component AVP. Equivalently, a message can also be encoded as a list whose head is the atom-valued message name (as specified in the relevant dictionary -file) and whose tail is a list of {AvpName, AvpValue} pairs.

+file) and whose tail is a list of {AvpName, AvpValues} pairs, +or as a map with values keyed on AVP names and the message name in key +:name. +The format at decode is determined by &mod_service_opt; +record_decode. +Any of the formats is accepted at encode.

Another list-valued representation allows a message to be specified diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index f411656e90..4269c84cd2 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -338,7 +338,7 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} - | {record_decode, boolean()} + | {record_decode, boolean() | map} | {string_decode, boolean()} | {strict_mbit, boolean()} | {incoming_maxlen, message_length()} diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 5e4c6e6d8f..0c43d52093 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -275,6 +275,9 @@ rec2msg(_, [Name|_]) when is_atom(Name) -> Name; +rec2msg(_, #{':name' := Name}) -> + Name; + rec2msg(Mod, Rec) -> Mod:rec2msg(element(1, Rec)). diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 46a3e362ac..a790b946c1 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -769,6 +769,9 @@ opt(K, true = B) K == string_decode -> B; +opt(record_decode, map = T) -> + T; + opt(restrict_connections, T) when T == node; T == nodes -> diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 4879ad8f6c..be2e221b7e 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -50,7 +50,9 @@ %% # encode_avps/3 %% --------------------------------------------------------------------------- --spec encode_avps(parent_name(), parent_record() | avp_values(), map()) +-spec encode_avps(parent_name(), + parent_record() | avp_values() | map(), + map()) -> iolist() | no_return(). @@ -83,6 +85,11 @@ encode(Name, Vals, Opts, Mod) when is_list(Vals) -> encode(Name, Mod:'#set-'(Vals, newrec(Mod, Name)), Opts, Mod); +encode(Name, Map, Opts, Mod) + when is_map(Map) -> + [enc(Name, F, A, V, Opts, Mod) || {F,A} <- Mod:avp_arity(Name), + V <- [maps:get(F, Map, def(A))]]; + encode(Name, Rec, Opts, Mod) -> [encode(Name, F, V, Opts, Mod) || {F,V} <- Mod:'#get-'(Rec)]. @@ -627,6 +634,14 @@ too_many(FieldName, M, Map) -> set(_, _, _, _, undefined = No) -> No; +set(1, F, Value, _, Map) + when is_map(Map) -> + maps:put(F, Value, Map); + +set(_, F, V, _, Map) + when is_map(Map) -> + maps:update_with(F, fun(Vs) -> [V|Vs] end, [V], Map); + set(1, F, Value, Mod, Rec) -> Mod:'#set-'({F, Value}, Rec); @@ -731,6 +746,9 @@ empty(Name, #{module := Mod} = Opts) -> newrec(_, _, #{record_decode := false}) -> undefined; +newrec(_, Name, #{record_decode := map}) -> + #{':name' => Name}; + newrec(Mod, Name, _) -> newrec(Mod, Name). @@ -738,3 +756,11 @@ newrec(Mod, Name, _) -> newrec(Mod, Name) -> Mod:'#new-'(Mod:name2rec(Name)). + +%% def/1 + +def(1) -> + undefined; + +def(_) -> + []. diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 6dc4889c82..3e555f6263 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -113,7 +113,7 @@ restrict_connections := diameter:restriction(), incoming_maxlen := diameter:message_length(), strict_mbit := boolean(), - record_decode := boolean(), + record_decode := boolean() | map, string_decode := boolean(), spawn_opt := list() | {module(), atom(), list()}}}). diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 228d9802ad..f7dec2441f 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -76,7 +76,7 @@ service_name :: diameter:service_name(), apps :: [#diameter_app{}], sequence :: diameter:sequence(), - codec :: #{record_decode := boolean(), + codec :: #{record_decode := boolean() | map, string_decode := boolean(), strict_mbit := boolean(), incoming_maxlen := diameter:message_length()}}). @@ -625,6 +625,12 @@ is_answer_message([#diameter_header{is_request = R, is_error = E} | _], _) -> is_answer_message([Name | _], _) -> Name == 'answer-message'; +%% Message sent as a map. +is_answer_message(Map, _) + when is_map(Map) -> + #{':name' := Name} = Map, + Name == 'answer-message'; + %% Message sent as a record. is_answer_message(Rec, Dict) -> try @@ -873,6 +879,11 @@ reset(Msg, [RC | Avps], Dict) -> set([_|_] = Ans, Avps, _) -> Ans ++ Avps; %% Values nearer tail take precedence. +%% ... a map ... +set(Ans, Avps, _) + when is_map(Ans) -> + maps:merge(Ans, maps:from_list(Avps)); + %% ... or record. set(Rec, Avps, Dict) -> Dict:'#set-'(Avps, Rec). @@ -891,6 +902,9 @@ rc([MsgName | _], RC, Dict) -> _ -> [] end; +rc(#{':name' := Name}, RC, Dict) -> + rc([Name], RC, Dict); + rc(Rec, RC, Dict) -> rc([Dict:rec2msg(element(1, Rec))], RC, Dict). @@ -902,34 +916,50 @@ failed_avp(_, [] = No, _) -> failed_avp(Msg, [_|_] = Avps, Dict) -> [failed(Msg, [{'AVP', Avps}], Dict)]. -%% Reply as name and tuple list ... -failed([MsgName | Values], FailedAvp, Dict) -> - RecName = Dict:msg2rec(MsgName), - try - Dict:'#info-'(RecName, {index, 'Failed-AVP'}), - {'Failed-AVP', [FailedAvp]} - catch - error: _ -> - Avps = proplists:get_value('AVP', Values, []), - A = #diameter_avp{name = 'Failed-AVP', - value = FailedAvp}, - {'AVP', [A|Avps]} - end; +%% failed/3 -%% ... or record. -failed(Rec, FailedAvp, Dict) -> +failed(Msg, FailedAvp, Dict) -> + RecName = msg2rec(Msg, Dict), try - RecName = element(1, Rec), - Dict:'#info-'(RecName, {index, 'Failed-AVP'}), + Dict:'#info-'(RecName, {index, 'Failed-AVP'}), %% assert existence {'Failed-AVP', [FailedAvp]} catch error: _ -> - Avps = Dict:'#get-'('AVP', Rec), + Avps = values(Msg, 'AVP', Dict), A = #diameter_avp{name = 'Failed-AVP', value = FailedAvp}, {'AVP', [A|Avps]} end. +%% msg2rec/2 + +%% Message as name/values list ... +msg2rec([MsgName | _], Dict) -> + Dict:msg2rec(MsgName); + +%% ... map ... +msg2rec(#{':name' := MsgName}, Dict) -> + Dict:msg2rec(MsgName); + +%% ... or record. +msg2rec(Rec, _) -> + element(1, Rec). + +%% values/2 + +%% Message as name/values list ... +values([_ | Avps], F, _) -> + proplists:get_value(F, Avps, []); + +%% ... map ... +values(Msg, F, _) + when is_map(Msg) -> + maps:get(F, Msg, []); + +%% ... or record. +values(Rec, F, Dict) -> + Dict:'#get-'(F, Rec). + %% 3. Diameter Header %% %% E(rror) - If set, the message contains a protocol error, @@ -1861,7 +1891,7 @@ str(T) -> get_avp(?RELAY, Name, Msg) -> get_avp(?BASE, Name, Msg); -%% Message as a header/avps list. +%% Message is a header/avps list. get_avp(Dict, Name, [#diameter_header{} | Avps]) -> try {Code, _, VId} = Dict:avp_header(Name), @@ -1874,7 +1904,7 @@ get_avp(Dict, Name, [#diameter_header{} | Avps]) -> undefined end; -%% Outgoing message as a name/values list. +%% Message as name/values list ... get_avp(_, Name, [_MsgName | Avps]) -> case lists:keyfind(Name, 1, Avps) of {_, V} -> @@ -1883,7 +1913,17 @@ get_avp(_, Name, [_MsgName | Avps]) -> undefined end; -%% Message is typically a record but not necessarily. +%% ... map ... +get_avp(_, Name, Map) + when is_map(Map) -> + case maps:find(Name, Map) of + {ok, V} -> + #diameter_avp{name = Name, value = V}; + error -> + undefined + end; + +%% ... or record (but not necessarily). get_avp(Dict, Name, Rec) -> try #diameter_avp{name = Name, value = Dict:'#get-'(Name, Rec)} @@ -1913,7 +1953,8 @@ ungroup(Avp) -> avp_decode(Dict, Name, #diameter_avp{value = undefined, data = Bin} - = Avp) -> + = Avp) + when is_binary(Bin) -> try Dict:avp(decode, Bin, Name, decode_opts(Dict)) of V -> Avp#diameter_avp{value = V} -- cgit v1.2.3 From d52611e9bd0628affa7b4f56a6126e4a99b69a7a Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Jul 2017 12:07:36 +0200 Subject: Let messages and grouped AVPs be decoded to lists That is, decode to the same format that encode already accepts. Only a message has its name at the head of the list since AVPs are already name/value pairs. --- lib/diameter/doc/src/diameter.xml | 3 ++- lib/diameter/src/base/diameter.erl | 2 +- lib/diameter/src/base/diameter_codec.erl | 8 ++++++- lib/diameter/src/base/diameter_config.erl | 4 +++- lib/diameter/src/base/diameter_gen.erl | 35 ++++++++++++++++++++---------- lib/diameter/src/base/diameter_service.erl | 2 +- lib/diameter/src/base/diameter_traffic.erl | 2 +- 7 files changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index bfb6da41b5..e525ab3345 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -970,7 +970,8 @@ occur in the message in question.

-{record_decode, boolean() | map} + +{record_decode, boolean() | list | map}

Whether or not to decode message and grouped AVPs to records in the diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 4269c84cd2..b033632c47 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -338,7 +338,7 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} - | {record_decode, boolean() | map} + | {record_decode, boolean() | list | map} | {string_decode, boolean()} | {strict_mbit, boolean()} | {incoming_maxlen, message_length()} diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 0c43d52093..9043af145e 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -379,10 +379,16 @@ decode_avps(MsgName, Mod, AppMod, Opts, Pkt, Avps) -> %% ... or not Opts#{dictionary => AppMod, failed_avp => false}), ?LOGC([] /= Errors, decode_errors, Pkt#diameter_packet.header), - Pkt#diameter_packet{msg = Rec, + Pkt#diameter_packet{msg = reformat(MsgName, Rec, Opts), errors = Errors, avps = As}. +reformat(MsgName, Avps, #{decode_format := list}) -> + [MsgName | Avps]; + +reformat(_, Msg, _) -> + Msg. + %%% --------------------------------------------------------------------------- %%% # decode_header/1 %%% --------------------------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index a790b946c1..8f958a67b4 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -769,7 +769,9 @@ opt(K, true = B) K == string_decode -> B; -opt(record_decode, map = T) -> +opt(record_decode, T) + when T == list; + T == map -> T; opt(restrict_connections, T) diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index be2e221b7e..2381b73d07 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -178,14 +178,17 @@ enc_AVP(_Name, {_Dict, _AvpName, _Data} = T, Opts, _) -> -> {parent_record(), [avp()], Failed} when Failed :: [{5000..5999, #diameter_avp{}}]. -decode_avps(Name, Recs, #{module := Mod} = Opts) -> +decode_avps(Name, Recs, #{module := Mod, record_decode := Fmt} = Opts) -> {Avps, {Rec, AM, Failed}} = mapfoldl(fun(T,A) -> decode(Name, Opts, Mod, T, A) end, - {newrec(Mod, Name, Opts), #{}, []}, + {newrec(Mod, Name, Fmt), #{}, []}, Recs), %% AM counts the number of top-level AVPs, which missing/4 then %% uses when adding 5005 errors. - {Rec, Avps, Failed ++ missing(Name, Opts, Mod, AM)}. + Arities = Mod:avp_arity(Name), + {reformat(Rec, Arities, Fmt), + Avps, + Failed ++ missing(Arities, Opts, Mod, AM)}. %% Append 5005 errors so that errors are reported in the order %% encountered. Failed-AVP should typically contain the first @@ -216,10 +219,10 @@ mapfoldl(_, Acc, [], List) -> %% Vendor-Id if applicable. The value field of the missing AVP %% should be of correct minimum length and contain zeros. -missing(Name, Opts, Mod, AM) -> +missing(Arities, Opts, Mod, AM) -> lists:foldl(fun(T,A) -> missing(T, AM, Opts, Mod, A) end, [], - Mod:avp_arity(Name)). + Arities). %% missing/5 @@ -631,7 +634,7 @@ too_many(FieldName, M, Map) -> %% set/5 -set(_, _, _, _, undefined = No) -> +set(_, _, _, _, false = No) -> No; set(1, F, Value, _, Map) @@ -743,20 +746,28 @@ empty(Name, #{module := Mod} = Opts) -> %% newrec/3 -newrec(_, _, #{record_decode := false}) -> - undefined; +newrec(_, _, false = No) -> + No; -newrec(_, Name, #{record_decode := map}) -> - #{':name' => Name}; +newrec(Mod, Name, true) -> + newrec(Mod, Name); -newrec(Mod, Name, _) -> - newrec(Mod, Name). +newrec(_, Name, _) -> + #{':name' => Name}. %% newrec/2 newrec(Mod, Name) -> Mod:'#new-'(Mod:name2rec(Name)). +%% reformat/3 + +reformat(Map, Arities, list) -> + [{F,V} || {F,_} <- Arities, #{F := V} <- [Map]]; + +reformat(Rec, _, _) -> + Rec. + %% def/1 def(1) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 3e555f6263..7f7e3e3a3f 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -113,7 +113,7 @@ restrict_connections := diameter:restriction(), incoming_maxlen := diameter:message_length(), strict_mbit := boolean(), - record_decode := boolean() | map, + record_decode := boolean() | map | list, string_decode := boolean(), spawn_opt := list() | {module(), atom(), list()}}}). diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index f7dec2441f..6594994cfa 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -76,7 +76,7 @@ service_name :: diameter:service_name(), apps :: [#diameter_app{}], sequence :: diameter:sequence(), - codec :: #{record_decode := boolean() | map, + codec :: #{record_decode := boolean() | map | list, string_decode := boolean(), strict_mbit := boolean(), incoming_maxlen := diameter:message_length()}}). -- cgit v1.2.3 From f0465811faf9085cfbd82b0bc1f91e2f0da07590 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 8 Jul 2017 00:15:08 +0200 Subject: Test map encoding in traffic suite --- lib/diameter/test/diameter_traffic_SUITE.erl | 110 ++++++++++++++++++--------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index dd0dfc776d..26bc96490a 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -139,8 +139,8 @@ %% Sequence mask for End-to-End and Hop-by-Hop identifiers. -define(CLIENT_MASK, {1,26}). %% 1 in top 6 bits -%% How to construct messages, as record or list. --define(ENCODINGS, [list, record]). +%% How to construct messages, as record, list, or map. +-define(ENCODINGS, [list, record, map]). %% How to send answers, in a diameter_packet or not. -define(CONTAINERS, [pkt, msg]). @@ -1013,15 +1013,17 @@ origin({A,C}) -> 2*codec(A) + container(C); origin(N) -> - {codec(N band 2), container(N rem 2)}. + {codec(N div 2), container(N rem 2)}. -%% Map booleans, but the readable atoms are part of (constructed) -%% group names, so it's good that they're readable. +%% Map atoms. The atoms are part of (constructed) group names, so it's +%% good that they're readable. codec(record) -> 0; codec(list) -> 1; +codec(map) -> 2; codec(0) -> record; -codec(_) -> list. +codec(1) -> list; +codec(2) -> map. container(pkt) -> 0; container(msg) -> 1; @@ -1032,12 +1034,19 @@ msg([H|_] = Msg, record = E, diameter_gen_base_rfc3588) when H == 'ACR'; H == 'ACA' -> msg(Msg, E, diameter_gen_base_accounting); + msg([H|_] = Msg, record = E, diameter_gen_base_rfc6733) when H == 'ACR'; H == 'ACA' -> msg(Msg, E, diameter_gen_acct_rfc6733); + msg([H|T], record, Dict) -> Dict:'#new-'(Dict:msg2rec(H), T); + +msg([H|T], map, _) -> + Map = maps:from_list(T), + Map#{':name' => H}; + msg(Msg, _, _) -> Msg. @@ -1049,20 +1058,26 @@ appdict(D) -> dict0(D) -> ?A("diameter_gen_base_" ++ ?L(D)). -dict(Msg, nas4005 = D) -> - if 'answer-message' == hd(Msg); - ?is_record(Msg, 'diameter_base_answer-message') -> +dict(Msg, Dict) -> + d(name(Msg), Dict). + +d(N, nas4005 = D) -> + if N == {list, 'answer-message'}; + N == {map, 'answer-message'}; + N == {record, 'diameter_base_answer-message'} -> diameter_gen_base_rfc3588; true -> D end; -dict(Msg, Dict0) - when 'ACR' == hd(Msg); - 'ACA' == hd(Msg); - ?is_record(Msg, diameter_base_accounting_ACR); - ?is_record(Msg, diameter_base_accounting_ACA) -> +d(N, Dict0) + when N == {list, 'ACR'}; + N == {list, 'ACA'}; + N == {map, 'ACR'}; + N == {map, 'ACA'}; + N == {record, diameter_base_accounting_ACR}; + N == {record, diameter_base_accounting_ACA} -> acct(Dict0); -dict(_, Dict0) -> +d(_, Dict0) -> Dict0. acct(diameter_gen_base_rfc3588) -> @@ -1071,21 +1086,28 @@ acct(diameter_gen_base_rfc6733) -> diameter_gen_acct_rfc6733. %% Set only values that aren't already. + set(_, [H|T], Vs) -> [H | Vs ++ T]; + +set(_, Map, Vs) + when is_map(Map) -> + maps:merge(maps:from_list(Vs), Map); + set(#group{client_dict = Dict0} = _Group, Rec, Vs) -> Dict = dict(Rec, Dict0), lists:foldl(fun({F,_} = FV, A) -> - set(Dict, Dict:'#get-'(F, A), FV, A) + reset(Dict, Dict:'#get-'(F, A), FV, A) end, Rec, Vs). -set(Dict, E, FV, Rec) +reset(Dict, E, FV, Rec) when E == undefined; E == [] -> Dict:'#set-'(FV, Rec); -set(_, _, _, Rec) -> + +reset(_, _, _, Rec) -> Rec. %% =========================================================================== @@ -1280,10 +1302,16 @@ prepare(Pkt, Caps, _Name, Group) -> %% prepare/3 -prepare(#diameter_packet{msg = Req}, Caps, Group) - when ?is_record(Req, diameter_base_accounting_ACR); - ?is_record(Req, nas_ACR); - 'ACR' == hd(Req) -> +prepare(#diameter_packet{msg = Req} = Pkt, Caps, Group) -> + set(name(Req), Pkt, Caps, Group). + +%% set/4 + +set(N, #diameter_packet{msg = Req}, Caps, Group) + when N == {record, diameter_base_accounting_ACR}; + N == {record, nas_ACR}; + N == {map, 'ACR'}; + N == {list, 'ACR'} -> #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} = Caps, @@ -1293,10 +1321,11 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) {'Origin-Realm', OR}, {'Destination-Realm', DR}]); -prepare(#diameter_packet{msg = Req}, Caps, Group) - when ?is_record(Req, diameter_base_ASR); - ?is_record(Req, nas_ASR); - 'ASR' == hd(Req) -> +set(N, #diameter_packet{msg = Req}, Caps, Group) + when N == {record, diameter_base_ASR}; + N == {record, nas_ASR}; + N == {map, 'ASR'}; + N == {list, 'ASR'} -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, @@ -1307,10 +1336,11 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]); -prepare(#diameter_packet{msg = Req}, Caps, Group) - when ?is_record(Req, diameter_base_STR); - ?is_record(Req, nas_STR); - 'STR' == hd(Req) -> +set(N, #diameter_packet{msg = Req}, Caps, Group) + when N == {record, diameter_base_STR}; + N == {record, nas_STR}; + N == {map, 'STR'}; + N == {list, 'STR'} -> #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} = Caps, @@ -1320,10 +1350,11 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]); -prepare(#diameter_packet{msg = Req}, Caps, Group) - when ?is_record(Req, diameter_base_RAR); - ?is_record(Req, nas_RAR); - 'RAR' == hd(Req) -> +set(N, #diameter_packet{msg = Req}, Caps, Group) + when N == {record, diameter_base_RAR}; + N == {record, nas_RAR}; + N == {map, 'RAR'}; + N == {list, 'RAR'} -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, @@ -1334,6 +1365,17 @@ prepare(#diameter_packet{msg = Req}, Caps, Group) {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]). +%% name/1 + +name([H|_]) -> + {list, H}; + +name(#{} = Map) -> + {map, maps:get(':name', Map)}; + +name(Rec) -> + {record, element(1, Rec)}. + %% prepare_retransmit/5 prepare_retransmit(_Pkt, false, _Peer, _Name, _Group) -> -- cgit v1.2.3 From e7e1cda23e60afd807669ab417f45e7faa62a5b8 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Jul 2017 16:38:03 +0200 Subject: Map answers to maps in traffic suite Instead of to lists, to simplify matching. --- lib/diameter/test/diameter_traffic_SUITE.erl | 146 ++++++++++++++++++--------- 1 file changed, 98 insertions(+), 48 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 26bc96490a..07d1c4937b 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -183,14 +183,16 @@ %% A common match when receiving answers in a client. -define(answer_message(SessionId, ResultCode), - ['answer-message', - {'Session-Id', SessionId}, - {'Origin-Host', _}, - {'Origin-Realm', _}, - {'Result-Code', ResultCode} - | _]). + #{':name' := 'answer-message', + 'Session-Id' := SessionId, + 'Origin-Host' := _, + 'Origin-Realm' := _, + 'Result-Code' := ResultCode}). -define(answer_message(ResultCode), - ?answer_message(_, ResultCode)). + #{':name' := 'answer-message', + 'Origin-Host' := _, + 'Origin-Realm' := _, + 'Result-Code' := ResultCode}). %% Config for diameter:start_service/2. -define(SERVICE(Name, Decode), @@ -567,7 +569,9 @@ send_ok(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 1}], - ['ACA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'ACA', + 'Result-Code' := ?SUCCESS, + 'Session-Id' := _} = call(Config, Req). %% Send an accounting ACR that the server answers badly to. @@ -583,7 +587,9 @@ send_eval(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 3}], - ['ACA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'ACA', + 'Result-Code' := ?SUCCESS, + 'Session-Id' := _} = call(Config, Req). %% Send an accounting ACR that the server tries to answer with an @@ -609,7 +615,8 @@ send_protocol_error(Config) -> send_experimental_result(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 5}], - ['ACA', {'Session-Id', _} | _] + #{':name' := 'ACA', + 'Session-Id' := _} = call(Config, Req). %% Send an ASR with an arbitrary non-mandatory AVP and expect success @@ -617,11 +624,12 @@ send_experimental_result(Config) -> send_arbitrary(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{name = 'Product-Name', value = "XXX"}]}], - ['ASA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | Avps] + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS, + 'AVP' := [#diameter_avp{name = 'Product-Name', + value = V}]} = call(Config, Req), - {'AVP', [#diameter_avp{name = 'Product-Name', - value = V}]} - = lists:last(Avps), "XXX" = string(V, Config). %% Send an unknown AVP (to some client) and check that it comes back. @@ -629,12 +637,13 @@ send_unknown(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = false, data = <<17>>}]}], - ['ASA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | Avps] - = call(Config, Req), - {'AVP', [#diameter_avp{code = 999, - is_mandatory = false, - data = <<17>>}]} - = lists:last(Avps). + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS, + 'AVP' := [#diameter_avp{code = 999, + is_mandatory = false, + data = <<17>>}]} + = call(Config, Req). %% Ditto, and point the AVP length past the end of the message. Expect %% 5014. @@ -645,7 +654,10 @@ send_unknown_short(Config, M, RC) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = M, data = <<17>>}]}], - ['ASA', {'Session-Id', _}, {'Result-Code', RC} | Avps] + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := RC, + 'Failed-AVP' := Avps} = call(Config, Req), [[#diameter_avp{code = 999, is_mandatory = M, @@ -657,7 +669,10 @@ send_unknown_mandatory(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = true, data = <<17>>}]}], - ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps] + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED, + 'Failed-AVP' := Avps} = call(Config, Req), [[#diameter_avp{code = 999, is_mandatory = true, @@ -675,7 +690,10 @@ send_unexpected_mandatory_decode(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 27, %% Session-Timeout is_mandatory = true, data = <<12:32>>}]}], - ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps] + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED, + 'Failed-AVP' := Avps} = call(Config, Req), [[#diameter_avp{code = 27, is_mandatory = true, @@ -691,7 +709,10 @@ send_unexpected_mandatory_decode(Config) -> send_grouped_error(Config) -> Req = ['ASR', {'Proxy-Info', [[{'Proxy-Host', "abcd"}, {'Proxy-State', ""}]]}], - ['ASA', {'Session-Id', _}, {'Result-Code', ?INVALID_AVP_LENGTH} | Avps] + #{':name' := 'ASA', + 'Session-Id' := _, + 'Result-Code' := ?INVALID_AVP_LENGTH, + 'Failed-AVP' := Avps} = call(Config, Req), [[#diameter_avp{name = 'Proxy-Info', value = V}]] = failed_avps(Avps, Config), @@ -724,7 +745,9 @@ send_error_bit(Config) -> %% Send a bad version and check that we get 5011. send_unsupported_version(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - ['STA', {'Session-Id', _}, {'Result-Code', ?UNSUPPORTED_VERSION} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?UNSUPPORTED_VERSION} = call(Config, Req). %% Send a request containing an AVP length > data size. @@ -744,15 +767,16 @@ send_zero_avp_length(Config) -> send_invalid_avp_length(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - ['STA', {'Session-Id', _}, - {'Result-Code', ?INVALID_AVP_LENGTH}, - {'Origin-Host', _}, - {'Origin-Realm', _}, - {'User-Name', _}, - {'Class', _}, - {'Error-Message', _}, - {'Error-Reporting-Host', _} - | Avps] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?INVALID_AVP_LENGTH, + 'Origin-Host' := _, + 'Origin-Realm' := _, + 'User-Name' := _, + 'Class' := _, + 'Error-Message' := _, + 'Error-Reporting-Host' := _, + 'Failed-AVP' := Avps} = call(Config, Req), [[_]] = failed_avps(Avps, Config). @@ -769,14 +793,18 @@ send_invalid_reject(Config) -> send_unexpected_mandatory(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - ['STA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED} = call(Config, Req). %% Send something long that will be fragmented by TCP. send_long(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}, {'User-Name', [binary:copy(<<$X>>, 1 bsl 20)]}], - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = call(Config, Req). %% Send something longer than the configure incoming_maxlen. @@ -819,7 +847,9 @@ send_any_2(Config) -> send_all_1(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], Realm = lists:foldr(fun(C,A) -> [C,A] end, [], ?REALM), - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = call(Config, Req, [{filter, {all, [{host, any}, {realm, Realm}]}}]). send_all_2(Config) -> @@ -848,9 +878,10 @@ send_detach(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], Ref = make_ref(), ok = call(Config, Req, [{extra, [{self(), Ref}]}, detach]), - Ans = receive {Ref, T} -> T end, - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] - = Ans. + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} + = receive {Ref, T} -> T end. %% Send a request which can't be encoded and expect {error, encode}. send_encode_error(Config) -> @@ -862,11 +893,15 @@ send_destination_1(Config) -> = group(Config), Req = ['STR', {'Termination-Cause', ?LOGOUT}, {'Destination-Host', [?HOST(SN, ?REALM)]}], - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = call(Config, Req, [{filter, {all, [host, realm]}}]). send_destination_2(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = call(Config, Req, [{filter, {all, [host, realm]}}]). %% Send with filtering on and expect failure when specifying an @@ -930,7 +965,9 @@ send_bad_filter(Config, F) -> %% Specify multiple filter options and expect them be conjunctive. send_multiple_filters_1(Config) -> Fun = fun(#diameter_caps{}) -> true end, - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = send_multiple_filters(Config, [host, {eval, Fun}]). send_multiple_filters_2(Config) -> E = {erlang, is_tuple, []}, @@ -941,7 +978,9 @@ send_multiple_filters_3(Config) -> E2 = {erlang, is_tuple, []}, E3 = {erlang, is_record, [diameter_caps]}, E4 = [{erlang, is_record, []}, diameter_caps], - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = send_multiple_filters(Config, [{eval, E} || E <- [E1,E2,E3,E4]]). send_multiple_filters(Config, Fs) -> @@ -952,14 +991,16 @@ send_multiple_filters(Config, Fs) -> %% only the return value from the prepare_request callback being %% significant. send_anything(Config) -> - ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _] + #{':name' := 'STA', + 'Session-Id' := _, + 'Result-Code' := ?SUCCESS} = call(Config, anything). %% =========================================================================== failed_avps(Avps, Config) -> #group{client_dict = D} = proplists:get_value(group, Config), - [failed_avp(D, T) || T <- proplists:get_value('Failed-AVP', Avps)]. + [failed_avp(D, T) || T <- Avps]. failed_avp(nas4005, {'nas_Failed-AVP', As}) -> As; @@ -1374,7 +1415,12 @@ name(#{} = Map) -> {map, maps:get(':name', Map)}; name(Rec) -> - {record, element(1, Rec)}. + try + {record, element(1, Rec)} + catch + error: badarg -> + false + end. %% prepare_retransmit/5 @@ -1396,7 +1442,11 @@ answer(Pkt, Req, _Peer, Name, #group{client_dict = Dict0}) -> #diameter_header{application_id = ApplId} = H, %% assert Dict = dict(Ans, Dict0), [R | Vs] = Dict:'#get-'(answer(Ans, Es, Name)), - [Dict:rec2msg(R) | Vs]. + maps:put(':name', + Dict:rec2msg(R), + maps:from_list([T || {_,V} = T <- Vs, + V /= undefined, + V /= []])). %% Missing Result-Code and inappropriate Experimental-Result-Code. answer(Rec, Es, send_experimental_result) -> -- cgit v1.2.3 From f87aeb3fb2c84790b37796d5e57b4a09ac2f4ed7 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Jul 2017 17:55:48 +0200 Subject: Test record_decode in traffic suite --- lib/diameter/test/diameter_traffic_SUITE.erl | 237 ++++++++++++++++----------- 1 file changed, 140 insertions(+), 97 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 07d1c4937b..47f83676bb 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -139,9 +139,12 @@ %% Sequence mask for End-to-End and Hop-by-Hop identifiers. -define(CLIENT_MASK, {1,26}). %% 1 in top 6 bits -%% How to construct messages, as record, list, or map. +%% How to construct outgoing messages. -define(ENCODINGS, [list, record, map]). +%% How to set record_decode. +-define(DECODINGS, [true, false, map, list]). + %% How to send answers, in a diameter_packet or not. -define(CONTAINERS, [pkt, msg]). @@ -169,6 +172,7 @@ client_dict, client_sender, server_service, + server_decoding, server_encoding, server_container, server_sender, @@ -264,25 +268,27 @@ all() -> groups() -> [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] ++ - [{?util:name([T,R,D,A,C,S,SS,ST,CS]), + [{?util:name([T,CE,D,SE,SD,SC,S,SS,ST,CS]), [], [{group, if S -> shuffle; not S -> parallel end}]} - || T <- ?TRANSPORTS, - R <- ?ENCODINGS, - D <- ?RFCS, - A <- ?ENCODINGS, - C <- ?CONTAINERS, - S <- ?STRING_DECODES, + || T <- ?TRANSPORTS, + CE <- ?ENCODINGS, + D <- ?RFCS, + SE <- ?ENCODINGS, + SD <- ?DECODINGS, + SC <- ?CONTAINERS, + S <- ?STRING_DECODES, SS <- ?SENDERS, ST <- ?CALLBACKS, CS <- ?SENDERS] ++ - [{T, [], groups([[T,R,D,A,C,S,SS,ST,CS] - || R <- ?ENCODINGS, - D <- ?RFCS, - A <- ?ENCODINGS, - C <- ?CONTAINERS, - S <- ?STRING_DECODES, + [{T, [], groups([[T,CE,D,SE,SD,SC,S,SS,ST,CS] + || CE <- ?ENCODINGS, + D <- ?RFCS, + SE <- ?ENCODINGS, + SD <- ?DECODINGS, + SC <- ?CONTAINERS, + S <- ?STRING_DECODES, SS <- ?SENDERS, ST <- ?CALLBACKS, CS <- ?SENDERS, @@ -292,7 +298,7 @@ groups() -> [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}]. %groups(_) -> %% debug -% Name = [sctp,record,rfc6733,record,pkt,false,false,false,false], +% Name = [tcp,record,rfc6733,record,map,pkt,false,false,false,false], % [{group, ?util:name(Name)}]; groups(Names) -> [{group, ?util:name(L)} || L <- Names]. @@ -331,18 +337,19 @@ init_per_group(sctp = Name, Config) -> init_per_group(Name, Config) -> Nas = proplists:get_value(rfc4005, Config, false), case ?util:name(Name) of - [_,_,D,_,_,_, _, _, _] when D == rfc4005, true /= Nas -> + [_,_,D,_,_,_,_,_,_,_] when D == rfc4005, true /= Nas -> {skip, rfc4005}; - [T,R,D,A,C,S,SS,ST,CS] -> + [T,CE,D,SE,SD,SC,S,SS,ST,CS] -> G = #group{transport = T, strings = S, client_service = [$C|?util:unique_string()], - client_encoding = R, + client_encoding = CE, client_dict = appdict(D), client_sender = CS, server_service = [$S|?util:unique_string()], - server_encoding = A, - server_container = C, + server_decoding = SD, + server_encoding = SE, + server_container = SC, server_sender = SS, server_throttle = ST}, %% Limit the number of testcase, since the number of @@ -452,9 +459,11 @@ start(_Config) -> start_services(Config) -> #group{strings = S, client_service = CN, - server_service = SN} + server_service = SN, + server_decoding = SD} = group(Config), - ok = diameter:start_service(SN, ?SERVICE(SN, S)), + ok = diameter:start_service(SN, [{record_decode, SD} + | ?SERVICE(SN, S)]), ok = diameter:start_service(CN, [{sequence, ?CLIENT_MASK} | ?SERVICE(CN, S)]). @@ -480,12 +489,13 @@ add_transports(Config) -> [T, {sender, CS}], LRef, [{id, Id} - | client_apps(D, [{'Origin-State-Id', origin(Id)}])]) - || A <- ?ENCODINGS, + | client_apps(R, [{'Origin-State-Id', origin(Id)}])]) + || D <- ?DECODINGS, + E <- ?ENCODINGS, C <- ?CONTAINERS, - D <- ?RFCS, - D /= rfc4005 orelse have_nas(), - Id <- [{A,C}]], + R <- ?RFCS, + R /= rfc4005 orelse have_nas(), + Id <- [{D,E,C}]], %% The server uses the client's Origin-State-Id to decide how to %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). @@ -772,10 +782,6 @@ send_invalid_avp_length(Config) -> 'Result-Code' := ?INVALID_AVP_LENGTH, 'Origin-Host' := _, 'Origin-Realm' := _, - 'User-Name' := _, - 'Class' := _, - 'Error-Message' := _, - 'Error-Reporting-Host' := _, 'Failed-AVP' := Avps} = call(Config, Req), [[_]] = failed_avps(Avps, Config). @@ -1050,21 +1056,30 @@ call(Config, Req, Opts) -> msg(Req, ReqEncoding, Dict0), [{extra, [{Name, Group}, diameter_lib:now()]} | Opts]). -origin({A,C}) -> - 2*codec(A) + container(C); +origin({D,E,C}) -> + 8*decode(D) + 2*encode(E) + container(C); origin(N) -> - {codec(N div 2), container(N rem 2)}. + {decode(N bsr 3), encode((N bsr 1) rem 4), container(N rem 2)}. %% Map atoms. The atoms are part of (constructed) group names, so it's %% good that they're readable. -codec(record) -> 0; -codec(list) -> 1; -codec(map) -> 2; -codec(0) -> record; -codec(1) -> list; -codec(2) -> map. +decode(true) -> 0; %% record +decode(list) -> 1; +decode(map) -> 2; +decode(false) -> 3; +decode(0) -> true; +decode(1) -> list; +decode(2) -> map; +decode(3) -> false. + +encode(record) -> 0; +encode(list) -> 1; +encode(map) -> 2; +encode(0) -> record; +encode(1) -> list; +encode(2) -> map. container(pkt) -> 0; container(msg) -> 1; @@ -1091,6 +1106,46 @@ msg([H|T], map, _) -> msg(Msg, _, _) -> Msg. +to_map(map, #diameter_packet{msg = Msg}) + when is_map(Msg) -> + Msg; + +to_map(list, #diameter_packet{msg = [MsgName | Avps]}) -> + maps:put(':name', MsgName, maps:from_list(Avps)); + +to_map(true, #diameter_packet{header = H, msg = Rec}) -> + rec_to_map(Rec, dict(H)); + +%% No record decode: do it ourselves. +to_map(false, #diameter_packet{header = H, + msg = false, + bin = Bin}) -> + Opts = #{record_decode => map, + string_decode => false, + strict_mbit => true, + rfc => 6733}, + #diameter_packet{msg = Msg} + = diameter_codec:decode(dict(H), Opts, Bin), + Msg. + +dict(#diameter_header{application_id = Id, + cmd_code = Code}) -> + if Id == 1 -> + nas4005; + Code == 271 -> + diameter_gen_base_accounting; + true -> + diameter_gen_base_rfc3588 + end. + +rec_to_map(Rec, Dict) -> + [R | Vs] = Dict:'#get-'(Rec), + maps:put(':name', + Dict:rec2msg(R), + maps:from_list([T || {_,V} = T <- Vs, + V /= undefined, + V /= []])). + appdict(rfc4005) -> nas4005; appdict(D) -> @@ -1177,10 +1232,11 @@ pick_peer(Peers, _, [$C|_], _State, {send_detach, Group}, _, {_,_}) -> find(Group, Peers). find(#group{client_service = CN, - server_encoding = A, + server_decoding = D, + server_encoding = E, server_container = C}, [_|_] = Peers) -> - Id = {A,C}, + Id = {D,E,C}, [P] = [P || P <- Peers, id(Id, P, CN)], {ok, P}. @@ -1441,12 +1497,7 @@ answer(Pkt, Req, _Peer, Name, #group{client_dict = Dict0}) -> ApplId = app(Req, Name, Dict0), #diameter_header{application_id = ApplId} = H, %% assert Dict = dict(Ans, Dict0), - [R | Vs] = Dict:'#get-'(answer(Ans, Es, Name)), - maps:put(':name', - Dict:rec2msg(R), - maps:from_list([T || {_,V} = T <- Vs, - V /= undefined, - V /= []])). + rec_to_map(answer(Ans, Es, Name), Dict). %% Missing Result-Code and inappropriate Experimental-Result-Code. answer(Rec, Es, send_experimental_result) -> @@ -1486,7 +1537,8 @@ handle_error(Reason, _Req, [$C|_], _Peer, _, _Time) -> %% Note that diameter will set Result-Code and Failed-AVPs if %% #diameter_packet.errors is non-null. -handle_request(#diameter_packet{header = H, msg = M, avps = As}, +handle_request(#diameter_packet{header = H, avps = As} + = Pkt, _, {_Ref, Caps}) -> #diameter_header{end_to_end_id = EI, @@ -1496,14 +1548,15 @@ handle_request(#diameter_packet{header = H, msg = M, avps = As}, V = EI bsr B, %% assert V = HI bsr B, %% #diameter_caps{origin_state_id = {_,[Id]}} = Caps, - wrap(origin(Id), H, request(nas_to_base(M, H), [H|As], Caps)). + {D,_,_} = T = origin(Id), + wrap(T, H, request(to_map(D, Pkt), [H|As], Caps)). -wrap(T, H, {Tag, Action, Post}) -> - {Tag, wrap(T, H, Action), Post}; +wrap(Id, H, {Tag, Action, Post}) -> + {Tag, wrap(Id, H, Action), Post}; wrap(_, _, {reply, [#diameter_header{} | _]} = T) -> T; -wrap({A,C}, H, {reply, Ans}) -> - Msg = msg(Ans, A, diameter_gen_base_rfc3588), +wrap({_,E,C}, H, {reply, Ans}) -> + Msg = msg(Ans, E, diameter_gen_base_rfc3588), wrap(C, H, {reply, base_to_nas(Msg, H)}); wrap(pkt, _, {reply, Ans}) when not is_record(Ans, diameter_packet) -> @@ -1511,28 +1564,6 @@ wrap(pkt, _, {reply, Ans}) wrap(_, _, T) -> T. -%% nas_to_base/1 -%% -%% Map an RFC 4005 message to RFC 3588, to return the same answer in -%% both cases. - -nas_to_base(Rec, #diameter_header{application_id = 1}) -> - [R | Values] = nas4005:'#get-'(Rec), - "nas_" ++ Name = ?L(R), - {D, RN} = case Name of - "ACR" -> - {diameter_gen_base_accounting, - diameter_base_accounting_ACR}; - _ -> - {diameter_gen_base_rfc3588, - ?A("diameter_base_" ++ Name)} - end, - Fs = D:'#info-'(RN), - D:'#new-'([RN | [T || {F,_} = T <- Values, lists:member(F, Fs)]]); - -nas_to_base(Rec, _) -> - Rec. - %% base_to_nas/2 base_to_nas(#diameter_packet{msg = Msg} = Pkt, H) -> @@ -1561,7 +1592,8 @@ base_to_nas(Msg, _) -> %% request/3 %% send_experimental_result -request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 5}, +request(#{':name' := 'ACR', + 'Accounting-Record-Number' := 5}, [Hdr | Avps], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> @@ -1594,14 +1626,16 @@ request(Msg, _Avps, Caps) -> %% request/2 %% send_nok -request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 0}, +request(#{':name' := 'ACR', + 'Accounting-Record-Number' := 0}, _) -> {eval_packet, {protocol_error, ?INVALID_AVP_BITS}, [fun log/2, invalid]}; %% send_bad_answer -request(#diameter_base_accounting_ACR{'Session-Id' = SId, - 'Accounting-Record-Type' = RT, - 'Accounting-Record-Number' = 2 = RN}, +request(#{':name' := 'ACR', + 'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 2 = RN}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['ACA', {'Result-Code', ?SUCCESS}, @@ -1615,9 +1649,10 @@ request(#diameter_base_accounting_ACR{'Session-Id' = SId, msg = Ans}}; %% send_eval -request(#diameter_base_accounting_ACR{'Session-Id' = SId, - 'Accounting-Record-Type' = RT, - 'Accounting-Record-Number' = 3 = RN}, +request(#{':name' := 'ACR', + 'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 3 = RN}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['ACA', {'Result-Code', ?SUCCESS}, @@ -1629,9 +1664,10 @@ request(#diameter_base_accounting_ACR{'Session-Id' = SId, {eval, {reply, Ans}, {erlang, now, []}}; %% send_ok -request(#diameter_base_accounting_ACR{'Session-Id' = SId, - 'Accounting-Record-Type' = RT, - 'Accounting-Record-Number' = 1 = RN}, +request(#{':name' := 'ACR', + 'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 1 = RN}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['ACA', {'Result-Code', ?SUCCESS}, @@ -1642,7 +1678,8 @@ request(#diameter_base_accounting_ACR{'Session-Id' = SId, {'Accounting-Record-Number', RN}]}; %% send_protocol_error -request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 4}, +request(#{':name' := 'ACR', + 'Accounting-Record-Number' := 4}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['answer-message', {'Result-Code', ?TOO_BUSY}, @@ -1650,40 +1687,46 @@ request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 4}, {'Origin-Realm', OR}], {reply, Ans}; -request(#diameter_base_ASR{'Session-Id' = SId, - 'AVP' = Avps}, +request(#{':name' := 'ASR', + 'Session-Id' := SId} + = Req, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['ASA', {'Result-Code', ?SUCCESS}, {'Session-Id', SId}, {'Origin-Host', OH}, {'Origin-Realm', OR}, - {'AVP', Avps}]}; + {'AVP', maps:get('AVP', Req, [])}]}; %% send_invalid_reject -request(#diameter_base_STR{'Termination-Cause' = ?USER_MOVED}, +request(#{':name' := 'STR', + 'Termination-Cause' := ?USER_MOVED}, _Caps) -> {protocol_error, ?TOO_BUSY}; %% send_noreply -request(#diameter_base_STR{'Termination-Cause' = T}, +request(#{':name' := 'STR', + 'Termination-Cause' := T}, _Caps) when T /= ?LOGOUT -> discard; %% send_destination_5 -request(#diameter_base_STR{'Destination-Realm' = R}, +request(#{':name' := 'STR', + 'Destination-Realm' := R}, #diameter_caps{origin_realm = {OR, _}}) when R /= undefined, R /= OR -> {protocol_error, ?REALM_NOT_SERVED}; %% send_destination_6 -request(#diameter_base_STR{'Destination-Host' = [H]}, +request(#{':name' := 'STR', + 'Destination-Host' := [H]}, #diameter_caps{origin_host = {OH, _}}) when H /= OH -> {protocol_error, ?UNABLE_TO_DELIVER}; -request(#diameter_base_STR{'Session-Id' = SId}, +request(#{':name' := 'STR', + 'Session-Id' := SId}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['STA', {'Result-Code', ?SUCCESS}, @@ -1692,7 +1735,7 @@ request(#diameter_base_STR{'Session-Id' = SId}, {'Origin-Realm', OR}]}; %% send_error/send_timeout -request(#diameter_base_RAR{}, _Caps) -> +request(#{':name' := 'RAR'}, _Caps) -> receive after 2000 -> {protocol_error, ?TOO_BUSY} end. %% message/3 -- cgit v1.2.3 From df12f634bec4b784f4c8d16846f2c24297b0e1ac Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 7 Jul 2017 23:58:19 +0200 Subject: Create fewer client connections in traffic suite One for each server decoding/encoding/container combination is overkill. Just want a few from which one can be chosen in the pick_peer callback. --- lib/diameter/test/diameter_traffic_SUITE.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 47f83676bb..adf8bf4d66 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -472,6 +472,8 @@ add_transports(Config) -> client_service = CN, client_sender = CS, server_service = SN, + server_encoding = SE, + server_container = SC, server_sender = SS, server_throttle = ST} = group(Config), @@ -490,12 +492,10 @@ add_transports(Config) -> LRef, [{id, Id} | client_apps(R, [{'Origin-State-Id', origin(Id)}])]) - || D <- ?DECODINGS, - E <- ?ENCODINGS, - C <- ?CONTAINERS, + || D <- ?DECODINGS, %% for multiple candidate peers R <- ?RFCS, R /= rfc4005 orelse have_nas(), - Id <- [{D,E,C}]], + Id <- [{D,SE,SC}]], %% The server uses the client's Origin-State-Id to decide how to %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). -- cgit v1.2.3 From 55e65b262cdf0b794ab443928676720a323cf6b0 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 8 Jul 2017 00:48:07 +0200 Subject: Rename record_decode -> decode_format {record_decode, map} is a bit too quirky. --- lib/diameter/doc/src/diameter.xml | 48 +++++++++++----------- lib/diameter/doc/src/diameter_codec.xml | 2 +- lib/diameter/src/base/diameter.erl | 6 ++- lib/diameter/src/base/diameter_codec.erl | 2 +- lib/diameter/src/base/diameter_config.erl | 10 ++--- lib/diameter/src/base/diameter_gen.erl | 4 +- lib/diameter/src/base/diameter_peer_fsm.erl | 6 +-- lib/diameter/src/base/diameter_service.erl | 2 +- lib/diameter/src/base/diameter_traffic.erl | 6 +-- lib/diameter/src/base/diameter_watchdog.erl | 6 +-- lib/diameter/test/diameter_codec_SUITE.erl | 2 +- .../diameter_test_unknown.erl | 2 +- lib/diameter/test/diameter_codec_test.erl | 2 +- lib/diameter/test/diameter_traffic_SUITE.erl | 14 +++---- 14 files changed, 57 insertions(+), 55 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index e525ab3345..a7f001e096 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -797,6 +797,29 @@ be matched by corresponding &capability; configuration, of + + +{decode_format, record | list | map | false} + +

+The type of decoded messages and grouped AVPs in the msg field +of diameter_packet records and value field of diameter_avp +records respectively. +If false then the fields are set this value. +See also &codec_message;.

+ +

+Defaults to record.

+ + +

+AVPs are decoded into a list of diameter_avp records in avps +field of diameter_packet records independently of +decode_format.

+
+ +
+ {incoming_maxlen, 0..16777215} @@ -969,31 +992,6 @@ occur in the message in question.

- - -{record_decode, boolean() | list | map} - -

-Whether or not to decode message and grouped AVPs to records in the -msg field of diameter_packet records and value field of -diameter_avp records respectively, or to an alternate format. -If false then the fields are set to the same value. -See also &codec_message;.

- -

-Defaults to true.

- - -

-Disabling the record is useful for applications in which the records -aren't used/needed. -AVP values are available in the avps field of -diameter_packet records regardless of whether or not there is a record -decode.

-
- -
- {string_decode, boolean()} diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml index 6262dbf00d..4df8e788b7 100644 --- a/lib/diameter/doc/src/diameter_codec.xml +++ b/lib/diameter/doc/src/diameter_codec.xml @@ -244,7 +244,7 @@ file) and whose tail is a list of {AvpName, AvpValues} pairs, or as a map with values keyed on AVP names and the message name in key :name. The format at decode is determined by &mod_service_opt; -record_decode. +decode_format. Any of the formats is accepted at encode.

diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index b033632c47..75deaad511 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -47,6 +47,7 @@ stop/0]). -export_type([evaluable/0, + decode_format/0, restriction/0, message_length/0, remotes/0, @@ -330,6 +331,9 @@ call(SvcName, App, Message) -> -type message_length() :: 0..16#FFFFFF. +-type decode_format() + :: record | list | map | false. + %% Options passed to start_service/2 -type service_opt() @@ -338,7 +342,7 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} - | {record_decode, boolean() | list | map} + | {decode_format, decode_format()} | {string_decode, boolean()} | {strict_mbit, boolean()} | {incoming_maxlen, message_length()} diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 9043af145e..275e80b9bb 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -290,7 +290,7 @@ rec2msg(Mod, Rec) -> %% longer *the* decode. decode(Mod, Pkt) -> - Opts = #{record_decode => true, + Opts = #{decode_format => record, string_decode => true, strict_mbit => true, rfc => 6733}, diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 8f958a67b4..09018308d5 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -713,7 +713,7 @@ make_config(SvcName, Opts) -> {nodes, restrict_connections}, {16#FFFFFF, incoming_maxlen}, {true, strict_mbit}, - {true, record_decode}, + {record, decode_format}, {true, string_decode}, {[], spawn_opt}]), @@ -757,7 +757,7 @@ opt(K, false = B) K == monitor; K == restrict_connections; K == strict_mbit; - K == record_decode; + K == decode_format; K == string_decode -> B; @@ -765,12 +765,12 @@ opt(K, true = B) when K == share_peers; K == use_shared_peers; K == strict_mbit; - K == record_decode; K == string_decode -> B; -opt(record_decode, T) - when T == list; +opt(decode_format, T) + when T == record; + T == list; T == map -> T; diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 2381b73d07..239d4a535f 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -178,7 +178,7 @@ enc_AVP(_Name, {_Dict, _AvpName, _Data} = T, Opts, _) -> -> {parent_record(), [avp()], Failed} when Failed :: [{5000..5999, #diameter_avp{}}]. -decode_avps(Name, Recs, #{module := Mod, record_decode := Fmt} = Opts) -> +decode_avps(Name, Recs, #{module := Mod, decode_format := Fmt} = Opts) -> {Avps, {Rec, AM, Failed}} = mapfoldl(fun(T,A) -> decode(Name, Opts, Mod, T, A) end, {newrec(Mod, Name, Fmt), #{}, []}, @@ -749,7 +749,7 @@ empty(Name, #{module := Mod} = Opts) -> newrec(_, _, false = No) -> No; -newrec(Mod, Name, true) -> +newrec(Mod, Name, record) -> newrec(Mod, Name); newrec(_, Name, _) -> diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index f2fbb70270..abf948593f 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -128,7 +128,7 @@ %% outgoing DPR; boolean says whether or not %% the request was sent explicitly with %% diameter:call/4. - codec :: #{record_decode := true, + codec :: #{decode_format := record, string_decode := boolean(), strict_mbit := boolean(), rfc := 3588 | 6733, @@ -254,13 +254,13 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) -> length_errors = LengthErr, strict = Strictness, incoming_maxlen = Maxlen, - codec = maps:with([record_decode, + codec = maps:with([decode_format, string_decode, strict_mbit, rfc, ordered_encode], SvcOpts#{ordered_encode => false, - record_decode => true})}. + decode_format => record})}. %% The transport returns its local ip addresses so that different %% transports on the same service can use different local addresses. %% The local addresses are put into Host-IP-Address avps here when diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 7f7e3e3a3f..43be4d889a 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -113,7 +113,7 @@ restrict_connections := diameter:restriction(), incoming_maxlen := diameter:message_length(), strict_mbit := boolean(), - record_decode := boolean() | map | list, + decode_format := diameter:decode_format(), string_decode := boolean(), spawn_opt := list() | {module(), atom(), list()}}}). diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 6594994cfa..f684f60cb7 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -76,7 +76,7 @@ service_name :: diameter:service_name(), apps :: [#diameter_app{}], sequence :: diameter:sequence(), - codec :: #{record_decode := boolean() | map | list, + codec :: #{decode_format := diameter:decode_format(), string_decode := boolean(), strict_mbit := boolean(), incoming_maxlen := diameter:message_length()}}). @@ -103,7 +103,7 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) -> peerT = PeerT, apps = Apps, sequence = Mask, - codec = maps:with([record_decode, + codec = maps:with([decode_format, string_decode, strict_mbit, ordered_encode, @@ -1976,7 +1976,7 @@ choose(false, _, X) -> X. %% Decode options sufficient for AVP extraction. decode_opts(Dict) -> - #{record_decode => true, + #{decode_format => record, string_decode => false, strict_mbit => false, failed_avp => false, diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index c3dc8c3bf0..60baf1e8a4 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -72,7 +72,7 @@ restrict := boolean(), suspect := non_neg_integer(), %% OKAY -> SUSPECT okay := non_neg_integer()}, %% REOPEN -> OKAY - codec :: #{record_decode := false, + codec :: #{decode_format := false, string_decode := false, strict_mbit := boolean(), failed_avp := false, @@ -136,7 +136,7 @@ i({Ack, T, Pid, {Opts, putr(restart, {T, Opts, Svc, SvcOpts}), %% save seeing it in trace putr(dwr, dwr(Caps)), %% Nodes = restrict_nodes(Restrict), - CodecKeys = [record_decode, + CodecKeys = [decode_format, string_decode, strict_mbit, incoming_maxlen, @@ -157,7 +157,7 @@ i({Ack, T, Pid, {Opts, suspect => 1, okay => 3}, Opts)), - codec = maps:with(CodecKeys, SvcOpts#{record_decode := false, + codec = maps:with(CodecKeys, SvcOpts#{decode_format := false, string_decode := false, ordered_encode => false})}. diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 31332537e9..c79b642c09 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -292,7 +292,7 @@ recode(Msg, Dict) -> opts(Mod) -> #{dictionary => Mod, - record_decode => true, + decode_format => record, string_decode => false, strict_mbit => true, rfc => 6733, diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl index fe602c9ee5..735339ebb9 100644 --- a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl +++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl @@ -78,7 +78,7 @@ dec('BR', #diameter_packet opts(Mod) -> #{dictionary => Mod, - record_decode => true, + decode_format => record, string_decode => true, strict_mbit => true, rfc => 6733, diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl index 7595e7edfc..22fb0550ea 100644 --- a/lib/diameter/test/diameter_codec_test.erl +++ b/lib/diameter/test/diameter_codec_test.erl @@ -219,7 +219,7 @@ opts(Mod) -> dictionary => Mod}. opts() -> - #{record_decode => true, + #{decode_format => record, string_decode => true, strict_mbit => true, rfc => 6733, diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index adf8bf4d66..aa0098ccd6 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -142,8 +142,8 @@ %% How to construct outgoing messages. -define(ENCODINGS, [list, record, map]). -%% How to set record_decode. --define(DECODINGS, [true, false, map, list]). +%% How to decode incoming messages. +-define(DECODINGS, [record, false, map, list]). %% How to send answers, in a diameter_packet or not. -define(CONTAINERS, [pkt, msg]). @@ -462,7 +462,7 @@ start_services(Config) -> server_service = SN, server_decoding = SD} = group(Config), - ok = diameter:start_service(SN, [{record_decode, SD} + ok = diameter:start_service(SN, [{decode_format, SD} | ?SERVICE(SN, S)]), ok = diameter:start_service(CN, [{sequence, ?CLIENT_MASK} | ?SERVICE(CN, S)]). @@ -1065,11 +1065,11 @@ origin(N) -> %% Map atoms. The atoms are part of (constructed) group names, so it's %% good that they're readable. -decode(true) -> 0; %% record +decode(record) -> 0; decode(list) -> 1; decode(map) -> 2; decode(false) -> 3; -decode(0) -> true; +decode(0) -> record; decode(1) -> list; decode(2) -> map; decode(3) -> false. @@ -1113,14 +1113,14 @@ to_map(map, #diameter_packet{msg = Msg}) to_map(list, #diameter_packet{msg = [MsgName | Avps]}) -> maps:put(':name', MsgName, maps:from_list(Avps)); -to_map(true, #diameter_packet{header = H, msg = Rec}) -> +to_map(record, #diameter_packet{header = H, msg = Rec}) -> rec_to_map(Rec, dict(H)); %% No record decode: do it ourselves. to_map(false, #diameter_packet{header = H, msg = false, bin = Bin}) -> - Opts = #{record_decode => map, + Opts = #{decode_format => map, string_decode => false, strict_mbit => true, rfc => 6733}, -- cgit v1.2.3 From fa2f0572aa0604bf03d4d3eaa358719ffd877545 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 8 Jul 2017 02:06:11 +0200 Subject: Add decode_format record_from_map Undocumented, for transforming a map decode to record. The record decode becomes more expensive the larger the number of AVPs in the message definition in question, since the record is recreated each time an AVP value is set in it. The map decode can potentially do better. --- lib/diameter/src/base/diameter.erl | 6 +++++- lib/diameter/src/base/diameter_config.erl | 3 ++- lib/diameter/src/base/diameter_gen.erl | 13 +++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 75deaad511..85a54c8e61 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -332,7 +332,11 @@ call(SvcName, App, Message) -> :: 0..16#FFFFFF. -type decode_format() - :: record | list | map | false. + :: record + | list + | map + | false + | record_from_map. %% Options passed to start_service/2 diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 09018308d5..d591fa903e 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -771,7 +771,8 @@ opt(K, true = B) opt(decode_format, T) when T == record; T == list; - T == map -> + T == map; + T == record_from_map -> T; opt(restrict_connections, T) diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 239d4a535f..78d8bd2fa3 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -186,7 +186,7 @@ decode_avps(Name, Recs, #{module := Mod, decode_format := Fmt} = Opts) -> %% AM counts the number of top-level AVPs, which missing/4 then %% uses when adding 5005 errors. Arities = Mod:avp_arity(Name), - {reformat(Rec, Arities, Fmt), + {reformat(Rec, Arities, Mod, Fmt), Avps, Failed ++ missing(Arities, Opts, Mod, AM)}. @@ -760,12 +760,17 @@ newrec(_, Name, _) -> newrec(Mod, Name) -> Mod:'#new-'(Mod:name2rec(Name)). -%% reformat/3 +%% reformat/4 -reformat(Map, Arities, list) -> +reformat(Map, Arities, _Mod, list) -> [{F,V} || {F,_} <- Arities, #{F := V} <- [Map]]; -reformat(Rec, _, _) -> +reformat(Map, Arities, Mod, record_from_map) -> + #{':name' := Name} = Map, + RecName = Mod:name2rec(Name), + list_to_tuple([RecName | [maps:get(F, Map, def(A)) || {F,A} <- Arities]]); + +reformat(Rec, _, _, _) -> Rec. %% def/1 -- cgit v1.2.3 From 2984749c093cc4b599190e2dcdaad4335899ecd4 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 8 Jul 2017 02:17:42 +0200 Subject: Don't exercise client/server encoding independently in traffic suite To reduce the number of config combinations that are tested. The encoding is the format in which messages are provided to diameter for encode (to binary), and if there is any difference in the end result then the peer will detect this at decode, independently of its encoding format. --- lib/diameter/test/diameter_traffic_SUITE.erl | 36 +++++++++++++--------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index aa0098ccd6..eb2a9833f7 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -167,13 +167,12 @@ -record(group, {transport, strings, + encoding, client_service, - client_encoding, client_dict, client_sender, server_service, server_decoding, - server_encoding, server_container, server_sender, server_throttle}). @@ -268,13 +267,12 @@ all() -> groups() -> [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] ++ - [{?util:name([T,CE,D,SE,SD,SC,S,SS,ST,CS]), + [{?util:name([T,E,D,SD,SC,S,SS,ST,CS]), [], [{group, if S -> shuffle; not S -> parallel end}]} || T <- ?TRANSPORTS, - CE <- ?ENCODINGS, + E <- ?ENCODINGS, D <- ?RFCS, - SE <- ?ENCODINGS, SD <- ?DECODINGS, SC <- ?CONTAINERS, S <- ?STRING_DECODES, @@ -282,10 +280,9 @@ groups() -> ST <- ?CALLBACKS, CS <- ?SENDERS] ++ - [{T, [], groups([[T,CE,D,SE,SD,SC,S,SS,ST,CS] - || CE <- ?ENCODINGS, + [{T, [], groups([[T,E,D,SD,SC,S,SS,ST,CS] + || E <- ?ENCODINGS, D <- ?RFCS, - SE <- ?ENCODINGS, SD <- ?DECODINGS, SC <- ?CONTAINERS, S <- ?STRING_DECODES, @@ -298,7 +295,7 @@ groups() -> [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}]. %groups(_) -> %% debug -% Name = [tcp,record,rfc6733,record,map,pkt,false,false,false,false], +% Name = [tcp,record,rfc6733,map,pkt,false,false,false,false], % [{group, ?util:name(Name)}]; groups(Names) -> [{group, ?util:name(L)} || L <- Names]. @@ -337,18 +334,17 @@ init_per_group(sctp = Name, Config) -> init_per_group(Name, Config) -> Nas = proplists:get_value(rfc4005, Config, false), case ?util:name(Name) of - [_,_,D,_,_,_,_,_,_,_] when D == rfc4005, true /= Nas -> + [_,_,D,_,_,_,_,_,_] when D == rfc4005, true /= Nas -> {skip, rfc4005}; - [T,CE,D,SE,SD,SC,S,SS,ST,CS] -> + [T,E,D,SD,SC,S,SS,ST,CS] -> G = #group{transport = T, strings = S, + encoding = E, client_service = [$C|?util:unique_string()], - client_encoding = CE, client_dict = appdict(D), client_sender = CS, server_service = [$S|?util:unique_string()], server_decoding = SD, - server_encoding = SE, server_container = SC, server_sender = SS, server_throttle = ST}, @@ -469,10 +465,10 @@ start_services(Config) -> add_transports(Config) -> #group{transport = T, + encoding = E, client_service = CN, client_sender = CS, server_service = SN, - server_encoding = SE, server_container = SC, server_sender = SS, server_throttle = ST} @@ -495,7 +491,7 @@ add_transports(Config) -> || D <- ?DECODINGS, %% for multiple candidate peers R <- ?RFCS, R /= rfc4005 orelse have_nas(), - Id <- [{D,SE,SC}]], + Id <- [{D,E,SC}]], %% The server uses the client's Origin-State-Id to decide how to %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). @@ -1046,14 +1042,14 @@ call(Config, Req) -> call(Config, Req, Opts) -> Name = proplists:get_value(testcase, Config), - #group{client_service = CN, - client_encoding = ReqEncoding, + #group{encoding = Enc, + client_service = CN, client_dict = Dict0} = Group = group(Config), diameter:call(CN, dict(Req, Dict0), - msg(Req, ReqEncoding, Dict0), + msg(Req, Enc, Dict0), [{extra, [{Name, Group}, diameter_lib:now()]} | Opts]). origin({D,E,C}) -> @@ -1231,9 +1227,9 @@ pick_peer(_Peers, _, [$C|_], _State, {send_nopeer, _}, _, ?EXTRA) -> pick_peer(Peers, _, [$C|_], _State, {send_detach, Group}, _, {_,_}) -> find(Group, Peers). -find(#group{client_service = CN, +find(#group{encoding = E, + client_service = CN, server_decoding = D, - server_encoding = E, server_container = C}, [_|_] = Peers) -> Id = {D,E,C}, -- cgit v1.2.3 From 6c30cae16dcb1dc320c51e38c5cc477d52b46078 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 10 Jul 2017 15:08:28 +0200 Subject: Randomly wrap answers in diameter_packet in transport suite To reduce the number of combinations tested, as in the parent commit. --- lib/diameter/test/diameter_traffic_SUITE.erl | 61 +++++++++++++--------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index eb2a9833f7..8533dcaf77 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -145,9 +145,6 @@ %% How to decode incoming messages. -define(DECODINGS, [record, false, map, list]). -%% How to send answers, in a diameter_packet or not. --define(CONTAINERS, [pkt, msg]). - %% Which dictionary to use in the clients. -define(RFCS, [rfc3588, rfc6733, rfc4005]). @@ -173,7 +170,6 @@ client_sender, server_service, server_decoding, - server_container, server_sender, server_throttle}). @@ -267,24 +263,22 @@ all() -> groups() -> [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] ++ - [{?util:name([T,E,D,SD,SC,S,SS,ST,CS]), + [{?util:name([T,E,D,SD,S,SS,ST,CS]), [], [{group, if S -> shuffle; not S -> parallel end}]} || T <- ?TRANSPORTS, E <- ?ENCODINGS, D <- ?RFCS, SD <- ?DECODINGS, - SC <- ?CONTAINERS, S <- ?STRING_DECODES, SS <- ?SENDERS, ST <- ?CALLBACKS, CS <- ?SENDERS] ++ - [{T, [], groups([[T,E,D,SD,SC,S,SS,ST,CS] + [{T, [], groups([[T,E,D,SD,S,SS,ST,CS] || E <- ?ENCODINGS, D <- ?RFCS, SD <- ?DECODINGS, - SC <- ?CONTAINERS, S <- ?STRING_DECODES, SS <- ?SENDERS, ST <- ?CALLBACKS, @@ -295,7 +289,7 @@ groups() -> [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}]. %groups(_) -> %% debug -% Name = [tcp,record,rfc6733,map,pkt,false,false,false,false], +% Name = [tcp,record,rfc6733,map,false,false,false,false], % [{group, ?util:name(Name)}]; groups(Names) -> [{group, ?util:name(L)} || L <- Names]. @@ -334,9 +328,9 @@ init_per_group(sctp = Name, Config) -> init_per_group(Name, Config) -> Nas = proplists:get_value(rfc4005, Config, false), case ?util:name(Name) of - [_,_,D,_,_,_,_,_,_] when D == rfc4005, true /= Nas -> + [_,_,D,_,_,_,_,_] when D == rfc4005, true /= Nas -> {skip, rfc4005}; - [T,E,D,SD,SC,S,SS,ST,CS] -> + [T,E,D,SD,S,SS,ST,CS] -> G = #group{transport = T, strings = S, encoding = E, @@ -345,7 +339,6 @@ init_per_group(Name, Config) -> client_sender = CS, server_service = [$S|?util:unique_string()], server_decoding = SD, - server_container = SC, server_sender = SS, server_throttle = ST}, %% Limit the number of testcase, since the number of @@ -469,7 +462,6 @@ add_transports(Config) -> client_service = CN, client_sender = CS, server_service = SN, - server_container = SC, server_sender = SS, server_throttle = ST} = group(Config), @@ -491,7 +483,7 @@ add_transports(Config) -> || D <- ?DECODINGS, %% for multiple candidate peers R <- ?RFCS, R /= rfc4005 orelse have_nas(), - Id <- [{D,E,SC}]], + Id <- [{D,E}]], %% The server uses the client's Origin-State-Id to decide how to %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). @@ -1052,11 +1044,11 @@ call(Config, Req, Opts) -> msg(Req, Enc, Dict0), [{extra, [{Name, Group}, diameter_lib:now()]} | Opts]). -origin({D,E,C}) -> - 8*decode(D) + 2*encode(E) + container(C); +origin({D,E}) -> + 4*decode(D) + encode(E); origin(N) -> - {decode(N bsr 3), encode((N bsr 1) rem 4), container(N rem 2)}. + {decode(N bsr 2), encode(N rem 4)}. %% Map atoms. The atoms are part of (constructed) group names, so it's %% good that they're readable. @@ -1077,11 +1069,6 @@ encode(0) -> record; encode(1) -> list; encode(2) -> map. -container(pkt) -> 0; -container(msg) -> 1; -container(0) -> pkt; -container(_) -> msg. - msg([H|_] = Msg, record = E, diameter_gen_base_rfc3588) when H == 'ACR'; H == 'ACA' -> @@ -1229,10 +1216,9 @@ pick_peer(Peers, _, [$C|_], _State, {send_detach, Group}, _, {_,_}) -> find(#group{encoding = E, client_service = CN, - server_decoding = D, - server_container = C}, + server_decoding = D}, [_|_] = Peers) -> - Id = {D,E,C}, + Id = {D,E}, [P] = [P || P <- Peers, id(Id, P, CN)], {ok, P}. @@ -1544,22 +1530,33 @@ handle_request(#diameter_packet{header = H, avps = As} V = EI bsr B, %% assert V = HI bsr B, %% #diameter_caps{origin_state_id = {_,[Id]}} = Caps, - {D,_,_} = T = origin(Id), + {D,_} = T = origin(Id), wrap(T, H, request(to_map(D, Pkt), [H|As], Caps)). wrap(Id, H, {Tag, Action, Post}) -> {Tag, wrap(Id, H, Action), Post}; + wrap(_, _, {reply, [#diameter_header{} | _]} = T) -> T; -wrap({_,E,C}, H, {reply, Ans}) -> - Msg = msg(Ans, E, diameter_gen_base_rfc3588), - wrap(C, H, {reply, base_to_nas(Msg, H)}); -wrap(pkt, _, {reply, Ans}) - when not is_record(Ans, diameter_packet) -> - {reply, #diameter_packet{msg = Ans}}; + +wrap({_,E}, H, {reply, Ans}) -> + Msg = base_to_nas(msg(Ans, E, diameter_gen_base_rfc3588), H), + {reply, wrap(Msg)}; + wrap(_, _, T) -> T. +%% Randomly wrap the answer in a diameter_packet. + +wrap(#diameter_packet{} = Pkt) -> + Pkt; + +wrap(Msg) -> + case rand:uniform(2) of + 1 -> #diameter_packet{msg = Msg}; + 2 -> Msg + end. + %% base_to_nas/2 base_to_nas(#diameter_packet{msg = Msg} = Pkt, H) -> -- cgit v1.2.3 From 58f9d631df0c256f7bc4ff3de2670b3b04e265f7 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 8 Jul 2017 09:35:59 +0200 Subject: Rearrange group names in traffic suite For slightly better readability in the ct logs --- lib/diameter/test/diameter_traffic_SUITE.erl | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 8533dcaf77..100a4eebc9 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -263,25 +263,25 @@ all() -> groups() -> [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] ++ - [{?util:name([T,E,D,SD,S,SS,ST,CS]), + [{?util:name([T,R,E,D,S,ST,SS,CS]), [], [{group, if S -> shuffle; not S -> parallel end}]} || T <- ?TRANSPORTS, + R <- ?RFCS, E <- ?ENCODINGS, - D <- ?RFCS, - SD <- ?DECODINGS, + D <- ?DECODINGS, S <- ?STRING_DECODES, - SS <- ?SENDERS, ST <- ?CALLBACKS, + SS <- ?SENDERS, CS <- ?SENDERS] ++ - [{T, [], groups([[T,E,D,SD,S,SS,ST,CS] - || E <- ?ENCODINGS, - D <- ?RFCS, - SD <- ?DECODINGS, + [{T, [], groups([[T,R,E,D,S,ST,SS,CS] + || R <- ?RFCS, + E <- ?ENCODINGS, + D <- ?DECODINGS, S <- ?STRING_DECODES, - SS <- ?SENDERS, ST <- ?CALLBACKS, + SS <- ?SENDERS, CS <- ?SENDERS, SS orelse CS])} %% avoid deadlock || T <- ?TRANSPORTS] @@ -289,7 +289,7 @@ groups() -> [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}]. %groups(_) -> %% debug -% Name = [tcp,record,rfc6733,map,false,false,false,false], +% Name = [tcp,rfc6733,record,map,false,false,false,false], % [{group, ?util:name(Name)}]; groups(Names) -> [{group, ?util:name(L)} || L <- Names]. @@ -328,17 +328,17 @@ init_per_group(sctp = Name, Config) -> init_per_group(Name, Config) -> Nas = proplists:get_value(rfc4005, Config, false), case ?util:name(Name) of - [_,_,D,_,_,_,_,_] when D == rfc4005, true /= Nas -> + [_,R,_,_,_,_,_,_] when R == rfc4005, true /= Nas -> {skip, rfc4005}; - [T,E,D,SD,S,SS,ST,CS] -> + [T,R,E,D,S,ST,SS,CS] -> G = #group{transport = T, strings = S, encoding = E, client_service = [$C|?util:unique_string()], - client_dict = appdict(D), + client_dict = appdict(R), client_sender = CS, server_service = [$S|?util:unique_string()], - server_decoding = SD, + server_decoding = D, server_sender = SS, server_throttle = ST}, %% Limit the number of testcase, since the number of -- cgit v1.2.3 From e0603ba18a67c1ef33f60122fe6f00393c0c0203 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 13 Jul 2017 01:28:06 +0200 Subject: Tweak map-valued decode Use the same [MsgName | Avps] representation as for the list decode, but with Avps a map instead of a AVP name/values list. As a result, don't set the message/AVP name on an additional key in the map, which felt a bit odd. Messages are [MsgName :: atom() | map()], Grouped AVPs are just map(). Fix at least one problem in the traffic suite along the way: with decode_format false, the own decode in to_map/2 didn't know whether or not to decode strings, resulting on some failures. --- lib/diameter/doc/src/diameter.xml | 12 +- lib/diameter/doc/src/diameter_codec.xml | 8 +- lib/diameter/src/base/diameter_codec.erl | 7 +- lib/diameter/src/base/diameter_gen.erl | 13 +- lib/diameter/src/base/diameter_traffic.erl | 58 ++--- lib/diameter/test/diameter_traffic_SUITE.erl | 332 ++++++++++++--------------- 6 files changed, 193 insertions(+), 237 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index a7f001e096..43cb3a538c 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -539,7 +539,7 @@ that matches no peer.

The host and realm filters cause the Destination-Host and Destination-Realm AVPs to be extracted from the -outgoing request, assuming it to be a record-, list- or map-valued +outgoing request, assuming it to be a record- or list-valued &codec_message;, and assuming at most one of each AVP. If this is not the case then the {host|realm, &dict_DiameterIdentity;} filters must be used to achieve the desired result. @@ -802,10 +802,16 @@ be matched by corresponding &capability; configuration, of {decode_format, record | list | map | false}

-The type of decoded messages and grouped AVPs in the msg field +The format of decoded messages and grouped AVPs in the msg field of diameter_packet records and value field of diameter_avp records respectively. -If false then the fields are set this value. +If record then a record whose definition is generated from the +dictionary file in question. +If list or map then a [Name | Avps] pair where +Avps is either a list of AVP name/values pairs or a map keyed on +AVP names respectively. +If false then the representation is omitted and msg and +value fields are set to false. See also &codec_message;.

diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml index 4df8e788b7..0846334d23 100644 --- a/lib/diameter/doc/src/diameter_codec.xml +++ b/lib/diameter/doc/src/diameter_codec.xml @@ -230,7 +230,8 @@ header.

-message() = record() | list() | map() +message() = record() + | maybe_improper_list()

The representation of a Diameter message as passed to @@ -240,9 +241,8 @@ a message as defined in a dictionary file is encoded as a record with one field for each component AVP. Equivalently, a message can also be encoded as a list whose head is the atom-valued message name (as specified in the relevant dictionary -file) and whose tail is a list of {AvpName, AvpValues} pairs, -or as a map with values keyed on AVP names and the message name in key -:name. +file) and whose tail is either a list of AVP name/values +pairs or a map with values keyed on AVP names. The format at decode is determined by &mod_service_opt; decode_format. Any of the formats is accepted at encode.

diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 275e80b9bb..9b21bf4141 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -275,9 +275,6 @@ rec2msg(_, [Name|_]) when is_atom(Name) -> Name; -rec2msg(_, #{':name' := Name}) -> - Name; - rec2msg(Mod, Rec) -> Mod:rec2msg(element(1, Rec)). @@ -383,7 +380,9 @@ decode_avps(MsgName, Mod, AppMod, Opts, Pkt, Avps) -> %% ... or not errors = Errors, avps = As}. -reformat(MsgName, Avps, #{decode_format := list}) -> +reformat(MsgName, Avps, #{decode_format := T}) + when T == map; + T == list -> [MsgName | Avps]; reformat(_, Msg, _) -> diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 78d8bd2fa3..597ec143a8 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -186,7 +186,7 @@ decode_avps(Name, Recs, #{module := Mod, decode_format := Fmt} = Opts) -> %% AM counts the number of top-level AVPs, which missing/4 then %% uses when adding 5005 errors. Arities = Mod:avp_arity(Name), - {reformat(Rec, Arities, Mod, Fmt), + {reformat(Name, Rec, Arities, Mod, Fmt), Avps, Failed ++ missing(Arities, Opts, Mod, AM)}. @@ -752,8 +752,8 @@ newrec(_, _, false = No) -> newrec(Mod, Name, record) -> newrec(Mod, Name); -newrec(_, Name, _) -> - #{':name' => Name}. +newrec(_, _, _) -> + #{}. %% newrec/2 @@ -762,15 +762,14 @@ newrec(Mod, Name) -> %% reformat/4 -reformat(Map, Arities, _Mod, list) -> +reformat(_, Map, Arities, _Mod, list) -> [{F,V} || {F,_} <- Arities, #{F := V} <- [Map]]; -reformat(Map, Arities, Mod, record_from_map) -> - #{':name' := Name} = Map, +reformat(Name, Map, Arities, Mod, record_from_map) -> RecName = Mod:name2rec(Name), list_to_tuple([RecName | [maps:get(F, Map, def(A)) || {F,A} <- Arities]]); -reformat(Rec, _, _, _) -> +reformat(_, Rec, _, _, _) -> Rec. %% def/1 diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index f684f60cb7..e9c422d6ab 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -621,16 +621,10 @@ is_answer_message(#diameter_packet{msg = Msg}, Dict0) -> is_answer_message([#diameter_header{is_request = R, is_error = E} | _], _) -> E andalso not R; -%% Message sent as a tagged avp/value list. +%% Message sent as a map or tagged avp/value list. is_answer_message([Name | _], _) -> Name == 'answer-message'; -%% Message sent as a map. -is_answer_message(Map, _) - when is_map(Map) -> - #{':name' := Name} = Map, - Name == 'answer-message'; - %% Message sent as a record. is_answer_message(Rec, Dict) -> try @@ -875,15 +869,13 @@ reset(Msg, [RC | Avps], Dict) -> %% set/3 -%% Reply as name and tuple list ... +%% Reply as name/values list ... +set([Name|As], Avps, _) + when is_map(As) -> + [Name | maps:merge(As, maps:from_list(Avps))]; set([_|_] = Ans, Avps, _) -> Ans ++ Avps; %% Values nearer tail take precedence. -%% ... a map ... -set(Ans, Avps, _) - when is_map(Ans) -> - maps:merge(Ans, maps:from_list(Avps)); - %% ... or record. set(Rec, Avps, Dict) -> Dict:'#set-'(Avps, Rec). @@ -902,9 +894,6 @@ rc([MsgName | _], RC, Dict) -> _ -> [] end; -rc(#{':name' := Name}, RC, Dict) -> - rc([Name], RC, Dict); - rc(Rec, RC, Dict) -> rc([Dict:rec2msg(element(1, Rec))], RC, Dict). @@ -937,10 +926,6 @@ failed(Msg, FailedAvp, Dict) -> msg2rec([MsgName | _], Dict) -> Dict:msg2rec(MsgName); -%% ... map ... -msg2rec(#{':name' := MsgName}, Dict) -> - Dict:msg2rec(MsgName); - %% ... or record. msg2rec(Rec, _) -> element(1, Rec). @@ -949,12 +934,11 @@ msg2rec(Rec, _) -> %% Message as name/values list ... values([_ | Avps], F, _) -> - proplists:get_value(F, Avps, []); - -%% ... map ... -values(Msg, F, _) - when is_map(Msg) -> - maps:get(F, Msg, []); + if is_map(Avps) -> + maps:get(F, Avps, []); + is_list(Avps) -> + proplists:get_value(F, Avps, []) + end; %% ... or record. values(Rec, F, Dict) -> @@ -1906,23 +1890,13 @@ get_avp(Dict, Name, [#diameter_header{} | Avps]) -> %% Message as name/values list ... get_avp(_, Name, [_MsgName | Avps]) -> - case lists:keyfind(Name, 1, Avps) of + case find(Name, Avps) of {_, V} -> #diameter_avp{name = Name, value = V}; _ -> undefined end; -%% ... map ... -get_avp(_, Name, Map) - when is_map(Map) -> - case maps:find(Name, Map) of - {ok, V} -> - #diameter_avp{name = Name, value = V}; - error -> - undefined - end; - %% ... or record (but not necessarily). get_avp(Dict, Name, Rec) -> try @@ -1932,6 +1906,16 @@ get_avp(Dict, Name, Rec) -> undefined end. +%% find/2 + +find(Key, Map) + when is_map(Map) -> + maps:find(Key, Map); + +find(Key, List) + when is_list(List) -> + lists:keyfind(Key, 1, List). + %% get_avp_value/3 get_avp_value(Dict, Name, Msg) -> diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 100a4eebc9..fae9f86c38 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -99,14 +99,14 @@ stop/1]). %% diameter callbacks --export([peer_up/3, - peer_down/3, - pick_peer/6, pick_peer/7, - prepare_request/5, prepare_request/6, - prepare_retransmit/5, - handle_answer/6, handle_answer/7, - handle_error/6, - handle_request/3]). +-export([peer_up/4, + peer_down/4, + pick_peer/7, pick_peer/8, + prepare_request/6, prepare_request/7, + prepare_retransmit/6, + handle_answer/7, handle_answer/8, + handle_error/7, + handle_request/4]). %% diameter_{tcp,sctp} callbacks -export([message/3]). @@ -182,19 +182,17 @@ %% A common match when receiving answers in a client. -define(answer_message(SessionId, ResultCode), - #{':name' := 'answer-message', - 'Session-Id' := SessionId, - 'Origin-Host' := _, - 'Origin-Realm' := _, - 'Result-Code' := ResultCode}). + ['answer-message' | #{'Session-Id' := SessionId, + 'Origin-Host' := _, + 'Origin-Realm' := _, + 'Result-Code' := ResultCode}]). -define(answer_message(ResultCode), - #{':name' := 'answer-message', - 'Origin-Host' := _, - 'Origin-Realm' := _, - 'Result-Code' := ResultCode}). + ['answer-message' | #{'Origin-Host' := _, + 'Origin-Realm' := _, + 'Result-Code' := ResultCode}]). %% Config for diameter:start_service/2. --define(SERVICE(Name, Decode), +-define(SERVICE(Name, Grp), [{'Origin-Host', Name ++ "." ++ ?REALM}, {'Origin-Realm', ?REALM}, {'Host-IP-Address', [?ADDR]}, @@ -203,10 +201,10 @@ {'Auth-Application-Id', [0]}, %% common messages {'Acct-Application-Id', [3]}, %% base accounting {restrict_connections, false}, - {string_decode, Decode}, + {string_decode, Grp#group.strings}, {incoming_maxlen, 1 bsl 21} | [{application, [{dictionary, D}, - {module, ?MODULE}, + {module, [?MODULE, Grp]}, {answer_errors, callback}]} || D <- [diameter_gen_base_rfc3588, diameter_gen_base_accounting, @@ -446,15 +444,15 @@ start(_Config) -> ok = diameter:start(). start_services(Config) -> - #group{strings = S, - client_service = CN, + #group{client_service = CN, server_service = SN, server_decoding = SD} + = Grp = group(Config), ok = diameter:start_service(SN, [{decode_format, SD} - | ?SERVICE(SN, S)]), + | ?SERVICE(SN, Grp)]), ok = diameter:start_service(CN, [{sequence, ?CLIENT_MASK} - | ?SERVICE(CN, S)]). + | ?SERVICE(CN, Grp)]). add_transports(Config) -> #group{transport = T, @@ -484,8 +482,6 @@ add_transports(Config) -> R <- ?RFCS, R /= rfc4005 orelse have_nas(), Id <- [{D,E}]], - %% The server uses the client's Origin-State-Id to decide how to - %% answer. ?util:write_priv(Config, "transport", [LRef | Cs]). server_apps() -> @@ -567,9 +563,8 @@ send_ok(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 1}], - #{':name' := 'ACA', - 'Result-Code' := ?SUCCESS, - 'Session-Id' := _} + ['ACA' | #{'Result-Code' := ?SUCCESS, + 'Session-Id' := _}] = call(Config, Req). %% Send an accounting ACR that the server answers badly to. @@ -585,9 +580,8 @@ send_eval(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 3}], - #{':name' := 'ACA', - 'Result-Code' := ?SUCCESS, - 'Session-Id' := _} + ['ACA' | #{'Result-Code' := ?SUCCESS, + 'Session-Id' := _}] = call(Config, Req). %% Send an accounting ACR that the server tries to answer with an @@ -613,8 +607,7 @@ send_protocol_error(Config) -> send_experimental_result(Config) -> Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, {'Accounting-Record-Number', 5}], - #{':name' := 'ACA', - 'Session-Id' := _} + ['ACA' | #{'Session-Id' := _}] = call(Config, Req). %% Send an ASR with an arbitrary non-mandatory AVP and expect success @@ -622,11 +615,10 @@ send_experimental_result(Config) -> send_arbitrary(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{name = 'Product-Name', value = "XXX"}]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS, - 'AVP' := [#diameter_avp{name = 'Product-Name', - value = V}]} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS, + 'AVP' := [#diameter_avp{name = 'Product-Name', + value = V}]}] = call(Config, Req), "XXX" = string(V, Config). @@ -635,12 +627,11 @@ send_unknown(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = false, data = <<17>>}]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS, - 'AVP' := [#diameter_avp{code = 999, - is_mandatory = false, - data = <<17>>}]} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS, + 'AVP' := [#diameter_avp{code = 999, + is_mandatory = false, + data = <<17>>}]}] = call(Config, Req). %% Ditto, and point the AVP length past the end of the message. Expect @@ -652,10 +643,9 @@ send_unknown_short(Config, M, RC) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = M, data = <<17>>}]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := RC, - 'Failed-AVP' := Avps} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := RC, + 'Failed-AVP' := Avps}] = call(Config, Req), [[#diameter_avp{code = 999, is_mandatory = M, @@ -667,10 +657,9 @@ send_unknown_mandatory(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 999, is_mandatory = true, data = <<17>>}]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := ?AVP_UNSUPPORTED, - 'Failed-AVP' := Avps} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED, + 'Failed-AVP' := Avps}] = call(Config, Req), [[#diameter_avp{code = 999, is_mandatory = true, @@ -688,10 +677,9 @@ send_unexpected_mandatory_decode(Config) -> Req = ['ASR', {'AVP', [#diameter_avp{code = 27, %% Session-Timeout is_mandatory = true, data = <<12:32>>}]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := ?AVP_UNSUPPORTED, - 'Failed-AVP' := Avps} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED, + 'Failed-AVP' := Avps}] = call(Config, Req), [[#diameter_avp{code = 27, is_mandatory = true, @@ -707,10 +695,9 @@ send_unexpected_mandatory_decode(Config) -> send_grouped_error(Config) -> Req = ['ASR', {'Proxy-Info', [[{'Proxy-Host', "abcd"}, {'Proxy-State', ""}]]}], - #{':name' := 'ASA', - 'Session-Id' := _, - 'Result-Code' := ?INVALID_AVP_LENGTH, - 'Failed-AVP' := Avps} + ['ASA' | #{'Session-Id' := _, + 'Result-Code' := ?INVALID_AVP_LENGTH, + 'Failed-AVP' := Avps}] = call(Config, Req), [[#diameter_avp{name = 'Proxy-Info', value = V}]] = failed_avps(Avps, Config), @@ -743,9 +730,8 @@ send_error_bit(Config) -> %% Send a bad version and check that we get 5011. send_unsupported_version(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?UNSUPPORTED_VERSION} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?UNSUPPORTED_VERSION}] = call(Config, Req). %% Send a request containing an AVP length > data size. @@ -765,12 +751,11 @@ send_zero_avp_length(Config) -> send_invalid_avp_length(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?INVALID_AVP_LENGTH, - 'Origin-Host' := _, - 'Origin-Realm' := _, - 'Failed-AVP' := Avps} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?INVALID_AVP_LENGTH, + 'Origin-Host' := _, + 'Origin-Realm' := _, + 'Failed-AVP' := Avps}] = call(Config, Req), [[_]] = failed_avps(Avps, Config). @@ -787,18 +772,16 @@ send_invalid_reject(Config) -> send_unexpected_mandatory(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?AVP_UNSUPPORTED} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?AVP_UNSUPPORTED}] = call(Config, Req). %% Send something long that will be fragmented by TCP. send_long(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}, {'User-Name', [binary:copy(<<$X>>, 1 bsl 20)]}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = call(Config, Req). %% Send something longer than the configure incoming_maxlen. @@ -841,9 +824,8 @@ send_any_2(Config) -> send_all_1(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], Realm = lists:foldr(fun(C,A) -> [C,A] end, [], ?REALM), - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = call(Config, Req, [{filter, {all, [{host, any}, {realm, Realm}]}}]). send_all_2(Config) -> @@ -872,9 +854,8 @@ send_detach(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], Ref = make_ref(), ok = call(Config, Req, [{extra, [{self(), Ref}]}, detach]), - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = receive {Ref, T} -> T end. %% Send a request which can't be encoded and expect {error, encode}. @@ -887,15 +868,13 @@ send_destination_1(Config) -> = group(Config), Req = ['STR', {'Termination-Cause', ?LOGOUT}, {'Destination-Host', [?HOST(SN, ?REALM)]}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = call(Config, Req, [{filter, {all, [host, realm]}}]). send_destination_2(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = call(Config, Req, [{filter, {all, [host, realm]}}]). %% Send with filtering on and expect failure when specifying an @@ -959,9 +938,8 @@ send_bad_filter(Config, F) -> %% Specify multiple filter options and expect them be conjunctive. send_multiple_filters_1(Config) -> Fun = fun(#diameter_caps{}) -> true end, - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = send_multiple_filters(Config, [host, {eval, Fun}]). send_multiple_filters_2(Config) -> E = {erlang, is_tuple, []}, @@ -972,9 +950,8 @@ send_multiple_filters_3(Config) -> E2 = {erlang, is_tuple, []}, E3 = {erlang, is_record, [diameter_caps]}, E4 = [{erlang, is_record, []}, diameter_caps], - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = send_multiple_filters(Config, [{eval, E} || E <- [E1,E2,E3,E4]]). send_multiple_filters(Config, Fs) -> @@ -985,9 +962,8 @@ send_multiple_filters(Config, Fs) -> %% only the return value from the prepare_request callback being %% significant. send_anything(Config) -> - #{':name' := 'STA', - 'Session-Id' := _, - 'Result-Code' := ?SUCCESS} + ['STA' | #{'Session-Id' := _, + 'Result-Code' := ?SUCCESS}] = call(Config, anything). %% =========================================================================== @@ -1037,12 +1013,11 @@ call(Config, Req, Opts) -> #group{encoding = Enc, client_service = CN, client_dict = Dict0} - = Group = group(Config), diameter:call(CN, dict(Req, Dict0), msg(Req, Enc, Dict0), - [{extra, [{Name, Group}, diameter_lib:now()]} | Opts]). + [{extra, [Name, diameter_lib:now()]} | Opts]). origin({D,E}) -> 4*decode(D) + encode(E); @@ -1082,32 +1057,37 @@ msg([H|_] = Msg, record = E, diameter_gen_base_rfc6733) msg([H|T], record, Dict) -> Dict:'#new-'(Dict:msg2rec(H), T); -msg([H|T], map, _) -> - Map = maps:from_list(T), - Map#{':name' => H}; +msg([H|As], map, _) + when is_list(As) -> + [H | maps:from_list(As)]; msg(Msg, _, _) -> Msg. -to_map(map, #diameter_packet{msg = Msg}) - when is_map(Msg) -> +to_map(#diameter_packet{msg = [_MsgName | Avps] = Msg}, + #group{server_decoding = map}) + when is_map(Avps) -> Msg; -to_map(list, #diameter_packet{msg = [MsgName | Avps]}) -> - maps:put(':name', MsgName, maps:from_list(Avps)); +to_map(#diameter_packet{msg = [MsgName | Avps]}, + #group{server_decoding = list}) -> + [MsgName | maps:from_list(Avps)]; -to_map(record, #diameter_packet{header = H, msg = Rec}) -> +to_map(#diameter_packet{header = H, msg = Rec}, + #group{server_decoding = record}) -> rec_to_map(Rec, dict(H)); %% No record decode: do it ourselves. -to_map(false, #diameter_packet{header = H, - msg = false, - bin = Bin}) -> +to_map(#diameter_packet{header = H, + msg = false, + bin = Bin}, + #group{server_decoding = false, + strings = B}) -> Opts = #{decode_format => map, - string_decode => false, + string_decode => B, strict_mbit => true, rfc => 6733}, - #diameter_packet{msg = Msg} + #diameter_packet{msg = [_MsgName | _Map] = Msg} = diameter_codec:decode(dict(H), Opts, Bin), Msg. @@ -1123,11 +1103,9 @@ dict(#diameter_header{application_id = Id, rec_to_map(Rec, Dict) -> [R | Vs] = Dict:'#get-'(Rec), - maps:put(':name', - Dict:rec2msg(R), - maps:from_list([T || {_,V} = T <- Vs, - V /= undefined, - V /= []])). + [Dict:rec2msg(R) | maps:from_list([T || {_,V} = T <- Vs, + V /= undefined, + V /= []])]. appdict(rfc4005) -> nas4005; @@ -1166,12 +1144,12 @@ acct(diameter_gen_base_rfc6733) -> %% Set only values that aren't already. -set(_, [H|T], Vs) -> - [H | Vs ++ T]; - -set(_, Map, Vs) - when is_map(Map) -> - maps:merge(maps:from_list(Vs), Map); +set(_, [N | As], Vs) -> + [N | if is_map(As) -> + maps:merge(maps:from_list(Vs), As); + is_list(As) -> + Vs ++ As + end]; set(#group{client_dict = Dict0} = _Group, Rec, Vs) -> Dict = dict(Rec, Dict0), @@ -1192,26 +1170,26 @@ reset(_, _, _, Rec) -> %% =========================================================================== %% diameter callbacks -%% peer_up/3 +%% peer_up/4 -peer_up(_SvcName, _Peer, State) -> +peer_up(_SvcName, _Peer, State, _Group) -> State. %% peer_down/3 -peer_down(_SvcName, _Peer, State) -> +peer_down(_SvcName, _Peer, State, _Group) -> State. -%% pick_peer/6-7 +%% pick_peer/7-8 -pick_peer(Peers, _, [$C|_], _State, {Name, Group}, _) +pick_peer(Peers, _, [$C|_], _State, Group, Name, _) when Name /= send_detach -> find(Group, Peers). -pick_peer(_Peers, _, [$C|_], _State, {send_nopeer, _}, _, ?EXTRA) -> +pick_peer(_Peers, _, [$C|_], _State, _Group, send_nopeer, _, ?EXTRA) -> false; -pick_peer(Peers, _, [$C|_], _State, {send_detach, Group}, _, {_,_}) -> +pick_peer(Peers, _, [$C|_], _State, Group, send_detach, _, {_,_}) -> find(Group, Peers). find(#group{encoding = E, @@ -1227,15 +1205,15 @@ id(Id, {Pid, _Caps}, SvcName) -> = diameter:service_info(SvcName, Pid), lists:member({id, Id}, Opts). -%% prepare_request/5-6 +%% prepare_request/6-7 -prepare_request(_Pkt, [$C|_], {_Ref, _Caps}, {send_discard, _}, _) -> +prepare_request(_Pkt, [$C|_], {_Ref, _Caps}, _, send_discard, _) -> {discard, unprepared}; -prepare_request(Pkt, [$C|_], {_Ref, Caps}, {Name, Group}, _) -> +prepare_request(Pkt, [$C|_], {_Ref, Caps}, Group, Name, _) -> {send, prepare(Pkt, Caps, Name, Group)}. -prepare_request(Pkt, [$C|_], {_Ref, Caps}, {send_detach, Group}, _, _) -> +prepare_request(Pkt, [$C|_], {_Ref, Caps}, Group, send_detach, _, _) -> {eval_packet, {send, prepare(Pkt, Caps, Group)}, [fun log/2, detach]}. log(#diameter_packet{bin = Bin} = P, T) @@ -1446,12 +1424,12 @@ set(N, #diameter_packet{msg = Req}, Caps, Group) %% name/1 +name([H|#{}]) -> + {map, H}; + name([H|_]) -> {list, H}; -name(#{} = Map) -> - {map, maps:get(':name', Map)}; - name(Rec) -> try {record, element(1, Rec)} @@ -1460,17 +1438,17 @@ name(Rec) -> false end. -%% prepare_retransmit/5 +%% prepare_retransmit/6 -prepare_retransmit(_Pkt, false, _Peer, _Name, _Group) -> +prepare_retransmit(_Pkt, false, _Peer, _Group, _Name, _) -> discard. -%% handle_answer/6-7 +%% handle_answer/7-8 -handle_answer(Pkt, Req, [$C|_], Peer, {Name, Group}, _) -> +handle_answer(Pkt, Req, [$C|_], Peer, Group, Name, _) -> answer(Pkt, Req, Peer, Name, Group). -handle_answer(Pkt, Req, [$C|_], Peer, {send_detach = Name, Group}, _, X) -> +handle_answer(Pkt, Req, [$C|_], Peer, Group, send_detach = Name, _, X) -> {Pid, Ref} = X, Pid ! {Ref, answer(Pkt, Req, Peer, Name, Group)}. @@ -1503,18 +1481,18 @@ app(Req, _, Dict0) -> Dict = dict(Req, Dict0), Dict:id(). -%% handle_error/6 +%% handle_error/7 -handle_error(timeout = Reason, _Req, [$C|_], _Peer, _, Time) -> +handle_error(timeout = Reason, _Req, [$C|_], _Peer, _, _, Time) -> Now = diameter_lib:now(), {Reason, {diameter_lib:timestamp(Time), diameter_lib:timestamp(Now), diameter_lib:micro_diff(Now, Time)}}; -handle_error(Reason, _Req, [$C|_], _Peer, _, _Time) -> +handle_error(Reason, _Req, [$C|_], _Peer, _, _, _Time) -> {error, Reason}. -%% handle_request/3 +%% handle_request/4 %% Note that diameter will set Result-Code and Failed-AVPs if %% #diameter_packet.errors is non-null. @@ -1522,7 +1500,10 @@ handle_error(Reason, _Req, [$C|_], _Peer, _, _Time) -> handle_request(#diameter_packet{header = H, avps = As} = Pkt, _, - {_Ref, Caps}) -> + {_Ref, Caps}, + #group{encoding = E, + server_decoding = D} + = Grp) -> #diameter_header{end_to_end_id = EI, hop_by_hop_id = HI} = H, @@ -1530,8 +1511,8 @@ handle_request(#diameter_packet{header = H, avps = As} V = EI bsr B, %% assert V = HI bsr B, %% #diameter_caps{origin_state_id = {_,[Id]}} = Caps, - {D,_} = T = origin(Id), - wrap(T, H, request(to_map(D, Pkt), [H|As], Caps)). + {D,E} = T = origin(Id), %% assert + wrap(T, H, request(to_map(Pkt, Grp), [H|As], Caps)). wrap(Id, H, {Tag, Action, Post}) -> {Tag, wrap(Id, H, Action), Post}; @@ -1585,8 +1566,7 @@ base_to_nas(Msg, _) -> %% request/3 %% send_experimental_result -request(#{':name' := 'ACR', - 'Accounting-Record-Number' := 5}, +request(['ACR' | #{'Accounting-Record-Number' := 5}], [Hdr | Avps], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> @@ -1619,16 +1599,14 @@ request(Msg, _Avps, Caps) -> %% request/2 %% send_nok -request(#{':name' := 'ACR', - 'Accounting-Record-Number' := 0}, +request(['ACR' | #{'Accounting-Record-Number' := 0}], _) -> {eval_packet, {protocol_error, ?INVALID_AVP_BITS}, [fun log/2, invalid]}; %% send_bad_answer -request(#{':name' := 'ACR', - 'Session-Id' := SId, - 'Accounting-Record-Type' := RT, - 'Accounting-Record-Number' := 2 = RN}, +request(['ACR' | #{'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 2 = RN}], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['ACA', {'Result-Code', ?SUCCESS}, @@ -1642,10 +1620,9 @@ request(#{':name' := 'ACR', msg = Ans}}; %% send_eval -request(#{':name' := 'ACR', - 'Session-Id' := SId, - 'Accounting-Record-Type' := RT, - 'Accounting-Record-Number' := 3 = RN}, +request(['ACR' | #{'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 3 = RN}], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['ACA', {'Result-Code', ?SUCCESS}, @@ -1657,10 +1634,9 @@ request(#{':name' := 'ACR', {eval, {reply, Ans}, {erlang, now, []}}; %% send_ok -request(#{':name' := 'ACR', - 'Session-Id' := SId, - 'Accounting-Record-Type' := RT, - 'Accounting-Record-Number' := 1 = RN}, +request(['ACR' | #{'Session-Id' := SId, + 'Accounting-Record-Type' := RT, + 'Accounting-Record-Number' := 1 = RN}], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['ACA', {'Result-Code', ?SUCCESS}, @@ -1671,8 +1647,7 @@ request(#{':name' := 'ACR', {'Accounting-Record-Number', RN}]}; %% send_protocol_error -request(#{':name' := 'ACR', - 'Accounting-Record-Number' := 4}, +request(['ACR' | #{'Accounting-Record-Number' := 4}], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> Ans = ['answer-message', {'Result-Code', ?TOO_BUSY}, @@ -1680,46 +1655,39 @@ request(#{':name' := 'ACR', {'Origin-Realm', OR}], {reply, Ans}; -request(#{':name' := 'ASR', - 'Session-Id' := SId} - = Req, +request(['ASR' | #{'Session-Id' := SId} = Avps], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['ASA', {'Result-Code', ?SUCCESS}, {'Session-Id', SId}, {'Origin-Host', OH}, {'Origin-Realm', OR}, - {'AVP', maps:get('AVP', Req, [])}]}; + {'AVP', maps:get('AVP', Avps, [])}]}; %% send_invalid_reject -request(#{':name' := 'STR', - 'Termination-Cause' := ?USER_MOVED}, +request(['STR' | #{'Termination-Cause' := ?USER_MOVED}], _Caps) -> {protocol_error, ?TOO_BUSY}; %% send_noreply -request(#{':name' := 'STR', - 'Termination-Cause' := T}, +request(['STR' | #{'Termination-Cause' := T}], _Caps) when T /= ?LOGOUT -> discard; %% send_destination_5 -request(#{':name' := 'STR', - 'Destination-Realm' := R}, +request(['STR' | #{'Destination-Realm' := R}], #diameter_caps{origin_realm = {OR, _}}) when R /= undefined, R /= OR -> {protocol_error, ?REALM_NOT_SERVED}; %% send_destination_6 -request(#{':name' := 'STR', - 'Destination-Host' := [H]}, +request(['STR' | #{'Destination-Host' := [H]}], #diameter_caps{origin_host = {OH, _}}) when H /= OH -> {protocol_error, ?UNABLE_TO_DELIVER}; -request(#{':name' := 'STR', - 'Session-Id' := SId}, +request(['STR' | #{'Session-Id' := SId}], #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, ['STA', {'Result-Code', ?SUCCESS}, @@ -1728,7 +1696,7 @@ request(#{':name' := 'STR', {'Origin-Realm', OR}]}; %% send_error/send_timeout -request(#{':name' := 'RAR'}, _Caps) -> +request(['RAR' | #{}], _Caps) -> receive after 2000 -> {protocol_error, ?TOO_BUSY} end. %% message/3 -- cgit v1.2.3 From e54f92c328c8fb117de88b1171f64358f1e7d3b1 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 9 Jul 2017 00:38:56 +0200 Subject: Don't take length of AVP lists unnecessarily at encode Count as AVPs are encoded instead. --- lib/diameter/src/base/diameter_gen.erl | 64 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 597ec143a8..313be5f215 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -104,7 +104,8 @@ enc(_, AvpName, 1, undefined, _, _) -> ?THROW([mandatory_avp_missing, AvpName]); enc(Name, AvpName, 1, Value, Opts, Mod) -> - enc(Name, AvpName, [Value], Opts, Mod); + H = avp_header(AvpName, Mod), + enc1(Name, AvpName, H, Value, Opts, Mod); enc(_, _, {0,_}, [], _, _) -> []; @@ -113,31 +114,47 @@ enc(_, AvpName, _, T, _, _) when not is_list(T) -> ?THROW([repeated_avp_as_non_list, AvpName, T]); -enc(_, AvpName, {Min, _}, L, _, _) - when length(L) < Min -> - ?THROW([repeated_avp_insufficient_arity, AvpName, Min, L]); +enc(Name, AvpName, {Min, Max}, Values, Opts, Mod) -> + H = avp_header(AvpName, Mod), + enc(Name, AvpName, H, Min, 0, Max, Values, Opts, Mod). -enc(_, AvpName, {_, Max}, L, _, _) - when Max < length(L) -> - ?THROW([repeated_avp_excessive_arity, AvpName, Max, L]); +%% enc/9 -enc(Name, AvpName, _, Values, Opts, Mod) -> - enc(Name, AvpName, Values, Opts, Mod). +enc(_, AvpName, _, Min, N, _, [], _, _) + when N < Min -> + ?THROW([repeated_avp_insufficient_arity, AvpName, Min, N]); -%% enc/5 +enc(_, _, _, _, _, _, [], _, _) -> + []; -enc(Name, 'AVP', Values, Opts, Mod) -> - [enc_AVP(Name, A, Opts, Mod) || A <- Values]; +enc(_, AvpName, _, _, N, Max, _, _, _) + when Max =< N -> + ?THROW([repeated_avp_excessive_arity, AvpName, Max]); -enc(_, AvpName, Values, Opts, Mod) -> - enc(AvpName, Values, Opts, Mod). +enc(Name, AvpName, H, Min, N, Max, [V|Vs], Opts, Mod) -> + [enc1(Name, AvpName, H, V, Opts, Mod) + | enc(Name, AvpName, H, Min, N+1, Max, Vs, Opts, Mod)]. -%% enc/4 +%% avp_header/2 + +avp_header('AVP', _) -> + false; + +avp_header(AvpName, Mod) -> + {_,_,_} = Mod:avp_header(AvpName). + +%% enc1/6 -enc(AvpName, Values, Opts, Mod) -> - H = Mod:avp_header(AvpName), - [diameter_codec:pack_data(H, Mod:avp(encode, V, AvpName, Opts)) - || V <- Values]. +enc1(Name, 'AVP', false, Value, Opts, Mod) -> + enc_AVP(Name, Value, Opts, Mod); + +enc1(_, AvpName, Hdr, Value, Opts, Mod) -> + enc1(AvpName, Hdr, Value, Opts, Mod). + +%% enc1/5 + +enc1(AvpName, {_,_,_} = Hdr, Value, Opts, Mod) -> + diameter_codec:pack_data(Hdr, Mod:avp(encode, Value, AvpName, Opts)). %% enc_AVP/4 @@ -160,16 +177,21 @@ enc_AVP(_, #diameter_avp{name = N, value = V}, _, _) enc_AVP(Name, #diameter_avp{name = AvpName, value = Data}, Opts, Mod) -> 0 == Mod:avp_arity(Name, AvpName) orelse ?THROW([known_avp_as_AVP, Name, AvpName, Data]), - enc(AvpName, [Data], Opts, Mod); + enc(AvpName, Data, Opts, Mod); %% The backdoor ... enc_AVP(_, {AvpName, Value}, Opts, Mod) -> - enc(AvpName, [Value], Opts, Mod); + enc(AvpName, Value, Opts, Mod); %% ... and the side door. enc_AVP(_Name, {_Dict, _AvpName, _Data} = T, Opts, _) -> diameter_codec:pack_avp(#diameter_avp{data = T}, Opts). +%% enc/4 + +enc(AvpName, Value, Opts, Mod) -> + enc1(AvpName, Mod:avp_header(AvpName), Value, Opts, Mod). + %% --------------------------------------------------------------------------- %% # decode_avps/3 %% --------------------------------------------------------------------------- -- cgit v1.2.3 From 9a94d2df5b761685038a5e7f7f0920c6a8c3d451 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 9 Jul 2017 06:17:25 +0200 Subject: Tweak limiting of testcases in traffic suite Since the number is now under 50K again. Also make testing of individual groups or testcases easier. --- lib/diameter/test/diameter_traffic_SUITE.erl | 74 +++++++++++++++------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index fae9f86c38..fbd57ca4d4 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -120,6 +120,11 @@ %% =========================================================================== +%% Positive number of testcases from which to select (randomly) from +%% tc(), the list of testcases to run, or [] to run all. The random +%% selection is to limit the time it takes for the suite to run. +-define(LIMIT, length(tc())). + -define(util, diameter_util). -define(A, list_to_atom). @@ -258,44 +263,40 @@ suite() -> all() -> [rfc4005, start, result_codes, {group, traffic}, empty, stop]. +%% Redefine this to run one or more groups for debugging purposes. +-define(GROUPS, []). +%-define(GROUPS, [[tcp,rfc6733,record,map,false,false,false,false]]). + groups() -> - [{P, [P], Ts} || Ts <- [tc(tc())], P <- [shuffle, parallel]] + Names = names(), + [{P, [P], Ts} || Ts <- [tc()], P <- [shuffle, parallel]] ++ - [{?util:name([T,R,E,D,S,ST,SS,CS]), - [], - [{group, if S -> shuffle; not S -> parallel end}]} - || T <- ?TRANSPORTS, - R <- ?RFCS, - E <- ?ENCODINGS, - D <- ?DECODINGS, - S <- ?STRING_DECODES, - ST <- ?CALLBACKS, - SS <- ?SENDERS, - CS <- ?SENDERS] + [{?util:name(N), [], [{group, if S -> shuffle; not S -> parallel end}]} + || [_,_,_,_,S|_] = N <- Names] ++ - [{T, [], groups([[T,R,E,D,S,ST,SS,CS] - || R <- ?RFCS, - E <- ?ENCODINGS, - D <- ?DECODINGS, - S <- ?STRING_DECODES, - ST <- ?CALLBACKS, - SS <- ?SENDERS, - CS <- ?SENDERS, - SS orelse CS])} %% avoid deadlock + [{T, [], [{group, ?util:name(N)} || N <- names(Names, ?GROUPS), + T == hd(N)]} || T <- ?TRANSPORTS] ++ [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}]. -%groups(_) -> %% debug -% Name = [tcp,rfc6733,record,map,false,false,false,false], -% [{group, ?util:name(Name)}]; -groups(Names) -> - [{group, ?util:name(L)} || L <- Names]. +names() -> + [[T,R,E,D,S,ST,SS,CS] || T <- ?TRANSPORTS, + R <- ?RFCS, + E <- ?ENCODINGS, + D <- ?DECODINGS, + S <- ?STRING_DECODES, + ST <- ?CALLBACKS, + SS <- ?SENDERS, + CS <- ?SENDERS]. + +names(Names, []) -> + [N || N <- Names, + [CS,SS|_] <- [lists:reverse(N)], + SS orelse CS]; %% avoid deadlock -%tc([N|_]) -> %% debug -% [N]; -tc(L) -> - L. +names(_, Names) -> + Names. %% -------------------- @@ -339,11 +340,7 @@ init_per_group(Name, Config) -> server_decoding = D, server_sender = SS, server_throttle = ST}, - %% Limit the number of testcase, since the number of - %% groups is large. - All = ?util:scramble(tc()), - TCs = lists:sublist(All, rand:uniform(32)), - [{group, G}, {runlist, TCs} | Config]; + [{group, G}, {runlist, select()} | Config]; _ -> Config end. @@ -357,6 +354,13 @@ end_per_group(Name, Config) end_per_group(_, _) -> ok. +select() -> + try rand:uniform(?LIMIT) of + N -> lists:sublist(?util:scramble(tc()), max(N,5)) + catch + error:_ -> ?LIMIT + end. + %% -------------------- %% Skip testcases that can reasonably fail under SCTP. -- cgit v1.2.3 From dec19d6f572a564502fb81c8f1ada5a470429d97 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 10 Jul 2017 14:54:28 +0200 Subject: Test decode_format record_from_map in traffic suite --- lib/diameter/test/diameter_traffic_SUITE.erl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index fbd57ca4d4..fb69cd831e 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -123,7 +123,7 @@ %% Positive number of testcases from which to select (randomly) from %% tc(), the list of testcases to run, or [] to run all. The random %% selection is to limit the time it takes for the suite to run. --define(LIMIT, length(tc())). +-define(LIMIT, 42). -define(util, diameter_util). @@ -148,7 +148,7 @@ -define(ENCODINGS, [list, record, map]). %% How to decode incoming messages. --define(DECODINGS, [record, false, map, list]). +-define(DECODINGS, [record, false, map, list, record_from_map]). %% Which dictionary to use in the clients. -define(RFCS, [rfc3588, rfc6733, rfc4005]). @@ -1036,10 +1036,12 @@ decode(record) -> 0; decode(list) -> 1; decode(map) -> 2; decode(false) -> 3; +decode(record_from_map) -> 4; decode(0) -> record; decode(1) -> list; decode(2) -> map; -decode(3) -> false. +decode(3) -> false; +decode(4) -> record_from_map. encode(record) -> 0; encode(list) -> 1; @@ -1078,7 +1080,9 @@ to_map(#diameter_packet{msg = [MsgName | Avps]}, [MsgName | maps:from_list(Avps)]; to_map(#diameter_packet{header = H, msg = Rec}, - #group{server_decoding = record}) -> + #group{server_decoding = D}) + when D == record; + D == record_from_map -> rec_to_map(Rec, dict(H)); %% No record decode: do it ourselves. -- cgit v1.2.3 From 246a5d8611e258119fc6bdc6c52772539c8b09ca Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 10 Jul 2017 20:32:02 +0200 Subject: Don't count AVPs unnecessarily at encode Stop counting when there can be no arity errors. --- lib/diameter/src/base/diameter_gen.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 313be5f215..a7dc3aaec3 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -127,6 +127,10 @@ enc(_, AvpName, _, Min, N, _, [], _, _) enc(_, _, _, _, _, _, [], _, _) -> []; +enc(Name, AvpName, H, Min, N, '*', Vs, Opts, Mod) + when Min =< N -> + [enc1(Name, AvpName, H, V, Opts, Mod) || V <- Vs]; + enc(_, AvpName, _, _, N, Max, _, _, _) when Max =< N -> ?THROW([repeated_avp_excessive_arity, AvpName, Max]); -- cgit v1.2.3 From 97256c5e098f36ee3459db768775c951e87ca717 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 17 Jul 2017 08:58:00 +0200 Subject: Increase init_per_suite timetrap in traffic suite Compiling dictionaries is relatively slow, resulting in timeouts on some hosts. --- lib/diameter/test/diameter_traffic_SUITE.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index fb69cd831e..d676614084 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -27,6 +27,7 @@ -export([suite/0, all/0, groups/0, + init_per_suite/0, init_per_suite/1, end_per_suite/1, init_per_group/2, @@ -300,6 +301,9 @@ names(_, Names) -> %% -------------------- +init_per_suite() -> + [{timetrap, {seconds, 60}}]. + init_per_suite(Config) -> [{rfc4005, compile_and_load()}, {sctp, ?util:have_sctp()} | Config]. -- cgit v1.2.3 From baa65db0f00c84c7248d2401272569f1daf2e2b9 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 17 Jul 2017 11:14:32 +0200 Subject: Don't search forms unnecessarily in diameter_exprecs parse transform The forms being extracted are in the head of the split. --- lib/diameter/src/compiler/diameter_exprecs.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/diameter/src/compiler/diameter_exprecs.erl b/lib/diameter/src/compiler/diameter_exprecs.erl index 9a0cb6baf2..143dede037 100644 --- a/lib/diameter/src/compiler/diameter_exprecs.erl +++ b/lib/diameter/src/compiler/diameter_exprecs.erl @@ -110,9 +110,9 @@ %% parse_transform/2 parse_transform(Forms, _Options) -> - Rs = [R || {attribute, _, record, R} <- Forms], - Es = lists:append([E || {attribute, _, export_records, E} <- Forms]), {H,T} = lists:splitwith(fun is_head/1, Forms), + Rs = [R || {attribute, _, record, R} <- H], + Es = lists:append([E || {attribute, _, export_records, E} <- H]), H ++ [a_export(Es) | f_accessors(Es, Rs)] ++ T. is_head(T) -> -- cgit v1.2.3 From fc718fb2a7f0871930fb2553ae02875a106c414d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 17 Jul 2017 11:40:34 +0200 Subject: Add diameter_util:eprof/1 for test Wrapping it around diameter_traffic_SUITE:compile_and_load/0 shows that it's not diameter that's expensive. See below. ****** Process <0.103.0> -- 1.11 % of profiled time *** FUNCTION CALLS % TIME [uS / CALLS] -------- ----- ------- ---- [----------] lists:append/1 3 0.00 0 [ 0.00] lists:usort/1 1 0.00 0 [ 0.00] lists:rmerge3_21_3/6 5 0.00 0 [ 0.00] lists:merge2_1/4 4 0.00 0 [ 0.00] lists:ukeysplit_1_1/10 2 0.00 0 [ 0.00] lists:ukeymergel/3 1 0.00 0 [ 0.00] lists:rukeymergel/3 2 0.00 0 [ 0.00] lists:rukeymerge3_1/11 3 0.00 0 [ 0.00] lists:rukeymerge2_1/6 1 0.00 0 [ 0.00] beam_lib:chunks/2 1 0.00 0 [ 0.00] beam_lib:read_chunk_data/2 1 0.00 0 [ 0.00] beam_lib:read_chunk_data/3 1 0.00 0 [ 0.00] beam_lib:check_chunks/5 2 0.00 0 [ 0.00] beam_lib:scan_beam/4 1 0.00 0 [ 0.00] beam_lib:scan_beam1/2 1 0.00 0 [ 0.00] beam_lib:scan_beam2/2 1 0.00 0 [ 0.00] beam_lib:get_atom_data/8 1 0.00 0 [ 0.00] beam_lib:get_chunk/4 2 0.00 0 [ 0.00] beam_lib:chunks_to_data/7 2 0.00 0 [ 0.00] beam_lib:extract_atom/2 1 0.00 0 [ 0.00] beam_lib:open_file/1 1 0.00 0 [ 0.00] beam_lib:beam_filename/1 1 0.00 0 [ 0.00] beam_lib:'-read_chunk_data/3-after$^0/0-0-'/1 1 0.00 0 [ 0.00] diameter_dict_scanner:scan/1 2 0.00 0 [ 0.00] diameter_codegen:from_dict/4 1 0.00 0 [ 0.00] diameter_codegen:mod/2 1 0.00 0 [ 0.00] diameter_codegen:maybe_write/5 1 0.00 0 [ 0.00] diameter_codegen:report/2 3 0.00 0 [ 0.00] diameter_codegen:report/3 3 0.00 0 [ 0.00] diameter_codegen:putr/2 1 0.00 0 [ 0.00] diameter_codegen:eraser/1 1 0.00 0 [ 0.00] diameter_codegen:gen/3 1 0.00 0 [ 0.00] diameter_codegen:erl_forms/2 1 0.00 0 [ 0.00] diameter_codegen:make_hrl_forms/1 1 0.00 0 [ 0.00] diameter_codegen:make_record_forms/1 1 0.00 0 [ 0.00] diameter_codegen:grp_proj/1 7 0.00 0 [ 0.00] diameter_codegen:f_name/1 1 0.00 0 [ 0.00] diameter_codegen:f_id/1 1 0.00 0 [ 0.00] diameter_codegen:c_id/1 1 0.00 0 [ 0.00] diameter_codegen:f_vendor_id/1 1 0.00 0 [ 0.00] diameter_codegen:b_vendor_id/1 1 0.00 0 [ 0.00] diameter_codegen:f_vendor_name/1 1 0.00 0 [ 0.00] diameter_codegen:b_vendor_name/1 1 0.00 0 [ 0.00] diameter_codegen:f_msg_name/1 1 0.00 0 [ 0.00] diameter_codegen:msg_name/1 1 0.00 0 [ 0.00] diameter_codegen:c_msg_name/1 5 0.00 0 [ 0.00] diameter_codegen:f_msg2rec/1 1 0.00 0 [ 0.00] diameter_codegen:msg2rec/1 1 0.00 0 [ 0.00] diameter_codegen:f_rec2msg/1 1 0.00 0 [ 0.00] diameter_codegen:rec2msg/1 1 0.00 0 [ 0.00] diameter_codegen:f_name2rec/1 1 0.00 0 [ 0.00] diameter_codegen:name2rec/1 1 0.00 0 [ 0.00] diameter_codegen:avps/1 6 0.00 0 [ 0.00] diameter_codegen:c_imported_avp_name/2 1 0.00 0 [ 0.00] diameter_codegen:f_avp_arity_2/1 1 0.00 0 [ 0.00] diameter_codegen:avp_arity/1 1 0.00 0 [ 0.00] diameter_codegen:f_avp/1 1 0.00 0 [ 0.00] diameter_codegen:avp/1 1 0.00 0 [ 0.00] diameter_codegen:types/1 1 0.00 0 [ 0.00] diameter_codegen:avp/4 1 0.00 0 [ 0.00] diameter_codegen:cs_imported_avp/3 1 0.00 0 [ 0.00] diameter_codegen:f_enumerated_avp/1 1 0.00 0 [ 0.00] diameter_codegen:enumerated_avp/1 1 0.00 0 [ 0.00] diameter_codegen:enumerated_avp/3 1 0.00 0 [ 0.00] diameter_codegen:f_msg_header/1 1 0.00 0 [ 0.00] diameter_codegen:msg_header/1 1 0.00 0 [ 0.00] diameter_codegen:msg_header/2 1 0.00 0 [ 0.00] diameter_codegen:f_avp_header/1 1 0.00 0 [ 0.00] diameter_codegen:avp_header/1 1 0.00 0 [ 0.00] diameter_codegen:f_empty_value/1 1 0.00 0 [ 0.00] diameter_codegen:empty_value/1 1 0.00 0 [ 0.00] diameter_codegen:f_dict/1 1 0.00 0 [ 0.00] diameter_codegen:to_upper/1 1 0.00 0 [ 0.00] diameter_codegen:tu/1 4 0.00 0 [ 0.00] diameter_codegen:preprocess/2 1 0.00 0 [ 0.00] diameter_codegen:pp/2 1 0.00 0 [ 0.00] diameter_codegen:abstract_code/1 1 0.00 0 [ 0.00] diameter_codegen:'-empty_value/1-fun-1-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-empty_value/1-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-f_avp_header/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-f_msg_header/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-enumerated_avp/1-fun-0-'/2 1 0.00 0 [ 0.00] diameter_codegen:'-avp/4-fun-4-'/3 1 0.00 0 [ 0.00] diameter_codegen:'-avp/4-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-avp_arity/1-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-avp_arities/1-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-f_avp_arity_1/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-avp_name/1-fun-0-'/2 1 0.00 0 [ 0.00] diameter_codegen:'-name2rec/1-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-rec2msg/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-msg2rec/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-make_record_forms/1-lc$^2/1-0-'/2 2 0.00 0 [ 0.00] diameter_codegen:'-make_record_forms/1-fun-1-'/1 2 0.00 0 [ 0.00] diameter_codegen:'-make_hrl_forms/1-fun-0-'/1 1 0.00 0 [ 0.00] diameter_codegen:'-from_dict/4-after$^0/0-0-'/0 1 0.00 0 [ 0.00] filename:dirname/1 1 0.00 0 [ 0.00] code:is_loaded/1 1 0.00 0 [ 0.00] code:get_object_code/1 1 0.00 0 [ 0.00] code:lib_dir/1 1 0.00 0 [ 0.00] code:add_pathsa/1 1 0.00 0 [ 0.00] code:which/1 1 0.00 0 [ 0.00] file:read_file_info/1 2 0.00 0 [ 0.00] file:read_file/1 1 0.00 0 [ 0.00] file:call/2 3 0.00 0 [ 0.00] file:check_and_call/2 3 0.00 0 [ 0.00] dict:new/0 1 0.00 0 [ 0.00] dict:fetch/2 2 0.00 0 [ 0.00] dict:fold/3 3 0.00 0 [ 0.00] dict:fold_dict/3 3 0.00 0 [ 0.00] dict:mk_seg/1 1 0.00 0 [ 0.00] diameter_make:default/1 1 0.00 0 [ 0.00] diameter_make:def/2 1 0.00 0 [ 0.00] diameter_make:modes/1 2 0.00 0 [ 0.00] diameter_make:identify/1 1 0.00 0 [ 0.00] diameter_make:make/3 1 0.00 0 [ 0.00] diameter_make:ok/1 1 0.00 0 [ 0.00] diameter_make:make/4 1 0.00 0 [ 0.00] diameter_make:'-make/3-fun-0-'/5 1 0.00 0 [ 0.00] diameter_traffic_SUITE:here/0 1 0.00 0 [ 0.00] diameter_traffic_SUITE:'-compile_and_load/0-lc$^1/1-2-'/2 4 0.00 0 [ 0.00] diameter_dict_util:parse/2 1 0.00 0 [ 0.00] diameter_dict_util:do_parse/2 1 0.00 0 [ 0.00] diameter_dict_util:read/1 1 0.00 0 [ 0.00] diameter_dict_util:make_dict/2 1 0.00 0 [ 0.00] diameter_dict_util:make_orddict/1 1 0.00 0 [ 0.00] diameter_dict_util:make_dict/1 1 0.00 0 [ 0.00] diameter_dict_util:reset/2 1 0.00 0 [ 0.00] diameter_dict_util:reset/3 3 0.00 0 [ 0.00] diameter_dict_util:opt/2 3 0.00 0 [ 0.00] diameter_dict_util:reinherit/3 1 0.00 0 [ 0.00] diameter_dict_util:pass1/1 1 0.00 0 [ 0.00] diameter_dict_util:no_messages_without_id/1 1 0.00 0 [ 0.00] diameter_dict_util:vendor_id_mismatch/6 2 0.00 0 [ 0.00] diameter_dict_util:grouped_flags/4 2 0.00 0 [ 0.00] diameter_dict_util:pass2/1 1 0.00 0 [ 0.00] diameter_dict_util:p2/3 1 0.00 0 [ 0.00] diameter_dict_util:pass3/2 1 0.00 0 [ 0.00] diameter_dict_util:insert_codes/1 1 0.00 0 [ 0.00] diameter_dict_util:import_avps/2 1 0.00 0 [ 0.00] diameter_dict_util:explode_imports/2 1 0.00 0 [ 0.00] diameter_dict_util:import_groups/1 1 0.00 0 [ 0.00] diameter_dict_util:import_enums/1 1 0.00 0 [ 0.00] diameter_dict_util:import/2 2 0.00 0 [ 0.00] diameter_dict_util:import_key/2 2 0.00 0 [ 0.00] diameter_dict_util:inherit/2 1 0.00 0 [ 0.00] diameter_dict_util:inherit_avps/2 1 0.00 0 [ 0.00] diameter_dict_util:find_avps/2 1 0.00 0 [ 0.00] diameter_dict_util:avps_from_module/1 1 0.00 0 [ 0.00] diameter_dict_util:examine/1 1 0.00 0 [ 0.00] diameter_dict_util:putr/2 1 0.00 0 [ 0.00] diameter_dict_util:eraser/1 1 0.00 0 [ 0.00] diameter_dict_util:flatmap/2 2 0.00 0 [ 0.00] diameter_dict_util:'-flatmap/2-fun-0-'/2 2 0.00 0 [ 0.00] diameter_dict_util:'-inherit/2-fun-1-'/2 1 0.00 0 [ 0.00] diameter_dict_util:'-import/2-fun-0-'/2 2 0.00 0 [ 0.00] diameter_dict_util:'-import_avps/2-fun-0-'/2 1 0.00 0 [ 0.00] diameter_dict_util:'-import_avps/2-fun-2-'/1 1 0.00 0 [ 0.00] diameter_dict_util:'-pass2/1-fun-1-'/2 1 0.00 0 [ 0.00] diameter_dict_util:'-pass2/1-fun-0-'/3 1 0.00 0 [ 0.00] diameter_dict_util:'-opt/2-lc$^1/1-0-'/3 2 0.00 0 [ 0.00] diameter_dict_util:'-reset/3-fun-1-'/2 3 0.00 0 [ 0.00] diameter_dict_util:'-reset/2-fun-0-'/3 3 0.00 0 [ 0.00] diameter_dict_util:'-do_parse/2-fun-0-'/1 1 0.00 0 [ 0.00] diameter_dict_util:'-parse/2-after$^0/0-0-'/0 1 0.00 0 [ 0.00] erl_abstract_code:debug_info/4 1 0.00 0 [ 0.00] compile:env_default_opts/0 1 0.00 0 [ 0.00] compile:do_compile/2 1 0.00 0 [ 0.00] compile:expand_opts/1 1 0.00 0 [ 0.00] compile:expand_opt/2 3 0.00 0 [ 0.00] compile:'-expand_opts/1-anonymous-0-'/2 3 0.00 0 [ 0.00] diameter_dict_parser:parse/1 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars0/5 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars1/5 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_0/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_1/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_3/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_4/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_10/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_11/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_13/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_22/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_76/7 5 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_82/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_83/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_84/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_86/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_88/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_89/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_90/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_91/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_92/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_93/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_94/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_95/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_96/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_97/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_99/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_100/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_101/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_102/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_103/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_105/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_106/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_122/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccpars2_130/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_avp_code/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_avp_header/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_avp_header_tok/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_avp_names/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_dictionary/7 1 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_group_def/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_group_defs/7 2 0.00 0 [ 0.00] diameter_dict_parser:yeccgoto_module/7 1 0.00 0 [ 0.00] file:native_name_encoding/0 3 0.00 0 [ 0.00] erlang:binary_to_atom/2 1 0.00 0 [ 0.00] erlang:put/2 2 0.00 0 [ 0.00] gen:'-call/4-fun-0-'/4 5 0.00 1 [ 0.20] diameter_util:eprof/1 1 0.00 1 [ 1.00] lists:sort/1 2 0.00 1 [ 0.50] lists:ukeysort/2 2 0.00 1 [ 0.50] lists:foldr/3 4 0.00 1 [ 0.25] lists:mergel/2 5 0.00 1 [ 0.20] lists:rmergel/2 8 0.00 1 [ 0.13] lists:merge3_12_3/6 7 0.00 1 [ 0.14] lists:merge3_21_3/6 12 0.00 1 [ 0.08] lists:rmerge3_12_3/6 7 0.00 1 [ 0.14] lists:merge2_2/5 6 0.00 1 [ 0.17] lists:ukeysplit_1/8 6 0.00 1 [ 0.17] lists:rukeymerge3_2/11 5 0.00 1 [ 0.20] beam_lib:scan_beam/5 12 0.00 1 [ 0.08] beam_lib:chunk_to_data/6 1 0.00 1 [ 1.00] code_server:call/1 5 0.00 1 [ 0.20] diameter_codegen:getr/1 3 0.00 1 [ 0.33] diameter_codegen:msg_proj/1 10 0.00 1 [ 0.10] diameter_codegen:a_record/3 3 0.00 1 [ 0.33] diameter_codegen:c_msg2rec/2 10 0.00 1 [ 0.10] diameter_codegen:c_rec2msg/2 10 0.00 1 [ 0.10] diameter_codegen:f_avp_name/1 1 0.00 1 [ 1.00] diameter_codegen:avp_name/1 1 0.00 1 [ 1.00] diameter_codegen:vendor_id_map/1 2 0.00 1 [ 0.50] diameter_codegen:f_avp_arity_1/1 1 0.00 1 [ 1.00] diameter_codegen:avp_arities/1 1 0.00 1 [ 1.00] diameter_codegen:cs_enumerated_avp/3 9 0.00 1 [ 0.11] diameter_codegen:c_msg_header/4 10 0.00 1 [ 0.10] diameter_codegen:emf/2 15 0.00 1 [ 0.07] diameter_codegen:prefix/1 4 0.00 1 [ 0.25] diameter_codegen:files/2 6 0.00 1 [ 0.17] diameter_codegen:'-to_upper/1-fun-0-'/1 4 0.00 1 [ 0.25] diameter_codegen:'-f_enumerated_avp/1-lc$^0/1-0-'/1 4 0.00 1 [ 0.25] diameter_codegen:'-vendor_id_map/1-fun-0-'/1 4 0.00 1 [ 0.25] diameter_codegen:'-name2rec/1-fun-1-'/2 7 0.00 1 [ 0.14] diameter_codegen:'-msg_name/1-fun-0-'/1 5 0.00 1 [ 0.20] diameter_codegen:'-make_record_forms/1-fun-3-'/1 5 0.00 1 [ 0.20] filename:skip_prefix/2 7 0.00 1 [ 0.14] filename:maybe_remove_dirsep/2 9 0.00 1 [ 0.11] filename:unix_pathtype/1 7 0.00 1 [ 0.14] code:call/1 5 0.00 1 [ 0.20] file:file_name/1 3 0.00 1 [ 0.33] file:check_args/1 6 0.00 1 [ 0.17] dict:fetch_val/2 6 0.00 1 [ 0.17] dict:expand_segs/2 4 0.00 1 [ 0.25] diameter_gen_base_rfc3588:dict/0 3 0.00 1 [ 0.33] diameter_make:codec/2 1 0.00 1 [ 1.00] diameter_make:parse/2 1 0.00 1 [ 1.00] diameter_make:is_mode/1 10 0.00 1 [ 0.10] diameter_traffic_SUITE:'-compile_and_load/0-lc$^0/1-1-'/1 3 0.00 1 [ 0.33] diameter_traffic_SUITE:'-compile_and_load/0-lc$^2/1-3-'/4 4 0.00 1 [ 0.25] orddict:from_list/1 2 0.00 1 [ 0.50] diameter_dict_util:post/2 5 0.00 1 [ 0.20] diameter_dict_util:mk_code/2 5 0.00 1 [ 0.20] diameter_dict_util:'-inherit/2-lc$^0/1-0-'/1 6 0.00 1 [ 0.17] diameter_dict_util:'-pass1/1-fun-1-'/2 11 0.00 1 [ 0.09] diameter_dict_util:'-opt/2-fun-0-'/1 7 0.00 1 [ 0.14] erlang:spawn_monitor/1 1 0.00 1 [ 1.00] compile:forms/2 1 0.00 1 [ 1.00] diameter_dict_parser:yeccpars2_24/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_25/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_28/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_30/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_53/7 11 0.00 1 [ 0.09] diameter_dict_parser:yeccpars2_59/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_60/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_64/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_66/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_68/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_69/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_71/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_72/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_73/7 15 0.00 1 [ 0.07] diameter_dict_parser:yeccpars2_75/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_78/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_80/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_81/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccpars2_107/7 14 0.00 1 [ 0.07] diameter_dict_parser:yeccgoto_bit/7 15 0.00 1 [ 0.07] diameter_dict_parser:yeccgoto_bits/7 15 0.00 1 [ 0.07] diameter_dict_parser:yeccgoto_command_def/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccgoto_command_id/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccgoto_header/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccgoto_header_tok/7 10 0.00 1 [ 0.10] diameter_dict_parser:yeccgoto_message_defs/7 10 0.00 1 [ 0.10] erlang:erase/1 2 0.00 1 [ 0.50] gen:do_call/4 5 0.00 2 [ 0.40] lists:seq_loop/3 9 0.00 2 [ 0.22] beam_lib:get_data/8 11 0.00 2 [ 0.18] diameter_codegen:a_record/2 17 0.00 2 [ 0.12] diameter_codegen:c_name2rec/2 17 0.00 2 [ 0.12] diameter_codegen:c_avp_arities/1 17 0.00 2 [ 0.12] diameter_codegen:c_avp_arity/1 18 0.00 2 [ 0.11] diameter_codegen:c_avp_arity/2 17 0.00 2 [ 0.12] diameter_codegen:cs_enumerated_avp/1 14 0.00 2 [ 0.14] diameter_codegen:encode_msg_flags/1 10 0.00 2 [ 0.20] diameter_codegen:'-include/2-lc$^0/1-0-'/2 12 0.00 2 [ 0.17] diameter_codegen:'-msg_header/2-fun-0-'/2 10 0.00 2 [ 0.20] diameter_codegen:'-enumerated_avp/3-fun-0-'/3 9 0.00 2 [ 0.22] diameter_codegen:'-rec2msg/1-fun-1-'/2 10 0.00 2 [ 0.20] diameter_codegen:'-msg2rec/1-fun-1-'/2 10 0.00 2 [ 0.20] diameter_codegen:'-make_record_forms/1-fun-0-'/1 10 0.00 2 [ 0.20] filename:basename/1 7 0.00 2 [ 0.29] filename:join/1 9 0.00 2 [ 0.22] filename:join/2 7 0.00 2 [ 0.29] filename:pathtype/1 7 0.00 2 [ 0.29] filename:major_os_type/0 9 0.00 2 [ 0.22] code:load_binary/3 1 0.00 2 [ 2.00] diameter_make:'-modes/1-fun-0-'/1 10 0.00 2 [ 0.20] diameter_dict_util:do/2 3 0.00 2 [ 0.67] diameter_dict_util:make/3 18 0.00 2 [ 0.11] diameter_dict_util:opt/1 12 0.00 2 [ 0.17] diameter_dict_util:report/3 21 0.00 2 [ 0.10] diameter_dict_util:application_id_mismatch/3 10 0.00 2 [ 0.20] diameter_dict_util:dict/1 3 0.00 2 [ 0.67] diameter_dict_util:'-explode/3-fun-0-'/4 15 0.00 2 [ 0.13] diameter_dict_util:'-pass1/1-fun-0-'/3 19 0.00 2 [ 0.11] diameter_dict_util:'-make_dict/1-fun-0-'/2 19 0.00 2 [ 0.11] diameter_dict_util:'-make/2-fun-0-'/3 18 0.00 2 [ 0.11] diameter_dict_util:'-make_orddict/1-lc$^0/1-0-'/1 10 0.00 2 [ 0.20] diameter_dict_parser:yeccpars2_2/7 19 0.00 2 [ 0.11] diameter_dict_parser:yeccpars2_32/7 10 0.00 2 [ 0.20] diameter_dict_parser:yeccpars2_65/7 10 0.00 2 [ 0.20] diameter_dict_parser:yeccpars2_70/7 10 0.00 2 [ 0.20] diameter_dict_parser:yeccpars2_74/7 15 0.00 2 [ 0.13] diameter_dict_parser:yeccpars2_77/7 15 0.00 2 [ 0.13] diameter_dict_parser:yeccpars2_109/7 14 0.00 2 [ 0.14] diameter_dict_parser:yeccpars2_131/7 19 0.00 2 [ 0.11] diameter_dict_parser:yeccgoto_section/7 19 0.00 2 [ 0.11] diameter_dict_parser:yeccgoto_sections/7 19 0.00 2 [ 0.11] os:getenv/1 1 0.00 2 [ 2.00] ets:delete/1 1 0.00 2 [ 2.00] ets:new/2 1 0.00 2 [ 2.00] gen:do_for_proc/2 5 0.01 3 [ 0.60] beam_lib:del_chunk/2 11 0.01 3 [ 0.27] diameter_codegen:filter/1 23 0.01 3 [ 0.13] diameter_codegen:'-empty_value/1-lc$^2/1-0-'/2 15 0.01 3 [ 0.20] diameter_codegen:'-encode_msg_flags/1-fun-0-'/2 15 0.01 3 [ 0.20] diameter_codegen:'-enumerated_avp/1-fun-1-'/1 14 0.01 3 [ 0.21] diameter_codegen:'-f_avp/1-lc$^0/1-0-'/1 5 0.01 3 [ 0.60] diameter_codegen:'-make_hrl_forms/1-fun-1-'/1 17 0.01 3 [ 0.18] filename:separators/0 8 0.01 3 [ 0.38] filename:flatten/1 8 0.01 3 [ 0.38] dict:append/3 28 0.01 3 [ 0.11] diameter_traffic_SUITE:'-compile_and_load/0-after$^3/0-0-'/0 1 0.01 3 [ 3.00] diameter_dict_util:make_body/1 12 0.01 3 [ 0.25] diameter_dict_util:section/2 19 0.01 3 [ 0.16] diameter_dict_util:explode_avps/4 12 0.01 3 [ 0.25] diameter_dict_util:'-reset/3-lc$^0/1-0-'/2 18 0.01 3 [ 0.17] diameter_dict_util:'-mk/2-fun-0-'/1 15 0.01 3 [ 0.20] gen_server:call/3 5 0.01 3 [ 0.60] lists:seq/2 7 0.01 4 [ 0.57] lists:merge3_2/6 23 0.01 4 [ 0.17] lists:rmerge3_2/6 20 0.01 4 [ 0.20] diameter_dict_scanner:'-split/1-fun-4-'/1 20 0.01 4 [ 0.20] diameter_codegen:c_avp_arities/2 17 0.01 4 [ 0.24] diameter_codegen:c_empty_value/1 29 0.01 4 [ 0.14] diameter_codegen:'-c_avp_arity/1-fun-0-'/1 17 0.01 4 [ 0.24] diameter_codegen:'-a_record/3-fun-0-'/3 17 0.01 4 [ 0.24] orddict:fetch/2 25 0.01 4 [ 0.16] diameter_dict_util:make/2 12 0.01 4 [ 0.33] diameter_dict_util:p1/3 19 0.01 4 [ 0.21] diameter_dict_util:is_enumerated_avp/3 14 0.01 4 [ 0.29] diameter_dict_util:choose/3 24 0.01 4 [ 0.17] diameter_dict_util:'-import_key/2-fun-0-'/2 14 0.01 4 [ 0.29] lists:merge3_1/6 28 0.01 5 [ 0.18] lists:rmerge3_1/6 22 0.01 5 [ 0.23] diameter_codegen:c_imported_avp/2 44 0.01 5 [ 0.11] diameter_codegen:include/2 42 0.01 5 [ 0.12] diameter_codegen:'-include/2-fun-1-'/1 23 0.01 5 [ 0.22] diameter_codegen:'-avp_arities/1-fun-1-'/1 17 0.01 5 [ 0.29] diameter_dict_util:'-explode_imports/2-fun-0-'/4 50 0.01 5 [ 0.10] diameter_dict_parser:yeccpars2_52/7 51 0.01 5 [ 0.10] gen:call/4 5 0.01 6 [ 1.20] lists:delete/2 31 0.01 6 [ 0.19] lists:rmerge2_1/4 43 0.01 6 [ 0.14] diameter_codegen:c_imported_avp_header/3 50 0.01 6 [ 0.12] diameter_codegen:rec_name/2 27 0.01 6 [ 0.22] diameter_codegen:'-empty_value/1-fun-3-'/1 29 0.01 6 [ 0.21] dict:'-append/3-fun-0-'/3 28 0.01 6 [ 0.21] diameter_dict_util:report/2 21 0.01 6 [ 0.29] erlang:whereis/1 5 0.01 6 [ 1.20] erlang:atom_to_list/1 28 0.01 6 [ 0.21] lists:split_1_1/6 34 0.01 7 [ 0.21] lists:rmerge2_2/5 54 0.01 7 [ 0.13] beam_lib:pread/3 15 0.01 7 [ 0.47] diameter_codegen:imported_avp/3 50 0.01 7 [ 0.14] dict:fold_segs/4 51 0.01 7 [ 0.14] diameter_dict_util:xi/4 50 0.01 7 [ 0.14] diameter_dict_util:getr/1 21 0.01 7 [ 0.33] diameter_dict_parser:yeccpars2_54/7 51 0.01 7 [ 0.14] erlang:send/3 5 0.01 7 [ 1.40] diameter_codegen:get_value/2 33 0.02 8 [ 0.24] os:type/0 24 0.02 8 [ 0.33] diameter_dict_scanner:section/1 19 0.02 9 [ 0.47] diameter_codegen:eaf/2 80 0.02 9 [ 0.11] diameter_codegen:'-pp/2-fun-0-'/2 42 0.02 9 [ 0.21] filename:dirname/4 63 0.02 9 [ 0.14] diameter_dict_util:'-p2/3-fun-0-'/2 82 0.02 9 [ 0.11] diameter_dict_parser:yeccpars2_41/7 77 0.02 9 [ 0.12] diameter_dict_parser:yeccpars2_45/7 77 0.02 9 [ 0.12] diameter_dict_parser:yeccpars2_121/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccpars2_123/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccpars2_126/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccpars2_128/7 80 0.02 9 [ 0.11] diameter_dict_parser:yeccgoto_avp_defs/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccgoto_avp_flags/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccgoto_avp_type/7 82 0.02 9 [ 0.11] diameter_dict_parser:yeccgoto_qual/7 77 0.02 9 [ 0.12] erlang:system_info/1 24 0.02 9 [ 0.38] diameter_codegen:c_avp_header/3 83 0.02 10 [ 0.12] diameter_dict_util:'-import_avps/2-lc$^1/1-0-'/1 51 0.02 10 [ 0.20] diameter_dict_util:'-p1/3-fun-2-'/3 94 0.02 10 [ 0.11] diameter_dict_parser:yeccpars2_63/7 77 0.02 10 [ 0.13] diameter_dict_parser:yeccpars2_124/7 82 0.02 10 [ 0.12] diameter_dict_parser:yeccpars2_127/7 82 0.02 10 [ 0.12] diameter_dict_parser:yeccgoto_avp_def/7 82 0.02 10 [ 0.12] diameter_codegen:'-files/2-fun-0-'/1 50 0.02 11 [ 0.22] diameter_codegen:'-c_avp_header/3-fun-0-'/3 50 0.02 11 [ 0.22] diameter_codegen:'-cs_imported_avp/3-fun-0-'/2 50 0.02 11 [ 0.22] diameter_codegen:'-cs_imported_avp/3-fun-1-'/3 50 0.02 11 [ 0.22] diameter_codegen:'-avp/4-fun-1-'/2 50 0.02 11 [ 0.22] orddict:reverse_pairs/2 93 0.02 11 [ 0.12] diameter_dict_util:vendor/1 82 0.02 11 [ 0.13] diameter_dict_util:foldl/3 59 0.02 11 [ 0.19] diameter_dict_util:'-find_avps/2-lc$^0/1-0-'/1 51 0.02 11 [ 0.22] diameter_dict_util:'-make/3-fun-0-'/3 94 0.02 11 [ 0.12] diameter_codegen:'-c_imported_avp_name/2-fun-0-'/3 50 0.02 12 [ 0.24] diameter_dict_parser:yeccpars2_6/7 107 0.02 12 [ 0.11] diameter_dict_parser:yeccpars2_129/7 82 0.02 12 [ 0.15] erlang:demonitor/2 10 0.02 12 [ 1.20] proplists:get_value/2 53 0.03 13 [ 0.25] erlang:'--'/2 83 0.03 13 [ 0.16] diameter_codegen:not_in/2 132 0.03 14 [ 0.11] diameter_codegen:c_base_avp/1 88 0.03 14 [ 0.16] diameter_dict_util:explode/3 94 0.03 14 [ 0.15] diameter_dict_parser:yeccpars2_108/7 131 0.03 14 [ 0.11] diameter_dict_util:'-p1/3-fun-1-'/4 131 0.03 15 [ 0.11] diameter_dict_parser:yeccpars2_110/7 131 0.03 15 [ 0.11] diameter_dict_parser:yeccgoto_enum_def/7 131 0.03 15 [ 0.11] diameter_dict_parser:yeccgoto_enum_defs/7 131 0.03 15 [ 0.11] diameter_codegen:c_avp_name_/3 132 0.03 16 [ 0.12] diameter_codegen:c_enumerated_avp/2 131 0.03 16 [ 0.12] diameter_dict_util:qual/2 77 0.03 16 [ 0.21] diameter_dict_parser:yeccpars2_111/7 131 0.03 16 [ 0.12] lists:ukeysplit_2/5 81 0.04 17 [ 0.21] diameter_codegen:c_avp_name/3 132 0.04 17 [ 0.13] diameter_dict_util:explode_avps/2 82 0.04 17 [ 0.21] diameter_dict_parser:yeccpars2_112/7 131 0.04 17 [ 0.13] diameter_codegen:'-encode_avp_flags/1-fun-0-'/2 80 0.04 18 [ 0.23] diameter_codegen:'-avp/4-fun-5-'/2 82 0.04 18 [ 0.22] diameter_codegen:'-types/1-fun-0-'/1 82 0.04 18 [ 0.22] dict:append_bkt/3 85 0.04 18 [ 0.21] diameter_make:is_path/1 136 0.04 18 [ 0.13] lists:split_1/5 96 0.04 19 [ 0.20] diameter_codegen:'-avp_header/1-fun-0-'/3 83 0.04 19 [ 0.23] diameter_codegen:'-avp/4-fun-6-'/1 82 0.04 19 [ 0.23] diameter_codegen:'-avp_name/1-fun-1-'/3 82 0.04 19 [ 0.23] diameter_dict_util:explode2/4 131 0.04 19 [ 0.15] diameter_codegen:encode_avp_flags/1 82 0.04 20 [ 0.24] diameter_dict_util:vendor_id/2 82 0.04 20 [ 0.24] diameter_dict_util:'-avp_flags_valid/3-fun-0-'/1 80 0.04 20 [ 0.25] diameter_dict_util:avp_type_known/3 82 0.04 21 [ 0.26] diameter_dict_util:avp_vendor_id/4 82 0.04 21 [ 0.26] orddict:find/2 156 0.05 22 [ 0.14] diameter_dict_util:avp_flags_valid/3 82 0.05 22 [ 0.27] lists:filter/2 86 0.05 23 [ 0.27] diameter_codegen:v/4 214 0.05 23 [ 0.11] lists:keymember/3 56 0.05 23 [ 0.41] diameter_dict_scanner:'-split/1-fun-1-'/1 109 0.05 24 [ 0.22] erlang:monitor/2 10 0.05 24 [ 2.40] filename:basename1/3 251 0.06 28 [ 0.11] diameter_dict_util:mk/2 109 0.06 28 [ 0.26] diameter_codegen:'-cs_enumerated_avp/1-fun-0-'/2 131 0.06 30 [ 0.23] diameter_dict_util:'-mk/2-fun-1-'/1 131 0.06 30 [ 0.23] erlang:list_to_integer/1 226 0.07 32 [ 0.14] diameter_dict_parser:yeccpars2_57/7 314 0.07 34 [ 0.11] diameter_dict_parser:yeccpars2_43/7 298 0.08 38 [ 0.13] diameter_dict_parser:yeccpars2_51/7 354 0.08 40 [ 0.11] diameter_dict_parser:yeccgoto_avps/7 375 0.08 40 [ 0.11] erlang:bitstring_to_list/1 284 0.08 40 [ 0.14] dict:maybe_expand_segs/1 152 0.09 41 [ 0.27] diameter_dict_parser:yeccpars2_47/7 365 0.09 41 [ 0.11] diameter_dict_util:delim/2 375 0.09 42 [ 0.11] diameter_dict_parser:yeccpars2_50/7 364 0.09 43 [ 0.12] diameter_dict_parser:yeccpars2_58/7 314 0.09 43 [ 0.14] diameter_dict_parser:yeccgoto_avp_name/7 365 0.09 43 [ 0.12] diameter_codegen:field/1 385 0.09 44 [ 0.11] diameter_dict_parser:yeccgoto_avp/7 375 0.09 44 [ 0.12] diameter_dict_parser:yeccgoto_avp_spec/7 364 0.09 44 [ 0.12] diameter_codegen:c_arity/2 385 0.09 45 [ 0.12] file:file_name_1/2 196 0.09 45 [ 0.23] diameter_dict_util:avp/1 375 0.09 45 [ 0.12] diameter_dict_parser:yeccpars2_23/7 374 0.09 45 [ 0.12] diameter_dict_parser:yeccgoto_avp_ref/7 375 0.09 45 [ 0.12] diameter_dict_parser:yeccgoto_diameter_name/7 374 0.09 45 [ 0.12] diameter_dict_parser:yeccpars2_44/7 375 0.10 46 [ 0.12] diameter_dict_parser:yeccpars2_62/7 375 0.10 47 [ 0.13] diameter_codegen:'-c_avp_arities/2-lc$^0/1-0-'/1 402 0.10 50 [ 0.12] diameter_dict_util:is_uint32/2 228 0.11 51 [ 0.22] lists:'-filter/2-lc$^0/1-0-'/2 308 0.11 52 [ 0.17] diameter_dict_util:avp/2 375 0.11 52 [ 0.14] diameter_codegen:vid/4 214 0.11 54 [ 0.25] diameter_codegen:arity/2 243 0.11 55 [ 0.23] diameter_dict_scanner:read_int/1 226 0.12 59 [ 0.26] diameter_dict_util:type/1 164 0.13 61 [ 0.37] filename:join1/4 476 0.14 66 [ 0.14] erlang:list_to_tuple/1 541 0.14 67 [ 0.12] filename:do_flatten/2 314 0.15 70 [ 0.22] diameter_dict_util:xa/5 422 0.15 72 [ 0.17] lists:member/2 554 0.16 75 [ 0.14] diameter_dict_util:key/1 131 0.16 76 [ 0.58] diameter_dict_util:'-make_body/1-fun-0-'/1 375 0.17 80 [ 0.21] diameter_dict_util:avp_is_defined/3 364 0.17 83 [ 0.23] diameter_dict_util:make_code/3 734 0.17 84 [ 0.11] diameter_codegen:'-a_record/2-fun-0-'/1 385 0.18 86 [ 0.22] diameter_dict_util:mo/3 838 0.18 86 [ 0.10] diameter_dict_parser:yeccpars2_19/7 766 0.18 89 [ 0.12] diameter_codegen:'-c_avp_arity/2-fun-0-'/2 385 0.19 90 [ 0.23] diameter_dict_scanner:'-split/1-fun-2-'/1 395 0.19 91 [ 0.23] lists:flatmap/2 396 0.20 95 [ 0.24] dict:put_bucket_s/3 304 0.20 95 [ 0.31] diameter_dict_parser:yeccgoto_ident/7 766 0.20 96 [ 0.13] dict:store/3 829 0.21 101 [ 0.12] dict:maybe_expand/2 857 0.21 101 [ 0.12] dict:fold_seg/4 816 0.22 106 [ 0.13] erlang:'++'/2 762 0.23 110 [ 0.14] lists:foldl/3 842 0.23 112 [ 0.13] diameter_dict_util:eval/1 845 0.24 115 [ 0.14] dict:maybe_expand_aux/2 857 0.25 122 [ 0.14] diameter_dict_util:x/3 838 0.27 128 [ 0.15] diameter_codegen:'-c_avp_arities/2-lc$^1/1-1-'/2 770 0.27 129 [ 0.17] diameter_dict_util:'-foldl/3-fun-0-'/3 543 0.27 132 [ 0.24] diameter_dict_util:'-insert_codes/1-fun-0-'/3 734 0.32 152 [ 0.21] diameter_dict_util:find/2 561 0.32 155 [ 0.28] erl_parse:not_string/4 1467 0.32 155 [ 0.11] diameter_dict_util:'-make_orddict/1-fun-1-'/3 838 0.36 175 [ 0.21] diameter_dict_util:store_new/5 821 0.37 177 [ 0.22] erlang:binary_to_list/1 12 0.37 180 [ 15.00] diameter_dict_util:'-examine/1-fun-0-'/4 838 0.38 183 [ 0.22] erlang:make_fun/3 1046 0.38 185 [ 0.18] dict:'-store/3-fun-0-'/3 829 0.42 200 [ 0.24] erlang:binary_to_term/1 1 0.44 214 [ 214.00] epp:default_encoding/0 1044 0.47 226 [ 0.22] diameter_dict_parser:yeccpars2/7 1954 0.47 227 [ 0.12] diameter_dict_scanner:is_digit/1 2119 0.49 235 [ 0.11] lists:dropwhile/2 1847 0.51 244 [ 0.13] erl_parse:enc_func/1 1044 0.51 244 [ 0.23] diameter_dict_parser:yeccpars1/7 1953 0.51 245 [ 0.13] lists:reverse/2 1594 0.52 249 [ 0.16] diameter_dict_scanner:splitwith/2 1040 0.52 251 [ 0.24] lists:splitwith/2 1067 0.54 258 [ 0.24] dict:on_bucket/3 857 0.54 259 [ 0.30] dict:get_bucket_s/2 1538 0.54 261 [ 0.17] dict:rehash/4 1206 0.58 280 [ 0.23] erlang:tuple_to_list/1 2311 0.62 297 [ 0.13] erl_parse:'-abstract/3-lc$^0/1-0-'/2 1420 0.64 309 [ 0.22] diameter_dict_scanner:scan/2 2695 0.65 315 [ 0.12] diameter_dict_scanner:word/1 814 0.66 318 [ 0.39] dict:get_bucket/2 1386 0.68 325 [ 0.23] dict:find/2 1384 0.68 326 [ 0.24] erl_parse:abstract/2 1044 0.68 326 [ 0.31] erl_parse:abstract_byte/2 1136 0.69 331 [ 0.29] diameter_codegen:avp_info/1 1398 0.83 400 [ 0.29] lists:map/2 1900 0.89 428 [ 0.23] diameter_dict_scanner:is_eol_ch/1 1847 0.91 440 [ 0.24] diameter_dict_scanner:'-split/1-fun-0-'/1 1847 0.93 446 [ 0.24] diameter_dict_scanner:tok/2 1953 0.93 449 [ 0.23] dict:fold_bucket/3 3178 1.00 483 [ 0.15] lists:reverse/1 2080 1.04 499 [ 0.24] dict:get_slot/2 2243 1.18 568 [ 0.25] diameter_dict_scanner:acc/3 2694 1.28 618 [ 0.23] diameter_codegen:remod/2 2872 1.32 633 [ 0.22] proplists:get_value/3 3492 1.39 668 [ 0.19] diameter_codegen:'-remod/2-lc$^0/1-0-'/2 3058 1.41 677 [ 0.22] erl_anno:new_location/1 7098 1.51 728 [ 0.10] erlang:spawn_opt/1 1 1.52 731 [ 731.00] orddict:store/3 3559 1.74 837 [ 0.24] erlang:setelement/3 3892 1.78 856 [ 0.22] diameter_dict_scanner:is_upper/1 4100 1.83 882 [ 0.22] erlang:phash/2 3297 1.95 940 [ 0.29] dict:find_val/2 7390 2.16 1041 [ 0.14] dict:store_bkt_val/3 4859 2.32 1114 [ 0.23] diameter_dict_scanner:is_name_ch/1 9714 2.32 1116 [ 0.11] lists:splitwith/3 9792 2.53 1216 [ 0.12] erl_parse:abstract_tuple_list/3 5646 2.72 1311 [ 0.23] erlang:list_to_atom/1 3609 2.76 1327 [ 0.37] erl_anno:new/1 7098 3.44 1653 [ 0.23] erl_parse:abstract_list/4 13813 3.77 1814 [ 0.13] erl_parse:abstract/3 7851 3.82 1840 [ 0.23] diameter_dict_scanner:'-split/1-fun-3-'/1 9210 4.24 2040 [ 0.22] diameter_dict_scanner:is_lower/1 9714 4.43 2133 [ 0.22] diameter_dict_scanner:is_alphanum/1 9714 4.50 2164 [ 0.22] diameter_codegen:is_printable_ascii/1 11352 5.25 2525 [ 0.22] diameter_dict_scanner:split/1 13351 5.39 2593 [ 0.19] ------------------------------------------------------------ ------ ------- ----- [----------] Total: 246336 100.00% 48114 [ 0.20] ****** Process <0.107.0> -- 98.89 % of profiled time *** FUNCTION CALLS % TIME [uS / CALLS] -------- ----- ------- ---- [----------] sys_core_bsm:module/2 1 0.00 0 [ 0.00] sys_core_bsm:bsm_an_2/4 1 0.00 0 [ 0.00] sys_core_bsm:bsm_an_3/4 1 0.00 0 [ 0.00] sys_core_bsm:bsm_nonempty/2 1 0.00 0 [ 0.00] sys_core_bsm:bsm_ensure_no_partition/2 1 0.00 0 [ 0.00] sys_core_bsm:bsm_ensure_no_partition_1/3 1 0.00 0 [ 0.00] erl_internal:add_predefined_functions/1 1 0.00 0 [ 0.00] erl_internal:predefined_functions/1 1 0.00 0 [ 0.00] erl_internal:get_optional_callbacks/1 1 0.00 0 [ 0.00] erl_internal:module_predef_func_beh_info/2 1 0.00 0 [ 0.00] erl_internal:module_predef_funcs_mod_info/1 1 0.00 0 [ 0.00] v3_core:expr_map/4 3 0.00 0 [ 0.00] v3_core:badmap_term/2 3 0.00 0 [ 0.00] v3_life:module/2 1 0.00 0 [ 0.00] v3_life:'-literal/2-lc$^0/1-1-'/2 3 0.00 0 [ 0.00] beam_record:module/2 1 0.00 0 [ 0.00] sys_core_fold:module/2 1 0.00 0 [ 0.00] sets:from_list/1 1 0.00 0 [ 0.00] sets:mk_seg/1 2 0.00 0 [ 0.00] lists:nth/2 3 0.00 0 [ 0.00] lists:sort/2 1 0.00 0 [ 0.00] lists:rukeymerge3_2/11 2 0.00 0 [ 0.00] lists:rukeymerge3_21_3/11 3 0.00 0 [ 0.00] lists:ukeymerge2_1/7 3 0.00 0 [ 0.00] diameter_exprecs:parse_transform/2 1 0.00 0 [ 0.00] diameter_exprecs:a_export/1 1 0.00 0 [ 0.00] diameter_exprecs:f_accessors/2 1 0.00 0 [ 0.00] diameter_exprecs:'#info-/1'/0 1 0.00 0 [ 0.00] diameter_exprecs:'#info-/2'/1 1 0.00 0 [ 0.00] diameter_exprecs:'#new-/1'/1 1 0.00 0 [ 0.00] diameter_exprecs:'#new-/2'/1 1 0.00 0 [ 0.00] diameter_exprecs:'#get-/1'/1 1 0.00 0 [ 0.00] diameter_exprecs:'#get-/2'/1 1 0.00 0 [ 0.00] diameter_exprecs:'#set-/2'/1 1 0.00 0 [ 0.00] diameter_exprecs:'-#set-/2/1-lc$^0/1-0-'/1 3 0.00 0 [ 0.00] diameter_exprecs:'-#get-/2/1-lc$^0/1-0-'/1 3 0.00 0 [ 0.00] diameter_exprecs:'-#get-/1/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_exprecs:'-#new-/2/1-lc$^0/1-0-'/1 3 0.00 0 [ 0.00] diameter_exprecs:'-#new-/1/1-lc$^0/1-0-'/1 2 0.00 0 [ 0.00] diameter_exprecs:'-#info-/2/1-lc$^0/1-0-'/1 3 0.00 0 [ 0.00] zlib:open/0 1 0.00 0 [ 0.00] zlib:close/1 1 0.00 0 [ 0.00] zlib:deflateInit/2 1 0.00 0 [ 0.00] zlib:deflate/3 1 0.00 0 [ 0.00] zlib:deflateEnd/1 1 0.00 0 [ 0.00] zlib:compress/1 1 0.00 0 [ 0.00] zlib:collect/1 1 0.00 0 [ 0.00] zlib:arg_flush/1 1 0.00 0 [ 0.00] zlib:arg_level/1 1 0.00 0 [ 0.00] zlib:reverse/1 1 0.00 0 [ 0.00] zlib:reverse/2 3 0.00 0 [ 0.00] zlib:'-compress/1-after$^0/0-0-'/1 1 0.00 0 [ 0.00] code_server:call/1 1 0.00 0 [ 0.00] beam_peep:module/2 1 0.00 0 [ 0.00] beam_jump:module/2 1 0.00 0 [ 0.00] beam_flatten:module/2 1 0.00 0 [ 0.00] v3_codegen:functions/2 1 0.00 0 [ 0.00] v3_codegen:'-set_cg/6-anonymous-2-'/2 3 0.00 0 [ 0.00] v3_kernel:module/2 1 0.00 0 [ 0.00] v3_kernel:expr_map/5 3 0.00 0 [ 0.00] v3_kernel:map_group_pairs/5 3 0.00 0 [ 0.00] v3_kernel:'-map_split_pairs_1/5-anonymous-0-'/1 3 0.00 0 [ 0.00] v3_kernel:'-map_split_pairs/5-anonymous-1-'/3 3 0.00 0 [ 0.00] beam_z:module/2 1 0.00 0 [ 0.00] filename:skip_prefix/2 1 0.00 0 [ 0.00] filename:basename/2 1 0.00 0 [ 0.00] filename:basename/4 1 0.00 0 [ 0.00] filename:dirname/1 1 0.00 0 [ 0.00] filename:dirname/4 1 0.00 0 [ 0.00] filename:separators/0 2 0.00 0 [ 0.00] filename:do_flatten/2 3 0.00 0 [ 0.00] beam_receive:module/2 1 0.00 0 [ 0.00] code:ensure_loaded/1 1 0.00 0 [ 0.00] code:call/1 1 0.00 0 [ 0.00] dict:fetch_keys/1 1 0.00 0 [ 0.00] dict:'-to_list/1-fun-0-'/3 3 0.00 0 [ 0.00] os:type/0 2 0.00 0 [ 0.00] beam_opcodes:format_number/0 1 0.00 0 [ 0.00] beam_validator:validate/2 1 0.00 0 [ 0.00] beam_validator:verify_put_map/6 3 0.00 0 [ 0.00] beam_validator:assert_unique_map_keys/1 3 0.00 0 [ 0.00] beam_bsm:module/2 1 0.00 0 [ 0.00] beam_asm:module/5 1 0.00 0 [ 0.00] beam_asm:assemble/5 1 0.00 0 [ 0.00] beam_asm:on_load/2 1 0.00 0 [ 0.00] beam_asm:build_file/9 1 0.00 0 [ 0.00] beam_asm:finalize_fun_table/2 1 0.00 0 [ 0.00] beam_asm:build_form/2 1 0.00 0 [ 0.00] beam_asm:flatten_exports/1 2 0.00 0 [ 0.00] beam_asm:flatten_imports/1 1 0.00 0 [ 0.00] beam_asm:build_attributes/4 1 0.00 0 [ 0.00] beam_asm:build_line_table/1 1 0.00 0 [ 0.00] beam_asm:set_vsn_attribute/2 1 0.00 0 [ 0.00] beam_asm:'-build_line_table/1-lbc$^1/2-1-'/2 2 0.00 0 [ 0.00] beam_asm:'-build_line_table/1-lc$^0/1-0-'/1 1 0.00 0 [ 0.00] beam_asm:'-build_file/9-lc$^1/1-1-'/1 2 0.00 0 [ 0.00] beam_block:module/2 1 0.00 0 [ 0.00] unicode:characters_to_binary/1 1 0.00 0 [ 0.00] beam_dict:new/0 1 0.00 0 [ 0.00] beam_dict:atom_table/2 1 0.00 0 [ 0.00] beam_dict:string_table/1 1 0.00 0 [ 0.00] beam_dict:lambda_table/1 1 0.00 0 [ 0.00] beam_dict:line_table/1 1 0.00 0 [ 0.00] beam_dict:'-line_table/1-lc$^0/1-0-'/1 3 0.00 0 [ 0.00] orddict:to_list/1 3 0.00 0 [ 0.00] erl_lint:value_option/7 1 0.00 0 [ 0.00] erl_lint:module/3 1 0.00 0 [ 0.00] erl_lint:compiler_options/1 1 0.00 0 [ 0.00] erl_lint:start/2 1 0.00 0 [ 0.00] erl_lint:return_status/1 1 0.00 0 [ 0.00] erl_lint:pack_errors/1 1 0.00 0 [ 0.00] erl_lint:pack_warnings/1 2 0.00 0 [ 0.00] erl_lint:forms/2 1 0.00 0 [ 0.00] erl_lint:includes_qlc_hrl/2 1 0.00 0 [ 0.00] erl_lint:eval_file_attribute/2 1 0.00 0 [ 0.00] erl_lint:start_state/2 1 0.00 0 [ 0.00] erl_lint:eof/2 1 0.00 0 [ 0.00] erl_lint:bif_clashes/2 1 0.00 0 [ 0.00] erl_lint:not_deprecated/2 1 0.00 0 [ 0.00] erl_lint:disallowed_compile_flags/2 1 0.00 0 [ 0.00] erl_lint:post_traversal_check/2 1 0.00 0 [ 0.00] erl_lint:check_behaviour/1 1 0.00 0 [ 0.00] erl_lint:behaviour_check/2 1 0.00 0 [ 0.00] erl_lint:all_behaviour_callbacks/3 1 0.00 0 [ 0.00] erl_lint:behaviour_missing_callbacks/2 1 0.00 0 [ 0.00] erl_lint:behaviour_conflicting/2 1 0.00 0 [ 0.00] erl_lint:behaviour_add_conflicts/2 1 0.00 0 [ 0.00] erl_lint:check_deprecated/2 1 0.00 0 [ 0.00] erl_lint:check_imports/2 1 0.00 0 [ 0.00] erl_lint:check_inlines/2 1 0.00 0 [ 0.00] erl_lint:check_unused_functions/2 1 0.00 0 [ 0.00] erl_lint:check_undefined_functions/1 1 0.00 0 [ 0.00] erl_lint:check_undefined_types/1 1 0.00 0 [ 0.00] erl_lint:check_bif_clashes/2 1 0.00 0 [ 0.00] erl_lint:check_option_functions/4 3 0.00 0 [ 0.00] erl_lint:nowarn_function/2 1 0.00 0 [ 0.00] erl_lint:func_line_warning/3 1 0.00 0 [ 0.00] erl_lint:func_line_error/3 3 0.00 0 [ 0.00] erl_lint:check_untyped_records/2 1 0.00 0 [ 0.00] erl_lint:check_unused_records/2 1 0.00 0 [ 0.00] erl_lint:check_callback_information/1 1 0.00 0 [ 0.00] erl_lint:export/3 2 0.00 0 [ 0.00] erl_lint:exports/1 1 0.00 0 [ 0.00] erl_lint:check_on_load/1 1 0.00 0 [ 0.00] erl_lint:check_specs_without_function/1 1 0.00 0 [ 0.00] erl_lint:check_functions_without_spec/2 1 0.00 0 [ 0.00] erl_lint:check_unused_types/2 1 0.00 0 [ 0.00] erl_lint:check_local_opaque_types/1 1 0.00 0 [ 0.00] erl_lint:check_dialyzer_attribute/2 1 0.00 0 [ 0.00] erl_lint:merge_state/2 1 0.00 0 [ 0.00] erl_lint:local_functions/1 1 0.00 0 [ 0.00] erl_lint:auto_import_suppressed/1 1 0.00 0 [ 0.00] erl_lint:'-auto_import_suppressed/1-lc$^1/1-1-'/1 1 0.00 0 [ 0.00] erl_lint:'-auto_import_suppressed/1-lc$^0/1-0-'/1 6 0.00 0 [ 0.00] erl_lint:'-vtmerge_pat/2-fun-0-'/3 1 0.00 0 [ 0.00] erl_lint:'-expr/3-fun-1-'/3 3 0.00 0 [ 0.00] erl_lint:'-nowarn_function/2-lc$^0/1-0-'/2 6 0.00 0 [ 0.00] erl_lint:'-check_option_functions/4-lc$^4/1-4-'/2 3 0.00 0 [ 0.00] erl_lint:'-check_option_functions/4-lc$^1/1-1-'/4 6 0.00 0 [ 0.00] erl_lint:'-check_undefined_types/1-lc$^0/1-0-'/3 1 0.00 0 [ 0.00] erl_lint:'-behaviour_check/2-lc$^2/1-1-'/2 1 0.00 0 [ 0.00] erl_lint:'-not_deprecated/2-lc$^5/1-5-'/1 1 0.00 0 [ 0.00] erl_lint:'-not_deprecated/2-lc$^4/1-4-'/1 1 0.00 0 [ 0.00] erl_lint:'-not_deprecated/2-lc$^3/1-3-'/1 1 0.00 0 [ 0.00] erl_lint:'-not_deprecated/2-lc$^1/1-1-'/3 2 0.00 0 [ 0.00] erl_lint:'-pack_warnings/1-lc$^0/1-2-'/1 2 0.00 0 [ 0.00] erl_lint:'-pack_warnings/1-lc$^1/1-0-'/2 2 0.00 0 [ 0.00] erl_expand_records:module/2 1 0.00 0 [ 0.00] erl_expand_records:compiler_options/1 1 0.00 0 [ 0.00] erl_expand_records:init_calltype/1 1 0.00 0 [ 0.00] erl_expand_records:record_match/6 2 0.00 0 [ 0.00] sofs:from_external/2 1 0.00 0 [ 0.00] sofs:set/2 1 0.00 0 [ 0.00] sofs:converse/1 1 0.00 0 [ 0.00] sofs:drestriction/2 1 0.00 0 [ 0.00] sofs:drestriction/3 1 0.00 0 [ 0.00] sofs:family_to_relation/1 1 0.00 0 [ 0.00] sofs:family_specification/2 1 0.00 0 [ 0.00] sofs:is_element_type/1 1 0.00 0 [ 0.00] sofs:rel_type/3 1 0.00 0 [ 0.00] sofs:relprod/2 1 0.00 0 [ 0.00] sofs:relprod1/2 1 0.00 0 [ 0.00] sofs:converse/2 1 0.00 0 [ 0.00] sofs:restrict/2 1 0.00 0 [ 0.00] sofs:family2rel/2 1 0.00 0 [ 0.00] sofs:fam_spec/4 1 0.00 0 [ 0.00] beam_a:module/2 1 0.00 0 [ 0.00] beam_trim:module/2 1 0.00 0 [ 0.00] sys_core_dsetel:module/2 1 0.00 0 [ 0.00] sys_core_dsetel:visit_module/1 1 0.00 0 [ 0.00] cerl:module_name/1 1 0.00 0 [ 0.00] cerl:map_es/1 3 0.00 0 [ 0.00] cerl:map_arg/1 3 0.00 0 [ 0.00] cerl:update_c_map/3 3 0.00 0 [ 0.00] cerl:map_pair_key/1 3 0.00 0 [ 0.00] cerl:map_pair_val/1 3 0.00 0 [ 0.00] cerl:map_pair_op/1 3 0.00 0 [ 0.00] cerl:ann_c_map_pair/4 3 0.00 0 [ 0.00] cerl:update_c_map_pair/4 3 0.00 0 [ 0.00] cerl:is_c_fname/1 3 0.00 0 [ 0.00] erlang:open_port/2 1 0.00 0 [ 0.00] erlang:port_command/2 1 0.00 0 [ 0.00] erlang:port_close/1 1 0.00 0 [ 0.00] erl_parse:new_anno/1 2 0.00 0 [ 0.00] compile:expand_opts/1 1 0.00 0 [ 0.00] compile:expand_opt/2 5 0.00 0 [ 0.00] compile:internal/2 1 0.00 0 [ 0.00] compile:build_compile/1 1 0.00 0 [ 0.00] compile:internal_comp/5 1 0.00 0 [ 0.00] compile:comp_ret_ok/2 1 0.00 0 [ 0.00] compile:werror/1 1 0.00 0 [ 0.00] compile:messages_per_file/1 1 0.00 0 [ 0.00] compile:mpf/1 2 0.00 0 [ 0.00] compile:passes/2 1 0.00 0 [ 0.00] compile:fix_first_pass/1 1 0.00 0 [ 0.00] compile:standard_passes/0 1 0.00 0 [ 0.00] compile:core_passes/0 1 0.00 0 [ 0.00] compile:kernel_passes/0 1 0.00 0 [ 0.00] compile:transform_module/2 1 0.00 0 [ 0.00] compile:foldl_transform/3 2 0.00 0 [ 0.00] compile:core_transforms/2 1 0.00 0 [ 0.00] compile:foldl_core_transforms/3 1 0.00 0 [ 0.00] compile:get_module/1 1 0.00 0 [ 0.00] compile:add_default_base/2 1 0.00 0 [ 0.00] compile:lint_module/2 1 0.00 0 [ 0.00] compile:expand_records/2 1 0.00 0 [ 0.00] compile:core/2 1 0.00 0 [ 0.00] compile:v3_kernel/2 1 0.00 0 [ 0.00] compile:test_old_inliner/1 2 0.00 0 [ 0.00] compile:test_core_inliner/1 2 0.00 0 [ 0.00] compile:test_any_inliner/1 1 0.00 0 [ 0.00] compile:save_abstract_code/2 1 0.00 0 [ 0.00] compile:keep_compile_option/1 4 0.00 0 [ 0.00] compile:beam_asm/2 1 0.00 0 [ 0.00] compile:test_native/1 1 0.00 0 [ 0.00] compile:is_native_enabled/1 6 0.00 0 [ 0.00] compile:report_warnings/1 1 0.00 0 [ 0.00] compile:outfile/3 1 0.00 0 [ 0.00] compile:objfile/2 1 0.00 0 [ 0.00] compile:'-core_transforms/2-lc$^0/1-0-'/1 6 0.00 0 [ 0.00] compile:'-foldl_transform/3-anonymous-2-'/3 1 0.00 0 [ 0.00] compile:'-foldl_transform/3-anonymous-0-'/3 1 0.00 0 [ 0.00] compile:'-asm_passes/0-anonymous-4-'/2 1 0.00 0 [ 0.00] compile:'-asm_passes/0-anonymous-0-'/1 1 0.00 0 [ 0.00] compile:'-kernel_passes/0-anonymous-2-'/2 1 0.00 0 [ 0.00] compile:'-core_passes/0-anonymous-7-'/2 1 0.00 0 [ 0.00] compile:'-core_passes/0-anonymous-5-'/1 1 0.00 0 [ 0.00] compile:'-core_passes/0-anonymous-3-'/1 1 0.00 0 [ 0.00] compile:'-core_passes/0-anonymous-1-'/1 1 0.00 0 [ 0.00] compile:'-standard_passes/0-anonymous-6-'/2 1 0.00 0 [ 0.00] compile:'-standard_passes/0-anonymous-5-'/2 1 0.00 0 [ 0.00] compile:'-standard_passes/0-anonymous-4-'/2 1 0.00 0 [ 0.00] compile:'-standard_passes/0-anonymous-3-'/2 1 0.00 0 [ 0.00] compile:'-standard_passes/0-anonymous-0-'/2 1 0.00 0 [ 0.00] compile:'-messages_per_file/1-anonymous-5-'/1 2 0.00 0 [ 0.00] compile:'-messages_per_file/1-lc$^0/1-0-'/1 1 0.00 0 [ 0.00] compile:'-expand_opts/1-anonymous-0-'/2 5 0.00 0 [ 0.00] compile:'-do_compile/2-anonymous-1-'/1 1 0.00 0 [ 0.00] compile:'-do_compile/2-anonymous-0-'/2 1 0.00 0 [ 0.00] beam_dead:module/2 1 0.00 0 [ 0.00] beam_dead:equal_ops/2 1 0.00 0 [ 0.00] beam_dead:shortcut_bs_ctb_1/4 1 0.00 0 [ 0.00] beam_split:module/2 1 0.00 0 [ 0.00] beam_except:module/2 1 0.00 0 [ 0.00] ordsets:new/0 1 0.00 0 [ 0.00] erlang:system_info/1 2 0.00 0 [ 0.00] erlang:make_tuple/2 2 0.00 0 [ 0.00] erlang:exit/1 1 0.00 0 [ 0.00] beam_clean:module/2 1 0.00 1 [ 1.00] beam_clean:rootset/3 1 0.00 1 [ 1.00] beam_clean:bs_fix/1 1 0.00 1 [ 1.00] sys_core_bsm:bsm_ensure_no_partition_2/5 3 0.00 1 [ 0.33] erl_internal:'-predefined_functions/1-lc$^3/1-3-'/1 3 0.00 1 [ 0.33] erl_internal:'-predefined_functions/1-lc$^2/1-2-'/1 3 0.00 1 [ 0.33] v3_core:module/2 1 0.00 1 [ 1.00] v3_core:map_build_pairs/4 3 0.00 1 [ 0.33] v3_core:maybe_warn_repeated_keys/4 3 0.00 1 [ 0.33] v3_core:is_valid_map_src/1 3 0.00 1 [ 0.33] v3_core:'-is_simple/1-anonymous-1-'/1 8 0.00 1 [ 0.13] v3_core:'-is_simple/1-anonymous-0-'/1 6 0.00 1 [ 0.17] sys_core_fold:sub_subst_scope/1 3 0.00 1 [ 0.33] cerl_sets:to_list/1 3 0.00 1 [ 0.33] cerl_sets:union/2 3 0.00 1 [ 0.33] beam_bs:module/2 1 0.00 1 [ 1.00] sets:new/0 2 0.00 1 [ 0.50] sets:expand_segs/2 2 0.00 1 [ 0.50] lists:usort_1/2 3 0.00 1 [ 0.33] zlib:collect/2 3 0.00 1 [ 0.33] zlib:call/3 3 0.00 1 [ 0.33] v3_codegen:module/2 1 0.00 1 [ 1.00] v3_codegen:set_cg_map/7 3 0.00 1 [ 0.33] v3_codegen:cg_build_args/2 5 0.00 1 [ 0.20] v3_codegen:fetch_var_prefer_y/2 6 0.00 1 [ 0.17] v3_codegen:find_stack/3 6 0.00 1 [ 0.17] v3_codegen:'-set_cg/6-lc$^1/1-1-'/1 6 0.00 1 [ 0.17] v3_codegen:'-set_cg/6-lc$^0/1-0-'/1 6 0.00 1 [ 0.17] v3_kernel:map_split_pairs/5 3 0.00 1 [ 0.33] v3_kernel:map_split_pairs_1/5 6 0.00 1 [ 0.17] v3_kernel:map_remove_dup_keys/2 6 0.00 1 [ 0.17] v3_kernel:map_key_clean/1 3 0.00 1 [ 0.33] v3_kernel:lit_list_vars/1 8 0.00 1 [ 0.13] v3_kernel:'-map_group_pairs/5-lc$^1/1-1-'/1 6 0.00 1 [ 0.17] v3_kernel:'-map_group_pairs/5-lc$^0/1-0-'/1 6 0.00 1 [ 0.17] filename:flatten/1 3 0.00 1 [ 0.33] dict:to_list/1 4 0.00 1 [ 0.25] beam_reorder:module/2 1 0.00 1 [ 1.00] beam_validator:module/2 1 0.00 1 [ 1.00] beam_validator:extract_map_keys/1 3 0.00 1 [ 0.33] beam_validator:validate_bs_get/6 13 0.00 1 [ 0.08] beam_validator:'-verify_put_map/6-anonymous-0-'/2 6 0.00 1 [ 0.17] beam_asm:'-finalize_fun_table/2-lc$^0/1-0-'/2 7 0.00 1 [ 0.14] beam_asm:'-build_file/9-lc$^0/1-0-'/1 7 0.00 1 [ 0.14] beam_type:module/2 1 0.00 1 [ 1.00] beam_dict:highest_opcode/1 1 0.00 1 [ 1.00] beam_dict:local_table/1 1 0.00 1 [ 1.00] beam_dict:import_table/1 1 0.00 1 [ 1.00] beam_dict:literal_table/1 1 0.00 1 [ 1.00] erl_lint:map_fields/4 6 0.00 1 [ 0.17] erl_lint:'-check_option_functions/4-lc$^3/1-3-'/1 3 0.00 1 [ 0.33] erl_lint:'-start/2-lc$^1/1-1-'/1 4 0.00 1 [ 0.25] erl_lint:'-value_option/7-fun-0-'/7 5 0.00 1 [ 0.20] erl_expand_records:record_upd_fs/3 4 0.00 1 [ 0.25] sofs:relation/1 2 0.00 1 [ 0.50] sofs:relative_product1/2 1 0.00 1 [ 1.00] sofs:image/2 1 0.00 1 [ 1.00] sofs:check_for_sort/2 1 0.00 1 [ 1.00] sys_core_dsetel:'-visit/2-anonymous-6-'/2 3 0.00 1 [ 0.33] cerl:is_c_atom/1 6 0.00 1 [ 0.17] erlang:apply/2 1 0.00 1 [ 1.00] erlang:port_control/3 3 0.00 1 [ 0.33] erl_parse:anno_to_term/1 1 0.00 1 [ 1.00] compile:passes_1/1 5 0.00 1 [ 0.20] compile:pass/1 4 0.00 1 [ 0.25] compile:select_list_passes/2 3 0.00 1 [ 0.33] compile:asm_passes/0 1 0.00 1 [ 1.00] compile:debug_info/1 1 0.00 1 [ 1.00] compile:effects_code_generation/1 8 0.00 1 [ 0.13] compile:'-debug_info/1-anonymous-0-'/1 4 0.00 1 [ 0.25] compile:'-transform_module/2-lc$^0/1-0-'/1 7 0.00 1 [ 0.14] compile:'-messages_per_file/1-anonymous-3-'/2 3 0.00 1 [ 0.33] maps:merge/2 3 0.00 1 [ 0.33] unicode:characters_to_binary/2 1 0.00 1 [ 1.00] erlang:demonitor/2 1 0.00 1 [ 1.00] erlang:function_exported/3 1 0.00 1 [ 1.00] beam_clean:clean_labels/1 3 0.00 2 [ 0.67] v3_core:map_build_pairs_1/3 6 0.00 2 [ 0.33] sys_core_fold:body/2 9 0.00 2 [ 0.22] sys_core_fold:pair_list/3 9 0.00 2 [ 0.22] sys_core_fold:'-pair_list/3-lc$^0/1-0-'/3 9 0.00 2 [ 0.22] beam_utils:is_not_used/3 17 0.00 2 [ 0.12] lists:ukeymergel/3 10 0.00 2 [ 0.20] lists:ukeymerge3_1/11 7 0.00 2 [ 0.29] diameter_exprecs:is_head/1 23 0.00 2 [ 0.09] diameter_exprecs:export/1 17 0.00 2 [ 0.12] diameter_exprecs:accessors/2 17 0.00 2 [ 0.12] diameter_exprecs:'info-'/1 17 0.00 2 [ 0.12] diameter_exprecs:'new-'/1 17 0.00 2 [ 0.12] diameter_exprecs:'new--'/1 17 0.00 2 [ 0.12] diameter_exprecs:'get--'/1 17 0.00 2 [ 0.12] diameter_exprecs:'get-'/1 17 0.00 2 [ 0.12] diameter_exprecs:'set-'/1 17 0.00 2 [ 0.12] v3_kernel:'-map_split_pairs/5-lc$^0/1-0-'/1 6 0.00 2 [ 0.33] proplists:get_value/2 5 0.00 2 [ 0.40] erl_lint:pseudolocals/0 6 0.00 2 [ 0.33] erl_lint:record_def/4 18 0.00 2 [ 0.11] erl_lint:check_type/2 18 0.00 2 [ 0.11] erl_lint:handle_comprehension/4 17 0.00 2 [ 0.12] sofs:relprod2/5 17 0.00 2 [ 0.12] sofs:relprod/8 17 0.00 2 [ 0.12] beam_trim:frame_layout_2/1 17 0.00 2 [ 0.12] cerl:ann_c_map/3 15 0.00 2 [ 0.13] compile:'-beam_asm/2-lc$^0/1-0-'/1 5 0.00 2 [ 0.40] compile:'-test_core_inliner/1-anonymous-1-'/1 10 0.00 2 [ 0.20] compile:'-test_core_inliner/1-anonymous-0-'/1 10 0.00 2 [ 0.20] compile:'-test_old_inliner/1-anonymous-0-'/1 10 0.00 2 [ 0.20] erlang:make_ref/0 13 0.00 2 [ 0.15] erlang:binary_to_list/1 13 0.00 2 [ 0.15] erl_internal:'-get_optional_callbacks/1-lc$^0/1-0-'/1 24 0.00 3 [ 0.13] erl_internal:'-predefined_functions/1-lc$^1/1-1-'/1 24 0.00 3 [ 0.13] sys_core_fold:pair/3 9 0.00 3 [ 0.33] lists:flatten/1 9 0.00 3 [ 0.33] lists:keysplit_1_1/10 22 0.00 3 [ 0.14] lists:rkeymergel/4 19 0.00 3 [ 0.16] diameter_exprecs:'-#set-/2/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-#get-/2/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-#get-/1/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-#new-/2/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-#new-/1/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-#info-/2/1-fun-1-'/1 17 0.00 3 [ 0.18] diameter_exprecs:'-parse_transform/2-lc$^2/1-1-'/1 23 0.00 3 [ 0.13] v3_codegen:select_cons/6 18 0.00 3 [ 0.17] v3_codegen:select_nil/6 17 0.00 3 [ 0.18] v3_codegen:get_bin_size_reg/2 13 0.00 3 [ 0.23] v3_codegen:bif_cg/7 17 0.00 3 [ 0.18] v3_codegen:'-cg_build_args/2-lc$^0/1-0-'/2 15 0.00 3 [ 0.20] v3_kernel:'-lit_list_vars/1-anonymous-0-'/2 16 0.00 3 [ 0.19] dict:expand_segs/2 8 0.00 3 [ 0.38] beam_asm:finalize_fun_table_1/2 7 0.00 3 [ 0.43] beam_asm:chunk/2 5 0.00 3 [ 0.60] beam_asm:filter_essentials/1 8 0.00 3 [ 0.38] beam_type:simplify_select_val_int/2 13 0.00 3 [ 0.23] beam_dict:export_table/1 1 0.00 3 [ 3.00] erl_lint:'-start/2-lc$^0/1-0-'/1 16 0.00 3 [ 0.19] beam_dead:shortcut_bs_start_match_1/4 13 0.00 3 [ 0.23] erlang:monitor/2 1 0.00 3 [ 3.00] v3_core:attribute/1 20 0.00 4 [ 0.20] sys_core_fold:sub_subst_scope_1/3 25 0.00 4 [ 0.16] lists:do_flatten/2 21 0.00 4 [ 0.19] lists:rukeymergel/3 22 0.00 4 [ 0.18] lists:rukeymerge2_2/8 27 0.00 4 [ 0.15] diameter_exprecs:fields/2 17 0.00 4 [ 0.24] diameter_exprecs:fname/1 14 0.00 4 [ 0.29] diameter_exprecs:'#new-X/0'/1 17 0.00 4 [ 0.24] diameter_exprecs:'#new-X/1'/1 17 0.00 4 [ 0.24] diameter_exprecs:'#set-X/2'/2 17 0.00 4 [ 0.24] diameter_exprecs:'#get-X/1'/2 17 0.00 4 [ 0.24] diameter_exprecs:'#get-X/2'/2 17 0.00 4 [ 0.24] diameter_exprecs:'#info-X/1'/2 17 0.00 4 [ 0.24] diameter_exprecs:'-f_accessors/2-fun-0-'/2 17 0.00 4 [ 0.24] diameter_exprecs:'-a_export/1-fun-0-'/1 17 0.00 4 [ 0.24] epp:default_encoding/0 17 0.00 4 [ 0.24] v3_codegen:select_binary/6 14 0.00 4 [ 0.29] v3_codegen:put_reg/2 18 0.00 4 [ 0.22] v3_kernel:include_attribute/1 20 0.00 4 [ 0.20] v3_kernel:iletrec_funs_gen/3 17 0.00 4 [ 0.24] v3_kernel:'-uexpr/3-anonymous-18-'/2 17 0.00 4 [ 0.24] v3_kernel:'-iletrec_funs/2-anonymous-1-'/2 17 0.00 4 [ 0.24] proplists:get_bool/2 18 0.00 4 [ 0.22] proplists:delete/2 15 0.00 4 [ 0.27] beam_validator:verify_no_ct_1/1 17 0.00 4 [ 0.24] beam_validator:is_bif_safe/2 17 0.00 4 [ 0.24] beam_block:alloc_may_pass/1 17 0.00 4 [ 0.24] erl_lint:bool_option/4 15 0.00 4 [ 0.27] erl_lint:attribute_state/2 22 0.00 4 [ 0.18] erl_lint:vt_no_unsafe/1 17 0.00 4 [ 0.24] erl_lint:vt_no_unused/1 17 0.00 4 [ 0.24] erl_expand_records:strict_record_access/2 34 0.00 4 [ 0.12] erl_expand_records:opt_rec_vars/2 34 0.00 4 [ 0.12] sofs:relprod1/5 36 0.00 4 [ 0.11] beam_trim:trim_instructions/1 17 0.00 4 [ 0.24] beam_trim:config_cost_1/2 17 0.00 4 [ 0.24] beam_trim:expand_config/2 17 0.00 4 [ 0.24] beam_trim:create_map/2 17 0.00 4 [ 0.24] beam_trim:try_remap/3 17 0.00 4 [ 0.24] beam_trim:frame_layout/3 17 0.00 4 [ 0.24] beam_trim:'-frame_layout/3-anonymous-0-'/3 17 0.00 4 [ 0.24] beam_trim:'-expand_config/2-lc$^0/1-0-'/1 17 0.00 4 [ 0.24] sys_core_dsetel:visit_def_list/2 17 0.00 4 [ 0.24] sys_core_dsetel:'-visit_def_list/2-anonymous-0-'/2 17 0.00 4 [ 0.24] cerl:update_c_letrec/3 17 0.00 4 [ 0.24] cerl:letrec_defs/1 17 0.00 4 [ 0.24] cerl:letrec_body/1 17 0.00 4 [ 0.24] erl_parse:enc_func/1 17 0.00 4 [ 0.24] erl_parse:'-new_anno/1-fun-0-'/2 16 0.00 4 [ 0.25] erts_internal:port_close/1 1 0.00 4 [ 4.00] v3_core:preprocess_quals/3 17 0.00 5 [ 0.29] v3_core:list_gen_pattern/3 17 0.00 5 [ 0.29] v3_core:'-uexpr/3-anonymous-3-'/1 17 0.00 5 [ 0.29] v3_core:'-uexpr/3-anonymous-2-'/3 17 0.00 5 [ 0.29] v3_life:is_gc_bif/2 17 0.00 5 [ 0.29] v3_life:'-k_bif/4-lc$^0/1-2-'/1 17 0.00 5 [ 0.29] sys_core_fold:v_is_value/2 34 0.00 5 [ 0.15] lists:keymergel/4 32 0.00 5 [ 0.16] lists:ukeymerge3_21_3/9 36 0.00 5 [ 0.14] diameter_exprecs:'-parse_transform/2-lc$^1/1-0-'/1 23 0.00 5 [ 0.22] diameter_exprecs:'-parse_transform/2-fun-0-'/1 23 0.00 5 [ 0.22] v3_codegen:select_extract_bin/12 13 0.00 5 [ 0.38] v3_codegen:build_bs_instr/8 13 0.00 5 [ 0.38] v3_codegen:internal_cg/7 17 0.00 5 [ 0.29] v3_codegen:'-match_cg/5-anonymous-0-'/4 37 0.00 5 [ 0.14] v3_kernel:group_bin_seg/2 26 0.00 5 [ 0.19] v3_kernel:'-uexpr/3-anonymous-19-'/2 17 0.00 5 [ 0.29] v3_kernel:'-uexpr/3-anonymous-15-'/2 17 0.00 5 [ 0.29] v3_kernel:'-uexpr/3-anonymous-14-'/2 17 0.00 5 [ 0.29] v3_kernel:'-uexpr/3-anonymous-3-'/2 17 0.00 5 [ 0.29] beam_validator:bif_type/3 17 0.00 5 [ 0.29] beam_asm:finalize_fun_table_2/3 18 0.00 5 [ 0.28] beam_block:alloc_live_regs/2 17 0.00 5 [ 0.29] beam_type:get_bs_integer_type/1 13 0.00 5 [ 0.38] beam_dict:string/2 13 0.00 5 [ 0.38] beam_dict:'-lambda_table/1-lc$^1/1-1-'/1 18 0.00 5 [ 0.28] beam_dict:'-import_table/1-lc$^0/1-0-'/1 23 0.00 5 [ 0.22] erl_lint:normalise_fields/1 18 0.00 5 [ 0.28] erl_lint:nowarn/0 18 0.00 5 [ 0.28] erl_lint:lc_quals/3 17 0.00 5 [ 0.29] erl_lint:handle_generator/5 17 0.00 5 [ 0.29] erl_lint:shadow_vars/4 17 0.00 5 [ 0.29] erl_expand_records:normalise_fields/1 18 0.00 5 [ 0.28] erl_expand_records:make_list/2 17 0.00 5 [ 0.29] beam_trim:trim_instructions_1/4 34 0.00 5 [ 0.15] beam_trim:save_config/4 17 0.00 5 [ 0.29] sys_core_dsetel:'-visit/2-lc$^0/1-0-'/1 17 0.00 5 [ 0.29] compile:select_cond/5 36 0.00 5 [ 0.14] compile:clean_parse_transforms_1/2 48 0.00 5 [ 0.10] erlang:term_to_binary/1 2 0.00 5 [ 2.50] v3_core:generator/4 17 0.00 6 [ 0.35] v3_core:lc_guard_tests/2 17 0.00 6 [ 0.35] v3_core:new_fun_name/2 17 0.00 6 [ 0.35] v3_core:'-cexpr/3-anonymous-0-'/2 17 0.00 6 [ 0.35] sets:maybe_expand_segs/1 18 0.00 6 [ 0.33] v3_codegen:select_extract_cons/6 18 0.00 6 [ 0.33] v3_kernel:ubody_used_vars/2 17 0.00 6 [ 0.35] v3_kernel:iletrec_funs/2 17 0.00 6 [ 0.35] v3_kernel:'-expr/3-anonymous-2-'/4 17 0.00 6 [ 0.35] beam_asm:bif_type/2 17 0.00 6 [ 0.35] beam_asm:'-flatten_imports/1-anonymous-0-'/1 22 0.00 6 [ 0.27] beam_block:x_live/2 34 0.00 6 [ 0.18] erl_lint:guard_test2/3 34 0.00 6 [ 0.18] erl_lint:def_fields/3 18 0.00 6 [ 0.33] erl_lint:exist_record/3 34 0.00 6 [ 0.18] erl_lint:check_type/3 18 0.00 6 [ 0.33] erl_expand_records:field_names/1 17 0.00 6 [ 0.35] erl_expand_records:record_info_call/3 34 0.00 6 [ 0.18] compile:compile_options/1 48 0.00 6 [ 0.13] erlang:list_to_bitstring/1 14 0.00 6 [ 0.43] lists:rkeymerge2_1/6 56 0.00 7 [ 0.13] lists:rkeymerge2_2/7 53 0.00 7 [ 0.13] eval_bits:match_field/10 56 0.00 7 [ 0.13] v3_codegen:protected_cg/7 37 0.00 7 [ 0.19] v3_codegen:test_cg/7 37 0.00 7 [ 0.19] v3_codegen:maybe_adjust_stack/5 20 0.00 7 [ 0.35] v3_codegen:'-select_bin_segs/5-anonymous-0-'/5 56 0.00 7 [ 0.13] v3_codegen:'-turn_yreg/2-lc$^0/1-0-'/2 37 0.00 7 [ 0.19] v3_kernel:attributes/1 21 0.00 7 [ 0.33] v3_kernel:new_fun_name/2 17 0.00 7 [ 0.41] v3_kernel:bif_returns/3 17 0.00 7 [ 0.41] v3_kernel:'-iletrec_funs_gen/3-anonymous-0-'/3 17 0.00 7 [ 0.41] v3_kernel:'-iletrec_funs/2-anonymous-3-'/3 17 0.00 7 [ 0.41] v3_kernel:'-iletrec_funs/2-lc$^0/1-0-'/1 17 0.00 7 [ 0.41] v3_kernel:'-iletrec_funs/2-anonymous-2-'/3 17 0.00 7 [ 0.41] beam_validator:test_heap/3 56 0.00 7 [ 0.13] beam_validator:branch_arities/3 45 0.00 7 [ 0.16] beam_block:live_regs/2 51 0.00 7 [ 0.14] beam_dict:lambda/3 17 0.00 7 [ 0.41] erl_lint:'-expr/3-fun-3-'/6 51 0.00 7 [ 0.14] erl_expand_records:in_guard/1 34 0.00 7 [ 0.21] compile:select_list_passes_1/3 55 0.00 7 [ 0.13] erts_internal:open_port/2 1 0.00 7 [ 7.00] v3_core:gexpr_test/3 34 0.00 8 [ 0.24] v3_life:'-k_bif/4-lc$^0/1-3-'/1 34 0.00 8 [ 0.24] lists:keymerge3_21_3/9 67 0.00 8 [ 0.12] lists:ukeysplit_1_1/10 37 0.00 8 [ 0.22] eval_bits:match_check_size/4 56 0.00 8 [ 0.14] v3_codegen:select_bin_segs/5 56 0.00 8 [ 0.14] v3_codegen:guard_clause_cg/4 37 0.00 8 [ 0.22] v3_kernel:'-uexpr/3-anonymous-2-'/2 34 0.00 8 [ 0.24] beam_validator:set_type/3 53 0.00 8 [ 0.15] beam_asm:'-encode_arg/2-anonymous-0-'/2 39 0.00 8 [ 0.21] beam_type:eq_ranges/3 56 0.00 8 [ 0.14] beam_dict:old_string/2 13 0.00 8 [ 0.62] beam_dict:'-lambda_table/1-lc$^0/1-0-'/1 38 0.00 8 [ 0.21] erl_lint:vtsubtract/2 34 0.00 8 [ 0.24] beam_trim:'-trim_instructions/1-lc$^0/1-0-'/1 34 0.00 8 [ 0.24] beam_trim:'-trim/3-anonymous-0-'/1 34 0.00 8 [ 0.24] beam_dead:shortcut_selectval/4 35 0.00 8 [ 0.23] erlang:erase/1 36 0.00 8 [ 0.22] v3_life:'-k_bif/4-lc$^0/1-5-'/1 34 0.00 9 [ 0.26] v3_life:'-k_bif/4-lc$^0/1-4-'/1 34 0.00 9 [ 0.26] v3_life:'-protected/3-lc$^0/1-1-'/1 37 0.00 9 [ 0.24] lists:keysplit_1/8 64 0.00 9 [ 0.14] v3_codegen:'-select_binary/6-anonymous-1-'/2 42 0.00 9 [ 0.21] v3_kernel:add_local_function/2 17 0.00 9 [ 0.53] beam_validator:upgrade_tuple_type/2 35 0.00 9 [ 0.26] beam_asm:chunk/3 9 0.00 9 [ 1.00] beam_asm:flag_to_bit/1 39 0.00 9 [ 0.23] beam_block:x_dead/2 51 0.00 9 [ 0.18] beam_dict:local/4 37 0.00 9 [ 0.24] erl_lint:pattern_fields/7 51 0.00 9 [ 0.18] erl_lint:init_fields/6 51 0.00 9 [ 0.18] erl_lint:lc_quals/4 34 0.00 9 [ 0.26] erl_lint:check_old_unused_vars/3 34 0.00 9 [ 0.26] erl_lint:'-gexpr_list/3-fun-0-'/3 34 0.00 9 [ 0.26] core_lib:'-vu_var_list/2-anonymous-0-'/2 34 0.00 9 [ 0.26] beam_trim:remap_block/3 51 0.00 9 [ 0.18] erl_internal:old_type_test/2 34 0.00 10 [ 0.29] v3_core:preprocess_quals/4 34 0.00 10 [ 0.29] v3_core:new_fun_name/1 17 0.00 10 [ 0.59] lists:rkeymerge3_21_3/9 81 0.00 10 [ 0.12] v3_codegen:'-guard_cg_list/6-anonymous-0-'/4 37 0.00 10 [ 0.27] v3_kernel:'-uexpr/3-anonymous-20-'/2 37 0.00 10 [ 0.27] beam_validator:'-verify_no_ct/1-lc$^0/1-0-'/1 51 0.00 10 [ 0.20] erl_lint:guard_test/3 34 0.00 10 [ 0.29] erl_lint:check_record_info_call/4 34 0.00 10 [ 0.29] erl_lint:is_imported_function/2 34 0.00 10 [ 0.29] erl_lint:'-vt_no_unused/1-lc$^0/1-0-'/1 51 0.00 10 [ 0.20] erl_expand_records:guard_tests/2 34 0.00 10 [ 0.29] erl_expand_records:guard_test/2 34 0.00 10 [ 0.29] erl_expand_records:normalise_test/2 34 0.00 10 [ 0.29] core_lib:vu_var_list/2 34 0.00 10 [ 0.29] beam_trim:frame_layout_1/5 51 0.00 10 [ 0.20] binary:match/2 13 0.00 10 [ 0.77] v3_core:guard_tests/1 34 0.00 11 [ 0.32] v3_core:gexpr_top/2 34 0.00 11 [ 0.32] v3_core:force_booleans_1/4 68 0.00 11 [ 0.16] v3_core:lc_tq/5 34 0.00 11 [ 0.32] v3_life:protected/3 37 0.00 11 [ 0.30] v3_life:guard_clause/5 37 0.00 11 [ 0.30] v3_life:'-expr/3-lc$^0/1-4-'/1 37 0.00 11 [ 0.30] sys_core_fold:'-expr/3-anonymous-4-'/3 34 0.00 11 [ 0.32] sets:put_bucket_s/3 36 0.00 11 [ 0.31] lists:keymerge3_12_3/9 85 0.00 11 [ 0.13] lists:keymerge2_1/6 83 0.00 11 [ 0.13] lists:keymerge2_2/7 85 0.00 11 [ 0.13] v3_kernel:integers/2 34 0.00 11 [ 0.32] v3_kernel:'-forest_pre_seq/2-lc$^2/1-2-'/1 37 0.00 11 [ 0.30] beam_validator:'-valfun_1/2-lc$^0/1-0-'/2 51 0.00 11 [ 0.22] erl_lint:gexpr/3 34 0.00 11 [ 0.32] erl_lint:no_guard_bif_clash/2 34 0.00 11 [ 0.32] erl_lint:'-vt_no_unsafe/1-lc$^0/1-0-'/1 51 0.00 11 [ 0.22] cerl_trees:mapfold_pairs/4 34 0.00 11 [ 0.32] erl_expand_records:lc_tq/3 34 0.00 11 [ 0.32] erl_expand_records:pattern_fields/2 51 0.00 11 [ 0.22] erl_expand_records:opt_rec_vars_2/2 34 0.00 11 [ 0.32] erl_expand_records:'-guard_test/2-fun-0-'/2 34 0.00 11 [ 0.32] beam_trim:frame_size/2 68 0.00 11 [ 0.16] maps:is_key/2 37 0.00 11 [ 0.30] erlang:iolist_to_binary/1 9 0.00 11 [ 1.22] beam_utils:bif_to_test/3 34 0.00 12 [ 0.35] beam_jump:extract_seq_1/2 69 0.00 12 [ 0.17] v3_codegen:turn_yregs/3 91 0.00 12 [ 0.13] v3_codegen:guard_cg_list/6 37 0.00 12 [ 0.32] v3_codegen:'-save_stack/4-anonymous-2-'/2 85 0.00 12 [ 0.14] v3_kernel:'-new_clauses/3-anonymous-2-'/3 51 0.00 12 [ 0.24] v3_kernel:'-expr/3-anonymous-1-'/2 17 0.00 12 [ 0.71] v3_kernel:'-extract_vars/1-anonymous-1-'/2 37 0.00 12 [ 0.32] v3_kernel:'-extract_all_vars/3-lc$^1/1-1-'/2 37 0.00 12 [ 0.32] v3_kernel:'-forest_pre_seq/2-lc$^0/1-0-'/1 37 0.00 12 [ 0.32] beam_validator:call/3 85 0.00 12 [ 0.14] beam_validator:allocate/5 69 0.00 12 [ 0.17] erl_lint:gexpr_list/3 34 0.00 12 [ 0.35] beam_trim:'-remap_block/3-lc$^0/1-0-'/2 51 0.00 12 [ 0.24] cerl:update_c_values/2 47 0.00 12 [ 0.26] cerl:update_c_alias/3 51 0.00 12 [ 0.24] lists:ukeymerge2_2/6 100 0.00 13 [ 0.13] eval_bits:add_bin_binding/4 56 0.00 13 [ 0.23] v3_kernel:wrap_guard/2 37 0.00 13 [ 0.35] v3_kernel:flatten_alias/1 51 0.00 13 [ 0.25] v3_kernel:'-new_clauses/3-anonymous-1-'/3 51 0.00 13 [ 0.25] v3_kernel:'-match_vars/2-anonymous-0-'/2 91 0.00 13 [ 0.14] erl_lint:obsolete_guard/2 34 0.00 13 [ 0.38] erl_expand_records:guard_test1/2 34 0.00 13 [ 0.38] erl_expand_records:opt_rec_vars_1/2 68 0.00 13 [ 0.19] erts_internal:port_command/3 1 0.00 13 [ 13.00] v3_core:pat_alias/2 51 0.00 14 [ 0.27] v3_life:test_op/1 37 0.00 14 [ 0.38] v3_life:k_bif/4 34 0.00 14 [ 0.41] lists:keysplit_2_1/10 101 0.00 14 [ 0.14] eval_bits:coerce_to_float/2 56 0.00 14 [ 0.25] eval_bits:match_check_size/3 56 0.00 14 [ 0.25] v3_codegen:select_bin_seg/5 56 0.00 14 [ 0.25] v3_kernel:guard/3 37 0.00 14 [ 0.38] dict:is_key/2 52 0.00 14 [ 0.27] dict:find_key/2 116 0.00 14 [ 0.12] beam_dict:'-line_table/1-lc$^1/1-1-'/1 67 0.00 14 [ 0.21] erl_lint:reject_invalid_alias/4 51 0.00 14 [ 0.27] erl_lint:init_fields/3 51 0.00 14 [ 0.27] erl_expand_records:record_inits/2 51 0.00 14 [ 0.27] beam_trim:remap/3 85 0.00 14 [ 0.16] sys_core_dsetel:rewrite/3 88 0.00 14 [ 0.16] maps:keys/1 40 0.00 14 [ 0.35] eval_bits:match_bits/6 56 0.00 15 [ 0.27] v3_codegen:select_extract_int/11 43 0.00 15 [ 0.35] v3_kernel:'-match_fun/1-anonymous-0-'/3 56 0.00 15 [ 0.27] beam_validator:set_type_y/3 85 0.00 15 [ 0.18] beam_validator:return_type_1/4 103 0.00 15 [ 0.15] beam_validator:return_type_erl/2 103 0.00 15 [ 0.15] beam_asm:encode_line_items/2 67 0.00 15 [ 0.22] erl_lint:'-bool_option/4-fun-0-'/4 75 0.00 15 [ 0.20] sys_core_dsetel:'-visit/2-anonymous-3-'/2 71 0.00 15 [ 0.21] lists:rkeymerge3_12_3/9 125 0.00 16 [ 0.13] lists:ukeysplit_1/8 80 0.00 16 [ 0.20] lists:rukeymerge3_1/11 91 0.00 16 [ 0.18] lists:rukeymerge2_1/6 109 0.00 16 [ 0.15] v3_kernel:translate_match_fail_1/4 68 0.00 16 [ 0.24] v3_kernel:store_free/4 17 0.00 16 [ 0.94] v3_kernel:'-expr/3-lc$^0/1-0-'/1 51 0.00 16 [ 0.31] beam_validator:bsm_get_context/2 59 0.00 16 [ 0.27] core_lib:'-vu_expr/2-anonymous-0-'/2 68 0.00 16 [ 0.24] beam_trim:'-remap_block/3-lc$^1/1-1-'/2 68 0.00 16 [ 0.24] beam_trim:'-create_map/2-anonymous-2-'/2 68 0.00 16 [ 0.24] cerl:primop_name/1 71 0.00 16 [ 0.23] cerl:primop_args/1 71 0.00 16 [ 0.23] eval_bits:get_value/6 56 0.00 17 [ 0.30] v3_kernel:guard_opt/2 37 0.00 17 [ 0.46] v3_kernel:select_assert_match_possible/3 56 0.00 17 [ 0.30] v3_kernel:'-extract_var_list/1-lc$^0/1-0-'/1 37 0.00 17 [ 0.46] proplists:get_value/3 82 0.00 17 [ 0.21] erl_lint:pre_scan/2 157 0.00 17 [ 0.11] erl_lint:'-check_dialyzer_attribute/2-lc$^2/1-0-'/1 157 0.00 17 [ 0.11] erl_lint:'-check_unused_types/2-lc$^0/1-0-'/1 157 0.00 17 [ 0.11] erl_lint:'-check_unused_records/2-lc$^0/1-0-'/1 157 0.00 17 [ 0.11] erl_lint:'-disallowed_compile_flags/2-lc$^2/1-2-'/2 157 0.00 17 [ 0.11] erl_lint:'-disallowed_compile_flags/2-lc$^0/1-0-'/2 157 0.00 17 [ 0.11] erl_lint:'-not_deprecated/2-lc$^0/1-0-'/1 157 0.00 17 [ 0.11] erl_lint:'-includes_qlc_hrl/2-lc$^0/1-0-'/1 157 0.00 17 [ 0.11] cerl:update_c_cons_skel/3 68 0.00 17 [ 0.25] cerl:update_c_primop/3 71 0.00 17 [ 0.24] v3_core:unforce/3 68 0.00 18 [ 0.26] sys_core_fold:sub_new/1 65 0.00 18 [ 0.28] sys_core_fold:eval_case_warn/1 65 0.00 18 [ 0.28] lists:unzip/1 65 0.00 18 [ 0.28] eval_bits:match_field_1/6 56 0.00 18 [ 0.32] v3_codegen:call_cg/7 68 0.00 18 [ 0.26] v3_kernel:match_fun/1 56 0.00 18 [ 0.32] beam_validator:eat_heap/2 66 0.00 18 [ 0.27] beam_block:gen_init/4 102 0.00 18 [ 0.18] erl_lint:'-bif_clashes/2-lc$^0/1-0-'/1 157 0.00 18 [ 0.11] erl_expand_records:init_calltype_imports/2 157 0.00 18 [ 0.11] compile:'-core/2-lc$^0/1-0-'/2 157 0.00 18 [ 0.11] v3_life:'-match/5-lc$^1/1-0-'/5 74 0.00 19 [ 0.26] lists:unzip/3 120 0.00 19 [ 0.16] beam_validator:heap_alloc/2 125 0.00 19 [ 0.15] erl_lint:'-compiler_options/1-lc$^0/1-0-'/1 157 0.00 19 [ 0.12] erl_expand_records:guard_tests1/2 68 0.00 19 [ 0.28] beam_except:dig_out_block_fc/1 68 0.00 19 [ 0.28] erl_internal:'-predefined_functions/1-lc$^0/1-0-'/1 157 0.00 20 [ 0.13] v3_codegen:put_stack/2 119 0.00 20 [ 0.17] v3_kernel:rewrite_bool/4 37 0.00 20 [ 0.54] v3_kernel:extract_vars/1 37 0.00 20 [ 0.54] erl_lint:clauses/2 132 0.00 20 [ 0.15] erl_lint:pattern_bin/5 131 0.00 20 [ 0.15] erl_lint:'-vtnew/2-fun-0-'/3 85 0.00 20 [ 0.24] sofs:restrict/5 130 0.00 20 [ 0.15] sofs:diff_restrict_n/6 134 0.00 20 [ 0.15] cerl:let_vars/1 88 0.00 20 [ 0.23] compile:select_passes/2 80 0.00 20 [ 0.25] beam_clean:find_all_used/3 169 0.00 21 [ 0.12] beam_bs:function/2 168 0.00 21 [ 0.13] v3_codegen:free_dead/1 68 0.00 21 [ 0.31] v3_kernel:'-uexpr/3-anonymous-12-'/2 85 0.00 21 [ 0.25] beam_block:'-init_yreg/2-anonymous-0-'/2 85 0.00 21 [ 0.25] erl_lint:function_state/2 133 0.00 21 [ 0.16] erl_lint:function/5 132 0.00 21 [ 0.16] sys_core_dsetel:'-visit/2-anonymous-8-'/2 91 0.00 21 [ 0.23] cerl:update_c_let/4 88 0.00 21 [ 0.24] cerl:let_body/1 88 0.00 21 [ 0.24] beam_clean:bs_fix/2 169 0.00 22 [ 0.13] v3_kernel:forest_pre_seq/2 37 0.00 22 [ 0.59] v3_kernel:extract_all_vars/3 74 0.00 22 [ 0.30] erl_lint:'-check_deprecated/2-lc$^0/1-0-'/3 157 0.00 22 [ 0.14] compile:fold_comp/4 38 0.00 22 [ 0.58] erl_internal:type_test/2 68 0.00 23 [ 0.34] v3_core:force_booleans/4 68 0.00 23 [ 0.34] sys_core_fold:make_var_name/0 55 0.00 23 [ 0.42] v3_codegen:select_bin_end/5 131 0.00 23 [ 0.18] v3_codegen:build_call/3 68 0.00 23 [ 0.34] v3_codegen:need_stack_frame/1 69 0.00 23 [ 0.33] v3_codegen:'-load_vars/2-anonymous-0-'/2 85 0.00 23 [ 0.27] beam_bsm:btb_index_find_start_match/1 168 0.00 23 [ 0.14] erl_lint:format_function/5 171 0.00 23 [ 0.13] lists:keymerge3_2/10 184 0.00 24 [ 0.13] erl_lint:expr_bin/4 153 0.00 24 [ 0.16] cerl:make_list/1 68 0.00 24 [ 0.35] v3_life:'-expr/3-lc$^0/1-9-'/1 102 0.00 25 [ 0.25] eval_bits:match_bits_1/6 112 0.00 25 [ 0.22] eval_bits:get_integer/4 56 0.00 25 [ 0.45] beam_bsm:btb_index_1/2 169 0.00 25 [ 0.15] lists:rmerge3_21_3/6 158 0.00 26 [ 0.16] v3_kernel:'-group_bin_seg/2-anonymous-0-'/2 117 0.00 26 [ 0.22] v3_kernel:'-extract_all_vars/3-lc$^0/1-0-'/2 74 0.00 26 [ 0.35] beam_validator:index_bs_start_match/2 169 0.00 26 [ 0.15] erl_expand_records:record_wildcard_init/1 102 0.00 26 [ 0.25] v3_core:cfun/3 151 0.00 27 [ 0.18] sys_core_fold:returns_integer/2 102 0.00 27 [ 0.26] sets:maybe_expand/1 185 0.00 27 [ 0.15] lists:rkeymerge3_1/10 190 0.00 27 [ 0.14] erl_lint:vtold/2 102 0.00 27 [ 0.26] compile:'-internal_comp/5-anonymous-1-'/3 31 0.00 27 [ 0.87] beam_dead:function/2 168 0.00 27 [ 0.16] erlang:put/2 92 0.00 27 [ 0.29] lists:keysplit_2/8 218 0.00 28 [ 0.13] v3_kernel:make_forest_1/4 74 0.00 28 [ 0.38] v3_kernel:extract_var_list/1 74 0.00 28 [ 0.38] v3_kernel:'-select_bin_con_2/1-anonymous-0-'/2 117 0.00 28 [ 0.24] sofs:restrict/4 169 0.00 28 [ 0.17] v3_core:'-module/2-lc$^1/1-1-'/1 132 0.00 29 [ 0.22] sys_core_fold:opt_bool_case_in_let_1/5 210 0.00 29 [ 0.14] sets:'-from_list/1-fun-0-'/2 131 0.00 29 [ 0.22] lists:keymerge3_1/10 195 0.00 29 [ 0.15] v3_codegen:guard_cg/5 74 0.00 29 [ 0.39] beam_block:count_ones/2 137 0.00 29 [ 0.21] erl_lint:form/2 156 0.00 29 [ 0.19] erl_expand_records:'-compiler_options/1-lc$^0/1-0-'/1 157 0.00 29 [ 0.18] sys_core_dsetel:visit_module_1/3 135 0.00 29 [ 0.21] cerl:binary_segments/1 131 0.00 29 [ 0.22] compile:'-select_passes/2-anonymous-2-'/3 23 0.00 29 [ 1.26] v3_kernel:pattern_bin/4 131 0.00 30 [ 0.23] beam_block:init_yreg/2 138 0.00 30 [ 0.22] v3_core:form/3 159 0.00 31 [ 0.19] v3_life:'-guard_clause/5-lc$^0/1-0-'/3 116 0.00 31 [ 0.27] sys_core_fold:opt_bool_case_in_let/2 210 0.00 31 [ 0.15] v3_codegen:free_dead/4 136 0.00 31 [ 0.23] dict:maybe_expand_segs/1 101 0.00 31 [ 0.31] beam_asm:assemble_1/4 169 0.00 31 [ 0.18] erl_lint:'-local_functions/1-lc$^0/1-0-'/1 157 0.00 31 [ 0.20] erl_lint:'-export/3-fun-0-'/3 129 0.00 31 [ 0.24] cerl:update_c_binary/2 131 0.00 31 [ 0.24] v3_core:pat_bin/2 131 0.00 32 [ 0.24] v3_life:'-expr/3-lc$^0/1-10-'/1 136 0.00 32 [ 0.24] beam_jump:extract_seq/2 138 0.00 32 [ 0.23] v3_codegen:set_cg/6 144 0.00 32 [ 0.22] beam_validator:validate_0/3 169 0.00 32 [ 0.19] beam_validator:heap_alloc_1/2 125 0.00 32 [ 0.26] erl_expand_records:pattern_bin/2 131 0.00 32 [ 0.24] erl_expand_records:'-init_calltype/1-lc$^0/1-0-'/1 157 0.00 32 [ 0.20] v3_life:functions/2 169 0.00 33 [ 0.20] sys_core_fold:make_vars/3 120 0.00 33 [ 0.28] v3_core:gexpr/3 68 0.00 34 [ 0.50] v3_core:constant_bin_1/1 153 0.00 34 [ 0.22] v3_core:bin_expand_strings/1 131 0.00 34 [ 0.26] v3_core:upat_bin/3 131 0.00 34 [ 0.26] v3_life:'-protected/3-lc$^0/1-0-'/3 116 0.00 34 [ 0.29] lists:rkeymerge3_2/10 260 0.00 34 [ 0.13] v3_codegen:function/3 168 0.00 34 [ 0.20] v3_kernel:translate_match_fail/4 71 0.00 34 [ 0.48] beam_dict:export/4 131 0.00 34 [ 0.26] erl_lint:eval_file_attr/2 157 0.00 34 [ 0.22] erl_lint:define_function/4 132 0.00 34 [ 0.26] sets:rehash/4 153 0.00 35 [ 0.23] v3_codegen:save_carefully/3 248 0.00 35 [ 0.14] v3_kernel:function/2 134 0.00 35 [ 0.26] erl_lint:'-forms/2-fun-0-'/2 156 0.00 35 [ 0.22] cerl:c_let/3 130 0.00 35 [ 0.27] beam_clean:'-module/2-lc$^0/1-0-'/1 169 0.00 36 [ 0.21] beam_bs:bsm_subst_labels_1/4 286 0.00 36 [ 0.13] v3_codegen:extend_stack/4 107 0.00 36 [ 0.34] beam_z:'-module/2-lc$^0/1-0-'/1 169 0.00 36 [ 0.21] cerl:fun_vars/1 151 0.00 36 [ 0.24] cerl:fun_body/1 151 0.00 36 [ 0.24] beam_clean:remove_unused/3 169 0.00 37 [ 0.22] sys_core_fold:'-body/3-lc$^0/1-0-'/3 133 0.00 37 [ 0.28] beam_flatten:'-module/2-lc$^0/1-0-'/1 169 0.00 37 [ 0.22] v3_codegen:cg_basic_block/7 107 0.00 37 [ 0.35] v3_codegen:x0_vars/4 107 0.00 37 [ 0.35] v3_kernel:'-module/2-anonymous-0-'/1 131 0.00 37 [ 0.28] beam_receive:'-module/2-lc$^0/1-0-'/1 169 0.00 37 [ 0.22] beam_validator:validate_2/5 168 0.00 37 [ 0.22] erl_lint:function_check_max_args/3 132 0.00 37 [ 0.28] cerl:update_c_fun/3 151 0.00 37 [ 0.25] cerl:alias_var/1 159 0.00 37 [ 0.23] cerl:alias_pat/1 159 0.00 37 [ 0.23] v3_core:expr_bin/3 153 0.00 38 [ 0.25] beam_flatten:block/1 168 0.00 38 [ 0.23] beam_flatten:norm_allocate/2 160 0.00 38 [ 0.24] v3_codegen:max_reg/1 123 0.00 38 [ 0.31] v3_kernel:'-module/2-anonymous-1-'/2 134 0.00 38 [ 0.28] beam_reorder:'-module/2-lc$^0/1-0-'/1 169 0.00 38 [ 0.22] erl_expand_records:expr_bin/2 153 0.00 38 [ 0.25] sofs:to_external/1 172 0.00 38 [ 0.22] beam_trim:'-module/2-lc$^0/1-0-'/1 169 0.00 38 [ 0.22] erlang:min/2 128 0.00 38 [ 0.30] beam_clean:'-rootset/3-lc$^0/1-0-'/1 169 0.00 39 [ 0.23] v3_core:new_vars/3 134 0.00 39 [ 0.29] sys_core_fold:'-module/2-lc$^0/1-0-'/1 135 0.00 39 [ 0.29] beam_peep:'-module/2-lc$^0/1-0-'/1 169 0.00 39 [ 0.23] v3_codegen:reserve_x0/2 141 0.00 39 [ 0.28] beam_bsm:btb_index_2/4 168 0.00 39 [ 0.23] beam_bsm:'-module/2-lc$^0/1-0-'/2 169 0.00 39 [ 0.23] erl_lint:set_form_file/2 156 0.00 39 [ 0.25] erl_lint:check_get_stacktrace/5 171 0.00 39 [ 0.23] beam_split:'-module/2-lc$^0/1-0-'/1 169 0.00 39 [ 0.23] beam_except:function/1 168 0.00 39 [ 0.23] beam_except:dig_out_fc/3 170 0.00 39 [ 0.23] beam_except:'-module/2-lc$^0/1-0-'/1 169 0.00 39 [ 0.23] beam_clean:bs_clean_saves/1 168 0.00 40 [ 0.24] v3_life:vdb_store_new/3 171 0.00 40 [ 0.23] beam_record:'-module/2-lc$^0/1-0-'/1 169 0.00 40 [ 0.24] beam_bs:'-module/2-anonymous-0-'/2 168 0.00 40 [ 0.24] v3_kernel:gexpr_test/2 74 0.00 40 [ 0.54] beam_validator:validate_3/7 168 0.00 40 [ 0.24] beam_validator:verify_local_call/3 257 0.00 40 [ 0.16] cerl_trees:mapfold/3 134 0.00 40 [ 0.30] sofs:rel2family/1 169 0.00 40 [ 0.24] gb_sets:balance/2 279 0.00 40 [ 0.14] beam_a:'-module/2-lc$^0/1-0-'/1 169 0.00 40 [ 0.24] sys_core_dsetel:'-visit/2-anonymous-7-'/2 180 0.00 40 [ 0.22] erl_parse:not_string/4 385 0.00 40 [ 0.10] beam_clean:make_save_point_dict/2 168 0.00 41 [ 0.24] beam_clean:'-module/2-anonymous-1-'/2 168 0.00 41 [ 0.24] v3_core:constant_bin/1 153 0.00 41 [ 0.27] beam_record:function/1 168 0.00 41 [ 0.24] lists:umergel/3 246 0.00 41 [ 0.17] beam_jump:find_fixpoint/2 276 0.00 41 [ 0.15] beam_validator:'-validate_3/7-lc$^0/1-0-'/2 168 0.00 41 [ 0.24] erl_lint:is_latin1_name/1 172 0.00 41 [ 0.24] erl_lint:check_qlc_hrl/5 171 0.00 41 [ 0.24] erl_lint:is_format_function/2 171 0.00 41 [ 0.24] erl_lint:'-vtold/2-fun-0-'/3 170 0.00 41 [ 0.24] sofs:relation_to_family/1 169 0.00 41 [ 0.24] sofs:rel/3 172 0.00 41 [ 0.24] beam_split:split_blocks/1 168 0.00 41 [ 0.24] beam_clean:bs_function/1 168 0.00 42 [ 0.25] beam_jump:'-module/2-lc$^0/1-0-'/1 169 0.00 42 [ 0.25] sofs:relation/2 171 0.00 42 [ 0.25] erl_anno:is_filename/1 385 0.00 42 [ 0.11] v3_core:'-module/2-anonymous-2-'/3 159 0.00 43 [ 0.27] beam_bs:bsm_opt/2 168 0.00 43 [ 0.26] beam_utils:empty_label_index/0 168 0.00 43 [ 0.26] beam_peep:function/1 168 0.00 43 [ 0.26] v3_codegen:fetch_stack/3 238 0.00 43 [ 0.18] beam_bsm:function/2 168 0.00 43 [ 0.26] beam_asm:'-flatten_exports/1-anonymous-0-'/1 168 0.00 43 [ 0.26] beam_type:'-module/2-lc$^0/1-0-'/1 169 0.00 43 [ 0.25] erl_lint:check_module_name/3 172 0.00 43 [ 0.25] erl_expand_records:'-make_list/2-fun-0-'/3 385 0.00 43 [ 0.11] beam_jump:function/1 168 0.00 44 [ 0.26] beam_flatten:function/1 168 0.00 44 [ 0.26] beam_z:function/1 168 0.00 44 [ 0.26] beam_validator:prune_x_regs/2 154 0.00 44 [ 0.29] gb_trees:keys/1 168 0.00 44 [ 0.26] beam_dead:'-module/2-anonymous-0-'/2 168 0.00 44 [ 0.26] beam_jump:share/1 168 0.00 45 [ 0.27] v3_kernel:'-uexpr/3-anonymous-23-'/2 178 0.00 45 [ 0.25] beam_receive:function/1 168 0.00 45 [ 0.27] beam_validator:index_bs_start_match_1/3 168 0.00 45 [ 0.27] beam_validator:init_state/1 168 0.00 45 [ 0.27] beam_block:opt_alloc/4 176 0.00 45 [ 0.26] erl_expand_records:forms/2 157 0.00 45 [ 0.29] sofs:diff_restrict_n/5 276 0.00 45 [ 0.16] beam_trim:function/1 168 0.00 45 [ 0.27] erl_parse:abstract_list/4 385 0.00 45 [ 0.12] v3_core:'-uexpr/3-anonymous-0-'/2 188 0.00 46 [ 0.24] diameter_exprecs:'info-X'/2 385 0.00 46 [ 0.12] v3_codegen:'-functions/2-anonymous-0-'/3 168 0.00 46 [ 0.27] v3_kernel:'-select_assert_match_possible/3-anonymous-0-'/2 168 0.00 46 [ 0.27] beam_validator:validate_1/5 168 0.00 46 [ 0.27] beam_block:function/1 168 0.00 46 [ 0.27] beam_block:'-module/2-lc$^0/1-0-'/1 169 0.00 46 [ 0.27] erl_lint:check_remote_function/5 171 0.00 46 [ 0.27] v3_core:ufun_clauses/3 151 0.00 47 [ 0.31] lists:rumergel/3 318 0.00 47 [ 0.15] diameter_exprecs:'set-X'/2 385 0.00 47 [ 0.12] diameter_exprecs:'get-X'/2 385 0.00 47 [ 0.12] beam_a:function/1 168 0.00 47 [ 0.28] lists:seq_loop/3 307 0.00 48 [ 0.16] beam_validator:validate_fun_info_branches/3 336 0.00 48 [ 0.14] beam_type:function/1 168 0.00 48 [ 0.29] beam_type:'-simplify_select_val_int/2-lc$^0/1-0-'/1 273 0.00 48 [ 0.18] gb_sets:to_list/1 174 0.00 48 [ 0.28] core_lib:is_var_used/2 210 0.00 48 [ 0.23] v3_core:cbody/2 134 0.00 49 [ 0.37] beam_reorder:function/1 168 0.00 49 [ 0.29] beam_validator:return_type/2 171 0.00 49 [ 0.29] erl_lint:'-expr/3-fun-2-'/4 385 0.00 49 [ 0.13] erl_lint:'-record_def/4-lc$^0/1-0-'/1 412 0.00 50 [ 0.12] erl_lint:'-expr/3-fun-4-'/4 385 0.00 50 [ 0.13] beam_dead:shortcut_label/2 198 0.00 50 [ 0.25] beam_except:function_1/1 168 0.00 50 [ 0.30] v3_core:body/4 134 0.00 51 [ 0.38] cerl:values_es/1 199 0.00 51 [ 0.26] v3_core:new_vars/2 151 0.00 52 [ 0.34] sets:update_bucket/3 185 0.00 52 [ 0.28] v3_codegen:cg_fun/7 168 0.00 52 [ 0.31] v3_codegen:'-x0_vars/4-lc$^0/1-0-'/3 289 0.00 52 [ 0.18] cerl:ann_make_list/3 170 0.00 52 [ 0.31] sys_core_bsm:function/3 135 0.00 53 [ 0.39] v3_kernel:ensure_return_vars/2 178 0.00 53 [ 0.30] orddict:is_key/2 340 0.00 53 [ 0.16] erl_expand_records:get_record_field/5 385 0.00 53 [ 0.14] v3_core:function/4 134 0.00 54 [ 0.40] eval_bits:expr_grp/3 209 0.00 54 [ 0.26] v3_codegen:cg_reg_args/2 187 0.00 54 [ 0.29] v3_kernel:c_apply/5 263 0.00 54 [ 0.21] erl_lint:'-expr/3-fun-5-'/5 385 0.00 54 [ 0.14] erl_lint:'-check_option_functions/4-lc$^0/1-0-'/2 471 0.00 54 [ 0.11] erl_expand_records:strict_get_record_field/5 385 0.00 54 [ 0.14] sys_core_fold:update_types_from_expr/3 210 0.00 55 [ 0.26] sys_core_fold:'-sub_add_scope/2-anonymous-0-'/2 213 0.00 55 [ 0.26] lists:seq/2 185 0.00 55 [ 0.30] cerl:apply_args/1 246 0.00 55 [ 0.22] sys_core_fold:'-expr/3-lc$^0/1-0-'/3 200 0.00 56 [ 0.28] cerl:let_arg/1 226 0.00 56 [ 0.25] cerl:apply_op/1 246 0.00 56 [ 0.23] erl_eval:new_bindings/0 209 0.00 57 [ 0.27] sys_core_fold:delay_build_1/2 385 0.00 57 [ 0.15] beam_block:opt_move_rev/3 470 0.00 57 [ 0.12] erl_lint:update_fields/5 385 0.00 57 [ 0.15] otp_internal:obsolete/3 239 0.00 58 [ 0.24] otp_internal:obsolete_1/3 239 0.00 58 [ 0.24] sys_core_fold:delay_build_expr/2 385 0.00 58 [ 0.15] lists:merge3_12_3/6 394 0.00 58 [ 0.15] v3_codegen:'-max_reg/1-anonymous-0-'/2 252 0.00 58 [ 0.23] v3_codegen:'-save_carefully/4-lc$^1/1-1-'/1 248 0.00 58 [ 0.23] beam_validator:verify_live/2 223 0.00 58 [ 0.26] erl_expand_records:'-pattern_bin/2-fun-0-'/2 524 0.00 58 [ 0.11] sys_core_fold:function_1/1 134 0.00 59 [ 0.44] sys_core_fold:opt_not_in_let_1/3 196 0.00 59 [ 0.30] beam_validator:kill_heap_allocation/1 293 0.00 59 [ 0.20] beam_type:live_regs_1/2 315 0.00 59 [ 0.19] sys_core_fold:delay_build_expr_1/2 385 0.00 60 [ 0.16] erl_expand_records:'-record_setel/4-fun-2-'/2 383 0.00 60 [ 0.16] cerl:update_c_apply/3 246 0.00 60 [ 0.24] v3_life:function/1 168 0.00 61 [ 0.36] sofs:is_types/2 513 0.00 61 [ 0.12] erlang:atom_to_binary/2 320 0.00 61 [ 0.19] sys_core_fold:extract_type/2 210 0.00 62 [ 0.30] erl_lint:call_function/4 212 0.00 62 [ 0.29] gb_sets:add_element/2 261 0.00 62 [ 0.24] beam_clean:add_to_work_list/2 274 0.00 63 [ 0.23] sys_core_fold:find_fixpoint/3 251 0.00 63 [ 0.25] v3_codegen:'-cg_fun/7-anonymous-0-'/2 239 0.00 65 [ 0.27] dict:put_bucket_s/3 202 0.00 65 [ 0.32] erl_eval:ret_expr/2 636 0.00 66 [ 0.10] sys_core_fold:is_any_var_used/2 210 0.00 66 [ 0.31] beam_validator:init_regs/2 237 0.00 66 [ 0.28] gb_sets:to_list_1/1 279 0.00 66 [ 0.24] v3_life:'-expr/3-lc$^0/1-12-'/1 288 0.00 67 [ 0.23] lists:split_2_1/6 318 0.00 67 [ 0.21] beam_clean:function_replace/3 507 0.00 68 [ 0.13] erl_lint:deprecated_function/5 239 0.00 68 [ 0.28] erl_expand_records:'-expr_bin/2-fun-0-'/2 612 0.00 68 [ 0.11] beam_dict:'-atom_table/2-lc$^0/1-0-'/2 321 0.00 69 [ 0.21] lists:merge3_21_3/6 462 0.00 70 [ 0.15] v3_codegen:cg_basic_block/4 355 0.00 71 [ 0.20] beam_dict:'-literal_table/1-anonymous-1-'/3 329 0.00 71 [ 0.22] erl_lint:pattern_element_1/4 524 0.00 71 [ 0.14] erl_expand_records:pattern_element/2 524 0.00 71 [ 0.14] beam_clean:function_renumber/3 507 0.00 72 [ 0.14] v3_codegen:save_carefully/4 248 0.00 72 [ 0.29] v3_kernel:'-ubody/3-anonymous-0-'/2 314 0.00 72 [ 0.23] gb_sets:from_ordset/1 508 0.00 73 [ 0.14] lists:rumerge3_21_3/7 529 0.00 75 [ 0.14] diameter_exprecs:fname/2 323 0.00 75 [ 0.23] beam_bsm:drop_to_label/2 504 0.00 75 [ 0.15] erl_internal:bool_op/2 315 0.00 76 [ 0.24] diameter_exprecs:fname_prefix/1 337 0.00 77 [ 0.23] beam_validator:verify_live_1/2 587 0.00 77 [ 0.13] erl_expand_records:bin_element/2 612 0.00 77 [ 0.13] v3_codegen:make_reservation/2 282 0.00 78 [ 0.28] v3_codegen:'-x0_vars/4-lc$^0/1-1-'/3 635 0.00 78 [ 0.12] beam_validator:'-init_regs/2-lc$^0/1-0-'/2 307 0.00 78 [ 0.25] beam_dict:'-literal_table/1-lc$^1/1-0-'/1 330 0.00 78 [ 0.24] dict:fetch/2 336 0.00 79 [ 0.24] erl_lint:pattern_element/4 524 0.00 79 [ 0.15] beam_validator:validate_fun_info_branches_1/3 407 0.00 80 [ 0.20] sofs:rel/4 669 0.00 80 [ 0.12] erl_expand_records:'-field_names/1-fun-0-'/1 385 0.00 83 [ 0.22] beam_except:translate_exception/4 773 0.00 83 [ 0.11] erl_lint:is_autoimport_suppressed/2 314 0.00 84 [ 0.27] sofs:atoms_only/2 512 0.00 84 [ 0.16] core_lib:'-vu_expr/2-anonymous-4-'/2 389 0.00 84 [ 0.22] beam_validator:merge_types/2 280 0.00 85 [ 0.30] erl_lint:is_warn_enabled/2 305 0.00 85 [ 0.28] sys_core_fold:sub_set_name/3 495 0.00 86 [ 0.17] diameter_exprecs:'-#info-X/1/2-fun-0-'/2 385 0.00 86 [ 0.22] diameter_exprecs:'-#set-X/2/2-fun-0-'/2 385 0.00 86 [ 0.22] beam_asm:encode1/2 702 0.00 86 [ 0.12] erl_lint:bin_element/4 612 0.00 86 [ 0.14] diameter_exprecs:'-#get-X/2/2-fun-0-'/2 385 0.00 87 [ 0.23] v3_codegen:'-cg_basic_block/7-anonymous-0-'/4 355 0.00 87 [ 0.25] erl_lint:'-update_fields/5-fun-0-'/3 385 0.00 91 [ 0.24] erl_expand_records:is_simple_val/1 385 0.00 91 [ 0.24] beam_validator:tail_call/3 639 0.00 92 [ 0.14] erl_lint:'-normalise_fields/1-fun-0-'/1 394 0.00 92 [ 0.23] lists:keymember/3 596 0.00 92 [ 0.15] v3_core:new_vars_1/4 661 0.00 93 [ 0.14] lists:rmerge3_12_3/6 677 0.00 93 [ 0.14] erl_lint:check_fields/6 487 0.00 93 [ 0.19] diameter_exprecs:'-fields/2-fun-0-'/1 385 0.00 94 [ 0.24] erl_expand_records:'-normalise_fields/1-fun-0-'/1 394 0.00 94 [ 0.24] erl_anno:set_file/2 385 0.00 94 [ 0.24] erl_internal:comp_op/2 315 0.00 96 [ 0.30] beam_validator:assert_type/2 553 0.00 96 [ 0.17] maps:to_list/1 532 0.00 96 [ 0.18] v3_core:'-cexpr/3-anonymous-1-'/3 770 0.00 97 [ 0.13] v3_codegen:allocate_x0/3 389 0.00 97 [ 0.25] erl_lint:'-def_fields/3-fun-0-'/3 394 0.00 97 [ 0.25] sys_core_fold:opt_simple_let/3 725 0.00 99 [ 0.14] lists:dropwhile/2 672 0.00 99 [ 0.15] beam_jump:opt/2 168 0.00 99 [ 0.59] erl_lint:is_local_function/2 331 0.00 99 [ 0.30] sets:is_element/2 442 0.00 100 [ 0.23] v3_life:'-function/1-lc$^0/1-1-'/1 407 0.00 101 [ 0.25] erl_anno:set_generated/2 788 0.00 101 [ 0.13] beam_jump:insert_fc_labels/2 552 0.00 103 [ 0.19] erl_expand_records:is_in_guard/0 385 0.00 103 [ 0.27] erl_expand_records:'-record_setel/4-fun-0-'/4 383 0.00 103 [ 0.27] sys_core_fold:delay_build/2 385 0.00 105 [ 0.27] v3_life:'-function/1-lc$^0/1-0-'/1 407 0.00 106 [ 0.26] v3_codegen:'-cg_reg_args/2-lc$^0/1-0-'/2 510 0.00 106 [ 0.21] beam_validator:verify_y_init_1/1 846 0.00 106 [ 0.13] beam_validator:'-prune_x_regs/2-lc$^0/1-0-'/2 467 0.00 106 [ 0.23] v3_core:'-bin_expand_strings/1-anonymous-1-'/2 524 0.00 107 [ 0.20] sys_core_fold:opt_simple_let_2/7 725 0.00 107 [ 0.15] dict:store/3 518 0.00 107 [ 0.21] beam_except:translate_1/5 856 0.00 107 [ 0.13] erl_expand_records:record_update/5 385 0.00 108 [ 0.28] beam_bs:bsm_subst_label/3 444 0.00 109 [ 0.25] gb_sets:from_list/1 508 0.00 109 [ 0.21] v3_kernel:get_free/3 297 0.00 110 [ 0.37] beam_dict:literal/2 400 0.00 110 [ 0.28] erl_lint:record_field/4 770 0.00 110 [ 0.14] binary:encode_unsigned/1 702 0.00 110 [ 0.16] sys_core_fold:move_let_into_expr/3 728 0.00 111 [ 0.15] sys_core_fold:opt_simple_let_0/3 725 0.00 111 [ 0.15] beam_utils:is_killed_block/2 436 0.00 111 [ 0.25] erl_expand_records:record_setel/4 383 0.00 111 [ 0.29] erlang:iolist_size/1 703 0.00 111 [ 0.16] erl_lint:bif_clash_specifically_disabled/2 280 0.00 112 [ 0.40] erl_expand_records:record_exprs/4 770 0.00 112 [ 0.15] cerl:data_type/1 385 0.00 112 [ 0.29] sys_core_fold:opt_simple_let_1/4 725 0.00 113 [ 0.16] erl_expand_records:call_error/2 385 0.00 113 [ 0.29] cerl:bitstr_type/1 524 0.00 113 [ 0.22] v3_core:verify_suitable_fields/1 765 0.00 114 [ 0.15] v3_core:fold_match/2 385 0.00 114 [ 0.30] lists:usplit_2_1/6 641 0.00 114 [ 0.18] cerl:bitstr_size/1 524 0.00 114 [ 0.22] cerl:bitstr_unit/1 524 0.00 114 [ 0.22] eval_bits:expr_grp/4 877 0.00 115 [ 0.13] beam_jump:'-opt/2-anonymous-0-'/2 276 0.00 115 [ 0.42] erl_lint:'-pattern_bin/5-fun-0-'/4 524 0.00 117 [ 0.22] cerl:bitstr_flags/1 524 0.00 117 [ 0.22] erlang:'--'/2 172 0.00 117 [ 0.68] sys_core_fold:is_compiler_generated/1 990 0.00 118 [ 0.12] cerl:bitstr_val/1 524 0.00 118 [ 0.23] erl_lint:pattern_list/5 770 0.00 119 [ 0.15] sofs:is_type/1 514 0.00 119 [ 0.23] sys_core_bsm:bsm_an_1/2 859 0.00 120 [ 0.14] cerl_sets:from_list/1 949 0.00 122 [ 0.13] sys_core_fold:update_let_types_1/3 935 0.00 123 [ 0.13] lists:merge2_1/4 837 0.00 123 [ 0.15] lists:rmerge2_2/5 863 0.00 123 [ 0.14] v3_core:'-uexpr/3-anonymous-1-'/2 550 0.00 124 [ 0.23] sys_core_dsetel:'-visit/2-anonymous-1-'/2 550 0.00 124 [ 0.23] lists:duplicate/2 497 0.00 125 [ 0.25] cerl:update_c_bitstr/6 524 0.00 126 [ 0.24] v3_core:coerce_to_float/2 524 0.00 127 [ 0.24] v3_codegen:'-extend_stack/4-lc$^0/1-0-'/4 924 0.00 127 [ 0.14] erl_lint:pat_bit_size/4 524 0.00 127 [ 0.24] sys_core_fold:eval_setelement/4 766 0.00 129 [ 0.17] sys_core_fold:'-let_substs/3-anonymous-1-'/2 495 0.00 130 [ 0.26] beam_block:eliminate_use_of_from_reg/4 487 0.00 130 [ 0.27] v3_core:upat_element/4 524 0.00 131 [ 0.25] dict:'-store/3-fun-0-'/3 518 0.00 132 [ 0.25] v3_core:lit_list_vars/2 906 0.00 133 [ 0.15] beam_jump:remove_unused_labels/1 504 0.00 133 [ 0.26] erl_lint:is_pattern_expr/1 524 0.00 133 [ 0.25] sys_core_fold:bit_pat_warn_int/4 1048 0.00 134 [ 0.13] sys_core_fold:'-sub_subst_var/3-lc$^0/1-0-'/3 598 0.00 134 [ 0.22] v3_codegen:turn_yregs/2 531 0.00 134 [ 0.25] v3_kernel:pat_list_vars/1 894 0.00 134 [ 0.15] erl_lint:is_pattern_expr_1/1 524 0.00 134 [ 0.26] v3_core:pat_segment/2 524 0.00 135 [ 0.26] erl_lint:'-expr_bin/4-fun-0-'/4 612 0.00 135 [ 0.22] beam_validator:assert_type/3 553 0.00 136 [ 0.25] erl_lint:pat_bit_expr/4 524 0.00 136 [ 0.26] erl_anno:reset_simplify/1 1173 0.00 136 [ 0.12] erl_lint:imported/3 412 0.00 138 [ 0.33] v3_core:'-pat_bin/2-lc$^0/1-0-'/2 655 0.00 139 [ 0.21] erl_anno:simplify/1 1173 0.00 139 [ 0.12] sys_core_fold:kill_types2/2 529 0.00 140 [ 0.26] v3_kernel:select_bin_int_1/4 407 0.00 140 [ 0.34] sys_core_dsetel:bind_vars/3 549 0.00 141 [ 0.26] lists:rmergel/2 934 0.00 143 [ 0.15] beam_validator:'-index_bs_start_match/2-anonymous-0-'/2 672 0.00 143 [ 0.21] erl_anno:set_anno/3 1173 0.00 143 [ 0.12] erl_lint:has_wildcard_field/1 770 0.00 144 [ 0.19] erl_lint:'-expr/3-fun-6-'/3 612 0.00 144 [ 0.24] lists:merge2_2/5 935 0.00 145 [ 0.16] beam_jump:insert_labels/4 1191 0.00 145 [ 0.12] erl_lint:bit_size/4 612 0.00 145 [ 0.24] erl_eval:line/1 636 0.00 146 [ 0.23] beam_dict:import/4 535 0.00 146 [ 0.27] sys_core_fold:'-expr/3-lc$^0/1-3-'/2 626 0.00 148 [ 0.24] beam_utils:live_opt/1 504 0.00 148 [ 0.29] beam_validator:all_ms_in_x_regs/2 863 0.00 148 [ 0.17] sys_core_fold:copy_type/3 495 0.00 149 [ 0.30] sys_core_fold:bin_pattern/2 1048 0.00 150 [ 0.14] lists:merge3_2/6 870 0.00 150 [ 0.17] erl_parse:map_anno/2 1155 0.00 150 [ 0.13] sys_core_fold:sub_subst_var/3 495 0.00 152 [ 0.31] erl_eval:partial_eval/1 636 0.00 153 [ 0.24] gb_sets:balance_list/2 787 0.00 153 [ 0.19] erl_anno:set/3 1173 0.00 154 [ 0.13] v3_core:bin_element/1 612 0.00 155 [ 0.25] v3_kernel:'-select_bin_con_1/1-anonymous-0-'/1 655 0.00 157 [ 0.24] v3_core:upat_bin/4 655 0.00 158 [ 0.24] eval_bits:eval_exp_field1/6 668 0.00 158 [ 0.24] erl_internal:bif/2 497 0.00 159 [ 0.32] sys_core_fold:fold_call_2/5 945 0.00 159 [ 0.17] v3_codegen:match_cg/6 938 0.00 159 [ 0.17] v3_codegen:'-top_level_block/4-anonymous-0-'/3 600 0.00 159 [ 0.27] erl_eval:ev_expr/1 636 0.00 160 [ 0.25] v3_kernel:'-uexpr/3-anonymous-11-'/2 669 0.00 160 [ 0.24] beam_asm:to_bytes/1 702 0.00 162 [ 0.23] v3_kernel:pattern_bin_1/4 655 0.00 165 [ 0.25] v3_codegen:turn_yreg/2 690 0.00 167 [ 0.24] lists:merge3_1/6 924 0.00 168 [ 0.18] erl_expand_records:mark_record/2 489 0.00 168 [ 0.34] beam_validator:labels_1/2 843 0.00 172 [ 0.20] v3_core:'-expr_bin/3-lc$^0/1-0-'/1 765 0.00 174 [ 0.23] sys_core_fold:fold_non_lit_args/5 945 0.00 174 [ 0.18] lists:mergel/2 1262 0.00 174 [ 0.14] eval_bits:eval_exp_field/6 668 0.00 174 [ 0.26] erl_parse:abstract/3 787 0.00 174 [ 0.22] lists:flatmap/2 732 0.00 175 [ 0.24] core_lib:vu_expr/2 956 0.00 177 [ 0.19] beam_validator:deallocate/1 673 0.00 178 [ 0.26] erl_lint:warn_invalid_record/3 770 0.00 178 [ 0.23] erl_expand_records:record_exprs/2 385 0.00 178 [ 0.46] maps:get/2 1291 0.00 178 [ 0.14] beam_bs:bsm_reroute/4 1362 0.00 179 [ 0.13] v3_codegen:finish_select_binary/1 775 0.00 179 [ 0.23] dict:fetch_val/2 1124 0.00 179 [ 0.16] beam_validator:verify_no_ct/1 673 0.00 179 [ 0.27] sys_core_fold:update_let_types/3 725 0.00 181 [ 0.25] beam_utils:is_killed/3 773 0.00 181 [ 0.23] erl_lint:vtmerge/1 612 0.00 181 [ 0.30] v3_core:'-new_in_all/1-anonymous-0-'/2 770 0.00 182 [ 0.24] erl_lint:is_valid_record/1 770 0.00 185 [ 0.24] maps:size/1 391 0.00 187 [ 0.48] beam_utils:is_killed_at/3 1176 0.00 188 [ 0.16] beam_record:is_killed/4 772 0.00 189 [ 0.24] beam_validator:verify_call_args/3 724 0.00 191 [ 0.26] v3_codegen:local_func_label/2 448 0.00 193 [ 0.43] sys_core_fold:simplify_let/2 728 0.00 194 [ 0.27] beam_block:is_killed_or_used/2 801 0.00 194 [ 0.24] erl_expand_records:new_var/2 772 0.00 194 [ 0.25] v3_core:'-uexpr/3-anonymous-6-'/3 770 0.00 196 [ 0.25] beam_validator:verify_y_init/1 727 0.00 196 [ 0.27] beam_utils:index_labels/1 840 0.00 197 [ 0.23] dict:rehash/4 848 0.00 199 [ 0.23] sys_core_fold:opt_not_in_let_0/3 667 0.00 200 [ 0.30] erl_expand_records:no_compiler_warning/1 770 0.00 200 [ 0.26] lists:usplit_1_1/6 1023 0.00 201 [ 0.20] eval_bits:make_bit_type/3 724 0.00 201 [ 0.28] cerl:case_arg/1 859 0.00 201 [ 0.23] erl_expand_records:index_expr/4 768 0.00 202 [ 0.26] sys_core_fold:opt_case_in_let/1 728 0.00 204 [ 0.28] v3_core:'-uexpr/3-anonymous-4-'/2 924 0.00 205 [ 0.22] sys_core_fold:opt_not_in_let/1 725 0.00 205 [ 0.28] lists:umerge3_2/7 1314 0.00 206 [ 0.16] sys_core_fold:let_substs/3 728 0.00 208 [ 0.29] erl_expand_records:new_var_name/1 772 0.00 208 [ 0.27] erlang:make_fun/3 962 0.00 208 [ 0.22] sys_core_fold:let_substs_1/3 728 0.00 210 [ 0.29] sys_core_fold:case_opt_arg_1/3 1705 0.00 211 [ 0.12] cerl:update_c_case/3 859 0.00 211 [ 0.25] lists:umerge3_1/7 1183 0.01 216 [ 0.18] beam_except:dig_out/2 856 0.01 218 [ 0.25] v3_core:uclauses/3 773 0.01 219 [ 0.28] sys_core_fold:add_warning/2 853 0.01 220 [ 0.26] erl_lint:record_expr/4 770 0.01 220 [ 0.29] sys_core_fold:should_suppress_warning/1 853 0.01 222 [ 0.26] sys_core_fold:'-let_substs/3-lc$^0/1-0-'/1 941 0.01 223 [ 0.24] sys_core_fold:'-warn_no_clause_match/2-anonymous-1-'/1 990 0.01 225 [ 0.23] ordsets:del_element/2 892 0.01 225 [ 0.25] v3_life:'-expr/3-lc$^0/1-8-'/1 938 0.01 226 [ 0.24] sys_core_fold:matches_data/2 728 0.01 228 [ 0.31] beam_validator:verify_call_args_1/2 1746 0.01 229 [ 0.13] lists:last/2 1769 0.01 231 [ 0.13] erl_lint:expr_var/4 1858 0.01 231 [ 0.12] beam_validator:merge_y_regs_1/3 2020 0.01 232 [ 0.11] v3_kernel:handle_reuse_annos/2 876 0.01 233 [ 0.27] erl_expand_records:'-record_setel/4-lc$^1/1-0-'/1 766 0.01 233 [ 0.30] sys_core_fold:sub_add_scope/2 728 0.01 235 [ 0.32] lists:rmerge3_1/6 1174 0.01 236 [ 0.20] beam_utils:check_liveness_block_1/6 1971 0.01 237 [ 0.12] erl_lint:pat_var/5 1823 0.01 237 [ 0.13] v3_core:new_in_all/1 773 0.01 239 [ 0.31] lists:umerge2_1/5 1700 0.01 239 [ 0.14] v3_core:cclauses/3 924 0.01 242 [ 0.26] dict:fold/3 1930 0.01 242 [ 0.13] erl_lint:elemtype_check/4 1136 0.01 242 [ 0.21] sys_core_fold:'-pattern/3-anonymous-1-'/2 1048 0.01 246 [ 0.23] erl_lint:'-copy_expr/2-fun-0-'/2 1155 0.01 246 [ 0.21] beam_jump:maps_append_list/3 985 0.01 248 [ 0.25] erlang:md5/1 1 0.01 248 [ 248.00] v3_kernel:kmatch/4 859 0.01 250 [ 0.29] beam_dead:shortcut_specific_label/3 1840 0.01 252 [ 0.14] lists:rmerge3_2/6 1557 0.01 254 [ 0.16] v3_kernel:'-expand_pat_lit/2-lc$^0/1-0-'/2 1155 0.01 255 [ 0.22] v3_kernel:flatten_seq/1 859 0.01 257 [ 0.30] beam_dict:line/2 758 0.01 257 [ 0.34] v3_codegen:select_extract_tuple/6 846 0.01 258 [ 0.30] lists:rmerge2_1/4 1873 0.01 261 [ 0.14] eval_bits:eval_field/3 668 0.01 262 [ 0.39] v3_codegen:return_cg/5 1844 0.01 262 [ 0.14] beam_except:dig_out_block/1 788 0.01 262 [ 0.33] v3_kernel:is_in_guard/1 913 0.01 266 [ 0.29] beam_dead:combine_eqs/4 962 0.01 266 [ 0.28] lists:rumerge3_12_3/7 2027 0.01 268 [ 0.13] erl_lint:check_record/4 1206 0.01 268 [ 0.22] v3_kernel:force_variable/2 903 0.01 270 [ 0.30] sys_core_fold:signedness/1 1048 0.01 271 [ 0.26] v3_codegen:'-save_carefully/4-lc$^0/1-0-'/4 2018 0.01 271 [ 0.13] beam_utils:check_liveness_at/3 1182 0.01 272 [ 0.23] v3_kernel:match_pre/3 859 0.01 272 [ 0.32] lists:rumerge2_2/5 2033 0.01 273 [ 0.13] erl_lint:bit_type/4 1136 0.01 274 [ 0.24] erl_expand_records:'-pattern_fields/2-fun-0-'/3 1155 0.01 274 [ 0.24] erl_anno:default/2 1173 0.01 275 [ 0.23] v3_kernel:build_match/2 859 0.01 282 [ 0.33] sys_core_fold:'-var_list/2-anonymous-0-'/2 1067 0.01 283 [ 0.27] erl_expand_records:'-record_inits/2-fun-0-'/3 1155 0.01 284 [ 0.25] v3_core:novars/2 1155 0.01 285 [ 0.25] maps:from_list/1 1479 0.01 285 [ 0.19] v3_codegen:'-match_cg/5-anonymous-1-'/6 2140 0.01 287 [ 0.13] v3_kernel:match_vars/2 859 0.01 288 [ 0.34] erl_lint:bit_size_check/4 1136 0.01 288 [ 0.25] erl_lint:add_bit_size/5 1136 0.01 288 [ 0.25] v3_kernel:select_bin_con_2/1 2206 0.01 289 [ 0.13] erl_lint:copy_expr/2 1155 0.01 291 [ 0.25] erl_parse:'-map_anno/2-fun-0-'/3 1155 0.01 292 [ 0.25] beam_peep:is_test_redundant_1/3 2768 0.01 293 [ 0.11] v3_core:make_bit_type/3 1136 0.01 295 [ 0.26] beam_flatten:move_past_kill/3 1329 0.01 296 [ 0.22] gb_trees:balance/2 2225 0.01 296 [ 0.13] sys_core_fold:let_subst_list/3 1436 0.01 302 [ 0.21] sys_core_fold:var_list/2 1013 0.01 302 [ 0.30] io_lib:latin1_char_list/1 2698 0.01 302 [ 0.11] sys_core_fold:bin_pat_warn/1 1048 0.01 306 [ 0.29] beam_validator:validate_src/2 1153 0.01 306 [ 0.27] v3_core:force_novars/2 1155 0.01 308 [ 0.27] cerl:c_tuple/1 1158 0.01 308 [ 0.27] lists:usort/1 2390 0.01 309 [ 0.13] v3_codegen:load_vars/2 1023 0.01 310 [ 0.30] erl_lint:warn_unused_vars/3 2645 0.01 310 [ 0.12] beam_jump:drop_upto_label/1 1534 0.01 311 [ 0.20] v3_codegen:enter_cg/6 1610 0.01 311 [ 0.19] cerl:call_name/1 1398 0.01 311 [ 0.22] beam_validator:'-validate_src/2-anonymous-0-'/2 1344 0.01 312 [ 0.23] erl_lint:guard_tests/3 2628 0.01 312 [ 0.12] erl_bits:set_bit_1/2 2784 0.01 314 [ 0.11] sets:get_bucket_s/2 1919 0.01 315 [ 0.16] beam_validator:kill_state/1 2080 0.01 315 [ 0.15] erl_anno:is_settable/2 1173 0.01 316 [ 0.27] cerl:update_c_tuple_skel/2 1279 0.01 316 [ 0.25] cerl:call_args/1 1398 0.01 316 [ 0.23] erl_expand_records:strict_record_tests/1 2310 0.01 319 [ 0.14] cerl:call_module/1 1398 0.01 321 [ 0.23] lists:umerge3_12_3/6 2562 0.01 323 [ 0.13] beam_validator:merge_states_1/2 2020 0.01 323 [ 0.16] erl_lint:'-init_fields/3-lc$^0/1-0-'/3 1206 0.01 323 [ 0.27] v3_core:fail_clause/3 1158 0.01 324 [ 0.28] v3_core:'-constant_bin_1/1-anonymous-0-'/2 1224 0.01 324 [ 0.26] sys_core_fold:will_fail/1 1218 0.01 326 [ 0.27] v3_kernel:match_con_1/4 2105 0.01 327 [ 0.16] erl_expand_records:strict_record_updates/1 2310 0.01 329 [ 0.14] erl_lint:check_unused_vars/3 2611 0.01 330 [ 0.13] v3_kernel:select_bin_con_1/1 2105 0.01 335 [ 0.16] v3_kernel:'-handle_reuse_annos/2-lc$^0/1-0-'/2 1796 0.01 337 [ 0.19] erl_expand_records:record_fields/2 1291 0.01 337 [ 0.26] erl_lint:'-init_fields/6-fun-1-'/3 1155 0.01 341 [ 0.30] cerl:ann_c_cons/3 2543 0.01 342 [ 0.13] cerl:update_c_call/4 1398 0.01 342 [ 0.24] lists:foreach/2 2506 0.01 345 [ 0.14] dict:fold_dict/3 1930 0.01 349 [ 0.18] beam_type:merge_type_info/2 1582 0.01 351 [ 0.22] beam_dead:shortcut_bs_test_1/4 3060 0.01 354 [ 0.12] v3_kernel:match_con/4 2105 0.01 356 [ 0.17] beam_jump:collect_labels_1/3 1976 0.01 359 [ 0.18] erl_lint:used_record/2 1291 0.01 359 [ 0.28] lists:rumerge2_1/4 2847 0.01 361 [ 0.13] beam_utils:'-live_opt/1-anonymous-0-'/1 1512 0.01 364 [ 0.24] v3_codegen:match_fmf/4 2233 0.01 369 [ 0.17] erl_bifs:is_safe/3 1414 0.01 370 [ 0.26] beam_dict:fname/2 755 0.01 371 [ 0.49] ordsets:from_list/1 2210 0.01 373 [ 0.17] v3_kernel:select_bin_int/1 2105 0.01 374 [ 0.18] erl_lint:'-pattern_list/5-fun-0-'/5 1540 0.01 374 [ 0.24] v3_core:ufun_clause/3 2747 0.01 376 [ 0.14] erl_lint:'-check_fields/6-fun-0-'/6 1540 0.01 376 [ 0.24] erl_lint:vtnew/2 2696 0.01 379 [ 0.14] beam_dead:shortcut_select_list/4 2588 0.01 384 [ 0.15] v3_core:'-uclauses/3-anonymous-0-'/3 1543 0.01 385 [ 0.25] v3_core:uclause/3 2316 0.01 386 [ 0.17] sys_core_fold:call_1/5 2860 0.01 387 [ 0.14] dict:get_bucket_s/2 2149 0.01 387 [ 0.18] lists:last/1 1352 0.01 389 [ 0.29] beam_block:opt_tuple_element_1/4 1665 0.01 389 [ 0.23] cerl:data_arity/1 385 0.01 389 [ 1.01] v3_codegen:trap_bif/3 1397 0.01 394 [ 0.28] erl_lint:'-vtmerge/1-fun-0-'/2 1836 0.01 394 [ 0.21] lists:partition/4 2764 0.01 398 [ 0.14] sys_core_fold:fold_call/5 2860 0.01 404 [ 0.14] v3_kernel:is_remote_bif/3 1397 0.01 408 [ 0.29] v3_core:'-lit_list_vars/2-anonymous-0-'/2 1869 0.01 411 [ 0.22] erl_lint:check_field/7 1540 0.01 413 [ 0.27] beam_dead:shortcut_rel_op_fp/3 3432 0.01 419 [ 0.12] erl_internal:op_type/2 1187 0.01 422 [ 0.36] cerl:var_name/1 1705 0.01 423 [ 0.25] beam_record:is_tagged_tuple/4 789 0.01 424 [ 0.54] erl_lint:'-unused_vars/3-fun-0-'/2 1874 0.01 432 [ 0.23] erl_internal:guard_bif/2 1241 0.01 434 [ 0.35] v3_core:new_var/2 1636 0.01 436 [ 0.27] v3_codegen:move_unsaved/4 3556 0.01 436 [ 0.12] lists:droplast/1 1734 0.01 440 [ 0.25] v3_kernel:op_vars/1 1486 0.01 440 [ 0.30] sets:get_bucket/2 1901 0.01 441 [ 0.23] v3_life:call_op/1 1678 0.01 443 [ 0.26] sys_core_fold:move_case_into_arg/2 1766 0.01 443 [ 0.25] cerl:is_c_var/1 1844 0.01 446 [ 0.24] beam_dead:normalize_op_1/3 3569 0.01 448 [ 0.13] v3_kernel:'-ubody/3-anonymous-1-'/2 1878 0.01 451 [ 0.24] dict:find/2 1660 0.01 451 [ 0.27] v3_life:'-expr/3-lc$^0/1-3-'/1 1844 0.01 455 [ 0.25] sys_core_fold:get_line/1 1891 0.01 460 [ 0.24] beam_utils:check_liveness_block_2/4 1954 0.01 460 [ 0.24] lists:umerge3_21_3/6 3631 0.01 460 [ 0.13] beam_dead:will_succeed/2 1739 0.01 461 [ 0.27] v3_codegen:enter_line/3 1609 0.01 463 [ 0.29] sets:get_slot/2 1901 0.01 464 [ 0.24] v3_codegen:func_vars/1 1678 0.01 468 [ 0.28] lists:rumerge3_2/7 2857 0.01 470 [ 0.16] v3_codegen:select_cg/6 2140 0.01 471 [ 0.22] sys_core_fold:is_boolean_type/2 1874 0.01 477 [ 0.25] dict:get_bucket/2 2048 0.01 479 [ 0.23] sys_core_fold:case_expand_var/2 1705 0.01 482 [ 0.28] beam_validator:min/2 2020 0.01 482 [ 0.24] sys_core_fold:warn_no_clause_match/2 1766 0.01 486 [ 0.28] beam_type:tdb_kill_xregs/1 3424 0.01 486 [ 0.14] gb_sets:add/2 2174 0.01 488 [ 0.22] cerl:is_c_values/1 1831 0.01 488 [ 0.27] erl_bits:as_list/1 1860 0.01 490 [ 0.26] sys_core_fold:'-call_1/5-lc$^0/1-0-'/2 1958 0.01 492 [ 0.25] erl_bits:merge_bittype/2 2060 0.01 495 [ 0.24] sys_core_fold:fold_call_1/5 2857 0.01 496 [ 0.17] dict:mk_seg/1 1933 0.01 497 [ 0.26] sys_core_fold:get_type/2 1874 0.01 499 [ 0.27] erl_expand_records:find_field/2 2312 0.01 499 [ 0.22] erl_bits:check_unit/1 2272 0.01 508 [ 0.22] sys_core_fold:case_opt_arg/4 1844 0.01 513 [ 0.28] beam_validator:merge_y_regs/2 2020 0.01 515 [ 0.25] sys_core_fold:case_opt/3 1766 0.01 518 [ 0.29] gb_trees:to_list_1/1 2225 0.01 518 [ 0.23] v3_kernel:match_guard/3 4142 0.01 524 [ 0.13] v3_codegen:'-saves/3-lc$^0/1-0-'/3 4562 0.01 525 [ 0.12] sys_core_fold:opt_bool_case/2 1766 0.01 526 [ 0.30] v3_life:type/1 2140 0.01 528 [ 0.25] beam_validator:valfun_2/2 3927 0.01 529 [ 0.13] beam_type:tag_literal/1 2146 0.01 532 [ 0.25] beam_split:make_block/2 3875 0.01 532 [ 0.14] sys_core_dsetel:'-visit/2-anonymous-4-'/2 2362 0.01 534 [ 0.23] dict:new/0 1933 0.01 536 [ 0.28] erlang:tuple_to_list/1 3749 0.01 537 [ 0.14] v3_core:'-uexpr/3-anonymous-5-'/2 2362 0.01 538 [ 0.23] erl_bifs:is_exit_bif/3 3414 0.01 538 [ 0.16] sys_core_fold:call/4 2860 0.01 539 [ 0.19] beam_jump:initial_labels/2 2844 0.01 539 [ 0.19] sys_core_fold:eval_case/2 1766 0.01 540 [ 0.31] sys_core_fold:shadow_warning/2 2619 0.01 541 [ 0.21] sys_core_fold:is_bool_expr/2 1976 0.01 542 [ 0.27] lists:partition/2 2109 0.01 543 [ 0.26] beam_validator:valfun_3/2 3927 0.01 543 [ 0.14] v3_codegen:build_enter/3 1609 0.01 544 [ 0.34] beam_utils:check_liveness_block/3 1996 0.01 545 [ 0.27] v3_kernel:call_type/3 1398 0.01 549 [ 0.39] dict:fold_segs/4 3826 0.01 549 [ 0.14] beam_validator:set_type_reg/3 3543 0.01 553 [ 0.16] sys_core_fold:case_will_var_match/1 1844 0.01 555 [ 0.30] v3_core:annotate_cons/4 2271 0.01 559 [ 0.25] cerl_sets:new/0 2155 0.01 565 [ 0.26] v3_kernel:uexpr/3 2891 0.01 572 [ 0.20] v3_codegen:find_loc/3 3500 0.01 576 [ 0.16] v3_kernel:'-uexpr/3-anonymous-13-'/2 2464 0.01 580 [ 0.24] orddict:erase/2 3096 0.01 580 [ 0.19] beam_validator:'-valfun_4/2-anonymous-1-'/2 2588 0.01 586 [ 0.23] beam_dead:prune_redundant/2 2588 0.01 591 [ 0.23] lists:usplit_1/5 3479 0.01 592 [ 0.17] erlang:atom_to_list/1 886 0.01 595 [ 0.67] v3_kernel:partition_intersection/4 2140 0.01 599 [ 0.28] v3_kernel:'-match_con_1/4-anonymous-0-'/3 2140 0.01 600 [ 0.28] erl_parse:abstract/2 17 0.01 602 [ 35.41] v3_life:type_clause/5 2140 0.01 607 [ 0.28] v3_codegen:select_val_cg/6 1904 0.01 608 [ 0.32] erl_lint:expr_list/3 4097 0.01 608 [ 0.15] erl_lint:'-clauses/2-fun-0-'/2 2560 0.01 609 [ 0.24] v3_codegen:fetch_reg/2 3078 0.01 611 [ 0.20] beam_dead:shortcut_select_label/4 2453 0.01 611 [ 0.25] v3_kernel:select_bin_con/1 2105 0.01 622 [ 0.30] sys_core_fold:'-signedness/1-lc$^0/1-0-'/1 3144 0.01 626 [ 0.20] beam_peep:prune_redundant_values/2 2633 0.01 629 [ 0.24] erl_lint:head/3 2560 0.01 632 [ 0.25] v3_kernel:build_select/2 2105 0.01 634 [ 0.30] erl_lint:clause/2 2560 0.01 638 [ 0.25] erl_lint:guard/3 2594 0.01 638 [ 0.25] v3_kernel:atomic_list/3 1784 0.01 639 [ 0.36] beam_validator:branch_state/2 3952 0.01 640 [ 0.16] v3_kernel:match_value/5 2140 0.02 642 [ 0.30] beam_validator:get_move_term_type/2 2612 0.02 642 [ 0.25] beam_type:tdb_update/2 4792 0.02 647 [ 0.14] erl_lint:unused_vars/3 2645 0.02 650 [ 0.25] beam_utils:check_liveness/3 2812 0.02 653 [ 0.23] v3_core:'-ufun_clauses/3-anonymous-0-'/3 2596 0.02 656 [ 0.25] erl_bits:type_to_record/1 2784 0.02 659 [ 0.24] erlang:throw/1 2616 0.02 661 [ 0.25] erlang:list_to_binary/1 21 0.02 662 [ 31.52] dict:store_bkt_val/3 3022 0.02 666 [ 0.22] v3_codegen:block_cg/4 4224 0.02 667 [ 0.16] beam_asm:encode_list/3 5137 0.02 672 [ 0.13] beam_peep:is_test_redundant/3 2768 0.02 684 [ 0.25] beam_dead:useful_to_insert_label/1 2912 0.02 684 [ 0.23] beam_flatten:norm/1 2607 0.02 690 [ 0.26] sys_core_fold:'-function_1/1-anonymous-0-'/1 251 0.02 694 [ 2.76] sys_core_fold:'-warn_no_clause_match/2-anonymous-0-'/1 2927 0.02 696 [ 0.24] cerl_sets:'-from_list/1-lc$^0/1-0-'/1 2976 0.02 696 [ 0.23] erl_bits:check_size_unit/3 2996 0.02 697 [ 0.23] erl_bits:set_bit/1 2996 0.02 699 [ 0.23] v3_kernel:'-match_pre/3-anonymous-0-'/3 4145 0.02 701 [ 0.17] lists:usplit_2/5 5084 0.02 716 [ 0.14] beam_dead:shortcut_bs_test/3 3060 0.02 717 [ 0.23] v3_life:'-expr/3-lc$^0/1-11-'/1 2963 0.02 718 [ 0.24] gb_trees:keys/2 4330 0.02 720 [ 0.17] cerl:update_c_tuple/2 2979 0.02 724 [ 0.24] v3_life:'-expr/3-lc$^0/1-7-'/3 3487 0.02 729 [ 0.21] beam_validator:valfun_4/2 3927 0.02 734 [ 0.19] gb_sets:count/1 3125 0.02 735 [ 0.24] gb_sets:is_element/2 3542 0.02 743 [ 0.21] lists:umerge2_2/4 5786 0.02 744 [ 0.13] v3_codegen:top_level_block/4 2684 0.02 745 [ 0.28] v3_codegen:cg/5 4745 0.02 749 [ 0.16] sys_core_fold:useless_call/2 2860 0.02 751 [ 0.26] erl_bifs:is_pure/3 2857 0.02 754 [ 0.26] v3_kernel:match_clause/4 4497 0.02 755 [ 0.17] lists:split_1/5 5072 0.02 762 [ 0.15] v3_kernel:expand_pat_lit/2 3339 0.02 764 [ 0.23] sys_core_bsm:bsm_leftmost_1/2 5004 0.02 765 [ 0.15] v3_core:cclause/3 5063 0.02 782 [ 0.15] sys_core_fold:case_opt_args/5 3610 0.02 785 [ 0.22] lists:any/2 4298 0.02 787 [ 0.18] v3_kernel:handle_reuse_anno/2 3042 0.02 787 [ 0.26] v3_kernel:'-atomic_list/3-anonymous-0-'/3 5982 0.02 792 [ 0.13] gb_trees:empty/0 3538 0.02 793 [ 0.22] dict:find_val/2 5799 0.02 800 [ 0.14] beam_dead:shortcut_any_label/2 3432 0.02 806 [ 0.23] v3_core:is_simple/1 3320 0.02 809 [ 0.24] dict:append/3 6241 0.02 811 [ 0.13] v3_kernel:literal/2 4667 0.02 813 [ 0.17] dict:maybe_expand/2 6759 0.02 814 [ 0.12] v3_codegen:put_reg_1/3 3274 0.02 820 [ 0.25] erl_internal:new_type_test/2 4564 0.02 824 [ 0.18] v3_kernel:'-umatch_list/3-anonymous-0-'/3 6742 0.02 837 [ 0.12] v3_codegen:line/1 3137 0.02 838 [ 0.27] erl_lint:merge_used/2 3765 0.02 841 [ 0.22] v3_codegen:unsaved_registers/5 3539 0.02 845 [ 0.24] erl_lint:merge_lines/2 3766 0.02 848 [ 0.23] erlang:list_to_tuple/1 5982 0.02 849 [ 0.14] beam_validator:check_limit/1 3543 0.02 857 [ 0.24] gb_trees:from_orddict/1 3637 0.02 862 [ 0.24] v3_codegen:gen_moves/2 3539 0.02 869 [ 0.25] lists:append/1 4010 0.02 883 [ 0.22] erts_internal:port_control/3 3 0.02 883 [ 294.33] beam_type:simplify_float/2 3855 0.02 890 [ 0.23] beam_flatten:norm_block/2 4760 0.02 902 [ 0.19] v3_codegen:move_unsaved/3 3539 0.02 905 [ 0.26] v3_kernel:group_value/3 2140 0.02 915 [ 0.43] erl_expand_records:head/2 4100 0.02 915 [ 0.22] v3_kernel:build_alt/2 4142 0.02 920 [ 0.22] lists:rumerge3_1/6 6334 0.02 925 [ 0.15] erl_lint:'-vtupdate/2-fun-0-'/3 3765 0.02 927 [ 0.25] erl_expand_records:guard/2 4134 0.02 931 [ 0.23] beam_validator:get_fls/1 3927 0.02 932 [ 0.24] erl_expand_records:opt_rec_vars/1 4100 0.02 937 [ 0.23] sets:add_element/2 1459 0.02 947 [ 0.65] cerl_clauses:match_list/2 3840 0.02 947 [ 0.25] sys_core_dsetel:'-visit/2-anonymous-2-'/2 4145 0.02 951 [ 0.23] beam_block:opt_block/1 3906 0.02 953 [ 0.24] v3_kernel:'-group_value/3-anonymous-1-'/4 4261 0.02 957 [ 0.22] gb_trees:size/1 4040 0.02 957 [ 0.24] v3_core:guard/2 4102 0.02 966 [ 0.24] gb_sets:is_member/2 5890 0.02 968 [ 0.16] v3_core:head/2 4102 0.02 972 [ 0.24] v3_codegen:cg_setup_call/4 3539 0.02 974 [ 0.28] beam_type:flt_liveness/1 3855 0.02 974 [ 0.25] beam_block:find_fixpoint/2 4325 0.02 975 [ 0.23] v3_core:'-cclauses/3-anonymous-0-'/3 4139 0.02 976 [ 0.24] beam_validator:merge_states/3 3932 0.02 981 [ 0.25] erl_expand_records:optimize_is_record/3 4100 0.02 995 [ 0.24] sys_core_fold:sub_get_var/2 7105 0.02 997 [ 0.14] erl_bits:set_bit_type/2 5268 0.02 999 [ 0.19] orddict:new/0 6525 0.02 1002 [ 0.15] erl_anno:record/1 4187 0.02 1003 [ 0.24] beam_type:simplify/2 3855 0.02 1014 [ 0.26] v3_life:'-match/5-lc$^0/1-1-'/5 4245 0.02 1015 [ 0.24] v3_kernel:ubody/3 6590 0.02 1020 [ 0.15] v3_kernel:pattern_list/4 5732 0.02 1026 [ 0.18] v3_codegen:select_labels/4 5741 0.02 1027 [ 0.18] beam_jump:skip_unreachable/3 7552 0.02 1030 [ 0.14] erl_anno:anno_info/3 8470 0.02 1032 [ 0.12] gb_sets:insert/2 4942 0.02 1035 [ 0.21] v3_core:record_anno/2 4187 0.02 1036 [ 0.25] v3_kernel:select_types/2 4210 0.02 1038 [ 0.25] dict:maybe_expand_aux/2 6759 0.02 1038 [ 0.15] beam_type:tdb_copy/3 6132 0.02 1046 [ 0.17] beam_validator:get_term_type/2 4982 0.02 1054 [ 0.21] beam_block:'-opt_block/1-anonymous-0-'/1 4325 0.02 1056 [ 0.24] cerl:tuple_es/1 4258 0.02 1060 [ 0.25] v3_kernel:'-op_vars/1-lc$^0/1-0-'/1 4458 0.02 1061 [ 0.24] v3_core:annotate_tuple/3 4187 0.02 1064 [ 0.25] erl_anno:new_location/1 10503 0.03 1072 [ 0.10] v3_kernel:is_enter_expr/1 4381 0.03 1074 [ 0.25] v3_codegen:cg_call_args/4 3539 0.03 1076 [ 0.30] beam_validator:'-valfun_4/2-lc$^0/1-0-'/2 5041 0.03 1076 [ 0.21] cerl:case_clauses/1 4391 0.03 1078 [ 0.25] erl_lint:vtmerge/2 5277 0.03 1079 [ 0.20] v3_codegen:collect_chain/4 4376 0.03 1103 [ 0.25] v3_codegen:saves/3 4477 0.03 1108 [ 0.25] v3_kernel:sub_size_var/2 4497 0.03 1114 [ 0.25] gb_trees:balance_list/2 5862 0.03 1114 [ 0.19] v3_core:clause/2 4102 0.03 1117 [ 0.27] sys_core_fold:clause_1/5 7922 0.03 1120 [ 0.14] beam_utils:index_label/3 4466 0.03 1120 [ 0.25] v3_kernel:pattern_list/3 4475 0.03 1123 [ 0.25] v3_codegen:'-select_val_cg/6-lc$^0/1-0-'/2 5041 0.03 1130 [ 0.22] v3_codegen:reserve/3 8344 0.03 1132 [ 0.14] v3_codegen:'-save_stack/4-lc$^1/1-1-'/1 4562 0.03 1136 [ 0.25] v3_kernel:arg_val/2 6371 0.03 1139 [ 0.18] beam_trim:trim/3 9557 0.03 1142 [ 0.12] v3_codegen:'-select_cg/6-anonymous-0-'/5 4261 0.03 1153 [ 0.27] v3_codegen:need_heap/2 4534 0.03 1166 [ 0.26] beam_type:'-tdb_update/2-anonymous-0-'/1 4828 0.03 1169 [ 0.24] v3_kernel:get_con/1 4497 0.03 1177 [ 0.26] v3_codegen:save_stack/4 4477 0.03 1179 [ 0.26] cerl:ann_c_tuple/2 6882 0.03 1181 [ 0.17] gb_trees:to_list/1 4973 0.03 1186 [ 0.24] v3_codegen:'-cg_list/5-anonymous-0-'/3 4390 0.03 1187 [ 0.27] v3_core:cguard/2 5063 0.03 1193 [ 0.24] lists:all/2 7433 0.03 1196 [ 0.16] v3_kernel:'-match_con/4-lc$^0/1-0-'/1 5473 0.03 1197 [ 0.22] v3_kernel:'-match_value/5-anonymous-0-'/3 4497 0.03 1199 [ 0.27] gb_trees:update/3 7316 0.03 1210 [ 0.17] sys_core_fold:update_types_2/3 4456 0.03 1211 [ 0.27] v3_codegen:gen_moves/4 8450 0.03 1213 [ 0.14] beam_flatten:block/2 9557 0.03 1217 [ 0.13] v3_codegen:match_cg/5 7260 0.03 1217 [ 0.17] v3_codegen:adjust_stack/4 4477 0.03 1220 [ 0.27] beam_block:opt_moves/2 5254 0.03 1228 [ 0.23] v3_kernel:umatch_list/3 4333 0.03 1229 [ 0.28] beam_type:flt_liveness_1/3 8435 0.03 1229 [ 0.15] v3_life:expr/3 4675 0.03 1240 [ 0.27] erl_expand_records:clauses/2 5002 0.03 1244 [ 0.25] v3_codegen:cg/4 4745 0.03 1255 [ 0.26] v3_codegen:basic_block/2 4470 0.03 1255 [ 0.28] v3_life:body/3 4675 0.03 1256 [ 0.27] v3_core:clauses/2 5006 0.03 1258 [ 0.25] beam_record:rewrite/3 9542 0.03 1259 [ 0.13] orddict:filter/2 7572 0.03 1262 [ 0.17] erl_lint:exprs/3 5120 0.03 1265 [ 0.25] cerl:is_literal/1 5246 0.03 1271 [ 0.24] beam_dead:shortcut_rel_op/4 5365 0.03 1274 [ 0.24] beam_block:opt_move_1/3 5782 0.03 1281 [ 0.22] v3_core:'-new_in_any/1-anonymous-0-'/2 5573 0.03 1288 [ 0.23] beam_validator:valfun/4 8912 0.03 1289 [ 0.14] v3_codegen:cg_list/5 4390 0.03 1294 [ 0.29] gb_sets:balance_list_1/2 5205 0.03 1300 [ 0.25] beam_dead:update_value_dict/3 2588 0.03 1300 [ 0.50] v3_core:uguard/4 5063 0.03 1309 [ 0.26] v3_codegen:collect_block/1 4470 0.03 1309 [ 0.29] sys_core_bsm:bsm_leftmost_2/4 10417 0.03 1313 [ 0.13] beam_asm:assemble_function/3 9587 0.03 1313 [ 0.14] beam_flatten:opt_1/2 10261 0.03 1316 [ 0.13] sys_core_fold:pattern_list/3 7925 0.03 1330 [ 0.17] lists:split_2/5 9072 0.03 1331 [ 0.15] v3_kernel:new_clauses/3 4497 0.03 1333 [ 0.30] erl_lint:exist_field/2 10254 0.03 1336 [ 0.13] v3_kernel:match_guard_1/3 4179 0.03 1337 [ 0.32] erl_lint:keyword_warning/3 5988 0.03 1338 [ 0.22] v3_codegen:'-clear_dead_stk/3-lc$^0/1-0-'/3 11348 0.03 1345 [ 0.12] sys_core_fold:'-case_will_var_match/1-anonymous-0-'/1 4569 0.03 1346 [ 0.29] beam_trim:safe_labels/2 9410 0.03 1359 [ 0.14] orddict:store/3 7603 0.03 1371 [ 0.18] v3_codegen:need_heap_1/2 4675 0.03 1372 [ 0.29] v3_codegen:select_val/5 4261 0.03 1380 [ 0.32] beam_bsm:btb_opt_1/3 11869 0.03 1385 [ 0.12] v3_codegen:order_moves/3 7414 0.03 1393 [ 0.19] beam_dict:atom/2 4805 0.03 1413 [ 0.29] beam_clean:bs_replace/3 11882 0.03 1414 [ 0.12] beam_receive:opt/3 11869 0.03 1425 [ 0.12] v3_kernel:get_match/2 4497 0.03 1428 [ 0.32] beam_utils:is_pure_test/1 4686 0.03 1430 [ 0.31] v3_kernel:atomic/3 5988 0.03 1431 [ 0.24] v3_codegen:add_vls/3 8098 0.03 1436 [ 0.18] beam_block:move_allocates_1/2 9109 0.03 1465 [ 0.16] v3_life:val_clause/5 4497 0.03 1471 [ 0.33] v3_core:'-safe_list/2-anonymous-0-'/2 12288 0.03 1477 [ 0.12] v3_kernel:'-partition/1-anonymous-0-'/2 6163 0.03 1478 [ 0.24] v3_core:cexprs/3 5590 0.04 1507 [ 0.27] v3_kernel:'-group_value/3-anonymous-0-'/2 6241 0.04 1513 [ 0.24] v3_core:uclause/4 5063 0.04 1516 [ 0.30] v3_codegen:longest/2 6572 0.04 1542 [ 0.23] v3_kernel:pre_seq/2 6656 0.04 1546 [ 0.23] v3_codegen:fetch_var/2 5770 0.04 1548 [ 0.27] erl_lint:head/4 7474 0.04 1548 [ 0.21] v3_codegen:'-block_cg/4-anonymous-0-'/2 7067 0.04 1560 [ 0.22] beam_split:split_block/3 8435 0.04 1562 [ 0.19] dict:'-append/3-fun-0-'/3 6241 0.04 1570 [ 0.25] v3_life:'-type_clause/5-lc$^0/1-0-'/5 6637 0.04 1577 [ 0.24] v3_kernel:lit_vars/1 6338 0.04 1577 [ 0.25] lists:keysort/2 8482 0.04 1583 [ 0.19] v3_codegen:find_scratch_reg/2 9018 0.04 1592 [ 0.18] beam_type:tdb_find/2 5902 0.04 1597 [ 0.27] beam_clean:update_work_list/2 11882 0.04 1602 [ 0.13] v3_kernel:clause_val/1 6371 0.04 1619 [ 0.25] v3_kernel:body/3 5476 0.04 1642 [ 0.30] erl_anno:anno_info/2 8488 0.04 1654 [ 0.19] beam_dead:get_literal/1 7173 0.04 1662 [ 0.23] lists:filter/2 6898 0.04 1674 [ 0.24] v3_kernel:'-select_bin_con/1-anonymous-0-'/1 7078 0.04 1684 [ 0.24] beam_asm:encode_op/3 9419 0.04 1706 [ 0.18] beam_validator:merge_regs_1/2 7234 0.04 1709 [ 0.24] v3_codegen:need_heap_0/3 9209 0.04 1738 [ 0.19] erl_bits:apply_defaults/5 12196 0.04 1752 [ 0.14] beam_peep:peep/3 11882 0.04 1758 [ 0.15] erl_lint:pattern/5 6607 0.04 1759 [ 0.27] beam_block:collect_block/2 9090 0.04 1765 [ 0.19] erl_bits:merge_field/3 8240 0.04 1777 [ 0.22] beam_type:x_live/2 9023 0.04 1788 [ 0.20] beam_jump:move_1/3 15981 0.04 1794 [ 0.11] v3_core:cexpr/3 6511 0.04 1845 [ 0.28] v3_codegen:clear_dead_reg/3 7328 0.04 1853 [ 0.25] beam_z:undo_rename/1 8780 0.04 1867 [ 0.21] gb_trees:enter/3 9837 0.04 1913 [ 0.19] sys_core_fold:pattern_list/2 7925 0.04 1916 [ 0.24] v3_codegen:clear_dead/3 7328 0.04 1916 [ 0.26] v3_kernel:maybe_add_warning/3 8216 0.04 1916 [ 0.23] v3_codegen:sr_merge/2 5190 0.04 1924 [ 0.37] beam_type:verify_type/1 7548 0.05 1936 [ 0.26] v3_kernel:expand_pat_lit_clause/2 7078 0.05 1947 [ 0.28] gb_sets:empty/0 9285 0.05 1954 [ 0.21] beam_clean:bs_clean_saves_1/3 17192 0.05 1978 [ 0.12] beam_validator:get_term_type_1/2 7594 0.05 1981 [ 0.26] sys_core_fold:clauses/5 7919 0.05 1993 [ 0.25] core_lib:make_values/1 8600 0.05 1997 [ 0.23] sys_core_fold:guard/2 7925 0.05 2011 [ 0.25] v3_life:atomic/1 7827 0.05 2015 [ 0.26] cerl_clauses:match/2 8713 0.05 2018 [ 0.23] v3_kernel:is_atomic/1 8141 0.05 2028 [ 0.25] erl_lint:'-expr_list/3-fun-0-'/3 8606 0.05 2030 [ 0.24] beam_bs:bsm_scan/4 16932 0.05 2044 [ 0.12] v3_life:match/5 7260 0.05 2046 [ 0.28] lists:duplicate/3 18233 0.05 2051 [ 0.11] beam_type:tdb_update1/2 10602 0.05 2059 [ 0.19] beam_bs:bsm_opt_2/2 17164 0.05 2063 [ 0.12] beam_block:embed_lines/2 17184 0.05 2073 [ 0.12] v3_codegen:cg_block/5 8553 0.05 2078 [ 0.24] erl_expand_records:exprs/2 9355 0.05 2082 [ 0.22] v3_core:lit_vars/2 10591 0.05 2091 [ 0.20] v3_kernel:force_atomic/2 8141 0.05 2092 [ 0.26] v3_codegen:match_cg/4 7260 0.05 2142 [ 0.30] beam_dict:opcode/2 9420 0.05 2157 [ 0.23] sys_core_fold:clause/4 7922 0.05 2159 [ 0.27] beam_utils:live_join_label/3 8843 0.05 2159 [ 0.24] dict:on_bucket/3 6759 0.05 2165 [ 0.32] v3_core:uexpr/3 6984 0.05 2167 [ 0.31] v3_codegen:load_arg_regs/3 8450 0.05 2172 [ 0.26] beam_block:opt_alloc/1 11937 0.05 2172 [ 0.18] cerl:make_lit_list/1 11523 0.05 2186 [ 0.19] beam_opcodes:opcode/2 9420 0.05 2223 [ 0.24] v3_core:exprs/2 8974 0.05 2231 [ 0.25] sys_core_fold:update_types/3 8234 0.05 2245 [ 0.27] beam_z:undo_renames/1 9587 0.05 2256 [ 0.24] erl_anno:new/1 10503 0.05 2262 [ 0.22] lists:split_1_1/6 784 0.05 2289 [ 2.92] beam_except:translate/3 17164 0.05 2311 [ 0.13] beam_split:split_blocks/2 17151 0.05 2325 [ 0.14] gb_sets:to_list/2 14255 0.05 2327 [ 0.16] sys_core_fold:will_match/2 7919 0.05 2331 [ 0.29] beam_validator:val_dsetel/2 8744 0.05 2341 [ 0.27] ordsets:add_element/2 12009 0.06 2397 [ 0.20] erlang:phash/2 11590 0.06 2445 [ 0.21] dict:get_slot/2 8807 0.06 2466 [ 0.28] beam_type:opt_fmoves/2 16145 0.06 2469 [ 0.15] sys_core_fold:'-case_opt/3-lc$^0/1-0-'/1 10538 0.06 2496 [ 0.24] beam_jump:is_unreachable_after/1 10395 0.06 2499 [ 0.24] beam_type:opt/3 17164 0.06 2501 [ 0.15] v3_core:'-used_in_any/1-anonymous-0-'/2 10516 0.06 2504 [ 0.24] beam_dead:backward/3 18352 0.06 2504 [ 0.14] sys_core_fold:'-case_opt/3-lc$^1/1-1-'/1 10538 0.06 2513 [ 0.24] v3_life:vdb_update/3 13239 0.06 2514 [ 0.19] beam_block:blockify/2 17185 0.06 2527 [ 0.15] beam_type:flt_alloc/2 11588 0.06 2529 [ 0.22] beam_utils:live_join_labels/3 15798 0.06 2538 [ 0.16] beam_validator:valfun_1/2 8744 0.06 2581 [ 0.30] ordsets:is_element/2 17110 0.06 2583 [ 0.15] beam_jump:eliminate_fallthroughs/2 17629 0.06 2590 [ 0.15] beam_reorder:reorder_1/3 19139 0.06 2598 [ 0.14] beam_dead:forward/4 17408 0.06 2599 [ 0.15] beam_block:opt_tuple_element/1 13904 0.06 2617 [ 0.19] beam_dead:normalize_op/1 10466 0.06 2617 [ 0.25] beam_jump:share_1/4 18255 0.06 2620 [ 0.14] lists:sort/1 10629 0.06 2632 [ 0.25] v3_codegen:clear_dead_stk/3 10974 0.06 2632 [ 0.24] beam_dead:move_move_into_block/2 20253 0.06 2644 [ 0.13] cerl_clauses:match_1/3 22337 0.06 2650 [ 0.12] v3_kernel:'-new_clauses/3-anonymous-3-'/2 7078 0.06 2688 [ 0.38] beam_jump:mark_used_list/2 20512 0.06 2703 [ 0.13] beam_asm:make_op/2 9436 0.06 2719 [ 0.29] beam_type:flt_need_heap_1/4 16145 0.06 2731 [ 0.17] sys_core_fold:body/3 11466 0.06 2769 [ 0.24] beam_type:simplify_float_1/4 16145 0.07 2781 [ 0.17] ordsets:union1/2 23048 0.07 2793 [ 0.12] maps:put/3 3108 0.07 2829 [ 0.91] beam_jump:'-function/1-anonymous-0-'/2 13709 0.07 2845 [ 0.21] ordsets:union/1 11598 0.07 2880 [ 0.25] cerl:clause_guard/1 12917 0.07 2917 [ 0.23] cerl:clause_body/1 12917 0.07 2918 [ 0.23] v3_core:uexprs/3 11092 0.07 2923 [ 0.26] beam_type:flt_need_heap_2/3 12165 0.07 2975 [ 0.24] beam_asm:encode_op_1/3 25603 0.07 2979 [ 0.12] sys_core_fold:'-pattern_list/3-anonymous-0-'/3 12691 0.07 2986 [ 0.24] v3_kernel:'-select_types/2-lc$^0/1-0-'/2 23155 0.07 3010 [ 0.13] v3_core:used_in_any/1 11840 0.07 3024 [ 0.26] v3_codegen:combine/1 12070 0.07 3026 [ 0.25] cerl:update_c_clause/4 12917 0.07 3055 [ 0.24] cerl:clause_pats/1 12917 0.07 3076 [ 0.24] lists:'-filter/2-lc$^0/1-0-'/2 18808 0.07 3101 [ 0.16] gb_sets:is_member_1/2 26104 0.08 3272 [ 0.13] v3_kernel:expr/3 12421 0.08 3336 [ 0.27] gb_trees:is_defined/2 14133 0.08 3374 [ 0.24] beam_clean:bs_restores/2 29074 0.08 3431 [ 0.12] cerl:update_c_cons/3 14636 0.08 3471 [ 0.24] beam_block:opt/1 13904 0.08 3503 [ 0.25] cerl:data_es/1 14418 0.08 3519 [ 0.24] beam_utils:live_regs_1/2 19169 0.08 3529 [ 0.18] erl_lint:expr/3 14519 0.08 3539 [ 0.24] cerl:cons_tl/1 14704 0.08 3552 [ 0.24] erl_expand_records:index_expr/3 27160 0.08 3572 [ 0.13] dict:append_bkt/3 18136 0.09 3668 [ 0.20] cerl:cons_hd/1 14704 0.09 3708 [ 0.25] beam_clean:'-replace/3-anonymous-0-'/2 14970 0.09 3744 [ 0.25] sys_core_fold:'-case_opt_args/5-lc$^0/1-0-'/1 15391 0.09 3744 [ 0.24] erl_expand_records:expr_list/2 16454 0.09 3792 [ 0.23] beam_a:rename_instr/1 16432 0.09 3835 [ 0.23] v3_kernel:umatch/3 14008 0.09 3857 [ 0.28] beam_block:opt_blocks/1 17164 0.09 3894 [ 0.23] erl_lint:vtupdate/2 15587 0.09 3903 [ 0.25] v3_core:safe/2 16839 0.09 3912 [ 0.23] beam_utils:code_at/2 16987 0.09 3944 [ 0.23] beam_bs:bs_put_opt/1 17062 0.09 3959 [ 0.23] beam_jump:is_exit_instruction/1 20021 0.09 3960 [ 0.20] beam_type:simplify_basic/2 16996 0.09 4009 [ 0.24] erl_expand_records:record_pattern/6 18108 0.10 4118 [ 0.23] sys_core_fold:letify/2 17544 0.10 4128 [ 0.24] v3_core:is_safe/1 18011 0.10 4129 [ 0.23] beam_block:move_allocates/1 17164 0.10 4155 [ 0.24] dict:fold_seg/4 32606 0.10 4210 [ 0.13] v3_kernel:select/2 18945 0.10 4283 [ 0.23] gb_trees:insert/3 18006 0.10 4348 [ 0.24] v3_core:force_safe/2 18011 0.10 4349 [ 0.24] sys_core_dsetel:visit/2 20233 0.11 4504 [ 0.22] cerl:lit_list_vals/1 20782 0.11 4544 [ 0.22] v3_kernel:new_vars/3 38405 0.11 4548 [ 0.12] beam_clean:label/2 17403 0.11 4561 [ 0.26] beam_a:rename_instrs/1 18150 0.11 4732 [ 0.26] maps:find/2 18432 0.11 4797 [ 0.26] v3_core:full_anno/2 19710 0.11 4801 [ 0.24] v3_codegen:'-clear_dead_reg/3-lc$^0/1-0-'/3 20503 0.11 4908 [ 0.24] cerl:is_lit_list/1 30858 0.12 5011 [ 0.16] beam_asm:encode/2 21230 0.12 5175 [ 0.24] v3_codegen:new_label/1 6214 0.12 5257 [ 0.85] v3_kernel:'-pattern_list/4-anonymous-0-'/3 45126 0.12 5279 [ 0.12] beam_utils:x_dead/2 28264 0.12 5286 [ 0.19] v3_kernel:'-match/4-anonymous-0-'/3 41079 0.13 5362 [ 0.13] gb_sets:insert_1/3 21011 0.13 5416 [ 0.26] v3_codegen:find_reg/2 12158 0.13 5458 [ 0.45] v3_kernel:match_var/4 38974 0.13 5487 [ 0.14] v3_kernel:match_varcon/4 41079 0.13 5493 [ 0.13] beam_jump:opt/3 39214 0.13 5560 [ 0.14] lists:member/2 36061 0.13 5567 [ 0.15] erl_lint:vtmerge_pat/2 23190 0.13 5609 [ 0.24] beam_utils:live_opt_block/4 29834 0.13 5621 [ 0.19] v3_codegen:'-unsaved_registers/5-lc$^0/1-0-'/5 49016 0.13 5695 [ 0.12] gb_trees:get/2 33999 0.13 5701 [ 0.17] erl_anno:to_term/1 27518 0.14 5803 [ 0.21] sys_core_dsetel:restore_vars/3 44018 0.14 5816 [ 0.13] v3_core:safe_list/2 4203 0.14 5830 [ 1.39] cerl:get_ann/1 24725 0.14 5839 [ 0.24] beam_block:collect/1 26107 0.14 5919 [ 0.23] beam_asm:encode_arg/2 21180 0.14 5922 [ 0.28] beam_type:simplify_basic_1/3 42427 0.14 6082 [ 0.14] beam_clean:replace/3 41489 0.14 6110 [ 0.15] erl_parse:'-anno_to_term/1-fun-0-'/2 27518 0.14 6163 [ 0.22] gb_trees:count/1 27728 0.15 6294 [ 0.23] erlang:max/2 24717 0.15 6340 [ 0.26] orddict:merge/3 49589 0.15 6357 [ 0.13] v3_core:expr/2 22900 0.15 6396 [ 0.28] sys_core_dsetel:visit_pats/3 50734 0.15 6451 [ 0.13] sys_core_fold:expr/3 33651 0.15 6468 [ 0.19] v3_kernel:match/4 44330 0.15 6474 [ 0.15] v3_codegen:'-save_stack/4-lc$^0/1-0-'/4 52503 0.16 6636 [ 0.13] lists:splitwith/3 48334 0.16 6742 [ 0.14] beam_clean:renumber_labels/3 42525 0.16 6750 [ 0.16] erl_expand_records:expr/2 23874 0.16 6796 [ 0.28] beam_jump:label_used/2 36676 0.16 6855 [ 0.19] gb_trees:lookup/2 30683 0.16 6975 [ 0.23] erl_lint:find_field/2 54324 0.16 7051 [ 0.13] v3_life:use_vars/3 24118 0.17 7110 [ 0.29] gb_trees:update_1/3 29635 0.17 7152 [ 0.24] dict:fold_bucket/3 35281 0.17 7284 [ 0.21] beam_utils:live_opt/4 49967 0.17 7339 [ 0.15] v3_core:new_in_any/1 10126 0.17 7483 [ 0.74] beam_jump:rem_unused/3 62921 0.18 7561 [ 0.12] ordsets:subtract/2 51321 0.18 7865 [ 0.15] lists:reverse/2 30707 0.19 8060 [ 0.26] cerl:is_data/1 34107 0.19 8117 [ 0.24] v3_life:'-literal/2-lc$^0/1-0-'/2 37431 0.19 8199 [ 0.22] beam_utils:index_labels_1/2 63625 0.20 8598 [ 0.14] v3_kernel:'-pat_list_vars/1-anonymous-0-'/2 37504 0.21 8838 [ 0.24] v3_codegen:'-select_extract_tuple/6-anonymous-0-'/5 37421 0.21 8998 [ 0.24] maps:remove/2 39703 0.21 9122 [ 0.23] beam_type:update/2 36624 0.21 9165 [ 0.25] v3_kernel:'-match_var/4-anonymous-1-'/3 39273 0.22 9426 [ 0.24] erlang:term_to_binary/2 330 0.23 9637 [ 29.20] v3_kernel:new_var_name/1 39420 0.23 9699 [ 0.25] gb_trees:is_defined_1/2 86526 0.23 9919 [ 0.11] v3_core:new_var_name/1 38685 0.24 10131 [ 0.26] beam_jump:'-remove_unused_labels/1-anonymous-0-'/2 48838 0.24 10148 [ 0.21] beam_utils:x_live/2 53759 0.24 10161 [ 0.19] beam_jump:ulbl/2 70747 0.24 10218 [ 0.14] v3_kernel:'-match_var/4-anonymous-0-'/3 39273 0.24 10237 [ 0.26] lists:splitwith/2 41778 0.24 10449 [ 0.25] v3_kernel:'-select/2-lc$^0/1-0-'/2 82647 0.25 10487 [ 0.13] orddict:from_list/1 78652 0.25 10596 [ 0.13] v3_kernel:pat_vars/1 42105 0.25 10645 [ 0.25] v3_codegen:flatmapfoldl/3 47583 0.27 11351 [ 0.24] erl_expand_records:pattern_list/2 51056 0.27 11369 [ 0.22] sys_core_bsm:'-function/3-anonymous-0-'/2 105235 0.27 11450 [ 0.11] v3_core:pattern_list/2 51110 0.27 11568 [ 0.23] erl_expand_records:pattern/2 46427 0.27 11677 [ 0.25] sys_core_bsm:bsm_an/2 105235 0.28 12181 [ 0.12] lists:ukeysort/2 77382 0.29 12218 [ 0.16] sys_core_fold:pattern/3 91530 0.29 12271 [ 0.13] v3_core:pattern/2 47003 0.29 12363 [ 0.26] v3_core:upattern/3 46333 0.29 12508 [ 0.27] v3_life:literal/2 44636 0.29 12582 [ 0.28] cerl:concrete/1 54877 0.29 12608 [ 0.23] v3_kernel:'-match_var/4-anonymous-2-'/2 39273 0.30 12847 [ 0.33] lists:keyfind/3 71791 0.30 12920 [ 0.18] v3_kernel:pattern/4 45769 0.30 12934 [ 0.28] beam_utils:delete_live_annos/1 63039 0.31 13115 [ 0.21] erlang:integer_to_list/1 79068 0.31 13136 [ 0.17] v3_core:upattern_list/3 51908 0.31 13167 [ 0.25] orddict:find/2 89347 0.34 14356 [ 0.16] v3_life:vdb_find/2 49254 0.34 14473 [ 0.29] gb_trees:to_list/2 94502 0.36 15491 [ 0.16] v3_core:lineno_anno/2 74513 0.37 15670 [ 0.21] erl_anno:location/1 74533 0.39 16540 [ 0.22] cerl_trees:mapfold_list/4 71716 0.39 16699 [ 0.23] erl_anno:line/1 74513 0.40 16895 [ 0.23] erl_anno:generated/1 74513 0.40 16986 [ 0.23] sys_core_fold:'-pattern/3-anonymous-2-'/3 76384 0.41 17600 [ 0.23] sys_core_dsetel:visit_pat/3 46419 0.42 17861 [ 0.38] gb_trees:balance_list_1/2 70256 0.43 18286 [ 0.26] sys_core_fold:sub_del_var/2 79753 0.45 19286 [ 0.24] sys_core_fold:sub_is_val/2 79753 0.45 19455 [ 0.24] v3_kernel:partition/1 81267 0.47 20263 [ 0.25] ordsets:intersection/2 144532 0.48 20342 [ 0.14] v3_kernel:is_var_clause/1 88321 0.52 22083 [ 0.25] cerl_clauses:match_list/3 176966 0.54 23136 [ 0.13] sys_core_bsm:bsm_an/1 105235 0.55 23434 [ 0.22] erlang:list_to_atom/1 79357 0.59 25074 [ 0.32] cerl_trees:'-mapfold/3-anonymous-0-'/2 105235 0.59 25195 [ 0.24] erl_parse:modify_anno1/3 99993 0.60 25693 [ 0.26] lists:map/2 110970 0.62 26584 [ 0.24] gb_trees:lookup_1/2 230216 0.64 27218 [ 0.12] lists:reverse/1 122044 0.65 27622 [ 0.23] cerl_trees:mapfold/4 105235 0.65 27889 [ 0.27] gb_trees:get_1/2 247600 0.66 28191 [ 0.11] cerl_clauses:'-match_1/3-lc$^0/1-0-'/1 150164 0.78 33173 [ 0.22] lists:mapfoldl/3 142434 0.78 33411 [ 0.23] gb_trees:insert_1/4 145420 0.82 35231 [ 0.24] v3_kernel:arg_con/1 160017 0.87 37325 [ 0.23] cerl_clauses:match/3 167587 0.88 37476 [ 0.22] lists:foldr/3 199608 0.98 41728 [ 0.21] erlang:'++'/2 337382 1.03 43981 [ 0.13] cerl_sets:is_element/2 219320 1.27 54228 [ 0.25] cerl_sets:add_element/2 158421 1.37 58422 [ 0.37] lists:foldl/3 384147 1.44 61755 [ 0.16] cerl:type/1 273982 1.55 66363 [ 0.24] erlang:setelement/3 409336 1.67 71545 [ 0.17] v3_life:vdb_update_vars/3 319576 1.69 72308 [ 0.23] v3_kernel:subst_vsub_2/3 343932 1.83 78060 [ 0.23] orddict:reverse_pairs/2 2497074 6.76 289258 [ 0.12] lists:ukeysplit_2/5 2336493 7.63 326450 [ 0.14] ordsets:union/2 1692288 8.93 381951 [ 0.23] v3_kernel:subst_vsub_1/3 2152994 11.93 510068 [ 0.24] ---------------------------------------------------------- -------- ------- ------- [----------] Total: 22253284 100.00% 4276149 [ 0.19] --- lib/diameter/test/diameter_util.erl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 03f79096ac..d249b0e4fa 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -32,7 +32,8 @@ foldl/3, scramble/1, unique_string/0, - have_sctp/0]). + have_sctp/0, + eprof/1]). %% diameter-specific -export([lport/2, @@ -48,6 +49,16 @@ -define(L, atom_to_list). +%% --------------------------------------------------------------------------- + +eprof(start) -> + eprof:start(), + eprof:start_profiling([self()]); + +eprof(stop) -> + eprof:stop_profiling(), + eprof:analyze(), + eprof:stop(). %% --------------------------------------------------------------------------- %% name/2 -- cgit v1.2.3 From 1339269fefcbd688b3eb4bde2bb6c55fe2e1b17d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 19 Jul 2017 14:48:12 +0200 Subject: Increase init_per_group timetrap in traffic suite Connection establishment is slow on some test hosts. --- lib/diameter/test/diameter_traffic_SUITE.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index d676614084..eb2fdb7721 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -30,6 +30,7 @@ init_per_suite/0, init_per_suite/1, end_per_suite/1, + init_per_group/1, init_per_group/2, end_per_group/2, init_per_testcase/2, @@ -314,6 +315,9 @@ end_per_suite(_Config) -> %% -------------------- +init_per_group(_) -> + [{timetrap, {seconds, 30}}]. + init_per_group(Name, Config) when Name == shuffle; Name == parallel -> -- cgit v1.2.3 From fa233bb7bc4f37632166c468a0381e695433c318 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 12 Jul 2017 11:43:06 +0200 Subject: Limit SCTP testing in traffic suite All SCTP testing on Solaris/Sparc was disabled in commit 69c5a741, but there are issues on other platforms as well, resulting in failures in diameter_gen_sctp_SUITE and more. The problems seem to be load-related, when testcases are run in parallel, so only run a smallish subset sequentially until the gen_sctp suite runs without error. --- lib/diameter/test/diameter_traffic_SUITE.erl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index eb2fdb7721..f05c850513 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -125,7 +125,7 @@ %% Positive number of testcases from which to select (randomly) from %% tc(), the list of testcases to run, or [] to run all. The random %% selection is to limit the time it takes for the suite to run. --define(LIMIT, 42). +-define(LIMIT, #{tcp => 42, sctp => 5}). -define(util, diameter_util). @@ -269,12 +269,15 @@ all() -> -define(GROUPS, []). %-define(GROUPS, [[tcp,rfc6733,record,map,false,false,false,false]]). +%% Issues with gen_sctp sporadically cause huge numbers of failed +%% testcases when running testcases in parallel. groups() -> Names = names(), [{P, [P], Ts} || Ts <- [tc()], P <- [shuffle, parallel]] ++ - [{?util:name(N), [], [{group, if S -> shuffle; not S -> parallel end}]} - || [_,_,_,_,S|_] = N <- Names] + [{?util:name(N), [], [{group, if T == sctp; S -> shuffle; + true -> parallel end}]} + || [T,_,_,_,S|_] = N <- Names] ++ [{T, [], [{group, ?util:name(N)} || N <- names(Names, ?GROUPS), T == hd(N)]} @@ -348,7 +351,7 @@ init_per_group(Name, Config) -> server_decoding = D, server_sender = SS, server_throttle = ST}, - [{group, G}, {runlist, select()} | Config]; + [{group, G}, {runlist, select(T)} | Config]; _ -> Config end. @@ -362,9 +365,10 @@ end_per_group(Name, Config) end_per_group(_, _) -> ok. -select() -> - try rand:uniform(?LIMIT) of - N -> lists:sublist(?util:scramble(tc()), max(N,5)) +select(T) -> + try maps:get(T, ?LIMIT) of + N -> + lists:sublist(?util:scramble(tc()), max(5, rand:uniform(N))) catch error:_ -> ?LIMIT end. -- cgit v1.2.3