annotate src/share/demo/jvmti/hprof/hprof_monitor.c @ 6581:cea72c2bf071

7197491: update copyright year to match last edit in jdk8 jdk repository Reviewed-by: chegar, ksrini
author alanb
date Fri, 02 Nov 2012 15:50:11 +0000
parents d8fccd6db59b
children
rev   line source
duke@0 1 /*
alanb@6581 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
duke@0 3 *
duke@0 4 * Redistribution and use in source and binary forms, with or without
duke@0 5 * modification, are permitted provided that the following conditions
duke@0 6 * are met:
duke@0 7 *
duke@0 8 * - Redistributions of source code must retain the above copyright
duke@0 9 * notice, this list of conditions and the following disclaimer.
duke@0 10 *
duke@0 11 * - Redistributions in binary form must reproduce the above copyright
duke@0 12 * notice, this list of conditions and the following disclaimer in the
duke@0 13 * documentation and/or other materials provided with the distribution.
duke@0 14 *
ohair@2362 15 * - Neither the name of Oracle nor the names of its
duke@0 16 * contributors may be used to endorse or promote products derived
duke@0 17 * from this software without specific prior written permission.
duke@0 18 *
duke@0 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
duke@0 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
duke@0 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
duke@0 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
duke@0 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
duke@0 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
duke@0 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
duke@0 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
duke@0 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
duke@0 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
duke@0 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
duke@0 30 */
duke@0 31
nloodin@4503 32 /*
nloodin@4503 33 * This source code is provided to illustrate the usage of a given feature
nloodin@4503 34 * or technique and has been deliberately simplified. Additional steps
nloodin@4503 35 * required for a production-quality application, such as security checks,
nloodin@4503 36 * input validation and proper error handling, might not be present in
nloodin@4503 37 * this sample code.
nloodin@4503 38 */
nloodin@4503 39
nloodin@4503 40
duke@0 41 /* Monitor contention tracking and monitor wait handling. */
duke@0 42
duke@0 43 /*
duke@0 44 * Monitor's under contention are unique per trace and signature.
duke@0 45 * Two monitors with the same trace and signature will be treated
duke@0 46 * the same as far as accumulated contention time.
duke@0 47 *
duke@0 48 * The tls table (or thread table) will be used to store the monitor in
duke@0 49 * contention or being waited on.
duke@0 50 *
duke@0 51 * Monitor wait activity is emitted as it happens.
duke@0 52 *
duke@0 53 * Monitor contention is tabulated and summarized at dump time.
duke@0 54 *
duke@0 55 */
duke@0 56
duke@0 57 #include "hprof.h"
duke@0 58
duke@0 59 typedef struct MonitorKey {
duke@0 60 TraceIndex trace_index;
duke@0 61 StringIndex sig_index;
duke@0 62 } MonitorKey;
duke@0 63
duke@0 64 typedef struct MonitorInfo {
duke@0 65 jint num_hits;
duke@0 66 jlong contended_time;
duke@0 67 } MonitorInfo;
duke@0 68
duke@0 69 typedef struct IterateInfo {
duke@0 70 MonitorIndex *monitors;
duke@0 71 int count;
duke@0 72 jlong total_contended_time;
duke@0 73 } IterateInfo;
duke@0 74
duke@0 75 /* Private internal functions. */
duke@0 76
duke@0 77 static MonitorKey*
duke@0 78 get_pkey(MonitorIndex index)
duke@0 79 {
duke@0 80 void * key_ptr;
duke@0 81 int key_len;
duke@0 82
duke@0 83 table_get_key(gdata->monitor_table, index, &key_ptr, &key_len);
duke@0 84 HPROF_ASSERT(key_len==sizeof(MonitorKey));
duke@0 85 HPROF_ASSERT(key_ptr!=NULL);
duke@0 86 return (MonitorKey*)key_ptr;
duke@0 87 }
duke@0 88
duke@0 89 static MonitorInfo *
duke@0 90 get_info(MonitorIndex index)
duke@0 91 {
duke@0 92 MonitorInfo * info;
duke@0 93
duke@0 94 HPROF_ASSERT(index!=0);
duke@0 95 info = (MonitorInfo*)table_get_info(gdata->monitor_table, index);
duke@0 96 HPROF_ASSERT(info!=NULL);
duke@0 97 return info;
duke@0 98 }
duke@0 99
duke@0 100 static MonitorIndex
duke@0 101 find_or_create_entry(JNIEnv *env, TraceIndex trace_index, jobject object)
duke@0 102 {
duke@0 103 static MonitorKey empty_key;
duke@0 104 MonitorKey key;
duke@0 105 MonitorIndex index;
duke@0 106 char *sig;
duke@0 107
duke@0 108 HPROF_ASSERT(object!=NULL);
duke@0 109 WITH_LOCAL_REFS(env, 1) {
duke@0 110 jclass clazz;
duke@0 111
duke@0 112 clazz = getObjectClass(env, object);
duke@0 113 getClassSignature(clazz, &sig, NULL);
duke@0 114 } END_WITH_LOCAL_REFS;
duke@0 115
duke@0 116 key = empty_key;
duke@0 117 key.trace_index = trace_index;
duke@0 118 key.sig_index = string_find_or_create(sig);
duke@0 119 jvmtiDeallocate(sig);
duke@0 120 index = table_find_or_create_entry(gdata->monitor_table, &key,
duke@0 121 (int)sizeof(key), NULL, NULL);
duke@0 122 return index;
duke@0 123 }
duke@0 124
duke@0 125 static void
duke@0 126 cleanup_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
duke@0 127 {
duke@0 128 }
duke@0 129
duke@0 130 static void
duke@0 131 list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
duke@0 132 {
duke@0 133 MonitorInfo *info;
duke@0 134 MonitorKey *pkey;
duke@0 135
duke@0 136 HPROF_ASSERT(key_len==sizeof(MonitorKey));
duke@0 137 HPROF_ASSERT(key_ptr!=NULL);
duke@0 138 HPROF_ASSERT(info_ptr!=NULL);
duke@0 139 pkey = (MonitorKey*)key_ptr;
duke@0 140 info = (MonitorInfo *)info_ptr;
duke@0 141 debug_message(
duke@0 142 "Monitor 0x%08x: trace=0x%08x, sig=0x%08x, "
duke@0 143 "num_hits=%d, contended_time=(%d,%d)\n",
duke@0 144 index,
duke@0 145 pkey->trace_index,
duke@0 146 pkey->sig_index,
duke@0 147 info->num_hits,
duke@0 148 jlong_high(info->contended_time),
duke@0 149 jlong_low(info->contended_time));
duke@0 150 }
duke@0 151
duke@0 152 static void
duke@0 153 collect_iterator(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
duke@0 154 {
duke@0 155 MonitorInfo *info;
duke@0 156 IterateInfo *iterate;
duke@0 157
duke@0 158 HPROF_ASSERT(key_len==sizeof(MonitorKey));
duke@0 159 HPROF_ASSERT(info_ptr!=NULL);
duke@0 160 HPROF_ASSERT(arg!=NULL);
duke@0 161 iterate = (IterateInfo *)arg;
duke@0 162 info = (MonitorInfo *)info_ptr;
duke@0 163 iterate->monitors[iterate->count++] = index;
duke@0 164 iterate->total_contended_time += info->contended_time;
duke@0 165 }
duke@0 166
duke@0 167 static int
duke@0 168 qsort_compare(const void *p_monitor1, const void *p_monitor2)
duke@0 169 {
duke@0 170 MonitorInfo * info1;
duke@0 171 MonitorInfo * info2;
duke@0 172 MonitorIndex monitor1;
duke@0 173 MonitorIndex monitor2;
duke@0 174 jlong result;
duke@0 175
duke@0 176 HPROF_ASSERT(p_monitor1!=NULL);
duke@0 177 HPROF_ASSERT(p_monitor2!=NULL);
duke@0 178 monitor1 = *(MonitorIndex *)p_monitor1;
duke@0 179 monitor2 = *(MonitorIndex *)p_monitor2;
duke@0 180 info1 = get_info(monitor1);
duke@0 181 info2 = get_info(monitor2);
duke@0 182
duke@0 183 result = info2->contended_time - info1->contended_time;
duke@0 184 if (result < (jlong)0) {
duke@0 185 return -1;
duke@0 186 } else if ( result > (jlong)0 ) {
duke@0 187 return 1;
duke@0 188 }
duke@0 189 return info2->num_hits - info1->num_hits;
duke@0 190 }
duke@0 191
duke@0 192 static void
duke@0 193 clear_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
duke@0 194 {
duke@0 195 MonitorInfo *info;
duke@0 196
duke@0 197 HPROF_ASSERT(key_len==sizeof(MonitorKey));
duke@0 198 HPROF_ASSERT(info_ptr!=NULL);
duke@0 199 info = (MonitorInfo *)info_ptr;
duke@0 200 info->contended_time = 0;
duke@0 201 }
duke@0 202
duke@0 203 static TraceIndex
duke@0 204 get_trace(TlsIndex tls_index, JNIEnv *env)
duke@0 205 {
duke@0 206 TraceIndex trace_index;
duke@0 207
duke@0 208 trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, JNI_FALSE);
duke@0 209 return trace_index;
duke@0 210 }
duke@0 211
duke@0 212 /* External functions (called from hprof_init.c) */
duke@0 213
duke@0 214 void
duke@0 215 monitor_init(void)
duke@0 216 {
duke@0 217 gdata->monitor_table = table_initialize("Monitor",
duke@0 218 32, 32, 31, (int)sizeof(MonitorInfo));
duke@0 219 }
duke@0 220
duke@0 221 void
duke@0 222 monitor_list(void)
duke@0 223 {
duke@0 224 debug_message(
duke@0 225 "------------------- Monitor Table ------------------------\n");
duke@0 226 table_walk_items(gdata->monitor_table, &list_item, NULL);
duke@0 227 debug_message(
duke@0 228 "----------------------------------------------------------\n");
duke@0 229 }
duke@0 230
duke@0 231 void
duke@0 232 monitor_cleanup(void)
duke@0 233 {
duke@0 234 table_cleanup(gdata->monitor_table, &cleanup_item, (void*)NULL);
duke@0 235 gdata->monitor_table = NULL;
duke@0 236 }
duke@0 237
duke@0 238 void
duke@0 239 monitor_clear(void)
duke@0 240 {
duke@0 241 table_walk_items(gdata->monitor_table, &clear_item, NULL);
duke@0 242 }
duke@0 243
duke@0 244 /* Contended monitor output */
duke@0 245 void
duke@0 246 monitor_write_contended_time(JNIEnv *env, double cutoff)
duke@0 247 {
duke@0 248 int n_entries;
duke@0 249
duke@0 250 n_entries = table_element_count(gdata->monitor_table);
duke@0 251 if ( n_entries == 0 ) {
duke@0 252 return;
duke@0 253 }
duke@0 254
duke@0 255 rawMonitorEnter(gdata->data_access_lock); {
duke@0 256 IterateInfo iterate;
duke@0 257 int i;
duke@0 258 int n_items;
duke@0 259 jlong total_contended_time;
duke@0 260
duke@0 261 /* First write all trace we might refer to. */
duke@0 262 trace_output_unmarked(env);
duke@0 263
duke@0 264 /* Looking for an array of monitor index values of interest */
duke@0 265 iterate.monitors = HPROF_MALLOC(n_entries*(int)sizeof(MonitorIndex));
duke@0 266 (void)memset(iterate.monitors, 0, n_entries*(int)sizeof(MonitorIndex));
duke@0 267
duke@0 268 /* Get a combined total and an array of monitor index numbers */
duke@0 269 iterate.total_contended_time = 0;
duke@0 270 iterate.count = 0;
duke@0 271 table_walk_items(gdata->monitor_table, &collect_iterator, &iterate);
duke@0 272
duke@0 273 /* Sort that list */
duke@0 274 n_entries = iterate.count;
duke@0 275 if ( n_entries > 0 ) {
duke@0 276 qsort(iterate.monitors, n_entries, sizeof(MonitorIndex),
duke@0 277 &qsort_compare);
duke@0 278 }
duke@0 279
duke@0 280 /* Apply the cutoff */
duke@0 281 n_items = 0;
duke@0 282 for (i = 0; i < n_entries; i++) {
duke@0 283 MonitorIndex index;
duke@0 284 MonitorInfo *info;
duke@0 285 double percent;
duke@0 286
duke@0 287 index = iterate.monitors[i];
duke@0 288 info = get_info(index);
duke@0 289 percent = (double)info->contended_time /
duke@0 290 (double)iterate.total_contended_time;
duke@0 291 if (percent < cutoff) {
duke@0 292 break;
duke@0 293 }
duke@0 294 iterate.monitors[n_items++] = index;
duke@0 295 }
duke@0 296
duke@0 297 /* Output the items that make sense */
duke@0 298 total_contended_time = iterate.total_contended_time / 1000000;
duke@0 299
duke@0 300 if ( n_items > 0 && total_contended_time > 0 ) {
duke@0 301 double accum;
duke@0 302
duke@0 303 /* Output the info on this monitor enter site */
duke@0 304 io_write_monitor_header(total_contended_time);
duke@0 305
duke@0 306 accum = 0.0;
duke@0 307 for (i = 0; i < n_items; i++) {
duke@0 308 MonitorIndex index;
duke@0 309 MonitorInfo *info;
duke@0 310 MonitorKey *pkey;
duke@0 311 double percent;
duke@0 312 char *sig;
duke@0 313
duke@0 314 index = iterate.monitors[i];
duke@0 315 pkey = get_pkey(index);
duke@0 316 info = get_info(index);
duke@0 317
duke@0 318 sig = string_get(pkey->sig_index);
duke@0 319
duke@0 320 percent = (double)info->contended_time /
duke@0 321 (double)iterate.total_contended_time * 100.0;
duke@0 322 accum += percent;
duke@0 323 io_write_monitor_elem(i + 1, percent, accum,
duke@0 324 info->num_hits,
duke@0 325 trace_get_serial_number(pkey->trace_index),
duke@0 326 sig);
duke@0 327 }
duke@0 328 io_write_monitor_footer();
duke@0 329 }
duke@0 330 HPROF_FREE(iterate.monitors);
duke@0 331 } rawMonitorExit(gdata->data_access_lock);
duke@0 332 }
duke@0 333
duke@0 334 void
duke@0 335 monitor_contended_enter_event(JNIEnv *env, jthread thread, jobject object)
duke@0 336 {
duke@0 337 TlsIndex tls_index;
duke@0 338 MonitorIndex index;
duke@0 339 TraceIndex trace_index;
duke@0 340
duke@0 341 HPROF_ASSERT(env!=NULL);
duke@0 342 HPROF_ASSERT(thread!=NULL);
duke@0 343 HPROF_ASSERT(object!=NULL);
duke@0 344
duke@0 345 tls_index = tls_find_or_create(env, thread);
duke@0 346 HPROF_ASSERT(tls_get_monitor(tls_index)==0);
duke@0 347 trace_index = get_trace(tls_index, env);
duke@0 348 index = find_or_create_entry(env, trace_index, object);
duke@0 349 tls_monitor_start_timer(tls_index);
duke@0 350 tls_set_monitor(tls_index, index);
duke@0 351 }
duke@0 352
duke@0 353 void
duke@0 354 monitor_contended_entered_event(JNIEnv* env, jthread thread, jobject object)
duke@0 355 {
duke@0 356 TlsIndex tls_index;
duke@0 357 MonitorInfo *info;
duke@0 358 MonitorIndex index;
duke@0 359
duke@0 360 HPROF_ASSERT(env!=NULL);
duke@0 361 HPROF_ASSERT(object!=NULL);
duke@0 362 HPROF_ASSERT(thread!=NULL);
duke@0 363
duke@0 364 tls_index = tls_find_or_create(env, thread);
duke@0 365 HPROF_ASSERT(tls_index!=0);
duke@0 366 index = tls_get_monitor(tls_index);
duke@0 367 HPROF_ASSERT(index!=0);
duke@0 368 info = get_info(index);
duke@0 369 info->contended_time += tls_monitor_stop_timer(tls_index);
duke@0 370 info->num_hits++;
duke@0 371 tls_set_monitor(tls_index, 0);
duke@0 372 }
duke@0 373
duke@0 374 void
duke@0 375 monitor_wait_event(JNIEnv *env, jthread thread, jobject object, jlong timeout)
duke@0 376 {
duke@0 377 TlsIndex tls_index;
duke@0 378 MonitorKey *pkey;
duke@0 379 MonitorIndex index;
duke@0 380 TraceIndex trace_index;
duke@0 381
duke@0 382 HPROF_ASSERT(env!=NULL);
duke@0 383 HPROF_ASSERT(object!=NULL);
duke@0 384 HPROF_ASSERT(thread!=NULL);
duke@0 385
duke@0 386 tls_index = tls_find_or_create(env, thread);
duke@0 387 HPROF_ASSERT(tls_index!=0);
duke@0 388 HPROF_ASSERT(tls_get_monitor(tls_index)==0);
duke@0 389 trace_index = get_trace(tls_index, env);
duke@0 390 index = find_or_create_entry(env, trace_index, object);
duke@0 391 pkey = get_pkey(index);
duke@0 392 tls_monitor_start_timer(tls_index);
duke@0 393 tls_set_monitor(tls_index, index);
duke@0 394
duke@0 395 rawMonitorEnter(gdata->data_access_lock); {
duke@0 396 io_write_monitor_wait(string_get(pkey->sig_index), timeout,
duke@0 397 tls_get_thread_serial_number(tls_index));
duke@0 398 } rawMonitorExit(gdata->data_access_lock);
duke@0 399 }
duke@0 400
duke@0 401 void
duke@0 402 monitor_waited_event(JNIEnv *env, jthread thread,
duke@0 403 jobject object, jboolean timed_out)
duke@0 404 {
duke@0 405 TlsIndex tls_index;
duke@0 406 MonitorIndex index;
duke@0 407 jlong time_waited;
duke@0 408
duke@0 409 tls_index = tls_find_or_create(env, thread);
duke@0 410 HPROF_ASSERT(tls_index!=0);
duke@0 411 time_waited = tls_monitor_stop_timer(tls_index);
duke@0 412 index = tls_get_monitor(tls_index);
duke@0 413
duke@0 414 if ( index ==0 ) {
duke@0 415 /* As best as I can tell, on Solaris X86 (not SPARC) I sometimes
duke@0 416 * get a "waited" event on a thread that I have never seen before
duke@0 417 * at all, so how did I get a WAITED event? Perhaps when I
duke@0 418 * did the VM_INIT handling, a thread I've never seen had already
duke@0 419 * done the WAIT (which I never saw?), and now I see this thread
duke@0 420 * for the first time, and also as it finishes it's WAIT?
duke@0 421 * Only happening on faster processors?
duke@0 422 */
duke@0 423 tls_set_monitor(tls_index, 0);
duke@0 424 return;
duke@0 425 }
duke@0 426 HPROF_ASSERT(index!=0);
duke@0 427 tls_set_monitor(tls_index, 0);
duke@0 428 if (object == NULL) {
duke@0 429 rawMonitorEnter(gdata->data_access_lock); {
duke@0 430 io_write_monitor_sleep(time_waited,
duke@0 431 tls_get_thread_serial_number(tls_index));
duke@0 432 } rawMonitorExit(gdata->data_access_lock);
duke@0 433 } else {
duke@0 434 MonitorKey *pkey;
duke@0 435
duke@0 436 pkey = get_pkey(index);
duke@0 437 rawMonitorEnter(gdata->data_access_lock); {
duke@0 438 io_write_monitor_waited(string_get(pkey->sig_index), time_waited,
duke@0 439 tls_get_thread_serial_number(tls_index));
duke@0 440 } rawMonitorExit(gdata->data_access_lock);
duke@0 441 }
duke@0 442 }