Update alignments.
[beam_stats.git] / src / beam_stats_process.erl
CommitLineData
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 49of_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.
77print(
78 ?T
79 { pid = Pid
80 , registered_name = RegisteredNameOpt
3088c08b 81 , ancestry = #beam_stats_process_ancestry
39ff67a6
SK
82 { raw_initial_call = InitialCallRaw
83 , otp_initial_call = InitialCallOTPOpt
84 , otp_ancestors = AncestorsOpt
3088c08b 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().
131pid_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
139pid_info_exn(Pid, Key) ->
140 {some, Value} = pid_info_opt(Pid, Key),
141 Value.
142
143pid_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 170get_best_known_origin(?T{registered_name={some, RegisteredName}}) ->
f2adf421 171 {registered_name, RegisteredName};
3088c08b 172get_best_known_origin(?T{registered_name=none, ancestry=Ancestry}) ->
f2adf421 173 {ancestry, Ancestry}.
This page took 0.039849 seconds and 4 git commands to generate.