b0b7da42d4db82f223de8cc299033dfa672fc4ee
[beam_stats.git] / src / beam_stats_process.erl
1 -module(beam_stats_process).
2
3 -include("include/beam_stats_process_ancestry.hrl").
4 -include("include/beam_stats_process.hrl").
5
6 -export_type(
7 [ t/0
8 , status/0
9 , ancestry/0
10 , best_known_origin/0
11 ]).
12
13 -export(
14 [ of_pid/1
15 , get_best_known_origin/1
16 , print/1
17 ]).
18
19 -type status() ::
20 exiting
21 | garbage_collecting
22 | runnable
23 | running
24 | suspended
25 | waiting
26 .
27
28 -type ancestry() ::
29 #beam_stats_process_ancestry{}.
30
31 -type best_known_origin() ::
32 {registered_name , atom()}
33 | {ancestry , ancestry()}
34 .
35
36 -define(T, #?MODULE).
37
38 -type t() ::
39 ?T{}.
40
41 %% ============================================================================
42 %% Public API
43 %% ============================================================================
44
45 -spec of_pid(pid()) ->
46 none % when process is dead
47 | {some, t()} % when process is alive
48 .
49 of_pid(Pid) ->
50 try
51 Dict = pid_info_exn(Pid, dictionary),
52 Ancestry =
53 #beam_stats_process_ancestry
54 { raw_initial_call = pid_info_exn(Pid, initial_call)
55 , otp_initial_call = hope_kv_list:get(Dict, '$initial_call')
56 , otp_ancestors = hope_kv_list:get(Dict, '$ancestors')
57 },
58 T =
59 ?T
60 { pid = Pid
61 , registered_name = pid_info_opt(Pid, registered_name)
62 , ancestry = Ancestry
63 , status = pid_info_exn(Pid, status)
64 , memory = pid_info_exn(Pid, memory)
65 , total_heap_size = pid_info_exn(Pid, total_heap_size)
66 , stack_size = pid_info_exn(Pid, stack_size)
67 , message_queue_len = pid_info_exn(Pid, message_queue_len)
68 },
69 {some, T}
70 catch throw:{process_dead, _} ->
71 none
72 end.
73
74 -spec print(t()) ->
75 ok.
76 print(
77 ?T
78 { pid = Pid
79 , registered_name = RegisteredNameOpt
80 , ancestry = #beam_stats_process_ancestry
81 { raw_initial_call = InitialCallRaw
82 , otp_initial_call = InitialCallOTPOpt
83 , otp_ancestors = AncestorsOpt
84 }
85 , status = Status
86 , memory = Memory
87 , total_heap_size = TotalHeapSize
88 , stack_size = StackSize
89 , message_queue_len = MsgQueueLen
90 }=T
91 ) ->
92 BestKnownOrigin = get_best_known_origin(T),
93 io:format("--------------------------------------------------~n"),
94 io:format(
95 "Pid : ~p~n"
96 "BestKnownOrigin : ~p~n"
97 "RegisteredNameOpt : ~p~n"
98 "InitialCallRaw : ~p~n"
99 "InitialCallOTPOpt : ~p~n"
100 "AncestorsOpt : ~p~n"
101 "Status : ~p~n"
102 "Memory : ~p~n"
103 "TotalHeapSize : ~p~n"
104 "StackSize : ~p~n"
105 "MsgQueueLen : ~p~n"
106 "~n",
107 [ Pid
108 , BestKnownOrigin
109 , RegisteredNameOpt
110 , InitialCallRaw
111 , InitialCallOTPOpt
112 , AncestorsOpt
113 , Status
114 , Memory
115 , TotalHeapSize
116 , StackSize
117 , MsgQueueLen
118 ]
119 ).
120
121 %% ============================================================================
122 %% Private helpers
123 %% ============================================================================
124
125 pid_info_exn(Pid, Key) ->
126 {some, Value} = pid_info_opt(Pid, Key),
127 Value.
128
129 pid_info_opt(Pid, Key) ->
130 case {Key, beam_stats_source:erlang_process_info(Pid, Key)}
131 of {registered_name, []} -> none
132 ; {_ , {Key, Value}} -> {some, Value}
133 ; {_ , undefined} -> throw({process_dead, Pid})
134 end.
135
136 %% ============================================================================
137 %% Process code origin approximation or naming the anonymous processes.
138 %%
139 %% At runtime, given a PID, how precicely can we identify the origin of the
140 %% code it is running?
141 %%
142 %% We have these data points:
143 %%
144 %% - Sometimes | registered name (if so, we're done)
145 %% - Sometimes | ancestor PIDs or registered names
146 %% - Always | initial_call (can be too generic, such as erlang:apply)
147 %% - Always | current_function (can be too far down the stack)
148 %% - Always | current_location (can be too far down the stack)
149 %% - Potentially | application tree, but maybe expensive to compute, need to check
150 %% ============================================================================
151
152 -define(TAG(Tag), fun (X) -> {Tag, X} end).
153
154 -spec get_best_known_origin(t()) ->
155 best_known_origin().
156 get_best_known_origin(?T{registered_name={some, RegisteredName}}) ->
157 {registered_name, RegisteredName};
158 get_best_known_origin(?T{registered_name=none, ancestry=Ancestry}) ->
159 {ancestry, Ancestry}.
This page took 0.074054 seconds and 3 git commands to generate.