jdk/src/share/demo/jvmti/hprof/hprof_monitor.c
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /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);
+    }
+}