From be89101a7cdf10aa4e6a166e2d24d7c33d8d44ca Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Fri, 10 Feb 2023 23:42:32 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20=E8=AF=BB=E5=8F=96record=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/comMisc/utReadRec.erl | 142 ++++++++++++++++++++++++++++++++++++++ src/measure/utTc.erl | 4 +- 2 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/comMisc/utReadRec.erl diff --git a/src/comMisc/utReadRec.erl b/src/comMisc/utReadRec.erl new file mode 100644 index 0000000..0077557 --- /dev/null +++ b/src/comMisc/utReadRec.erl @@ -0,0 +1,142 @@ +-module(utReadRec). +-compile([export_all]). + +read_records(FileOrModule, Opts0) -> + Opts = lists:delete(report_warnings, Opts0), + case find_file(FileOrModule) of + {beam, Beam, File} -> + read_records_from_beam(Beam, File); + {files, [File]} -> + read_file_records(File, Opts); + {files, Files} -> + lists:flatmap(fun(File) -> + case read_file_records(File, Opts) of + RAs when is_list(RAs) -> RAs; + _ -> [] + end + end, Files); + Error -> + Error + end. + +-include_lib("kernel/include/file.hrl"). +find_file(Mod) when is_atom(Mod) -> + case code:which(Mod) of + File when is_list(File) -> + %% Special cases: + %% - Modules not in the code path (loaded with code:load_abs/1): + %% code:get_object_code/1 only searches in the code path + %% but code:which/1 finds all loaded modules + %% - File can also be a file in an archive, + %% beam_lib:chunks/2 cannot handle such paths but + %% erl_prim_loader:get_file/1 can + case erl_prim_loader:get_file(File) of + {ok, Beam, _} -> + {beam, Beam, File}; + error -> + {error, nofile} + end; + preloaded -> + {_M, Beam, File} = code:get_object_code(Mod), + {beam, Beam, File}; + _Else -> % non_existing, interpreted, cover_compiled + {error, nofile} + end; +find_file(File) -> + case catch filelib:wildcard(File) of + {'EXIT', _} -> + {error, invalid_filename}; + Files -> + {files, Files} + end. + +read_file_records(File, Opts) -> + case filename:extension(File) of + ".beam" -> + read_records_from_beam(File, File); + _ -> + parse_file(File, Opts) + end. + +read_records_from_beam(Beam, File) -> + case beam_lib:chunks(Beam, [abstract_code, "CInf"]) of + {ok, {_Mod, [{abstract_code, {Version, Forms}}, {"CInf", CB}]}} -> + case record_attrs(Forms) of + [] when Version =:= raw_abstract_v1 -> + []; + [] -> + %% If the version is raw_X, then this test + %% is unnecessary. + try_source(File, CB); + Records -> + Records + end; + {ok, {_Mod, [{abstract_code, no_abstract_code}, {"CInf", CB}]}} -> + try_source(File, CB); + Error -> + %% Could be that the "Abst" chunk is missing (pre R6). + Error + end. + +%% This is how the debugger searches for source files. See int.erl. +try_source(Beam, RawCB) -> + EbinDir = filename:dirname(Beam), + CB = binary_to_term(RawCB), + Os = proplists:get_value(options, CB, []), + Src0 = filename:rootname(Beam) ++ ".erl", + Src1 = filename:join([filename:dirname(EbinDir), "src", + filename:basename(Src0)]), + Src2 = proplists:get_value(source, CB, []), + try_sources([Src0, Src1, Src2], Os). + +try_sources([], _) -> + {error, nofile}; +try_sources([Src | Rest], Os) -> + case is_file(Src) of + true -> parse_file(Src, Os); + false -> try_sources(Rest, Os) + end. + +is_file(Name) -> + case filelib:is_file(Name) of + true -> + not filelib:is_dir(Name); + false -> + false + end. + +parse_file(File, Opts) -> + Cwd = ".", + Dir = filename:dirname(File), + IncludePath = [Cwd, Dir | inc_paths(Opts)], + case epp:parse_file(File, IncludePath, pre_defs(Opts)) of + {ok, Forms} -> + record_attrs(Forms); + Error -> + Error + end. + +pre_defs([{d, M, V} | Opts]) -> + [{M, V} | pre_defs(Opts)]; +pre_defs([{d, M} | Opts]) -> + [M | pre_defs(Opts)]; +pre_defs([_ | Opts]) -> + pre_defs(Opts); +pre_defs([]) -> []. + +inc_paths(Opts) -> + [P || {i, P} <- Opts, is_list(P)]. + +record_attrs(Forms) -> + [{RecName, [record_field(OneAttr) || OneAttr <- FieldsAttr]} || {attribute, _, record, {RecName, FieldsAttr}} <- Forms]. + +record_field({record_field, _Anno, {_, _, Filed}}) -> + Filed; +record_field({record_field, _Anno, {_, _, Filed}, _Val}) -> + Filed; +record_field({typed_record_field, {record_field, _Anno, {_, _, Filed}}, _Type}) -> + Filed; +record_field({typed_record_field, {record_field, _Anno, {_, _, Filed}, _Val}, _Type}) -> + Filed; +record_field({typed_record_field, Field, _Type}) -> + record_field(Field). diff --git a/src/measure/utTc.erl b/src/measure/utTc.erl index 3d11566..62350dd 100644 --- a/src/measure/utTc.erl +++ b/src/measure/utTc.erl @@ -68,7 +68,7 @@ distribution([], _Aver, Greater, Less) -> ts(LoopTime, M, F, A) -> {Max, Min, Sum, Aver, Greater, Less} = loopTs(LoopTime, M, F, A, LoopTime, 0, 0, 0, []), io:format("=====================~n"), - <<_:16, ArgsStr/binary>> = << <<", ", (iolist_to_binary(io_lib:format("~p", [OArg], [{chars_limit, 80}])))/binary>> || OArg <- A>>, + case A of [] -> ArgsStr = <<>>; _ -> <<_:16, ArgsStr/binary>> = << <<", ", (iolist_to_binary(io_lib:format("~p", [OArg], [{chars_limit, 80}])))/binary>> || OArg <- A>> end, io:format("execute ~p:~p(~s).~n", [M, F, ArgsStr]), io:format("execute LoopTime:~p~n", [LoopTime]), io:format("MaxTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Max), float_to_binary(Max / 1000000000, [{decimals, 6}, compact])]), @@ -111,7 +111,7 @@ tm(ProcCnt, LoopTime, M, F, A) -> loopSpawn(ProcCnt, M, F, A, self(), LoopTime), {Max, Min, Sum, Aver, Greater, Less} = collector(ProcCnt, 0, 0, 0, ProcCnt, []), io:format("=====================~n"), - <<_:16, ArgsStr/binary>> = << <<", ", (iolist_to_binary(io_lib:format("~p", [OArg], [{chars_limit, 80}])))/binary>> || OArg <- A>>, + case A of [] -> ArgsStr = <<>>; _ -> <<_:16, ArgsStr/binary>> = << <<", ", (iolist_to_binary(io_lib:format("~p", [OArg], [{chars_limit, 80}])))/binary>> || OArg <- A>> end, io:format("execute ~p:~p(~s).~n", [M, F, ArgsStr]), io:format("execute LoopTime:~p~n", [LoopTime]), io:format("execute ProcCnts:~p~n", [ProcCnt]),