anchor.diff:      process_loop/0,
       register_on_node/4,
       unregister_on_node/4,
  -    wait_registry_propagation/1
  +    join_on_node/3,
  +    leave_on_node/3,
  +    wait_registry_propagation/1,
  +    wait_groups_propagation/1
   ]).
   -export([
       start_profiling/0,
       stop_profiling/0
   ]).
  +
  +%% macros
  +-define(TEST_GROUP_NAME, <<"test-group">>).
   
   %% ===================================================================
   %% API
  
positive.code:         maps:put(Node, Pids, Acc)
      end, #{}, NodesInfo),
  
      %% start registration
      lists:foreach(fun({Node, FromName, _ToName}) ->
          Pids = maps:get(Node, PidsMap),
          rpc:cast(Node, ?MODULE, register_on_node, [CollectorPid, WorkersPerNode, FromName, Pids])
      end, NodesInfo),
  
      %% wait
      RegRemoteNodesTimes = wait_from_all_remote_nodes(nodes(), []),
  
      io:format("----> Remote registration times:~n"),
      io:format("      --> MIN: ~p secs.~n", [lists:min(RegRemoteNodesTimes)]),
      io:format("      --> MAX: ~p secs.~n", [lists:max(RegRemoteNodesTimes)]),
  
      {RegPropagationTimeMs, _} = timer:tc(?MODULE, wait_registry_propagation, [ProcessCount]),
      RegPropagationTime = RegPropagationTimeMs / 1000000,
      io:format("----> Eventual additional time to propagate all to master: ~p secs.~n", [RegPropagationTime]),
  
      %% sum
      RegTakenTime = (lists:max(RegRemoteNodesTimes) + RegPropagationTime),
      RegistrationRate = ProcessCount / RegTakenTime,
      io:format("====> Registeration rate (with propagation): ~p/sec.~n~n", [RegistrationRate]),
  
      timer:sleep(1000),
  
      %% start unregistration
      lists:foreach(fun({Node, FromName, ToName}) ->
          rpc:cast(Node, ?MODULE, unregister_on_node, [CollectorPid, WorkersPerNode, FromName, ToName])
      end, NodesInfo),
  
      %% wait
      UnregRemoteNodesTimes = wait_from_all_remote_nodes(nodes(), []),
  
      io:format("----> Remote unregistration times:~n"),
      io:format("      --> MIN: ~p secs.~n", [lists:min(UnregRemoteNodesTimes)]),
      io:format("      --> MAX: ~p secs.~n", [lists:max(UnregRemoteNodesTimes)]),
  
      {UnregPropagationTimeMs, _} = timer:tc(?MODULE, wait_registry_propagation, [0]),
      UnregPropagationTime = UnregPropagationTimeMs / 1000000,
      io:format("----> Eventual additional time to propagate all to master: ~p secs.~n", [UnregPropagationTime]),
  
      %% sum
      UnregTakenTime = (lists:max(UnregRemoteNodesTimes) + UnregPropagationTime),
      UnregistrationRate = ProcessCount / UnregTakenTime,
      io:format("====> Unregisteration rate (with propagation): ~p/sec.~n~n", [UnregistrationRate]),
  
      %% start re-registration
      lists:foreach(fun({Node, FromName, _ToName}) ->
          Pids = maps:get(Node, PidsMap),
          rpc:cast(Node, ?MODULE, register_on_node, [CollectorPid, WorkersPerNode, FromName, Pids])
      end, NodesInfo),
  
      %% wait
      ReRegRemoteNodesTimes = wait_from_all_remote_nodes(nodes(), []),
  
      io:format("----> Remote re-registration times:~n"),
      io:format("      --> MIN: ~p secs.~n", [lists:min(ReRegRemoteNodesTimes)]),
      io:format("      --> MAX: ~p secs.~n", [lists:max(ReRegRemoteNodesTimes)]),
  
      {ReRegPropagationTimeMs, _} = timer:tc(?MODULE, wait_registry_propagation, [ProcessCount]),
      ReRegPropagationTime = ReRegPropagationTimeMs / 1000000,
      io:format("----> Eventual additional time to propagate all to master: ~p secs.~n", [ReRegPropagationTime]),
  
      %% sum
      ReRegTakenTime = (lists:max(ReRegRemoteNodesTimes) + ReRegPropagationTime),
      ReRegistrationRate = ProcessCount / ReRegTakenTime,
      io:format("====> Re-registeration rate (with propagation): ~p/sec.~n~n", [ReRegistrationRate]),
  
      %% kill all processes
      maps:foreach(fun(_Node, Pids) ->
          lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids)
      end, PidsMap),
  
      %% wait all unregistered
      {KillPropagationTimeMs, _} = timer:tc(?MODULE, wait_registry_propagation, [0]),
      KillPropagationTime = KillPropagationTimeMs / 1000000,
      io:format("----> Time to propagate killed process to to master: ~p secs.~n", [KillPropagationTime]),
  
      KillRate = ProcessCount / KillPropagationTime,
      io:format("====> Unregistered after kill rate (with propagation): ~p/sec.~n~n", [KillRate]),
  
      %% stop node
      init:stop().
  
negative.code:             wait_registry_propagation(DesiredCount)
      end.
  
  wait_groups_propagation(DesiredCount) ->
      case length(syn:members(?TEST_GROUP_NAME)) of
          DesiredCount ->
              ok;
  
          _ ->
              timer:sleep(50),
              wait_groups_propagation(DesiredCount)
      end.
  
  start_profiling() ->
      {ok, P} = eprof:start(),
      eprof:start_profiling(erlang:processes() -- [P]).
  