Sketch process origin identification.
authorSiraaj Khandkar <siraaj@khandkar.net>
Wed, 16 Sep 2015 23:18:30 +0000 (19:18 -0400)
committerSiraaj Khandkar <siraaj@khandkar.net>
Wed, 16 Sep 2015 23:27:40 +0000 (19:27 -0400)
src/beam_stats_process.erl

index 412b4f8..9b2ae8a 100644 (file)
@@ -5,10 +5,13 @@
 -export_type(
     [ t/0
     , status/0
+    , ancestor/0
+    , best_known_origin/0
     ]).
 
 -export(
     [ of_pid/1
+    , best_known_origin/1
     , print/1
     ]).
 
     | waiting
     .
 
+-type ancestor() ::
+      {otp_ancestors    , [pid() | atom()]}
+    | {otp_initial_call , mfa()}
+    | {raw_initial_call , mfa()}
+    .
+
+-type best_known_origin() ::
+      {registered_name , atom()}
+    | {ancestry        , [ancestor()]}
+    .
+
 -define(T, #?MODULE).
 
 -type t() ::
@@ -61,11 +75,13 @@ print(
     , total_heap_size   = TotalHeapSize
     , stack_size        = StackSize
     , message_queue_len = MsgQueueLen
-    }
+    }=T
 ) ->
+    BestKnownOrigin = best_known_origin(T),
     io:format("--------------------------------------------------~n"),
     io:format(
         "Pid               : ~p~n"
+        "BestKnownOrigin   : ~p~n"
         "RegisteredNameOpt : ~p~n"
         "InitialCallRaw    : ~p~n"
         "InitialCallOTPOpt : ~p~n"
@@ -77,6 +93,7 @@ print(
         "MsgQueueLen       : ~p~n"
         "~n",
         [ Pid
+        , BestKnownOrigin
         , RegisteredNameOpt
         , InitialCallRaw
         , InitialCallOTPOpt
@@ -102,3 +119,52 @@ pid_info_opt(Pid, Key) ->
     of  {registered_name, []}           -> none
     ;   {_              , {Key, Value}} -> {some, Value}
     end.
+
+%% ============================================================================
+%% Process code origin approximation or naming the anonymous processes.
+%%
+%% At runtime, given a PID, how precicely can we identify the origin of the
+%% code it is running?
+%%
+%% We have these data points:
+%%
+%% - Sometimes   | registered name (if so, we're done)
+%% - Sometimes   | ancestor PIDs or registered names
+%% - Always      | initial_call (can be too generic, such as erlang:apply)
+%% - Always      | current_function (can be too far down the stack)
+%% - Always      | current_location (can be too far down the stack)
+%% - Potentially | application tree, but maybe expensive to compute, need to check
+%% ============================================================================
+
+-define(TAG(Tag), fun (X) -> {Tag, X} end).
+
+-spec best_known_origin(t()) ->
+    best_known_origin().
+best_known_origin(?T{registered_name={some, RegisteredName}}) ->
+    {registered_name, RegisteredName};
+best_known_origin(
+    ?T
+    { pid               = _Pid
+    , registered_name   = none
+    , raw_initial_call  = InitCallRaw
+    , otp_initial_call  = InitCallOTPOpt1
+    , otp_ancestors     = AncestorsOpt1
+    , status            = _Status
+    , memory            = _Memory
+    , total_heap_size   = _TotalHeapSize
+    , stack_size        = _StackSize
+    , message_queue_len = _MsgQueueLen
+    }
+) ->
+    ToSingleton       = fun (X) -> [X] end,
+    InitCallOTPOpt2   = hope_option:map(InitCallOTPOpt1, ?TAG(otp_initial_call)),
+    AncestorsOpt2     = hope_option:map(AncestorsOpt1  , ?TAG(otp_ancestors)),
+    InitCallOTPOpt3   = hope_option:map(InitCallOTPOpt2, ToSingleton),
+    AncestorsOpt3     = hope_option:map(AncestorsOpt2  , ToSingleton),
+    MaybeInitCallOTP  = hope_option:get(InitCallOTPOpt3, []),
+    MaybeAncestors    = hope_option:get(AncestorsOpt3  , []),
+    Ancestry =
+        [{raw_initial_call, InitCallRaw}] ++
+        MaybeInitCallOTP ++
+        MaybeAncestors,
+    {ancestry, Ancestry}.
This page took 0.030139 seconds and 4 git commands to generate.