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