[erlang-questions] [patch] Suggested improvement to supervisor.erl

Jay Nelson jay@REDACTED
Fri May 16 15:17:03 CEST 2008


I have heard others in the past complain about a simple_one_for_one  
supervisor which launches thousands of children.  When a node becomes  
sluggish (typically running out of memory or too many processes), it  
may be useful to look at the supervisors to find the culprit of the  
excessive demand.  The problem is that which_children/1 will generate  
a list of all the children, thus exacerbating the low resource issue.

I recently came across a situation where I wanted to have a count of  
the number of children, but didn't want to use additional memory in  
determining the number of processes.  My solution was a function  
count_children/1 which returns a property list of counts by  
traversing the existing supervisor children list without copying it.   
The resulting property list has the form:

[{specs, integer()}, {active, integer()}, {supervisors, integer()},  
{workers, integer()}]

In code, the results should of course be treated as a real property  
list, rather than relying on the order of attributes specified  
above.  Specs counts the number of child specifications present,  
active is the number of live child processes, supervisors is the  
number of supervisor processes and workers is the number of child  
processes including those that are no longer alive but have not been  
removed from the supervisor's list.

jay
--------------

Below is a patch that adds count_children/1:

--- stdlib/src/supervisor.erl.orig      2008-04-20 23:09:48.000000000  
-0700
+++ stdlib/src/supervisor.erl   2008-04-20 23:19:27.000000000 -0700
@@ -23,7 +23,7 @@
  -export([start_link/2,start_link/3,
          start_child/2, restart_child/2,
          delete_child/2, terminate_child/2,
-        which_children/1,
+        which_children/1, count_children/1,
          check_childspecs/1]).

  -export([behaviour_info/1]).
@@ -94,6 +94,9 @@
  which_children(Supervisor) ->
      call(Supervisor, which_children).

+count_children(Supervisor) ->
+    call(Supervisor, count_children).
+
  call(Supervisor, Req) ->
      gen_server:call(Supervisor, Req, infinity).

@@ -296,7 +299,49 @@
                     {Name, Pid, ChildType, Mods}
                   end,
                   State#state.children),
-    {reply, Resp, State}.
+    {reply, Resp, State};
+
+handle_call(count_children, _From, State) when ?is_simple(State) ->
+    [#child{child_type = CT}] = State#state.children,
+    {Active, Count} =
+       ?DICT:fold(fun(Pid, _Val, {Alive, Tot}) ->
+                          if is_pid(Pid) -> {Alive+1, Tot +1};
+                             true -> {Alive, Tot + 1} end
+                  end, {0, 0}, State#state.dynamics),
+    Reply = case CT of
+               supervisor -> [{specs, 1}, {active, Active},
+                              {supervisors, Count}, {workers, 0}];
+               worker -> [{specs, 1}, {active, Active},
+                          {supervisors, 0}, {workers, Count}]
+           end,
+    {reply, Reply, State};
+
+handle_call(count_children, _From, State) ->
+
+    %% Specs and children are together on the children list...
+    [Specs, Active, Supers, Workers] =
+       lists:foldl(fun(Child, Counts) ->
+                          count_child(Child, Counts)
+                  end, [0,0,0,0], State#state.children),
+
+    %% Reformat counts to a property list.
+    Reply = [{specs, Specs}, {active, Active},
+            {supervisors, Supers}, {workers, Workers}],
+    {reply, Reply, State}.
+
+
+count_child(#child{pid = Pid, child_type = worker},
+           [Specs, Active, Supers, Workers]) ->
+    case is_pid(Pid) andalso is_process_alive(Pid) of
+       true ->  [Specs+1, Active+1, Supers, Workers+1];
+       false -> [Specs+1, Active, Supers, Workers+1]
+    end;
+count_child(#child{pid = Pid, child_type = supervisor},
+           [Specs, Active, Supers, Workers]) ->
+    case is_pid(Pid) andalso is_process_alive(Pid) of
+       true ->  [Specs+1, Active+1, Supers+1, Workers];
+       false -> [Specs+1, Active, Supers+1, Workers]
+    end.





More information about the erlang-questions mailing list