United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6296437 : HPROF: hat is throwing exception on hprof output in mustang

Details
Type:
Bug
Submit Date:
2005-07-13
Status:
Resolved
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2005-09-30
Component:
tools
OS:
solaris_10
Sub-Component:
hprof
CPU:
sparc
Priority:
P4
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
I'm trying to use hat tool from http://hat.dev.java.net, with the
  latest mustang build, and it's not going too well.

  hat throws this exception when trying to parse the binary output
  file created by hprof:
#>/import/java/jdk1.6.0/solaris-sparc/bin/java -client -version
java version "1.6.0-ea"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-ea-b42)
Java HotSpot(TM) Client VM (build 1.6.0-ea-b42, mixed mode)

/import/java/jdk1.6.0/solaris-sparc/bin/java -client -agentlib:hprof=depth=6,format=b LeakWindow

[tdv@nukite:] -< ~/public_html/bugs/disposer_leak >
#>/import/java/jdk1.6.0/solaris-sparc/bin/java -jar ~/perf/hat/bin/hat.jar ./java.hprof
Started HTTP server on port 7000
Reading from ./java.hprof...
Dump file created Thu Feb 27 04:56:57 PST 1992
java.io.IOException: Thread 200001 not found for JNI local ref
        at hat.parser.HprofReader.getThreadObjectFromSequence(HprofReader.java:577)
        at hat.parser.HprofReader.readHeapDump(HprofReader.java:379)
        at hat.parser.HprofReader.read(HprofReader.java:221)
        at hat.parser.Reader.readFile(Reader.java:90)
        at hat.Main.main(Main.java:149)

I've attached the hprof file.

###@###.### 2005-07-13 18:02:42 GMT

                                    

Comments
SUGGESTED FIX

+++ hprof_tls.c Fri Sep 16 21:39:20 2005
@@ -1,7 +1,7 @@
 /*
- * @(#)hprof_tls.c     1.52 05/04/28
+ * @(#)hprof_tls.c     1.53 05/09/15
  * 
  * Copyright (c) 2004 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:
@@ -37,16 +37,19 @@
 #include "hprof.h"
 
 /* Thread Local Storage Table and method entry/exit handling. */
 
 /*
- * The tls table items have no key, and are searched via a walk of
- *   the table looking for a jthread match. This isn't a performance
+ * The tls table items have a key of it's serial number, but may be
+ *   searched via a walk of the table looking for a jthread match. 
+ *   This isn't a performance
  *   issue because the table index should normally be stored in the
  *   Thread Local Storage for the thread. The table is only searched
  *   when the jthread is seen before the Thread Local Storage is set
  *   (e.g. before VM_INIT or the ThreadStart).
+ *   The key is only used when we need to lookup a tls table entry by
+ *   way of it's serial number, which should be unique per thread.
  *
  * Each active thread that we have seen should have a unique TlsIndex
  *   which is an index into this table.
  *
  * For cpu=times, each table entry will have a stack to hold the method
@@ -80,11 +83,10 @@
 } StackElement;
 
 typedef struct TlsInfo {
     jint            sample_status;      /* Thread status for cpu sampling */
     jboolean        agent_thread;       /* Is thread our own agent thread? */
-    SerialNumber    thread_serial_num;  /* unique thread serial number */
     jthread         globalref;          /* Global reference for thread */
     Stack          *stack;              /* Stack of StackElements entry/exit */
     MonitorIndex    monitor_index;      /* last contended mon */
     jint            tracker_status;     /* If we are inside Tracker class */
     FrameIndex     *frames_buffer;      /* Buffer used to create TraceIndex */
@@ -91,10 +93,11 @@
     jvmtiFrameInfo *jframes_buffer;     /* Buffer used to create TraceIndex */
     int             buffer_depth;       /* Frames allowed in buffer */
     TraceIndex      last_trace;         /* Last trace for this thread */
     ObjectIndex     thread_object_index;/* If heap=dump */
     jlong           monitor_start_time; /* Start time for monitor */
