Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_monitor.c
38829 views
/*1* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940/* Monitor contention tracking and monitor wait handling. */4142/*43* Monitor's under contention are unique per trace and signature.44* Two monitors with the same trace and signature will be treated45* the same as far as accumulated contention time.46*47* The tls table (or thread table) will be used to store the monitor in48* contention or being waited on.49*50* Monitor wait activity is emitted as it happens.51*52* Monitor contention is tabulated and summarized at dump time.53*54*/5556#include "hprof.h"5758typedef struct MonitorKey {59TraceIndex trace_index;60StringIndex sig_index;61} MonitorKey;6263typedef struct MonitorInfo {64jint num_hits;65jlong contended_time;66} MonitorInfo;6768typedef struct IterateInfo {69MonitorIndex *monitors;70int count;71jlong total_contended_time;72} IterateInfo;7374/* Private internal functions. */7576static MonitorKey*77get_pkey(MonitorIndex index)78{79void * key_ptr;80int key_len;8182table_get_key(gdata->monitor_table, index, &key_ptr, &key_len);83HPROF_ASSERT(key_len==sizeof(MonitorKey));84HPROF_ASSERT(key_ptr!=NULL);85return (MonitorKey*)key_ptr;86}8788static MonitorInfo *89get_info(MonitorIndex index)90{91MonitorInfo * info;9293HPROF_ASSERT(index!=0);94info = (MonitorInfo*)table_get_info(gdata->monitor_table, index);95HPROF_ASSERT(info!=NULL);96return info;97}9899static MonitorIndex100find_or_create_entry(JNIEnv *env, TraceIndex trace_index, jobject object)101{102static MonitorKey empty_key;103MonitorKey key;104MonitorIndex index;105char *sig;106107HPROF_ASSERT(object!=NULL);108WITH_LOCAL_REFS(env, 1) {109jclass clazz;110111clazz = getObjectClass(env, object);112getClassSignature(clazz, &sig, NULL);113} END_WITH_LOCAL_REFS;114115key = empty_key;116key.trace_index = trace_index;117key.sig_index = string_find_or_create(sig);118jvmtiDeallocate(sig);119index = table_find_or_create_entry(gdata->monitor_table, &key,120(int)sizeof(key), NULL, NULL);121return index;122}123124static void125cleanup_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)126{127}128129static void130list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)131{132MonitorInfo *info;133MonitorKey *pkey;134135HPROF_ASSERT(key_len==sizeof(MonitorKey));136HPROF_ASSERT(key_ptr!=NULL);137HPROF_ASSERT(info_ptr!=NULL);138pkey = (MonitorKey*)key_ptr;139info = (MonitorInfo *)info_ptr;140debug_message(141"Monitor 0x%08x: trace=0x%08x, sig=0x%08x, "142"num_hits=%d, contended_time=(%d,%d)\n",143index,144pkey->trace_index,145pkey->sig_index,146info->num_hits,147jlong_high(info->contended_time),148jlong_low(info->contended_time));149}150151static void152collect_iterator(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)153{154MonitorInfo *info;155IterateInfo *iterate;156157HPROF_ASSERT(key_len==sizeof(MonitorKey));158HPROF_ASSERT(info_ptr!=NULL);159HPROF_ASSERT(arg!=NULL);160iterate = (IterateInfo *)arg;161info = (MonitorInfo *)info_ptr;162iterate->monitors[iterate->count++] = index;163iterate->total_contended_time += info->contended_time;164}165166static int167qsort_compare(const void *p_monitor1, const void *p_monitor2)168{169MonitorInfo * info1;170MonitorInfo * info2;171MonitorIndex monitor1;172MonitorIndex monitor2;173jlong result;174175HPROF_ASSERT(p_monitor1!=NULL);176HPROF_ASSERT(p_monitor2!=NULL);177monitor1 = *(MonitorIndex *)p_monitor1;178monitor2 = *(MonitorIndex *)p_monitor2;179info1 = get_info(monitor1);180info2 = get_info(monitor2);181182result = info2->contended_time - info1->contended_time;183if (result < (jlong)0) {184return -1;185} else if ( result > (jlong)0 ) {186return 1;187}188return info2->num_hits - info1->num_hits;189}190191static void192clear_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)193{194MonitorInfo *info;195196HPROF_ASSERT(key_len==sizeof(MonitorKey));197HPROF_ASSERT(info_ptr!=NULL);198info = (MonitorInfo *)info_ptr;199info->contended_time = 0;200}201202static TraceIndex203get_trace(TlsIndex tls_index, JNIEnv *env)204{205TraceIndex trace_index;206207trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, JNI_FALSE);208return trace_index;209}210211/* External functions (called from hprof_init.c) */212213void214monitor_init(void)215{216gdata->monitor_table = table_initialize("Monitor",21732, 32, 31, (int)sizeof(MonitorInfo));218}219220void221monitor_list(void)222{223debug_message(224"------------------- Monitor Table ------------------------\n");225table_walk_items(gdata->monitor_table, &list_item, NULL);226debug_message(227"----------------------------------------------------------\n");228}229230void231monitor_cleanup(void)232{233table_cleanup(gdata->monitor_table, &cleanup_item, (void*)NULL);234gdata->monitor_table = NULL;235}236237void238monitor_clear(void)239{240table_walk_items(gdata->monitor_table, &clear_item, NULL);241}242243/* Contended monitor output */244void245monitor_write_contended_time(JNIEnv *env, double cutoff)246{247int n_entries;248249n_entries = table_element_count(gdata->monitor_table);250if ( n_entries == 0 ) {251return;252}253254rawMonitorEnter(gdata->data_access_lock); {255IterateInfo iterate;256int i;257int n_items;258jlong total_contended_time;259260/* First write all trace we might refer to. */261trace_output_unmarked(env);262263/* Looking for an array of monitor index values of interest */264iterate.monitors = HPROF_MALLOC(n_entries*(int)sizeof(MonitorIndex));265(void)memset(iterate.monitors, 0, n_entries*(int)sizeof(MonitorIndex));266267/* Get a combined total and an array of monitor index numbers */268iterate.total_contended_time = 0;269iterate.count = 0;270table_walk_items(gdata->monitor_table, &collect_iterator, &iterate);271272/* Sort that list */273n_entries = iterate.count;274if ( n_entries > 0 ) {275qsort(iterate.monitors, n_entries, sizeof(MonitorIndex),276&qsort_compare);277}278279/* Apply the cutoff */280n_items = 0;281for (i = 0; i < n_entries; i++) {282MonitorIndex index;283MonitorInfo *info;284double percent;285286index = iterate.monitors[i];287info = get_info(index);288percent = (double)info->contended_time /289(double)iterate.total_contended_time;290if (percent < cutoff) {291break;292}293iterate.monitors[n_items++] = index;294}295296/* Output the items that make sense */297total_contended_time = iterate.total_contended_time / 1000000;298299if ( n_items > 0 && total_contended_time > 0 ) {300double accum;301302/* Output the info on this monitor enter site */303io_write_monitor_header(total_contended_time);304305accum = 0.0;306for (i = 0; i < n_items; i++) {307MonitorIndex index;308MonitorInfo *info;309MonitorKey *pkey;310double percent;311char *sig;312313index = iterate.monitors[i];314pkey = get_pkey(index);315info = get_info(index);316317sig = string_get(pkey->sig_index);318319percent = (double)info->contended_time /320(double)iterate.total_contended_time * 100.0;321accum += percent;322io_write_monitor_elem(i + 1, percent, accum,323info->num_hits,324trace_get_serial_number(pkey->trace_index),325sig);326}327io_write_monitor_footer();328}329HPROF_FREE(iterate.monitors);330} rawMonitorExit(gdata->data_access_lock);331}332333void334monitor_contended_enter_event(JNIEnv *env, jthread thread, jobject object)335{336TlsIndex tls_index;337MonitorIndex index;338TraceIndex trace_index;339340HPROF_ASSERT(env!=NULL);341HPROF_ASSERT(thread!=NULL);342HPROF_ASSERT(object!=NULL);343344tls_index = tls_find_or_create(env, thread);345HPROF_ASSERT(tls_get_monitor(tls_index)==0);346trace_index = get_trace(tls_index, env);347index = find_or_create_entry(env, trace_index, object);348tls_monitor_start_timer(tls_index);349tls_set_monitor(tls_index, index);350}351352void353monitor_contended_entered_event(JNIEnv* env, jthread thread, jobject object)354{355TlsIndex tls_index;356MonitorInfo *info;357MonitorIndex index;358359HPROF_ASSERT(env!=NULL);360HPROF_ASSERT(object!=NULL);361HPROF_ASSERT(thread!=NULL);362363tls_index = tls_find_or_create(env, thread);364HPROF_ASSERT(tls_index!=0);365index = tls_get_monitor(tls_index);366HPROF_ASSERT(index!=0);367info = get_info(index);368info->contended_time += tls_monitor_stop_timer(tls_index);369info->num_hits++;370tls_set_monitor(tls_index, 0);371}372373void374monitor_wait_event(JNIEnv *env, jthread thread, jobject object, jlong timeout)375{376TlsIndex tls_index;377MonitorKey *pkey;378MonitorIndex index;379TraceIndex trace_index;380381HPROF_ASSERT(env!=NULL);382HPROF_ASSERT(object!=NULL);383HPROF_ASSERT(thread!=NULL);384385tls_index = tls_find_or_create(env, thread);386HPROF_ASSERT(tls_index!=0);387HPROF_ASSERT(tls_get_monitor(tls_index)==0);388trace_index = get_trace(tls_index, env);389index = find_or_create_entry(env, trace_index, object);390pkey = get_pkey(index);391tls_monitor_start_timer(tls_index);392tls_set_monitor(tls_index, index);393394rawMonitorEnter(gdata->data_access_lock); {395io_write_monitor_wait(string_get(pkey->sig_index), timeout,396tls_get_thread_serial_number(tls_index));397} rawMonitorExit(gdata->data_access_lock);398}399400void401monitor_waited_event(JNIEnv *env, jthread thread,402jobject object, jboolean timed_out)403{404TlsIndex tls_index;405MonitorIndex index;406jlong time_waited;407408tls_index = tls_find_or_create(env, thread);409HPROF_ASSERT(tls_index!=0);410time_waited = tls_monitor_stop_timer(tls_index);411index = tls_get_monitor(tls_index);412413if ( index ==0 ) {414/* As best as I can tell, on Solaris X86 (not SPARC) I sometimes415* get a "waited" event on a thread that I have never seen before416* at all, so how did I get a WAITED event? Perhaps when I417* did the VM_INIT handling, a thread I've never seen had already418* done the WAIT (which I never saw?), and now I see this thread419* for the first time, and also as it finishes it's WAIT?420* Only happening on faster processors?421*/422tls_set_monitor(tls_index, 0);423return;424}425HPROF_ASSERT(index!=0);426tls_set_monitor(tls_index, 0);427if (object == NULL) {428rawMonitorEnter(gdata->data_access_lock); {429io_write_monitor_sleep(time_waited,430tls_get_thread_serial_number(tls_index));431} rawMonitorExit(gdata->data_access_lock);432} else {433MonitorKey *pkey;434435pkey = get_pkey(index);436rawMonitorEnter(gdata->data_access_lock); {437io_write_monitor_waited(string_get(pkey->sig_index), time_waited,438tls_get_thread_serial_number(tls_index));439} rawMonitorExit(gdata->data_access_lock);440}441}442443444