91 lines
3.1 KiB
Erlang
91 lines
3.1 KiB
Erlang
-module(statistician).
|
|
-export([init/0, startRecording/0, inactive/0, stopRecording/0, printStatistics/0]).
|
|
|
|
-record(stats, {requestsCount = 0,
|
|
errorsCount = 0,
|
|
responseTimesAvg = 0,
|
|
responseTimesSquareAvg = 0
|
|
}).
|
|
|
|
%% @spec init() -> void()
|
|
%% @doc Initialize the statistician.
|
|
%% The process it's named "statistician".
|
|
init() ->
|
|
StatisticianPid = spawn(?MODULE, inactive, []),
|
|
register(statistician, StatisticianPid).
|
|
|
|
%% @spec stopRecording() -> void()
|
|
%% @doc Stop recording the statistics.
|
|
stopRecording() ->
|
|
statistician ! {stop_recording}.
|
|
|
|
%% @spec startRecording() -> void()
|
|
%% @doc Start recording the statistics.
|
|
startRecording() ->
|
|
statistician ! {start_recording}.
|
|
|
|
%% @spec inactive() -> void()
|
|
%% @doc Remain inactive waiting to record the statistics.
|
|
%% All messages received while waiting are discarded.
|
|
inactive() ->
|
|
receive
|
|
{start_recording} -> recording(#stats{});
|
|
_ -> inactive()
|
|
end.
|
|
|
|
%% @spec recording(S::#stats{}) -> ok
|
|
%% @doc Calculate the statistics of the received response times.
|
|
recording(S = #stats{requestsCount = RequestsCount,
|
|
errorsCount = ErrorsCount,
|
|
responseTimesAvg = ResponseTimesAvg,
|
|
responseTimesSquareAvg = ResponseTimesSquareAvg}) ->
|
|
receive
|
|
{ok, Begin, End} ->
|
|
NewResponseTime = (End - Begin) / 1000000,
|
|
recording(S#stats{requestsCount = RequestsCount + 1,
|
|
responseTimesAvg =
|
|
average(RequestsCount, ResponseTimesAvg, NewResponseTime),
|
|
responseTimesSquareAvg =
|
|
average(RequestsCount, ResponseTimesSquareAvg, math:pow(NewResponseTime, 2))
|
|
});
|
|
{error, _Begin, _End} ->
|
|
recording(S#stats{errorsCount = ErrorsCount = 1});
|
|
{connection_error, _Begin, _End} ->
|
|
recording(S#stats{errorsCount = ErrorsCount = 1});
|
|
{printStats} ->
|
|
Variance = variance(S),
|
|
io:format(
|
|
"Num requests: ~p~nAverage response time: ~pms~nVariance: ~p~nDeviation: ~p~nErrors: ~p~n",
|
|
[RequestsCount, ResponseTimesAvg, Variance, math:sqrt(Variance), ErrorsCount]
|
|
),
|
|
recording(S);
|
|
{stop_recording} ->
|
|
inactive()
|
|
end.
|
|
|
|
%% @spec printStatistics() -> void()
|
|
%% @doc Print the statistics of the requests completed so far.
|
|
printStatistics() ->
|
|
statistician ! {printStats}.
|
|
|
|
%% @spec average(OldCount::integer(), OldAvg::float(),
|
|
%% NewValue::float()) -> float()
|
|
%% @doc Calculate the average given the old count, the old average and
|
|
%% the new value.
|
|
average(OldCount, OldAvg, NewValue) ->
|
|
case OldCount of
|
|
0 -> NewValue;
|
|
_ -> OldAvg * (OldCount / (OldCount + 1)) + NewValue / (OldCount + 1)
|
|
end.
|
|
|
|
%% @spec variance(#stats{}) -> float()
|
|
%% @doc Calculate the variance of the response time.
|
|
%% If the number of requests is zero then it returns zero.
|
|
variance(#stats{requestsCount = RequestsCount,
|
|
responseTimesAvg = ResponseTimesAvg,
|
|
responseTimesSquareAvg = ResponseTimesSquareAvg}) ->
|
|
case RequestsCount of
|
|
0 -> 0;
|
|
_ -> ResponseTimesSquareAvg - math:pow(ResponseTimesAvg, 2)
|
|
end.
|