1 -module(beam_stats_process).
3 -include("include/beam_stats_process_ancestry.hrl").
4 -include("include/beam_stats_process.hrl").
15 , get_best_known_origin/1
29 #beam_stats_process_ancestry{}.
31 -type best_known_origin() ::
32 {registered_name , atom()}
33 | {ancestry , ancestry()}
41 %% ============================================================================
43 %% ============================================================================
45 -spec of_pid(pid()) ->
48 Dict = pid_info_exn(Pid, dictionary),
50 #beam_stats_process_ancestry
51 { raw_initial_call = pid_info_exn(Pid, initial_call)
52 , otp_initial_call = hope_kv_list:get(Dict, '$initial_call')
53 , otp_ancestors = hope_kv_list:get(Dict, '$ancestors')
57 , registered_name = pid_info_opt(Pid, registered_name)
59 , status = pid_info_exn(Pid, status)
60 , memory = pid_info_exn(Pid, memory)
61 , total_heap_size = pid_info_exn(Pid, total_heap_size)
62 , stack_size = pid_info_exn(Pid, stack_size)
63 , message_queue_len = pid_info_exn(Pid, message_queue_len)
71 , registered_name = RegisteredNameOpt
72 , ancestry = #beam_stats_process_ancestry
73 { raw_initial_call = InitialCallRaw
74 , otp_initial_call = InitialCallOTPOpt
75 , otp_ancestors = AncestorsOpt
79 , total_heap_size = TotalHeapSize
80 , stack_size = StackSize
81 , message_queue_len = MsgQueueLen
84 BestKnownOrigin = get_best_known_origin(T),
85 io:format("--------------------------------------------------~n"),
88 "BestKnownOrigin : ~p~n"
89 "RegisteredNameOpt : ~p~n"
90 "InitialCallRaw : ~p~n"
91 "InitialCallOTPOpt : ~p~n"
95 "TotalHeapSize : ~p~n"
113 %% ============================================================================
115 %% ============================================================================
117 pid_info_exn(Pid, Key) ->
118 {some, Value} = pid_info_opt(Pid, Key),
121 pid_info_opt(Pid, Key) ->
122 case {Key, erlang:process_info(Pid, Key)}
123 of {registered_name, []} -> none
124 ; {_ , {Key, Value}} -> {some, Value}
127 %% ============================================================================
128 %% Process code origin approximation or naming the anonymous processes.
130 %% At runtime, given a PID, how precicely can we identify the origin of the
131 %% code it is running?
133 %% We have these data points:
135 %% - Sometimes | registered name (if so, we're done)
136 %% - Sometimes | ancestor PIDs or registered names
137 %% - Always | initial_call (can be too generic, such as erlang:apply)
138 %% - Always | current_function (can be too far down the stack)
139 %% - Always | current_location (can be too far down the stack)
140 %% - Potentially | application tree, but maybe expensive to compute, need to check
141 %% ============================================================================
143 -define(TAG(Tag), fun (X) -> {Tag, X} end).
145 -spec get_best_known_origin(t()) ->
147 get_best_known_origin(?T{registered_name={some, RegisteredName}}) ->
148 {registered_name, RegisteredName};
149 get_best_known_origin(?T{registered_name=none, ancestry=Ancestry}) ->
150 {ancestry, Ancestry}.