+    jint            in_heap_dump;       /* If we are an object in the dump */
 } TlsInfo;
 
 typedef struct SearchData {
     JNIEnv      *env;
     jthread      thread;
@@ -120,10 +123,27 @@
     jint         sample_status;
 } SampleData;
 
 /* Private internal functions. */
 
+static SerialNumber
+get_key(TlsIndex index)
+{
+    SerialNumber *pkey;
+    int           key_len;
+
+    if ( index == 0 ) {
+       return 0;
+    }
+    pkey    = NULL;
+    key_len = 0;
+    table_get_key(gdata->tls_table, index, (void**)&pkey, &key_len);
+    HPROF_ASSERT(pkey!=NULL);
+    HPROF_ASSERT(key_len==(int)sizeof(SerialNumber));
+    return *pkey;
+}
+
 static TlsInfo *
 get_info(TlsIndex index)
 {
     return (TlsInfo*)table_get_info(gdata->tls_table, index);
 }
@@ -188,11 +208,11 @@
     info        = (TlsInfo*)info_ptr;
     debug_message( "Tls 0x%08x: SN=%u, sample_status=%d, agent=%d, "
                          "thread=%p, monitor=0x%08x, "
                          "tracker_status=%d\n",
                 index,
-                info->thread_serial_num,
+                *(SerialNumber*)key_ptr,
                 info->sample_status,
                 info->agent_thread,
                 (void*)info->globalref,
                 info->monitor_index,
                 info->tracker_status);
