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