README.md

# RMPC (Remote Multi Procedure Call)
An Erlang library for calling multiple `M:F/A` of other nodes in **one** request.

# Example
Suppose i have node `x` +200K processes:
```sh
~/rmpc $ erl -sname x
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0  (abort with ^G)
```
```erlang
%% Spawning 200K processes:
(x@codefather)1> lists:foreach(fun(_) -> spawn(fun() -> receive _ -> ok end end) end, lists:seq(1, 200000)).
ok

%% A filter function for giving process with memory >= 10KB:
(x@codefather)2> Filter = fun(Pid) -> case erlang:process_info(Pid, memory) of {_, Int} when Int > 10240 -> true; _ -> false end end.   
#Fun<erl_eval.6.52032458>

(x@codefather)3> lists:filter(Filter, processes()).
[<0.4.0>,<0.31.0>,<0.36.0>,<0.44.0>,<0.46.0>,<0.55.0>,
 <0.57.0>,<0.58.0>,<0.64.0>]

%% Giving time:
(x@codefather)4> timer:tc(lists, filter, [Filter, processes()]).
{412862, %% About 0.4s
 [<0.4.0>,<0.31.0>,<0.36.0>,<0.44.0>,<0.46.0>,<0.55.0>,
  <0.57.0>,<0.58.0>,<0.64.0>]}
```

I want to do this on  node `x` from node `y` using Erlang/OTP `rpc` module:
```sh
~/rmpc $ erl -pa _build/default/lib/rmpc/ebin/ -sname y
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0  (abort with ^G)
```
```erlang
%% Use rpc module:
(y@codefather)1> RPC = fun(Node) ->
(y@codefather)1>  Filter = fun(Pid) -> case rpc:call(Node, erlang, process_info, [Pid, memory]) of {_, Int} when Int > 10240 -> true; _ -> false end end,
(y@codefather)1>  lists:filter(Filter, rpc:call(Node, erlang, processes, []))
(y@codefather)1> end.
#Fun<erl_eval.6.52032458>

%% Giving time:
(y@codefather)2> timer:tc(RPC, [x@codefather]).
{12714994, %% About 13s !
 [<7444.4.0>,<7444.31.0>,<7444.36.0>,<7444.40.0>,<7444.44.0>,
  <7444.46.0>,<7444.48.0>,<7444.55.0>,<7444.57.0>,<7444.58.0>,
  <7444.64.0>]}
```

Finally i want to use our `rmpc` module. First we need to package our code in a module:
```erlang
-module(monitoring).
-export([process_memory_rmpc/0]).

%% Every function with arity 0 which its name ends with _rmpc has to transformed.
%% So you need rmpc header file included.
-include("include/rmpc.hrl").

process_memory_rmpc() ->
    Filter =
        fun(Pid) ->
            case erlang:process_info(Pid, memory) of
                {_, Int} when Int > 10240 ->
                    true;
                _ ->
                    false
            end
        end,
    lists:filter(Filter, processes()).
```

Back to the shell `y`:
```erlang
%% We need to start an RMCP process on that node, I call it monitoring_agent
%% Note that we dont need to have this library beam files there, RMCP will load its binary object code there.
(y@codefather)3> rmpc:start(x@codefather, monitoring_agent).
{ok,<7444.17184.30>}

%% Compiling the code:
(y@codefather)4> c(monitoring).                             
{ok,monitoring}

(y@codefather)5> rmpc:execute(x@codefather, monitoring_agent, monitoring, process_memory_rmpc).
[<7444.4.0>,<7444.31.0>,<7444.36.0>,<7444.40.0>,<7444.44.0>,
 <7444.46.0>,<7444.48.0>,<7444.55.0>,<7444.57.0>,<7444.58.0>,
 <7444.64.0>,<7444.17184.30>]
 
 %% Giving time:
(y@codefather)6> timer:tc(rmpc, execute, [x@codefather, monitoring_agent, monitoring,process_memory_rmpc]).
{417276, %% About 0.4s !
 [<7444.4.0>,<7444.31.0>,<7444.36.0>,<7444.40.0>,<7444.44.0>,
  <7444.46.0>,<7444.48.0>,<7444.55.0>,<7444.57.0>,<7444.58.0>,
  <7444.64.0>,<7444.17184.30>]}
```

### License
`BSD 3-Clause`

### Author
`pouriya.jahanbakhsh@gmail.com`