@@ -338,25 +358,28 @@
 
 /* Get various lists on known threads */
 static void
 get_thread_list(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
 {
+    SerialNumber thread_serial_num;
     TlsInfo    *info;
     ThreadList *list;
     jthread     thread;
     
+    HPROF_ASSERT(key_ptr!=NULL);
     HPROF_ASSERT(info_ptr!=NULL);
     
+    thread_serial_num = *(SerialNumber*)key_ptr;
     info  = (TlsInfo*)info_ptr;
     list  = (ThreadList*)arg;
     thread = newLocalReference(list->env, info->globalref);
     if ( thread != NULL && info->sample_status != 0 && !info->agent_thread ) {
        if ( list->infos != NULL ) {
            list->infos[list->count] = info;
        }
        if ( list->serial_nums != NULL ) {
-           list->serial_nums[list->count] = info->thread_serial_num;
+           list->serial_nums[list->count] = thread_serial_num;
        }
        list->threads[list->count] = thread;
        list->count++;
        /* Local reference gets freed by caller */
     } else {
@@ -455,10 +478,11 @@
 }
 
 static void
 pop_method(TlsIndex index, jlong current_time, jmethodID method, FrameIndex frame_index)
 {
+    SerialNumber  thread_serial_num;
     TlsInfo  *    info;
     StackElement  element;
     void         *p;
     int           depth;
     int           trace_depth;
@@ -468,10 +492,11 @@
     TraceIndex    trace_index;
 
     HPROF_ASSERT(method!=NULL);
     HPROF_ASSERT(frame_index!=0);
     
+    thread_serial_num  = get_key(index);
     info = get_info(index);
     HPROF_ASSERT(info!=NULL);
     HPROF_ASSERT(info->stack!=NULL);
     depth   = stack_depth(info->stack);
     p = stack_pop(info->stack);
@@ -499,11 +524,11 @@
        
        e = *(StackElement*)stack_element(info->stack, (depth - i) - 1);
        info->frames_buffer[i] = e.frame_index;
        HPROF_ASSERT(e.frame_index!=0);
     }
-    trace_index = trace_find_or_create(info->thread_serial_num,
+    trace_index = trace_find_or_create(thread_serial_num,
                    trace_depth, info->frames_buffer, info->jframes_buffer);
    
     /* Calculate time spent */
     total_time = current_time - element.method_start_time;
     if ( total_time < 0 ) {
@@ -523,16 +548,19 @@
 }
 
 static void
 dump_thread_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
 {
+    SerialNumber thread_serial_num;
     TlsInfo *info;
     jthread  thread;
     JNIEnv  *env;
     
+    HPROF_ASSERT(key_ptr!=NULL);
     HPROF_ASSERT(info_ptr!=NULL);
     env    = (JNIEnv*)arg;
+    thread_serial_num    = *(SerialNumber*)key_ptr;
     info   = (TlsInfo*)info_ptr;
     thread = newLocalReference(env, info->globalref);
     if ( thread != NULL ) {
        jint         threadState;
        SerialNumber trace_serial_num;
@@ -545,28 +573,27 @@
        if ( info->last_trace == 0 ) {
            trace_serial_num = trace_get_serial_number(gdata->system_trace_index);
        } else {
            trace_serial_num = trace_get_serial_number(info->last_trace);
        }
-       io_write_monitor_dump_thread_state(info->thread_serial_num,
+       io_write_monitor_dump_thread_state(thread_serial_num,
                       trace_serial_num, threadState);
        deleteLocalReference(env, thread);
     }
 }
 
 static SerialNumber
 get_serial_number(JNIEnv *env, jthread thread)
 {
     TlsIndex index;
-    TlsInfo *info;
     
+    if ( thread == NULL ) {
+       return gdata->unknown_thread_serial_num;
+    }
     HPROF_ASSERT(env!=NULL);
-    
     index = tls_find_or_create(env, thread);
-
-    info = get_info(index);
-    return info->thread_serial_num;
+    return get_key(index);
 }
 
 static void
 dump_monitor_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
 {
@@ -650,10 +677,11 @@
 /* External interfaces */
 
 TlsIndex
 tls_find_or_create(JNIEnv *env, jthread thread)
 {
+    SerialNumber    thread_serial_num;
     static TlsInfo  empty_info;
     TlsInfo  info;
     TlsIndex index;
 
     HPROF_ASSERT(env!=NULL);
@@ -668,21 +696,21 @@
     index = search(env, thread);
     if ( index != 0 ) {
        setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);
        return index;
     }
+    thread_serial_num      = gdata->thread_serial_number_counter++;
     info                   = empty_info;
-    info.thread_serial_num = gdata->thread_serial_number_counter++;
     info.monitor_index     = 0;
     info.sample_status     = 1;
     info.agent_thread      = JNI_FALSE;
     info.stack             = stack_init(INITIAL_THREAD_STACK_LIMIT, 
                                INITIAL_THREAD_STACK_LIMIT,
                                (int)sizeof(StackElement));
     setup_trace_buffers(&info, gdata->max_trace_depth);
     info.globalref = newWeakGlobalReference(env, thread);
-    index = table_create_entry(gdata->tls_table, NULL, 0, (void*)&info);
+    index = table_create_entry(gdata->tls_table, &thread_serial_num, (int)sizeof(SerialNumber), (void*)&info);
     setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);
     HPROF_ASSERT(search(env,thread)==index);
     return index;
 }
 
@@ -700,11 +728,11 @@
 
 void
 tls_init(void)
 {
     gdata->tls_table = table_initialize("TLS",
-                            16, 16, 0, (int)sizeof(TlsInfo));
+                            16, 16, 16, (int)sizeof(TlsInfo));
 }
 
 void
 tls_list(void)
 {
@@ -747,11 +775,11 @@
   
     index             = tls_find_or_create(env, thread);
     info              = get_info(index);
     *ppstatus         = &(info->tracker_status);
     status            = **ppstatus;
-    thread_serial_num = info->thread_serial_num;
+    thread_serial_num = get_key(index);
     
     if ( pindex != NULL ) {
        *pindex = index;
     }
     if ( status != 0 ) {
@@ -788,17 +816,11 @@
 }
 
 SerialNumber
 tls_get_thread_serial_number(TlsIndex index)
 {
-    TlsInfo *info;
-
-    if ( index == 0 ) {
-       return 0;
-    }
-    info = get_info(index);
-    return info->thread_serial_num;
+    return get_key(index);
 }
 
 void
 tls_set_monitor(TlsIndex index, MonitorIndex monitor_index)
 {
@@ -826,18 +848,20 @@
 {
     HPROF_ASSERT(env!=NULL);
    
     /* Sample thread stack for last time, do NOT free the entry yet. */
     table_lock_enter(gdata->tls_table); {
+       SerialNumber thread_serial_num;
         TlsInfo     *info;
        jthread      thread;
        
+       thread_serial_num = get_key(index);
        info = get_info(index);
        thread = newLocalReference(env, info->globalref);
        if (gdata->heap_dump && thread!=NULL) {
            setup_trace_buffers(info, gdata->max_trace_depth);
-           info->last_trace = get_trace(thread, info->thread_serial_num,
+           info->last_trace = get_trace(thread, thread_serial_num,
                                    gdata->max_trace_depth, JNI_FALSE,
                                    info->frames_buffer, info->jframes_buffer);
        }
        if ( thread != NULL ) {
            deleteLocalReference(env, thread);
@@ -1092,24 +1116,71 @@
 }
 
 TraceIndex   
 tls_get_trace(TlsIndex index, JNIEnv *env, int depth, jboolean skip_init)
 {
+    SerialNumber thread_serial_num;
     TraceIndex trace_index;
     TlsInfo   *info;
     jthread    thread;
 
+    thread_serial_num = get_key(index);
     info = get_info(index);
     HPROF_ASSERT(info!=NULL);
     setup_trace_buffers(info, depth);
     thread = newLocalReference(env, info->globalref);
     if ( thread != NULL ) {
-        trace_index = get_trace(thread, info->thread_serial_num, 
-                       depth, skip_init,
+        trace_index = get_trace(thread, thread_serial_num, depth, skip_init,
                        info->frames_buffer, info->jframes_buffer);
        deleteLocalReference(env, thread);
     } else {
         trace_index = gdata->system_trace_index;
     }
     return trace_index;
 }
 
+void
+tls_set_in_heap_dump(TlsIndex index, jint in_heap_dump)
+{
+    TlsInfo  *info;
+    
+    info = get_info(index);
+    info->in_heap_dump = in_heap_dump;
+}
+
+jint
+tls_get_in_heap_dump(TlsIndex index)
+{
+    TlsInfo  *info;
+    
+    info = get_info(index);
+    return info->in_heap_dump;
+}
+
+static void
+clean_in_heap_dump(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+    TlsInfo *info;
+    
+    HPROF_ASSERT(info_ptr!=NULL);
+    info  = (TlsInfo*)info_ptr;
+    info->in_heap_dump = 0;
+}
+
+void
+tls_clear_in_heap_dump(void)
+{
+    table_walk_items(gdata->tls_table, &clean_in_heap_dump, NULL);
+}
+
+TlsIndex
+tls_find(SerialNumber thread_serial_num)
+{
+    TlsIndex index;
+   
+    if ( thread_serial_num == 0 ) {
+       return 0;
+    }
+    index = table_find_entry(gdata->tls_table, 
+         (void*)&thread_serial_num, (int)sizeof(SerialNumber));
+    return index;
+}
                                     
2005-09-20
EVALUATION

Added a field in the TLS (thread local storage) table of hprof to track which threads have been dumped, and when a reference to that thread (via it's serial number) we will make sure we use the 'unknown thread' serial number if the thread does not exist anymore.  Added a search key of the thread serial number on the TLS table for quick lookups.
                                     
2005-09-20
SUGGESTED FIX

Track threads placed in dumps, don't let any locals refer to threads that have not been dumped.
                                     
2005-09-14
EVALUATION

Need to track threads dumped closely.  But a separate bug may need to be filed to make jhat more forgiving.
                                     
2005-09-13



Hardware and Software, Engineered to Work Together