1 | /* |
2 | * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | #include "precompiled.hpp" |
25 | #include "memory/resourceArea.hpp" |
26 | #include "runtime/mutexLocker.hpp" |
27 | #include "runtime/vmThread.hpp" |
28 | #include "runtime/vmOperations.hpp" |
29 | #include "services/nmtDCmd.hpp" |
30 | #include "services/memReporter.hpp" |
31 | #include "services/memTracker.hpp" |
32 | #include "utilities/globalDefinitions.hpp" |
33 | |
34 | NMTDCmd::NMTDCmd(outputStream* output, |
35 | bool heap): DCmdWithParser(output, heap), |
36 | _summary("summary" , "request runtime to report current memory summary, " \ |
37 | "which includes total reserved and committed memory, along " \ |
38 | "with memory usage summary by each subsytem." , |
39 | "BOOLEAN" , false, "false" ), |
40 | _detail("detail" , "request runtime to report memory allocation >= " |
41 | "1K by each callsite." , |
42 | "BOOLEAN" , false, "false" ), |
43 | _baseline("baseline" , "request runtime to baseline current memory usage, " \ |
44 | "so it can be compared against in later time." , |
45 | "BOOLEAN" , false, "false" ), |
46 | _summary_diff("summary.diff" , "request runtime to report memory summary " \ |
47 | "comparison against previous baseline." , |
48 | "BOOLEAN" , false, "false" ), |
49 | _detail_diff("detail.diff" , "request runtime to report memory detail " \ |
50 | "comparison against previous baseline, which shows the memory " \ |
51 | "allocation activities at different callsites." , |
52 | "BOOLEAN" , false, "false" ), |
53 | _shutdown("shutdown" , "request runtime to shutdown itself and free the " \ |
54 | "memory used by runtime." , |
55 | "BOOLEAN" , false, "false" ), |
56 | _statistics("statistics" , "print tracker statistics for tuning purpose." , \ |
57 | "BOOLEAN" , false, "false" ), |
58 | _scale("scale" , "Memory usage in which scale, KB, MB or GB" , |
59 | "STRING" , false, "KB" ) { |
60 | _dcmdparser.add_dcmd_option(&_summary); |
61 | _dcmdparser.add_dcmd_option(&_detail); |
62 | _dcmdparser.add_dcmd_option(&_baseline); |
63 | _dcmdparser.add_dcmd_option(&_summary_diff); |
64 | _dcmdparser.add_dcmd_option(&_detail_diff); |
65 | _dcmdparser.add_dcmd_option(&_shutdown); |
66 | _dcmdparser.add_dcmd_option(&_statistics); |
67 | _dcmdparser.add_dcmd_option(&_scale); |
68 | } |
69 | |
70 | |
71 | size_t NMTDCmd::get_scale(const char* scale) const { |
72 | if (scale == NULL) return 0; |
73 | return NMTUtil::scale_from_name(scale); |
74 | } |
75 | |
76 | void NMTDCmd::execute(DCmdSource source, TRAPS) { |
77 | // Check NMT state |
78 | // native memory tracking has to be on |
79 | if (MemTracker::tracking_level() == NMT_off) { |
80 | output()->print_cr("Native memory tracking is not enabled" ); |
81 | return; |
82 | } else if (MemTracker::tracking_level() == NMT_minimal) { |
83 | output()->print_cr("Native memory tracking has been shutdown" ); |
84 | return; |
85 | } |
86 | |
87 | const char* scale_value = _scale.value(); |
88 | size_t scale_unit = get_scale(scale_value); |
89 | if (scale_unit == 0) { |
90 | output()->print_cr("Incorrect scale value: %s" , scale_value); |
91 | return; |
92 | } |
93 | |
94 | int nopt = 0; |
95 | if (_summary.is_set() && _summary.value()) { ++nopt; } |
96 | if (_detail.is_set() && _detail.value()) { ++nopt; } |
97 | if (_baseline.is_set() && _baseline.value()) { ++nopt; } |
98 | if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } |
99 | if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } |
100 | if (_shutdown.is_set() && _shutdown.value()) { ++nopt; } |
101 | if (_statistics.is_set() && _statistics.value()) { ++nopt; } |
102 | |
103 | if (nopt > 1) { |
104 | output()->print_cr("At most one of the following option can be specified: " \ |
105 | "summary, detail, metadata, baseline, summary.diff, detail.diff, shutdown" ); |
106 | return; |
107 | } else if (nopt == 0) { |
108 | if (_summary.is_set()) { |
109 | output()->print_cr("No command to execute" ); |
110 | return; |
111 | } else { |
112 | _summary.set_value(true); |
113 | } |
114 | } |
115 | |
116 | // Serialize NMT query |
117 | MutexLocker locker(MemTracker::query_lock()); |
118 | |
119 | if (_summary.value()) { |
120 | report(true, scale_unit); |
121 | } else if (_detail.value()) { |
122 | if (!check_detail_tracking_level(output())) { |
123 | return; |
124 | } |
125 | report(false, scale_unit); |
126 | } else if (_baseline.value()) { |
127 | MemBaseline& baseline = MemTracker::get_baseline(); |
128 | if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) { |
129 | output()->print_cr("Baseline failed" ); |
130 | } else { |
131 | output()->print_cr("Baseline succeeded" ); |
132 | } |
133 | } else if (_summary_diff.value()) { |
134 | MemBaseline& baseline = MemTracker::get_baseline(); |
135 | if (baseline.baseline_type() >= MemBaseline::Summary_baselined) { |
136 | report_diff(true, scale_unit); |
137 | } else { |
138 | output()->print_cr("No baseline for comparison" ); |
139 | } |
140 | } else if (_detail_diff.value()) { |
141 | if (!check_detail_tracking_level(output())) { |
142 | return; |
143 | } |
144 | MemBaseline& baseline = MemTracker::get_baseline(); |
145 | if (baseline.baseline_type() == MemBaseline::Detail_baselined) { |
146 | report_diff(false, scale_unit); |
147 | } else { |
148 | output()->print_cr("No detail baseline for comparison" ); |
149 | } |
150 | } else if (_shutdown.value()) { |
151 | MemTracker::shutdown(); |
152 | output()->print_cr("Native memory tracking has been turned off" ); |
153 | } else if (_statistics.value()) { |
154 | if (check_detail_tracking_level(output())) { |
155 | MemTracker::tuning_statistics(output()); |
156 | } |
157 | } else { |
158 | ShouldNotReachHere(); |
159 | output()->print_cr("Unknown command" ); |
160 | } |
161 | } |
162 | |
163 | int NMTDCmd::num_arguments() { |
164 | ResourceMark rm; |
165 | NMTDCmd* dcmd = new NMTDCmd(NULL, false); |
166 | if (dcmd != NULL) { |
167 | DCmdMark mark(dcmd); |
168 | return dcmd->_dcmdparser.num_arguments(); |
169 | } else { |
170 | return 0; |
171 | } |
172 | } |
173 | |
174 | void NMTDCmd::report(bool summaryOnly, size_t scale_unit) { |
175 | MemBaseline baseline; |
176 | if (baseline.baseline(summaryOnly)) { |
177 | if (summaryOnly) { |
178 | MemSummaryReporter rpt(baseline, output(), scale_unit); |
179 | rpt.report(); |
180 | } else { |
181 | MemDetailReporter rpt(baseline, output(), scale_unit); |
182 | rpt.report(); |
183 | } |
184 | } |
185 | } |
186 | |
187 | void NMTDCmd::report_diff(bool summaryOnly, size_t scale_unit) { |
188 | MemBaseline& early_baseline = MemTracker::get_baseline(); |
189 | assert(early_baseline.baseline_type() != MemBaseline::Not_baselined, |
190 | "Not yet baselined" ); |
191 | assert(summaryOnly || early_baseline.baseline_type() == MemBaseline::Detail_baselined, |
192 | "Not a detail baseline" ); |
193 | |
194 | MemBaseline baseline; |
195 | if (baseline.baseline(summaryOnly)) { |
196 | if (summaryOnly) { |
197 | MemSummaryDiffReporter rpt(early_baseline, baseline, output(), scale_unit); |
198 | rpt.report_diff(); |
199 | } else { |
200 | MemDetailDiffReporter rpt(early_baseline, baseline, output(), scale_unit); |
201 | rpt.report_diff(); |
202 | } |
203 | } |
204 | } |
205 | |
206 | bool NMTDCmd::check_detail_tracking_level(outputStream* out) { |
207 | if (MemTracker::tracking_level() == NMT_detail) { |
208 | return true; |
209 | } else if (MemTracker::cmdline_tracking_level() == NMT_detail) { |
210 | out->print_cr("Tracking level has been downgraded due to lack of resources" ); |
211 | return false; |
212 | } else { |
213 | out->print_cr("Detail tracking is not enabled" ); |
214 | return false; |
215 | } |
216 | } |
217 | |