1/*
2 * Copyright (c) 2001, 2019, 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
25#include "precompiled.hpp"
26#include "classfile/systemDictionary.hpp"
27#include "classfile/vmSymbols.hpp"
28#include "memory/allocation.inline.hpp"
29#include "memory/resourceArea.hpp"
30#include "oops/oop.inline.hpp"
31#include "runtime/arguments.hpp"
32#include "runtime/java.hpp"
33#include "runtime/javaCalls.hpp"
34#include "runtime/os.hpp"
35#include "runtime/perfData.inline.hpp"
36#include "runtime/statSampler.hpp"
37#include "runtime/vm_version.hpp"
38
39// --------------------------------------------------------
40// StatSamplerTask
41
42class StatSamplerTask : public PeriodicTask {
43 public:
44 StatSamplerTask(int interval_time) : PeriodicTask(interval_time) {}
45 void task() { StatSampler::collect_sample(); }
46};
47
48
49//----------------------------------------------------------
50// Implementation of StatSampler
51
52StatSamplerTask* StatSampler::_task = NULL;
53PerfDataList* StatSampler::_sampled = NULL;
54
55/*
56 * the initialize method is called from the engage() method
57 * and is responsible for initializing various global variables.
58 */
59void StatSampler::initialize() {
60
61 if (!UsePerfData) return;
62
63 // create performance data that could not be created prior
64 // to vm_init_globals() or otherwise have no logical home.
65
66 create_misc_perfdata();
67
68 // get copy of the sampled list
69 _sampled = PerfDataManager::sampled();
70
71}
72
73/*
74 * The engage() method is called at initialization time via
75 * Thread::create_vm() to initialize the StatSampler and
76 * register it with the WatcherThread as a periodic task.
77 */
78void StatSampler::engage() {
79
80 if (!UsePerfData) return;
81
82 if (!is_active()) {
83
84 initialize();
85
86 // start up the periodic task
87 _task = new StatSamplerTask(PerfDataSamplingInterval);
88 _task->enroll();
89 }
90}
91
92
93/*
94 * the disengage() method is responsible for deactivating the periodic
95 * task and, if logging was enabled, for logging the final sample. This
96 * method is called from before_exit() in java.cpp and is only called
97 * after the WatcherThread has been stopped.
98 */
99void StatSampler::disengage() {
100
101 if (!UsePerfData) return;
102
103 if (!is_active())
104 return;
105
106 // remove StatSamplerTask
107 _task->disenroll();
108 delete _task;
109 _task = NULL;
110
111 // force a final sample
112 sample_data(_sampled);
113}
114
115/*
116 * the destroy method is responsible for releasing any resources used by
117 * the StatSampler prior to shutdown of the VM. this method is called from
118 * before_exit() in java.cpp and is only called after the WatcherThread
119 * has stopped.
120 */
121void StatSampler::destroy() {
122
123 if (!UsePerfData) return;
124
125 if (_sampled != NULL) {
126 delete(_sampled);
127 _sampled = NULL;
128 }
129}
130
131/*
132 * The sample_data() method is responsible for sampling the
133 * the data value for each PerfData instance in the given list.
134 */
135void StatSampler::sample_data(PerfDataList* list) {
136
137 assert(list != NULL, "null list unexpected");
138
139 for (int index = 0; index < list->length(); index++) {
140 PerfData* item = list->at(index);
141 item->sample();
142 }
143}
144
145/*
146 * the collect_sample() method is the method invoked by the
147 * WatcherThread via the PeriodicTask::task() method. This method
148 * is responsible for collecting data samples from sampled
149 * PerfData instances every PerfDataSamplingInterval milliseconds.
150 * It is also responsible for logging the requested set of
151 * PerfData instances every _sample_count milliseconds. While
152 * logging data, it will output a column header after every _print_header
153 * rows of data have been logged.
154 */
155void StatSampler::collect_sample() {
156
157 // future - check for new PerfData objects. PerfData objects might
158 // get added to the PerfDataManager lists after we have already
159 // built our local copies.
160 //
161 // if (PerfDataManager::count() > previous) {
162 // // get a new copy of the sampled list
163 // if (_sampled != NULL) {
164 // delete(_sampled);
165 // _sampled = NULL;
166 // }
167 // _sampled = PerfDataManager::sampled();
168 // }
169
170 assert(_sampled != NULL, "list not initialized");
171
172 sample_data(_sampled);
173}
174
175/*
176 * method to upcall into Java to return the value of the specified
177 * property as a utf8 string, or NULL if does not exist. The caller
178 * is responsible for setting a ResourceMark for proper cleanup of
179 * the utf8 strings.
180 */
181const char* StatSampler::get_system_property(const char* name, TRAPS) {
182
183 // setup the arguments to getProperty
184 Handle key_str = java_lang_String::create_from_str(name, CHECK_NULL);
185
186 // return value
187 JavaValue result(T_OBJECT);
188
189 // public static String getProperty(String key, String def);
190 JavaCalls::call_static(&result,
191 SystemDictionary::System_klass(),
192 vmSymbols::getProperty_name(),
193 vmSymbols::string_string_signature(),
194 key_str,
195 CHECK_NULL);
196
197 oop value_oop = (oop)result.get_jobject();
198 if (value_oop == NULL) {
199 return NULL;
200 }
201
202 // convert Java String to utf8 string
203 char* value = java_lang_String::as_utf8_string(value_oop);
204
205 return value;
206}
207
208/*
209 * The list of System Properties that have corresponding PerfData
210 * string instrumentation created by retrieving the named property's
211 * value from System.getProperty() and unconditionally creating a
212 * PerfStringConstant object initialized to the retrieved value. This
213 * is not an exhaustive list of Java properties with corresponding string
214 * instrumentation as the create_system_property_instrumentation() method
215 * creates other property based instrumentation conditionally.
216 */
217
218// stable interface, supported counters
219static const char* property_counters_ss[] = {
220 "java.vm.specification.version",
221 "java.vm.specification.name",
222 "java.vm.specification.vendor",
223 "java.vm.version",
224 "java.vm.name",
225 "java.vm.vendor",
226 "java.vm.info",
227 "jdk.debug",
228 "java.library.path",
229 "java.class.path",
230 "java.version",
231 "java.home",
232 NULL
233};
234
235// unstable interface, supported counters
236static const char* property_counters_us[] = {
237 NULL
238};
239
240// unstable interface, unsupported counters
241static const char* property_counters_uu[] = {
242 "sun.boot.library.path",
243 NULL
244};
245
246typedef struct {
247 const char** property_list;
248 CounterNS name_space;
249} PropertyCounters;
250
251static PropertyCounters property_counters[] = {
252 { property_counters_ss, JAVA_PROPERTY },
253 { property_counters_us, COM_PROPERTY },
254 { property_counters_uu, SUN_PROPERTY },
255 { NULL, SUN_PROPERTY }
256};
257
258
259/*
260 * Method to create PerfData string instruments that contain the values
261 * of various system properties. String instruments are created for each
262 * property specified in the property lists provided in property_counters[].
263 * Property counters have a counter name space prefix prepended to the
264 * property name as indicated in property_counters[].
265 */
266void StatSampler::create_system_property_instrumentation(TRAPS) {
267
268 ResourceMark rm;
269
270 for (int i = 0; property_counters[i].property_list != NULL; i++) {
271
272 for (int j = 0; property_counters[i].property_list[j] != NULL; j++) {
273
274 const char* property_name = property_counters[i].property_list[j];
275 assert(property_name != NULL, "property name should not be NULL");
276
277 const char* value = get_system_property(property_name, CHECK);
278
279 // the property must exist
280 assert(value != NULL, "property name should be valid");
281
282 if (value != NULL) {
283 // create the property counter
284 PerfDataManager::create_string_constant(property_counters[i].name_space,
285 property_name, value, CHECK);
286 }
287 }
288 }
289}
290
291/*
292 * The create_misc_perfdata() method provides a place to create
293 * PerfData instances that would otherwise have no better place
294 * to exist.
295 */
296void StatSampler::create_misc_perfdata() {
297
298 ResourceMark rm;
299 EXCEPTION_MARK;
300
301 // numeric constants
302
303 // frequency of the native high resolution timer
304 PerfDataManager::create_constant(SUN_OS, "hrt.frequency",
305 PerfData::U_Hertz, os::elapsed_frequency(),
306 CHECK);
307
308 // string constants
309
310 // create string instrumentation for various Java properties.
311 create_system_property_instrumentation(CHECK);
312
313 // HotSpot flags (from .hotspotrc) and args (from command line)
314 //
315 PerfDataManager::create_string_constant(JAVA_RT, "vmFlags",
316 Arguments::jvm_flags(), CHECK);
317 PerfDataManager::create_string_constant(JAVA_RT, "vmArgs",
318 Arguments::jvm_args(), CHECK);
319
320 // java class name/jar file and arguments to main class
321 // note: name is cooridnated with launcher and Arguments.cpp
322 PerfDataManager::create_string_constant(SUN_RT, "javaCommand",
323 Arguments::java_command(), CHECK);
324
325 // the Java VM Internal version string
326 PerfDataManager::create_string_constant(SUN_RT, "internalVersion",
327 VM_Version::internal_vm_info_string(),
328 CHECK);
329
330 // create sampled instrumentation objects
331 create_sampled_perfdata();
332}
333
334/*
335 * helper class to provide for sampling of the elapsed_counter value
336 * maintained in the OS class.
337 */
338class HighResTimeSampler : public PerfSampleHelper {
339 public:
340 jlong take_sample() { return os::elapsed_counter(); }
341};
342
343/*
344 * the create_sampled_perdata() method provides a place to instantiate
345 * sampled PerfData instances that would otherwise have no better place
346 * to exist.
347 */
348void StatSampler::create_sampled_perfdata() {
349
350 EXCEPTION_MARK;
351
352 // setup sampling of the elapsed time counter maintained in the
353 // the os class. This counter can be used as either a time stamp
354 // for each logged entry or as a liveness indicator for the VM.
355 PerfSampleHelper* psh = new HighResTimeSampler();
356 PerfDataManager::create_counter(SUN_OS, "hrt.ticks",
357 PerfData::U_Ticks, psh, CHECK);
358}
359