diff --git a/README.md b/README.md index 513c6f1..3402271 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,5 @@ An OTP library Build ----- - + $ rebar3 escriptize $ rebar3 compile diff --git a/rebar.config b/rebar.config index 01fa765..b1fe1bf 100644 --- a/rebar.config +++ b/rebar.config @@ -1,4 +1,12 @@ {erl_opts, [no_debug_info]}. {deps, [ {eFmt, {git, "http://47.108.26.175:53000/SisMaker/eFmt.git", {branch, "master"}}} -]}. \ No newline at end of file +]}. + + +%% escript +{escript_main_app, eAcs}. % specify which app is the escript app +{escript_name, genAcs}. % name of final generated escript +{escript_emu_args, "%%! -escript main genAcs\n"}. % emulator args +%%{escript_shebang, "#!/usr/bin/env escript\n"}. % executable line +%%{escript_comment, "%%\n"}. % comment at top of escript file \ No newline at end of file diff --git a/src/eAcs.erl b/src/eAcs.erl index a9e2b9f..df7f433 100644 --- a/src/eAcs.erl +++ b/src/eAcs.erl @@ -1,54 +1,128 @@ -module(eAcs). -export([ - match/2 + matchSw/1 %% 返回匹配的敏感词列表 + , isHasSw/1 %% 检查是否包含敏感词 + , replaceSw/1 %% 替换敏感词 ]). -%% State is used to locate node, every node is a map %% state 0 is the root node -%% -%% Goto: State -> Map{Char -> State} -%% Ouput: State -> String -%% Failure: State -> State +%% Goto: State -> #{Word -> State} +%% failOut: State -> {FailState, BinStr} +%% *************************************** matchSw start *************************************************************** +-spec matchSw(BinStr :: binary()) -> [{StartIndex :: integer(), EndIndex :: integer(), Pattern :: binary()}]. +matchSw(BinStr) -> + doMatch(BinStr, 0, _Index = 1, _MatchList = []). -%% try to find patterns in string -%% the match index starts from 1 -%% @return [{StartIndex, EndIndex, Pattern},...] -match(String, {Goto, Failure, Output}) -> - do_match(String, 0, {Goto, Failure, Output}, _Index = 1, _MatchList = []). - - -do_match([], _, _, _Index, MatchList) -> +doMatch(<<>>, _, _Index, MatchList) -> MatchList; -do_match([Char|Tail], State, {Goto, Failure, Output}, Index, MatchList) -> - {NewState, NewMatchList} = do_match_inner(Char, State, {Goto, Failure, Output}, Index, MatchList), - do_match(Tail, NewState, {Goto, Failure, Output}, Index + 1, NewMatchList). - -%% {NewState, NewMatchList} -do_match_inner(Char, State, {Goto, Failure, Output}, Index, MatchList) -> - #{State := Node} = Goto, - case maps:find(Char, Node) of - error -> - case State =:= 0 of - true -> +doMatch(<>, State, Index, MatchList) -> + {NewState, NewMatchList} = matchInner(Word, State, Index, MatchList), + doMatch(Tail, NewState, Index + 1, NewMatchList). + +matchInner(Word, State, Index, MatchList) -> + Node = acsTrees:goto(State), + case Node of + undefined -> + case State of + 0 -> {State, MatchList}; - false -> - NextState = maps:get(State, Failure, 0), - do_match_inner(Char, NextState, {Goto, Failure, Output}, Index, MatchList) + _ -> + {NextState, _} = acsTrees:failOut(State), + matchInner(Word, NextState, Index, MatchList) end; - {ok, NextState} -> - NewMatchList = get_output(NextState, {Goto, Failure, Output}, Index, MatchList), - {NextState, NewMatchList} + _ -> + case Node of + #{Word := NextState} -> + NewMatchList = getOutput(NextState, Index, MatchList), + {NextState, NewMatchList}; + _ -> + case State of + 0 -> + {State, MatchList}; + _ -> + {NextState, _} = acsTrees:failOut(State), + matchInner(Word, NextState, Index, MatchList) + end + end end. -get_output(0, _, _Index, MatchList) -> +getOutput(0, _Index, MatchList) -> MatchList; -get_output(State, {Goto, Failure, Output}, Index, MatchList) -> - NewMatchList = case maps:find(State, Output) of - error -> MatchList; - {ok, Pattern} -> [{Index-length(Pattern) + 1, Index, Pattern} | MatchList] - end, - FailureState = maps:get(State, Failure, 0), - get_output(FailureState, {Goto, Failure, Output}, Index, NewMatchList). +getOutput(State, Index, MatchList) -> + {FailState, Pattern} = acsTrees:failOut(State), + case Pattern of + undefined -> + getOutput(FailState, Index, MatchList); + _ -> + NewMatchList = [{Index - patternSize(Pattern, 0) + 1, Index, Pattern} | MatchList], + getOutput(FailState, Index, NewMatchList) + end. + +%% *************************************** matchSw end *************************************************************** +%% *************************************** isHasSw start *************************************************************** +-spec isHasSw(BinStr :: binary()) -> boolean(). +isHasSw(BinStr) -> + doMatch(BinStr, 0). +doMatch(<<>>, _) -> + false; +doMatch(<>, State) -> + case matchInner(Word, State) of + true -> + true; + NewState -> + doMatch(Tail, NewState) + end. + +matchInner(Word, State) -> + Node = acsTrees:goto(State), + case Node of + undefined -> + case State of + 0 -> + State; + _ -> + {NextState, _} = acsTrees:failOut(State), + matchInner(Word, NextState) + end; + _ -> + case Node of + #{Word := NextState} -> + case getOutput(NextState) of + false -> + NextState; + _ -> + true + end; + _ -> + case State of + 0 -> + State; + _ -> + {NextState, _} = acsTrees:failOut(State), + matchInner(Word, NextState) + end + end + end. + +getOutput(0) -> + false; +getOutput(State) -> + {FailState, Pattern} = acsTrees:failOut(State), + case Pattern of + undefined -> + false; + _ -> + getOutput(FailState) + end. +%% *************************************** matchSw end *************************************************************** +%% *************************************** replaceSw start ************************************************************* +replaceSw(_BinStr) -> + ok. +%% *************************************** replaceSw end ************************************************************* +patternSize(<<>>, Cnt) -> + Cnt; +patternSize(<<_Word/utf8, Left/binary>>, Cnt) -> + patternSize(Left, Cnt + 1). \ No newline at end of file diff --git a/src/genAcs.erl b/src/genAcs.erl index 04cedb5..b15d532 100644 --- a/src/genAcs.erl +++ b/src/genAcs.erl @@ -6,24 +6,28 @@ ]). main(Args) -> - [SNFile, WriteDir] = Args, - case file:open(SNFile, [read, raw, binary, {read_ahead, 65536}, {'encoding', 'utf8'}]) of + [SWFile, WriteDir] = Args, + case file:open(SWFile, [read, raw, binary, {read_ahead, 65536}, {encoding, utf8}]) of {ok, IoDevice} -> - {Goto, Output} = dealEveryLine(IoDevice, _Goto=#{0 => #{}}, _Output=#{}, _State=0), + {Goto, Output} = dealEveryLine(IoDevice, _Goto = #{0 => #{}}, _Output = #{}, _State = 0), Failure = genFailure(Goto), genErl(WriteDir, Goto, Failure, Output); _Err -> - io:format("genAcs open the file:~p error ~p~n", [SNFile, _Err]) + io:format("genAcs open the file:~p error ~p~n", [SWFile, _Err]) end. dealEveryLine(IoDevice, Goto, Output, MaxState) -> case file:read_line(IoDevice) of {ok, DataStr} -> - %% io:format("IMY*********** ~w ~n", [DataStr]), BinStr = binary:part(DataStr, 0, byte_size(DataStr) - 1), - {NewGoto, NewState, NewMaxState} = addPattern(BinStr, Goto, 0, MaxState), - NewOutput = Output#{NewState => BinStr}, - dealEveryLine(IoDevice, NewGoto, NewOutput, NewMaxState); + case BinStr =/= <<>> of + true -> + {NewGoto, NewState, NewMaxState} = addPattern(BinStr, Goto, 0, MaxState), + NewOutput = Output#{NewState => BinStr}, + dealEveryLine(IoDevice, NewGoto, NewOutput, NewMaxState); + _ -> + dealEveryLine(IoDevice, Goto, Output, MaxState) + end; eof -> {Goto, Output}; _Err -> @@ -33,15 +37,20 @@ dealEveryLine(IoDevice, Goto, Output, MaxState) -> %% 从字符串模式列表构建ac搜索树 genTree(BinStrList) -> %% 先构造 goto and output table - {Goto, Output} = genGotoOutput(BinStrList, _Goto=#{0 => #{}}, _Output=#{}, _State=0), + {Goto, Output} = genGotoOutput(BinStrList, _Goto = #{0 => #{}}, _Output = #{}, _State = 0), %% 然后构造 failure table Failure = genFailure(Goto), {Goto, Failure, Output}. -genGotoOutput([BinStr |Tail], Goto, Output, MaxState) -> - {NewGoto, NewState, NewMaxState} = addPattern(BinStr, Goto, 0, MaxState), - NewOutput = Output#{NewState => BinStr}, - genGotoOutput(Tail, NewGoto, NewOutput, NewMaxState); +genGotoOutput([BinStr | Tail], Goto, Output, MaxState) -> + case BinStr =/= <<>> of + true -> + {NewGoto, NewState, NewMaxState} = addPattern(BinStr, Goto, 0, MaxState), + NewOutput = Output#{NewState => BinStr}, + genGotoOutput(Tail, NewGoto, NewOutput, NewMaxState); + _ -> + genGotoOutput(Tail, Goto, Output, MaxState) + end; genGotoOutput([], Goto, Output, _MaxState) -> {Goto, Output}. @@ -60,55 +69,55 @@ addPattern(<<>>, Goto, State, MaxState) -> genFailure(#{0 := Node} = Goto) -> States = maps:values(Node), - genFailure(States, Goto, _Failure=#{}). + genFailure(States, Goto, _Failure = #{}). %% 构造 failure with bfs搜索 -genFailure([], _Goto, Failure) -> - Failure; -genFailure([State|Tail], Goto, Failure) -> +genFailure([State | Tail], Goto, Failure) -> #{State := Node} = Goto, %% find the starting point: the parent's failure node - FailureState = maps:get(State, Failure, 0), + FailState = maps:get(State, Failure, 0), %% children Kvs = maps:to_list(Node), %% find failure node for all children - NewFailure = genFailureInner(Kvs, FailureState, Goto, Failure), + NewFailure = genFailureInner(Kvs, FailState, Goto, Failure), %% add children states to the queue NewQueue = Tail ++ maps:values(Node), - genFailure(NewQueue, Goto, NewFailure). + genFailure(NewQueue, Goto, NewFailure); +genFailure([], _Goto, Failure) -> + Failure. %% 为节点构造失败指针 -%% @param FailureState 是当前节点的失败指针 -genFailureInner([], _FailureState, _Goto, Failure) -> +%% @param FailState 是当前节点的失败指针 +genFailureInner([], _FailState, _Goto, Failure) -> Failure; -genFailureInner([{Word, State}|Tail], FailureState, Goto, Failure) -> - NewFailure = findFailureNode(Word, State, FailureState, Goto, Failure), - genFailureInner(Tail, FailureState, Goto, NewFailure). +genFailureInner([{Word, State} | Tail], FailState, Goto, Failure) -> + NewFailure = findFailureNode(Word, State, FailState, Goto, Failure), + genFailureInner(Tail, FailState, Goto, NewFailure). %% 为某个儿子节点构造失败指针 -findFailureNode(Word, State, FailureState, Goto, Failure) -> - #{FailureState := Node} = Goto, +findFailureNode(Word, State, FailState, Goto, Failure) -> + #{FailState := Node} = Goto, case Node of - #{Word := TheFailureState} -> + #{Word := TheFailState} -> %% 找到最近的失败节点的儿子节点拥有当前儿子节点的值,查找成功 - Failure#{State => TheFailureState}; + Failure#{State => TheFailState}; _ -> - case FailureState =:= 0 of + case FailState =:= 0 of true -> %% 找不到,而且已经到了根节点,查找失败 Failure; _ -> %% 找不到但是还没到根节点,继续往上找 - NewFailureState = maps:get(FailureState, Failure, 0), - findFailureNode(Word, State, NewFailureState, Goto, Failure) + NewFailState = maps:get(FailState, Failure, 0), + findFailureNode(Word, State, NewFailState, Goto, Failure) end end. genHead() -> - <<"-module(acsTrees).\n\n-export([goto/1, failure/1, output/1]).\n\n">>. + <<"-module(acsTrees).\n\n-compile([deterministic, no_line_info]).\n\n-export([goto/1, failOut/1]).\n\n">>. genGoto(Goto, StrAcc) -> Kvs = maps:to_list(Goto), @@ -116,47 +125,51 @@ genGoto(Goto, StrAcc) -> doGenGoto(SortKvs, StrAcc). doGenGoto([], StrAcc) -> - StrAcc; + < undefined.\n\n">>; doGenGoto([{K, V}], StrAcc) -> - < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ".\n\n">>; + case maps:size(V) > 0 of + true -> + < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ";\ngoto(_) -> undefined.\n\n">>; + _ -> + < undefined.\n\n">> + end; doGenGoto([{K, V} | SortKvs], StrAcc) -> - NewStrAcc = < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ";\n">>, - doGenGoto(SortKvs, NewStrAcc). - -genFailure(Goto, StrAcc) -> - Kvs = maps:to_list(Goto), - SortKvs = lists:sort(Kvs), - doGenFailure(SortKvs, StrAcc). - -doGenFailure([], StrAcc) -> - StrAcc; -doGenFailure([{K, V}], StrAcc) -> - < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ".\n\n">>; -doGenFailure([{K, V} | SortKvs], StrAcc) -> - NewStrAcc = < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ";\n">>, - doGenFailure(SortKvs, NewStrAcc). - -genOutput(Goto, StrAcc) -> - Kvs = maps:to_list(Goto), - SortKvs = lists:sort(Kvs), - doGenOutput(SortKvs, StrAcc). - -doGenOutput([], StrAcc) -> - StrAcc; -doGenOutput([{K, V}], StrAcc) -> - < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ".\n\n">>; -doGenOutput([{K, V} | SortKvs], StrAcc) -> - NewStrAcc = < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ";\n">>, - doGenOutput(SortKvs, NewStrAcc). + case maps:size(V) > 0 of + true -> + NewStrAcc = < ", (eFmt:formatBin(<<"~w">>, [V]))/binary, ";\n">>, + doGenGoto(SortKvs, NewStrAcc); + _ -> + doGenGoto(SortKvs, StrAcc) + end. +genFailOut([], _Failure, _Output, StrAcc) -> + < {0, undefined}.\n\n">>; +genFailOut([State], Failure, Output, StrAcc) -> + FailState = maps:get(State, Failure, 0), + Pattern = maps:get(State, Output, undefined), + case FailState /= 0 orelse Pattern /= undefined of + true -> + < ", (eFmt:formatBin(<<"~w">>, [{FailState, Pattern}]))/binary, ";\nfailOut(_) -> {0, undefined}.\n\n">>; + _ -> + < {0, undefined}.\n\n">> + end; +genFailOut([State | SortStates], Failure, Output, StrAcc) -> + FailState = maps:get(State, Failure, 0), + Pattern = maps:get(State, Output, undefined), + case FailState /= 0 orelse Pattern /= undefined of + true -> + NewStrAcc = < ", (eFmt:formatBin(<<"~w">>, [{FailState, Pattern}]))/binary, ";\n">>, + genFailOut(SortStates, Failure, Output, NewStrAcc); + _ -> + genFailOut(SortStates, Failure, Output, StrAcc) + end. genErl(WriteDir, Goto, Failure, Output) -> HeadStr = genHead(), GotoStr = genGoto(Goto, HeadStr), - FailureStr = genFailure(Failure, GotoStr), - OutputStr = genOutput(Output, FailureStr), + FailureStr = genFailOut(lists:sort(maps:keys(Goto)), Failure, Output, GotoStr), FileName = filename:join([WriteDir, "acsTrees.erl"]), - file:write_file(FileName, OutputStr). + file:write_file(FileName, FailureStr). diff --git a/config/sensitiveWord.txt b/src/test/SWord.txt similarity index 100% rename from config/sensitiveWord.txt rename to src/test/SWord.txt diff --git a/src/test/acTc.erl b/src/test/acTc.erl new file mode 100644 index 0000000..60c805a --- /dev/null +++ b/src/test/acTc.erl @@ -0,0 +1,216 @@ +-module(acTc). + +-compile(inline). +-compile({inline_size, 128}). + +-export([ + tc/1 + , tc/2 + , tc/3 + , ts/4 + , tm/5 + , cvrTimeUnit/3 + , test/1 +]). + +%% Measure the execution time (in nanoseconds) for Fun(). +-spec tc(Fun :: function()) -> {Time :: integer(), Value :: term()}. +tc(F) -> + T1 = erlang:monotonic_time(), + Val = F(), + T2 = erlang:monotonic_time(), + Time = cvrTimeUnit(T2 - T1, native, nanosecond), + {Time, Val}. + +%% Measure the execution time (in nanoseconds) for Fun(Args). +-spec tc(Fun :: function(), Arguments :: [term()]) -> {Time :: integer(), Value :: term()}. +tc(F, A) -> + T1 = erlang:monotonic_time(), + Val = apply(F, A), + T2 = erlang:monotonic_time(), + Time = cvrTimeUnit(T2 - T1, native, nanosecond), + {Time, Val}. + +%% Measure the execution time (in nanoseconds) for an MFA. +-spec tc(Module :: module(), Function :: atom(), Arguments :: [term()]) -> {Time :: integer(), Value :: term()}. +tc(M, F, A) -> + T1 = erlang:monotonic_time(), + Val = apply(M, F, A), + T2 = erlang:monotonic_time(), + Time = cvrTimeUnit(T2 - T1, native, nanosecond), + {Time, Val}. + +-spec cvrTimeUnit(Time :: integer(), FromUnit :: erlang:time_unit(), ToUnit :: erlang:time_unit()) -> ConvertedTime :: integer(). +cvrTimeUnit(Time, FromUnit, ToUnit) -> + try + FU = + case FromUnit of + native -> erts_internal:time_unit(); + perf_counter -> erts_internal:perf_counter_unit(); + nanosecond -> 1000 * 1000 * 1000; + microsecond -> 1000 * 1000; + millisecond -> 1000; + second -> 1 + end, + TU = + case ToUnit of + native -> erts_internal:time_unit(); + perf_counter -> erts_internal:perf_counter_unit(); + nanosecond -> 1000 * 1000 * 1000; + microsecond -> 1000 * 1000; + millisecond -> 1000; + second -> 1 + end, + case Time < 0 of + true -> (TU * Time - (FU - 1)) div FU; + _ -> TU * Time div FU + end + catch + _ : _ -> + erlang:error(badarg, [Time, FromUnit, ToUnit]) + end. + +%% 单进程循环测试:LoopTimes是循环次数 +%% utTc:ts(LoopTimes, Module, Function, ArgsList). +%% 多进程并发测试:SpawnProcessesCount是并发的进程数 LoopTimes是循环次数 +%% utTc:tm(ProcessesCount, LoopTimes, Module, Function, ArgsList). + +doTc(M, F, A) -> + T1 = erlang:monotonic_time(), + apply(M, F, A), + T2 = erlang:monotonic_time(), + cvrTimeUnit(T2 - T1, native, nanosecond). + +distribution(List, Aver) -> + distribution(List, Aver, 0, 0). +distribution([H | T], Aver, Greater, Less) -> + case H > Aver of + true -> + distribution(T, Aver, Greater + 1, Less); + false -> + distribution(T, Aver, Greater, Less + 1) + end; +distribution([], _Aver, Greater, Less) -> + {Greater, Less}. + +%% =================================================================== +%% test: one process test N times +%% =================================================================== +ts(LoopTime, M, F, A) -> + {Max, Min, Sum, Aver, Greater, Less} = loopTs(LoopTime, M, F, A, LoopTime, 0, 0, 0, []), + io:format("=====================~n"), + io:format("execute Args:~p~n", [A]), + io:format("execute Fun :~p~n", [F]), + io:format("execute Mod :~p~n", [M]), + 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])]), + io:format("MinTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Min), float_to_binary(Min / 1000000000, [{decimals, 6}, compact])]), + io:format("SumTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Sum), float_to_binary(Sum / 1000000000, [{decimals, 6}, compact])]), + io:format("AvgTime: ~10s(ns) ~10s(s)~n", [float_to_binary(Aver, [{decimals, 6}, compact]), float_to_binary(Aver / 1000000000, [{decimals, 6}, compact])]), + io:format("Grar : ~10s(cn) ~10s(~s)~n", [integer_to_binary(Greater), float_to_binary(Greater / LoopTime, [{decimals, 2}]), <<"%">>]), + io:format("Less : ~10s(cn) ~10s(~s)~n", [integer_to_binary(Less), float_to_binary(Less / LoopTime, [{decimals, 2}]), <<"%">>]), + io:format("=====================~n"). + + +loopTs(0, _M, _F, _A, LoopTime, Max, Min, Sum, List) -> + Aver = Sum / LoopTime, + {Greater, Less} = distribution(List, Aver), + {Max, Min, Sum, Aver, Greater, Less}; +loopTs(Index, M, F, A, LoopTime, Max, Min, Sum, List) -> + Nanosecond = doTc(M, F, A), + NewSum = Sum + Nanosecond, + if + Max == 0 -> + NewMax = NewMin = Nanosecond; + Max < Nanosecond -> + NewMax = Nanosecond, + NewMin = Min; + Min > Nanosecond -> + NewMax = Max, + NewMin = Nanosecond; + true -> + NewMax = Max, + NewMin = Min + end, + loopTs(Index - 1, M, F, A, LoopTime, NewMax, NewMin, NewSum, [Nanosecond | List]). + + +%% =================================================================== +%% Concurrency test: N processes each test one time +%% =================================================================== + +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"), + io:format("execute Args:~p~n", [A]), + io:format("execute Fun :~p~n", [F]), + io:format("execute Mod :~p~n", [M]), + io:format("execute LoopTime:~p~n", [LoopTime]), + io:format("execute ProcCnts:~p~n", [ProcCnt]), + io:format("MaxTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Max), float_to_binary(Max / 1000000000, [{decimals, 6}, compact])]), + io:format("MinTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Min), float_to_binary(Min / 1000000000, [{decimals, 6}, compact])]), + io:format("SumTime: ~10s(ns) ~10s(s)~n", [integer_to_binary(Sum), float_to_binary(Sum / 1000000000, [{decimals, 6}, compact])]), + io:format("AvgTime: ~10s(ns) ~10s(s)~n", [float_to_binary(Aver, [{decimals, 6}, compact]), float_to_binary(Aver / 1000000000, [{decimals, 6}, compact])]), + io:format("Grar : ~10s(cn) ~10s(~s)~n", [integer_to_binary(Greater), float_to_binary(Greater / LoopTime, [{decimals, 2}]), <<"%">>]), + io:format("Less : ~10s(cn) ~10s(~s)~n", [integer_to_binary(Less), float_to_binary(Less / LoopTime, [{decimals, 2}]), <<"%">>]), + io:format("=====================~n"). + + +loopSpawn(0, _, _, _, _, _) -> + ok; +loopSpawn(ProcCnt, M, F, A, CollectorPid, LoopTime) -> + spawn_link(fun() -> worker(LoopTime, M, F, A, CollectorPid) end), + loopSpawn(ProcCnt - 1, M, F, A, CollectorPid, LoopTime). + +collector(0, Max, Min, Sum, ProcCnt, List) -> + Aver = Sum / ProcCnt, + {Greater, Less} = distribution(List, Aver), + {Max, Min, Sum, Aver, Greater, Less}; +collector(Index, Max, Min, Sum, ProcCnt, List) -> + receive + {result, Nanosecond} -> + NewSum = Sum + Nanosecond, + if + Max == 0 -> + NewMax = NewMin = Nanosecond; + Max < Nanosecond -> + NewMax = Nanosecond, + NewMin = Min; + Min > Nanosecond -> + NewMax = Max, + NewMin = Nanosecond; + true -> + NewMax = Max, + NewMin = Min + end, + collector(Index - 1, NewMax, NewMin, NewSum, ProcCnt, [Nanosecond | List]) + after 1800000 -> + io:format("execute time out~n"), + ok + end. + +worker(LoopTime, M, F, A, CollectorPid) -> + SumTime = loopTm(LoopTime, M, F, A, 0), + CollectorPid ! {result, SumTime}. + +loopTm(0, _, _, _, SumTime) -> + SumTime; +loopTm(LoopTime, M, F, A, SumTime) -> + Microsecond = doTc(M, F, A), + loopTm(LoopTime - 1, M, F, A, SumTime + Microsecond). + +test(N) -> + M1 = erlang:monotonic_time(), + timer:sleep(N), + M2 = erlang:monotonic_time(), + Time = cvrTimeUnit(M2 - M1, native, nanosecond), + io:format("IMY******************111 ~p~n", [Time]), + + S1 = erlang:system_time(nanosecond), + timer:sleep(N), + S2 = erlang:system_time(nanosecond), + io:format("IMY******************222 ~p~n", [S2 - S1]). + + + diff --git a/config/test.txt b/src/test/test.txt similarity index 80% rename from config/test.txt rename to src/test/test.txt index 8fcec00..86da781 100644 --- a/config/test.txt +++ b/src/test/test.txt @@ -1,3 +1,8 @@ 去你妈的 + + 你妈 + + +