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