SPSBenchmark/src/statistician.erl

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.