|
-module(utTc).
|
|
|
|
-compile(inline).
|
|
-compile({inline_size, 128}).
|
|
|
|
-export([
|
|
tc/1
|
|
, tc/2
|
|
, tc/3
|
|
, tc/4
|
|
, tc/5
|
|
, 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 = erlang:convert_time_unit(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 = erlang:convert_time_unit(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 = erlang:convert_time_unit(T2 - T1, native, nanosecond),
|
|
{Time, Val}.
|
|
|
|
%% 单进程循环测试: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(),
|
|
erlang:convert_time_unit(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
|
|
%% ===================================================================
|
|
tc(LoopTime, M, F, A) ->
|
|
{Max, Min, Sum, Aver, Greater, Less} = loopTs(LoopTime, M, F, A, LoopTime, 0, 0, 0, []),
|
|
io:format("=====================~n"),
|
|
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: ~15s(ns) ~15s(s)~n", [integer_to_binary(Max), float_to_binary(Max / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("MinTime: ~15s(ns) ~15s(s)~n", [integer_to_binary(Min), float_to_binary(Min / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("SumTime: ~15s(ns) ~15s(s)~n", [integer_to_binary(Sum), float_to_binary(Sum / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("AvgTime: ~15s(ns) ~15s(s)~n", [float_to_binary(Aver, [{decimals, 2}, compact]), float_to_binary(Aver / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("Grar : ~15s(cn) ~15s(~s)~n", [integer_to_binary(Greater), float_to_binary(Greater / LoopTime, [{decimals, 2}]), <<"%">>]),
|
|
io:format("Less : ~15s(cn) ~15s(~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
|
|
%% ===================================================================
|
|
|
|
tc(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"),
|
|
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]),
|
|
io:format("PMaxTime: ~15s(ns) ~15s(s)~n", [integer_to_binary(Max), float_to_binary(Max / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("PMinTime: ~15s(ns) ~15s(s)~n", [integer_to_binary(Min), float_to_binary(Min / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("PSumTime: ~15s(ns) ~15s(s)~n", [integer_to_binary(Sum), float_to_binary(Sum / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("PAvgTime: ~15s(ns) ~15s(s)~n", [float_to_binary(Aver, [{decimals, 2}, compact]), float_to_binary(Aver / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("FAvgTime: ~15s(ns) ~15s(s)~n", [float_to_binary(Aver / LoopTime, [{decimals, 2}, compact]), float_to_binary(Aver / LoopTime / 1000000000, [{decimals, 2}, compact])]),
|
|
io:format("PGrar : ~15s(cn) ~15s(~s)~n", [integer_to_binary(Greater), float_to_binary(Greater / ProcCnt, [{decimals, 2}]), <<"%">>]),
|
|
io:format("PLess : ~15s(cn) ~15s(~s)~n", [integer_to_binary(Less), float_to_binary(Less / ProcCnt, [{decimals, 2}]), <<"%">>]),
|
|
io:format("=====================~n").
|
|
|
|
|
|
loopSpawn(0, _, _, _, _, _, AllPid) ->
|
|
[OnePid ! do_work || OnePid <- AllPid],
|
|
ok;
|
|
loopSpawn(ProcCnt, M, F, A, CollectorPid, LoopTime, AllPid) ->
|
|
Pid = spawn_link(fun() -> worker(LoopTime, M, F, A, CollectorPid) end),
|
|
loopSpawn(ProcCnt - 1, M, F, A, CollectorPid, LoopTime, [Pid | AllPid]).
|
|
|
|
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) ->
|
|
receive
|
|
do_work ->
|
|
SumTime = loopTm(LoopTime, M, F, A, 0),
|
|
CollectorPid ! {result, SumTime}
|
|
end.
|
|
|
|
loopTm(0, _, _, _, SumTime) ->
|
|
SumTime;
|
|
loopTm(LoopTime, M, F, A, SumTime) ->
|
|
Nanosecond = doTc(M, F, A),
|
|
loopTm(LoopTime - 1, M, F, A, SumTime + Nanosecond).
|
|
|
|
test(N) ->
|
|
M1 = erlang:monotonic_time(),
|
|
timer:sleep(N),
|
|
M2 = erlang:monotonic_time(),
|
|
Time = erlang:convert_time_unit(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]).
|
|
|
|
|
|
|