154 lines
5.0 KiB
Erlang
154 lines
5.0 KiB
Erlang
-module(requester).
|
|
-export([init/0, startServiceTime/1, startOpenLoop/2, startClosedLoop/3,
|
|
waiting/1, stop/1, printActiveWorkers/1, exponential_time/1]).
|
|
|
|
%% @spec init() -> pid()
|
|
%% @doc Initialize the requester.
|
|
%% This fuction will not return until all the pages will be read from
|
|
%% the file and shuffled.
|
|
init() ->
|
|
Filename = application:get_env(spsBenchmark, pageFile, "pages.csv"),
|
|
Domain = application:get_env(spsBenchmark, domain, "https://en.wikipedia.org/wiki/"),
|
|
NumPages = application:get_env(spsBenchmark, nPages, 1000),
|
|
Pages = shuffle:list(resources:n_pages(Filename, 0, NumPages)),
|
|
Links = resources:urls(Domain, Pages),
|
|
Pid = spawn(?MODULE, waiting, [Links]),
|
|
Pid.
|
|
|
|
%% @spec waiting(Links::[string()]) -> void()
|
|
%% @doc Keep the links while waiting to start the requester.
|
|
waiting(Links) ->
|
|
receive
|
|
{service_time} -> service_time(Links);
|
|
{open_loop, Rate} -> open_loop(Rate, Links, 0);
|
|
{closed_loop, Rate, NumWorkers} -> closed_loop(Rate, NumWorkers, Links)
|
|
end.
|
|
|
|
%% @spec startServiceTime(Pid::pid()) -> void()
|
|
%% @doc Start the requests to calculate the service time.
|
|
startServiceTime(Pid) ->
|
|
Pid ! {service_time}.
|
|
|
|
%% @spec startOpenLoop(Pid::pid(), Rate::float()) -> void()
|
|
%% @doc Start the open loop requests.
|
|
startOpenLoop(Pid, Rate) ->
|
|
Pid ! {open_loop, Rate}.
|
|
|
|
%% @spec startClosedLoop(Pid::pid(), Rate::float(),
|
|
%% NumWorkers::integer()) -> void()
|
|
%% @doc Start the closed loop requests.
|
|
startClosedLoop(Pid, Rate, NumWorkers) ->
|
|
Pid ! {closed_loop, Rate, NumWorkers}.
|
|
|
|
%% @spec stop(Pid::pid()) -> void()
|
|
%% @doc Stop the benchmark.
|
|
stop(Pid) ->
|
|
Pid ! {stop}.
|
|
|
|
%% @spec printActiveWorkers(Pid::pid()) -> void()
|
|
%% @doc Print the number of active workers of the requester with the
|
|
%% specific pid.
|
|
printActiveWorkers(Pid) ->
|
|
Pid ! {print_active_workers}.
|
|
|
|
%% @spec service_time(Links::[string()]) -> void()
|
|
%% @doc Generate a single request to calculate the service time and then wait.
|
|
service_time(Links) ->
|
|
case Links of
|
|
[] -> ok;
|
|
[Link | RemainigLinks] ->
|
|
generate_worker(Link),
|
|
service_time_wait(RemainigLinks)
|
|
end.
|
|
|
|
%% @spec service_time_wait(Links::[string()]) -> void()
|
|
%% @doc Wait until the service time request ends and then generate a new one.
|
|
service_time_wait(Links) ->
|
|
receive
|
|
{'DOWN', _MonitorReference, process, _Pid, _Reason} ->
|
|
service_time(Links);
|
|
{print_active_workers} ->
|
|
service_time_wait(Links);
|
|
{stop} -> ok
|
|
end.
|
|
|
|
%% @spec open_loop(Rate::float(), Links::[string()],
|
|
%% ActiveWorkers::integer()) -> ok
|
|
%% @doc Generate requests in open loop with an exponential sampling.
|
|
open_loop(Rate, Links, ActiveWorkers) ->
|
|
receive
|
|
{'DOWN', _MonitorReference, process, _Pid, _Reason} ->
|
|
open_loop(Rate, Links, ActiveWorkers - 1);
|
|
{print_active_workers} ->
|
|
io:format("Num active requests: ~p~n", [ActiveWorkers]),
|
|
open_loop(Rate, Links, ActiveWorkers);
|
|
{stop} -> ok
|
|
after exponential_time(Rate) ->
|
|
case Links of
|
|
[] -> case ActiveWorkers of
|
|
0 -> ok;
|
|
_ -> open_loop(Rate, Links, ActiveWorkers)
|
|
end;
|
|
[Link | RemainigLinks] ->
|
|
generate_worker(Link),
|
|
open_loop(Rate, RemainigLinks, ActiveWorkers + 1)
|
|
end
|
|
end.
|
|
|
|
%% @spec closed_loop(Rate::float(), NumWorkers::integer(),
|
|
%% Links::[string()]) -> ok
|
|
%% @doc Generate requests in closed loop.
|
|
closed_loop(Rate, NumWorkers, Links) ->
|
|
closed_loop_aux(Rate, NumWorkers,
|
|
partition:list(Links, length(Links) div NumWorkers)).
|
|
|
|
%% @spec closed_loop_aux(Rate::float(), NumWorkers::integer(),
|
|
%% LinksLists::[[string()]]) -> ok
|
|
%% @doc Auxiliary function for closed_loop that takes the Links already
|
|
%% partitioned for each worker.
|
|
closed_loop_aux(Rate, NumWorkers, LinksLists) ->
|
|
case NumWorkers of
|
|
0 -> closed_loop_wait();
|
|
_ ->
|
|
[WorkersLinks | OtherLinks] = LinksLists,
|
|
generate_loop_worker(WorkersLinks, Rate),
|
|
closed_loop_aux(Rate, NumWorkers - 1, OtherLinks)
|
|
end.
|
|
|
|
%% @spec closed_loop_wait() -> void()
|
|
%% @doc Wait until the closed loop is stopped.
|
|
closed_loop_wait() ->
|
|
receive
|
|
{stop} -> exit(shutdown)
|
|
end.
|
|
|
|
%% @spec exponential_time(Rate::float()) -> integer()
|
|
%% @doc Get the number of millisecond to wait sampling
|
|
%% an exponential variable with specific rate.
|
|
exponential_time(Rate) ->
|
|
round(exponential(Rate) * 1000).
|
|
|
|
%% @spec exponential(Rate::float()) -> float()
|
|
%% @doc Get the sample of an exponential variable with specific rate.
|
|
exponential(Rate) ->
|
|
-math:log(rand:uniform()) / Rate.
|
|
|
|
%% @spec generate_worker(Url::string()) -> void
|
|
%% @doc Spawn and monitor a worker for a given url.
|
|
generate_worker(Url) ->
|
|
spawn_monitor(
|
|
requestWorker,
|
|
request,
|
|
[Url]
|
|
).
|
|
|
|
%% @spec generate_loop_worker(Urls::[string()], Rate::float()) -> void
|
|
%% @doc Spawn and link to a worker that makes requests in a loop
|
|
%% using the given urls.
|
|
generate_loop_worker(Urls, Rate) ->
|
|
spawn_link(
|
|
requestWorker,
|
|
loop_request,
|
|
[Urls, Rate]
|
|
).
|