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