16
16
17
17
-module (rabbit_vm ).
18
18
19
- -export ([memory /0 , binary /0 , ets_tables_memory /1 ]).
19
+ -export ([memory /0 , total_memory / 0 , binary /0 , ets_tables_memory /1 ]).
20
20
21
21
-define (MAGIC_PLUGINS , [" cowboy" , " ranch" , " sockjs" ]).
22
22
30
30
31
31
% %----------------------------------------------------------------------------
32
32
33
- % % Like erlang:memory(), but with awareness of rabbit-y things
34
33
memory () ->
35
34
All = interesting_sups (),
36
35
{Sums , _Other } = sum_processes (
@@ -41,7 +40,7 @@ memory() ->
41
40
[aggregate (Names , Sums , memory , fun (X ) -> X end )
42
41
|| Names <- distinguished_interesting_sups ()],
43
42
44
- Mnesia = mnesia_memory (),
43
+ MnesiaETS = mnesia_memory (),
45
44
MsgIndexETS = ets_memory (msg_stores ()),
46
45
MetricsETS = ets_memory ([rabbit_metrics ]),
47
46
MetricsProc =
@@ -53,8 +52,9 @@ memory() ->
53
52
0
54
53
end ,
55
54
MgmtDbETS = ets_memory ([rabbit_mgmt_storage ]),
55
+ OsTotal = total_memory (),
56
56
57
- [{total , Total },
57
+ [{total , ErlangTotal },
58
58
{processes , Processes },
59
59
{ets , ETS },
60
60
{atom , Atom },
@@ -67,30 +67,137 @@ memory() ->
67
67
- ConnsReader - ConnsWriter - ConnsChannel - ConnsOther
68
68
- Qs - QsSlave - MsgIndexProc - Plugins - MgmtDbProc - MetricsProc ,
69
69
70
- [{total , Total },
70
+ [
71
+ % % Connections
71
72
{connection_readers , ConnsReader },
72
73
{connection_writers , ConnsWriter },
73
74
{connection_channels , ConnsChannel },
74
75
{connection_other , ConnsOther },
76
+
77
+ % % Queues
75
78
{queue_procs , Qs },
76
79
{queue_slave_procs , QsSlave },
80
+
81
+ % % Processes
77
82
{plugins , Plugins },
78
83
{other_proc , lists :max ([0 , OtherProc ])}, % % [1]
79
- {mnesia , Mnesia },
84
+
85
+ % % Metrics
80
86
{metrics , MetricsETS + MetricsProc },
81
87
{mgmt_db , MgmtDbETS + MgmtDbProc },
82
- {msg_index , MsgIndexETS + MsgIndexProc },
83
- {other_ets , ETS - Mnesia - MsgIndexETS - MgmtDbETS },
88
+
89
+ % % ETS
90
+ {mnesia , MnesiaETS },
91
+ {other_ets , ETS - MnesiaETS - MetricsETS - MgmtDbETS - MsgIndexETS },
92
+
93
+ % % Messages (mostly, some binaries are not messages)
84
94
{binary , Bin },
95
+ {msg_index , MsgIndexETS + MsgIndexProc },
96
+
97
+ % % System
85
98
{code , Code },
86
99
{atom , Atom },
87
- {other_system , System - ETS - Atom - Bin - Code }].
100
+ {other_system , System - ETS - Bin - Code - Atom + ( OsTotal - ErlangTotal )},
88
101
102
+ {total , OsTotal }
103
+ ].
89
104
% % [1] - erlang:memory(processes) can be less than the sum of its
90
105
% % parts. Rather than display something nonsensical, just silence any
91
106
% % claims about negative memory. See
92
107
% % http://erlang.org/pipermail/erlang-questions/2012-September/069320.html
93
108
109
+ % % Memory reported by erlang:memory(total) is not supposed to
110
+ % % be equal to the total size of all pages mapped to the emulator,
111
+ % % according to http://erlang.org/doc/man/erlang.html#memory-0
112
+ % % erlang:memory(total) under-reports memory usage by around 20%
113
+ -spec total_memory () -> Bytes :: integer ().
114
+ total_memory () ->
115
+ case get_memory_calculation_strategy () of
116
+ rss ->
117
+ case get_system_process_resident_memory () of
118
+ {ok , MemInBytes } ->
119
+ MemInBytes ;
120
+ {error , Reason } ->
121
+ rabbit_log :debug (" Unable to get system memory used. Reason: ~p ."
122
+ " Falling back to erlang memory reporting" ,
123
+ [Reason ]),
124
+ erlang :memory (total )
125
+ end ;
126
+ erlang ->
127
+ erlang :memory (total )
128
+ end .
129
+
130
+ -spec get_memory_calculation_strategy () -> rss | erlang .
131
+ get_memory_calculation_strategy () ->
132
+ case application :get_env (rabbit , vm_memory_calculation_strategy , rss ) of
133
+ erlang ->
134
+ erlang ;
135
+ rss ->
136
+ rss ;
137
+ UnsupportedValue ->
138
+ rabbit_log :warning (
139
+ " Unsupported value '~p ' for vm_memory_calculation_strategy. "
140
+ " Supported values: (rss|erlang). "
141
+ " Defaulting to 'rss'" ,
142
+ [UnsupportedValue ]
143
+ ),
144
+ rss
145
+ end .
146
+
147
+ -spec get_system_process_resident_memory () -> {ok , Bytes :: integer ()} | {error , term ()}.
148
+ get_system_process_resident_memory () ->
149
+ try
150
+ get_system_process_resident_memory (os :type ())
151
+ catch _ :Error ->
152
+ {error , {" Failed to get process resident memory" , Error }}
153
+ end .
154
+
155
+ get_system_process_resident_memory ({unix ,darwin }) ->
156
+ get_ps_memory ();
157
+
158
+ get_system_process_resident_memory ({unix , linux }) ->
159
+ get_ps_memory ();
160
+
161
+ get_system_process_resident_memory ({unix ,freebsd }) ->
162
+ get_ps_memory ();
163
+
164
+ get_system_process_resident_memory ({unix ,openbsd }) ->
165
+ get_ps_memory ();
166
+
167
+ get_system_process_resident_memory ({win32 ,_OSname }) ->
168
+ OsPid = os :getpid (),
169
+ Cmd = " tasklist /fi \" pid eq " ++ OsPid ++ " \" /fo LIST 2>&1 " ,
170
+ CmdOutput = os :cmd (Cmd ),
171
+ % % Memory usage is displayed in kilobytes
172
+ % % with comma-separated thousands
173
+ case re :run (CmdOutput , " Mem Usage:\\ s+([0-9,]+)\\ s+K" , [{capture , all_but_first , list }]) of
174
+ {match , [Match ]} ->
175
+ NoCommas = [ N || N <- Match , N =/= $, ],
176
+ {ok , list_to_integer (NoCommas ) * 1024 };
177
+ _ ->
178
+ {error , {unexpected_output_from_command , Cmd , CmdOutput }}
179
+ end ;
180
+
181
+ get_system_process_resident_memory ({unix , sunos }) ->
182
+ get_ps_memory ();
183
+
184
+ get_system_process_resident_memory ({unix , aix }) ->
185
+ get_ps_memory ();
186
+
187
+ get_system_process_resident_memory (_OsType ) ->
188
+ {error , not_implemented_for_os }.
189
+
190
+ get_ps_memory () ->
191
+ OsPid = os :getpid (),
192
+ Cmd = " ps -p " ++ OsPid ++ " -o rss=" ,
193
+ CmdOutput = os :cmd (Cmd ),
194
+ case re :run (CmdOutput , " [0-9]+" , [{capture , first , list }]) of
195
+ {match , [Match ]} ->
196
+ {ok , list_to_integer (Match ) * 1024 };
197
+ _ ->
198
+ {error , {unexpected_output_from_command , Cmd , CmdOutput }}
199
+ end .
200
+
94
201
binary () ->
95
202
All = interesting_sups (),
96
203
{Sums , Rest } =
0 commit comments