1

I have a few questions regarding processes because I get a high CPU-usage increase after running Eunit test on several connected modules I have created that consists of a supervised structure of gen_servers in erlang with a main server that communicates with another server through spawned workers. I think the CPU-usage might arise because processes aren't exited correctly and keeps running in the background.

I have tried to exit the called main servers after conducting the tests. I go about it in the following way:

cache_client_read_val() ->
  {"Reads from a key once a key is placed in the cache by set(FS, key1, 2, 2)",
  fun() -> 
      {_Response, Pid} = cache:new(80),
      Val = 2,
      Key = key1,
      cache:set(Pid, key1, Val, 2),
      cache:set(Pid, key2, 4, 2),      
      ok = ?assertMatch({ok, Val}, cache:read(Pid, Key)),
      ok = cache:stop(Pid)
  end}.

For the main server frappe it can be called using the set and fresh operation.

It looks like the following for the main-server and the other server (lru) it starts up when created:

init(Cap) ->        
    process_flag(trap_exit, true),
    {ok, LRU} =  start_link(lru, {self(), Cap}),   
    {ok,  LRU}.

set(Fs, Key, Value, C) ->
  gen_server:call(Fs, {set, Key, Value, C}).

stop(Name) ->
    gen_server:call(Name, stop).

handle_call(stop, _From, State) ->
    {stop, normal, ok, State};


handle_call({set, Key, Value, C}, APIid, {Cap, LRU, WrMap, Workers}) ->           
    {Resp, WrMap3, Workers3} = case (Cap - C) < 0 of
      true ->
        {{error, "Costs too high"}, WrMap, nothing};
      false ->       
        ...
        {ok, WrMap2, Workers2}
      end,    
    {reply, Resp, {Cap, LRU, WrMap3, Workers3}} 

...

For workers created to communicate between the two servers I use:

process_flag(trap_exit, true),
        Wid = spawn_link(fun() -> gen_server:call(LRU, Args) end)

Which I guess would kill the workers as well once the server (calling process) is 'stopped' such as is the case in my test suite.

This leads to quite a few questions:

Is it likely that the high CPU-usage caused by beam.smp is due to zombie processes, caused by bad exit behaviour? And is there a way I can identify ID's of these processes, I have tried using registered(..) as recommended here: How to show all processes in Erlang?. However I was only able to see the names of Pids that corresponded to the shell Pids and that had a name. Can you see Pids without names as well.

How might I in that case exit the processes correctly, so they will not use up CPU?

Piskator
  • 605
  • 1
  • 9
  • A gen_server process that doesn't receive any messages or calls uses very little CPU - it just waits for incoming requests. You could try using a tool such as entop to see which processes are active: https://github.com/mazenharake/entop – legoscia Aug 02 '22 at 08:08
  • But what about `spawn(..)` do they use much CPU? – Piskator Aug 02 '22 at 11:03
  • I try to exit the `spawn(..)` proces with `exit(SpawnID, Reason)` but I dont know if this correctly will exit it. – Piskator Aug 02 '22 at 11:04
  • And likewise, if I let a gen_server run with `[]`, as it's next state argument, does it mean that the process will be ended (exited correctly) although no call to `gen_server:terminate(...)` were made? – Piskator Aug 02 '22 at 11:15
  • That `exit` call will kill the process, as long as it's not trapping exits. (Use `exit(Pid, kill)` to bypass that.) A more common way for a spawned process to exit is for the function in the `spawn` call to return. The way to stop a gen_server from within is by returning a `{stop, ...}` tuple, like in one of the `handle_call` clauses in the code above. – legoscia Aug 02 '22 at 12:17
  • Is it the case that by trapping a proces, you can no longer exit the proces it's proces ID is saved in the `process_trap(...)`-proces and thereby is kept until that `process_trap(...)`-proces dies. – Piskator Aug 03 '22 at 12:01

0 Answers0