--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/jvmti/hprof/hprof_monitor.c Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Monitor contention tracking and monitor wait handling. */
+
+/*
+ * Monitor's under contention are unique per trace and signature.
+ * Two monitors with the same trace and signature will be treated
+ * the same as far as accumulated contention time.
+ *
+ * The tls table (or thread table) will be used to store the monitor in
+ * contention or being waited on.
+ *
+ * Monitor wait activity is emitted as it happens.
+ *
+ * Monitor contention is tabulated and summarized at dump time.
+ *
+ */
+
+#include "hprof.h"
+
+typedef struct MonitorKey {
+ TraceIndex trace_index;
+ StringIndex sig_index;
+} MonitorKey;
+
+typedef struct MonitorInfo {
+ jint num_hits;
+ jlong contended_time;
+} MonitorInfo;
+
+typedef struct IterateInfo {
+ MonitorIndex *monitors;
+ int count;
+ jlong total_contended_time;
+} IterateInfo;
+
+/* Private internal functions. */
+
+static MonitorKey*
+get_pkey(MonitorIndex index)
+{
+ void * key_ptr;
+ int key_len;
+
+ table_get_key(gdata->monitor_table, index, &key_ptr, &key_len);
+ HPROF_ASSERT(key_len==sizeof(MonitorKey));
+ HPROF_ASSERT(key_ptr!=NULL);
+ return (MonitorKey*)key_ptr;
+}
+
+static MonitorInfo *
+get_info(MonitorIndex index)
+{
+ MonitorInfo * info;
+
+ HPROF_ASSERT(index!=0);
+ info = (MonitorInfo*)table_get_info(gdata->monitor_table, index);
+ HPROF_ASSERT(info!=NULL);
+ return info;
+}
+
+static MonitorIndex
+find_or_create_entry(JNIEnv *env, TraceIndex trace_index, jobject object)
+{
+ static MonitorKey empty_key;
+ MonitorKey key;
+ MonitorIndex index;
+ char *sig;
+
+ HPROF_ASSERT(object!=NULL);
+ WITH_LOCAL_REFS(env, 1) {
+ jclass clazz;
+
+ clazz = getObjectClass(env, object);
+ getClassSignature(clazz, &sig, NULL);
+ } END_WITH_LOCAL_REFS;
+
+ key = empty_key;
+ key.trace_index = trace_index;
+ key.sig_index = string_find_or_create(sig);
+ jvmtiDeallocate(sig);
+ index = table_find_or_create_entry(gdata->monitor_table, &key,
+ (int)sizeof(key), NULL, NULL);
+ return index;
+}
+
+static void
+cleanup_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+}
+
+static void
+list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ MonitorInfo *info;
+ MonitorKey *pkey;
+
+ HPROF_ASSERT(key_len==sizeof(MonitorKey));
+ HPROF_ASSERT(key_ptr!=NULL);
+ HPROF_ASSERT(info_ptr!=NULL);
+ pkey = (MonitorKey*)key_ptr;
+ info = (MonitorInfo *)info_ptr;
+ debug_message(
+ "Monitor 0x%08x: trace=0x%08x, sig=0x%08x, "
+ "num_hits=%d, contended_time=(%d,%d)\n",
+ index,
+ pkey->trace_index,
+ pkey->sig_index,
+ info->num_hits,
+ jlong_high(info->contended_time),
+ jlong_low(info->contended_time));
+}
+
+static void
+collect_iterator(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ MonitorInfo *info;
+ IterateInfo *iterate;
+
+ HPROF_ASSERT(key_len==sizeof(MonitorKey));
+ HPROF_ASSERT(info_ptr!=NULL);
+ HPROF_ASSERT(arg!=NULL);
+ iterate = (IterateInfo *)arg;
+ info = (MonitorInfo *)info_ptr;
+ iterate->monitors[iterate->count++] = index;
+ iterate->total_contended_time += info->contended_time;
+}
+
+static int
+qsort_compare(const void *p_monitor1, const void *p_monitor2)
+{
+ MonitorInfo * info1;
+ MonitorInfo * info2;
+ MonitorIndex monitor1;
+ MonitorIndex monitor2;
+ jlong result;
+
+ HPROF_ASSERT(p_monitor1!=NULL);
+ HPROF_ASSERT(p_monitor2!=NULL);
+ monitor1 = *(MonitorIndex *)p_monitor1;
+ monitor2 = *(MonitorIndex *)p_monitor2;
+ info1 = get_info(monitor1);
+ info2 = get_info(monitor2);
+
+ result = info2->contended_time - info1->contended_time;
+ if (result < (jlong)0) {
+ return -1;
+ } else if ( result > (jlong)0 ) {
+ return 1;
+ }
+ return info2->num_hits - info1->num_hits;
+}
+
+static void
+clear_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ MonitorInfo *info;
+
+ HPROF_ASSERT(key_len==sizeof(MonitorKey));
+ HPROF_ASSERT(info_ptr!=NULL);
+ info = (MonitorInfo *)info_ptr;
+ info->contended_time = 0;
+}
+
+static TraceIndex
+get_trace(TlsIndex tls_index, JNIEnv *env)
+{
+ TraceIndex trace_index;
+
+ trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, JNI_FALSE);
+ return trace_index;
+}
+
+/* External functions (called from hprof_init.c) */
+
+void
+monitor_init(void)
+{
+ gdata->monitor_table = table_initialize("Monitor",
+ 32, 32, 31, (int)sizeof(MonitorInfo));
+}
+
+void
+monitor_list(void)
+{
+ debug_message(
+ "------------------- Monitor Table ------------------------\n");
+ table_walk_items(gdata->monitor_table, &list_item, NULL);
+ debug_message(
+ "----------------------------------------------------------\n");
+}
+
+void
+monitor_cleanup(void)
+{
+ table_cleanup(gdata->monitor_table, &cleanup_item, (void*)NULL);
+ gdata->monitor_table = NULL;
+}
+
+void
+monitor_clear(void)
+{
+ table_walk_items(gdata->monitor_table, &clear_item, NULL);
+}
+
+/* Contended monitor output */
+void
+monitor_write_contended_time(JNIEnv *env, double cutoff)
+{
+ int n_entries;
+
+ n_entries = table_element_count(gdata->monitor_table);
+ if ( n_entries == 0 ) {
+ return;
+ }
+
+ rawMonitorEnter(gdata->data_access_lock); {
+ IterateInfo iterate;
+ int i;
+ int n_items;
+ jlong total_contended_time;
+
+ /* First write all trace we might refer to. */
+ trace_output_unmarked(env);
+
+ /* Looking for an array of monitor index values of interest */
+ iterate.monitors = HPROF_MALLOC(n_entries*(int)sizeof(MonitorIndex));
+ (void)memset(iterate.monitors, 0, n_entries*(int)sizeof(MonitorIndex));
+
+ /* Get a combined total and an array of monitor index numbers */
+ iterate.total_contended_time = 0;
+ iterate.count = 0;
+ table_walk_items(gdata->monitor_table, &collect_iterator, &iterate);
+
+ /* Sort that list */
+ n_entries = iterate.count;
+ if ( n_entries > 0 ) {
+ qsort(iterate.monitors, n_entries, sizeof(MonitorIndex),
+ &qsort_compare);
+ }
+
+ /* Apply the cutoff */
+ n_items = 0;
+ for (i = 0; i < n_entries; i++) {
+ MonitorIndex index;
+ MonitorInfo *info;
+ double percent;
+
+ index = iterate.monitors[i];
+ info = get_info(index);
+ percent = (double)info->contended_time /
+ (double)iterate.total_contended_time;
+ if (percent < cutoff) {
+ break;
+ }
+ iterate.monitors[n_items++] = index;
+ }
+
+ /* Output the items that make sense */
+ total_contended_time = iterate.total_contended_time / 1000000;
+
+ if ( n_items > 0 && total_contended_time > 0 ) {
+ double accum;
+
+ /* Output the info on this monitor enter site */
+ io_write_monitor_header(total_contended_time);
+
+ accum = 0.0;
+ for (i = 0; i < n_items; i++) {
+ MonitorIndex index;
+ MonitorInfo *info;
+ MonitorKey *pkey;
+ double percent;
+ char *sig;
+
+ index = iterate.monitors[i];
+ pkey = get_pkey(index);
+ info = get_info(index);
+
+ sig = string_get(pkey->sig_index);
+
+ percent = (double)info->contended_time /
+ (double)iterate.total_contended_time * 100.0;
+ accum += percent;
+ io_write_monitor_elem(i + 1, percent, accum,
+ info->num_hits,
+ trace_get_serial_number(pkey->trace_index),
+ sig);
+ }
+ io_write_monitor_footer();
+ }
+ HPROF_FREE(iterate.monitors);
+ } rawMonitorExit(gdata->data_access_lock);
+}
+
+void
+monitor_contended_enter_event(JNIEnv *env, jthread thread, jobject object)
+{
+ TlsIndex tls_index;
+ MonitorIndex index;
+ TraceIndex trace_index;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(object!=NULL);
+
+ tls_index = tls_find_or_create(env, thread);
+ HPROF_ASSERT(tls_get_monitor(tls_index)==0);
+ trace_index = get_trace(tls_index, env);
+ index = find_or_create_entry(env, trace_index, object);
+ tls_monitor_start_timer(tls_index);
+ tls_set_monitor(tls_index, index);
+}
+
+void
+monitor_contended_entered_event(JNIEnv* env, jthread thread, jobject object)
+{
+ TlsIndex tls_index;
+ MonitorInfo *info;
+ MonitorIndex index;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ HPROF_ASSERT(thread!=NULL);
+
+ tls_index = tls_find_or_create(env, thread);
+ HPROF_ASSERT(tls_index!=0);
+ index = tls_get_monitor(tls_index);
+ HPROF_ASSERT(index!=0);
+ info = get_info(index);
+ info->contended_time += tls_monitor_stop_timer(tls_index);
+ info->num_hits++;
+ tls_set_monitor(tls_index, 0);
+}
+
+void
+monitor_wait_event(JNIEnv *env, jthread thread, jobject object, jlong timeout)
+{
+ TlsIndex tls_index;
+ MonitorKey *pkey;
+ MonitorIndex index;
+ TraceIndex trace_index;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ HPROF_ASSERT(thread!=NULL);
+
+ tls_index = tls_find_or_create(env, thread);
+ HPROF_ASSERT(tls_index!=0);
+ HPROF_ASSERT(tls_get_monitor(tls_index)==0);
+ trace_index = get_trace(tls_index, env);
+ index = find_or_create_entry(env, trace_index, object);
+ pkey = get_pkey(index);
+ tls_monitor_start_timer(tls_index);
+ tls_set_monitor(tls_index, index);
+
+ rawMonitorEnter(gdata->data_access_lock); {
+ io_write_monitor_wait(string_get(pkey->sig_index), timeout,
+ tls_get_thread_serial_number(tls_index));
+ } rawMonitorExit(gdata->data_access_lock);
+}
+
+void
+monitor_waited_event(JNIEnv *env, jthread thread,
+ jobject object, jboolean timed_out)
+{
+ TlsIndex tls_index;
+ MonitorIndex index;
+ jlong time_waited;
+
+ tls_index = tls_find_or_create(env, thread);
+ HPROF_ASSERT(tls_index!=0);
+ time_waited = tls_monitor_stop_timer(tls_index);
+ index = tls_get_monitor(tls_index);
+
+ if ( index ==0 ) {
+ /* As best as I can tell, on Solaris X86 (not SPARC) I sometimes
+ * get a "waited" event on a thread that I have never seen before
+ * at all, so how did I get a WAITED event? Perhaps when I
+ * did the VM_INIT handling, a thread I've never seen had already
+ * done the WAIT (which I never saw?), and now I see this thread
+ * for the first time, and also as it finishes it's WAIT?
+ * Only happening on faster processors?
+ */
+ tls_set_monitor(tls_index, 0);
+ return;
+ }
+ HPROF_ASSERT(index!=0);
+ tls_set_monitor(tls_index, 0);
+ if (object == NULL) {
+ rawMonitorEnter(gdata->data_access_lock); {
+ io_write_monitor_sleep(time_waited,
+ tls_get_thread_serial_number(tls_index));
+ } rawMonitorExit(gdata->data_access_lock);
+ } else {
+ MonitorKey *pkey;
+
+ pkey = get_pkey(index);
+ rawMonitorEnter(gdata->data_access_lock); {
+ io_write_monitor_waited(string_get(pkey->sig_index), time_waited,
+ tls_get_thread_serial_number(tls_index));
+ } rawMonitorExit(gdata->data_access_lock);
+ }
+}