jdk/src/jdk.hprof.agent/share/native/libhprof/hprof_trace.c
changeset 32247 9f3dd33507b9
parent 32246 ffea646fc05f
parent 32237 125cdb60b55f
child 32249 ba2c9c7773b6
equal deleted inserted replaced
32246:ffea646fc05f 32247:9f3dd33507b9
     1 /*
       
     2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 /*
       
    33  * This source code is provided to illustrate the usage of a given feature
       
    34  * or technique and has been deliberately simplified. Additional steps
       
    35  * required for a production-quality application, such as security checks,
       
    36  * input validation and proper error handling, might not be present in
       
    37  * this sample code.
       
    38  */
       
    39 
       
    40 
       
    41 /* Trace table. */
       
    42 
       
    43 /*
       
    44  * A trace is an optional thread serial number plus N frames.
       
    45  *
       
    46  * The thread serial number is added to the key only if the user asks for
       
    47  *    threads in traces, which will cause many more traces to be created.
       
    48  *    Without it all threads share the traces.
       
    49  *
       
    50  * This is a variable length Key, depending on the number of frames.
       
    51  *   The frames are FrameIndex values into the frame table.
       
    52  *
       
    53  * It is important that the thread serial number is used and not the
       
    54  *    TlsIndex, threads come and go, and TlsIndex values are re-used
       
    55  *    but the thread serial number is unique per thread.
       
    56  *
       
    57  * The cpu=times and cpu=samples dumps rely heavily on traces, the trace
       
    58  *   dump preceeds the cpu information and uses the trace information.
       
    59  *   Depending on the cpu= request, different sorts are applied to the
       
    60  *   traces that are dumped.
       
    61  *
       
    62  */
       
    63 
       
    64 #include "hprof.h"
       
    65 
       
    66 typedef struct TraceKey {
       
    67     SerialNumber thread_serial_num; /* Thread serial number */
       
    68     short        n_frames;          /* Number of frames that follow. */
       
    69     jvmtiPhase   phase : 8;         /* Makes some traces unique */
       
    70     FrameIndex   frames[1];         /* Variable length */
       
    71 } TraceKey;
       
    72 
       
    73 typedef struct TraceInfo {
       
    74     SerialNumber serial_num;        /* Trace serial number */
       
    75     jint         num_hits;          /* Number of hits this trace has */
       
    76     jlong        total_cost;        /* Total cost associated with trace */
       
    77     jlong        self_cost;         /* Total cost without children cost */
       
    78     jint         status;            /* Status of dump of trace */
       
    79 } TraceInfo;
       
    80 
       
    81 typedef struct IterateInfo {
       
    82     TraceIndex* traces;
       
    83     int         count;
       
    84     jlong       grand_total_cost;
       
    85 } IterateInfo;
       
    86 
       
    87 /* Private internal functions. */
       
    88 
       
    89 static TraceKey*
       
    90 get_pkey(TraceIndex index)
       
    91 {
       
    92     void *      pkey;
       
    93     int         key_len;
       
    94 
       
    95     table_get_key(gdata->trace_table, index, &pkey, &key_len);
       
    96     HPROF_ASSERT(pkey!=NULL);
       
    97     HPROF_ASSERT(key_len>=(int)sizeof(TraceKey));
       
    98     HPROF_ASSERT(((TraceKey*)pkey)->n_frames<=1?key_len==(int)sizeof(TraceKey) :
       
    99              key_len==(int)sizeof(TraceKey)+
       
   100                       (int)sizeof(FrameIndex)*(((TraceKey*)pkey)->n_frames-1));
       
   101     return (TraceKey*)pkey;
       
   102 }
       
   103 
       
   104 static TraceInfo *
       
   105 get_info(TraceIndex index)
       
   106 {
       
   107     TraceInfo *         info;
       
   108 
       
   109     info        = (TraceInfo*)table_get_info(gdata->trace_table, index);
       
   110     return info;
       
   111 }
       
   112 
       
   113 static TraceIndex
       
   114 find_or_create(SerialNumber thread_serial_num, jint n_frames,
       
   115             FrameIndex *frames, jvmtiPhase phase, TraceKey *trace_key_buffer)
       
   116 {
       
   117     TraceInfo * info;
       
   118     TraceKey *  pkey;
       
   119     int         key_len;
       
   120     TraceIndex  index;
       
   121     jboolean    new_one;
       
   122     static TraceKey empty_key;
       
   123 
       
   124     HPROF_ASSERT(frames!=NULL);
       
   125     HPROF_ASSERT(trace_key_buffer!=NULL);
       
   126     key_len = (int)sizeof(TraceKey);
       
   127     if ( n_frames > 1 ) {
       
   128         key_len += (int)((n_frames-1)*(int)sizeof(FrameIndex));
       
   129     }
       
   130     pkey = trace_key_buffer;
       
   131     *pkey = empty_key;
       
   132     pkey->thread_serial_num = (gdata->thread_in_traces ? thread_serial_num : 0);
       
   133     pkey->n_frames = (short)n_frames;
       
   134     pkey->phase = phase;
       
   135     if ( n_frames > 0 ) {
       
   136         (void)memcpy(pkey->frames, frames, (n_frames*(int)sizeof(FrameIndex)));
       
   137     }
       
   138 
       
   139     new_one = JNI_FALSE;
       
   140     index = table_find_or_create_entry(gdata->trace_table,
       
   141                                 pkey, key_len, &new_one, NULL);
       
   142     if ( new_one ) {
       
   143         info = get_info(index);
       
   144         info->serial_num = gdata->trace_serial_number_counter++;
       
   145     }
       
   146     return index;
       
   147 }
       
   148 
       
   149 static void
       
   150 list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
       
   151 {
       
   152     TraceInfo *info;
       
   153     TraceKey         *key;
       
   154     int               i;
       
   155 
       
   156     HPROF_ASSERT(key_ptr!=NULL);
       
   157     HPROF_ASSERT(key_len>0);
       
   158     HPROF_ASSERT(info_ptr!=NULL);
       
   159     key = (TraceKey*)key_ptr;
       
   160     info = (TraceInfo *)info_ptr;
       
   161 
       
   162     debug_message( "Trace 0x%08x: SN=%u, threadSN=%u, n_frames=%d, frames=(",
       
   163              index,
       
   164              info->serial_num,
       
   165              key->thread_serial_num,
       
   166              key->n_frames);
       
   167     for ( i = 0 ; i < key->n_frames ; i++ ) {
       
   168         debug_message( "0x%08x, ", key->frames[i]);
       
   169     }
       
   170     debug_message( "), traceSN=%u, num_hits=%d, self_cost=(%d,%d), "
       
   171                         "total_cost=(%d,%d), status=0x%08x\n",
       
   172                         info->serial_num,
       
   173                         info->num_hits,
       
   174                         jlong_high(info->self_cost),
       
   175                         jlong_low(info->self_cost),
       
   176                         jlong_high(info->total_cost),
       
   177                         jlong_low(info->total_cost),
       
   178                         info->status);
       
   179 }
       
   180 
       
   181 static void
       
   182 clear_cost(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
       
   183 {
       
   184     TraceInfo *info;
       
   185 
       
   186     HPROF_ASSERT(key_ptr!=NULL);
       
   187     HPROF_ASSERT(key_len>0);
       
   188     HPROF_ASSERT(info_ptr!=NULL);
       
   189     info = (TraceInfo *)info_ptr;
       
   190     info->num_hits = 0;
       
   191     info->total_cost = 0;
       
   192     info->self_cost = 0;
       
   193 }
       
   194 
       
   195 /* Get the names for a frame in order to dump it. */
       
   196 static void
       
   197 get_frame_details(JNIEnv *env, FrameIndex frame_index,
       
   198                 SerialNumber *frame_serial_num, char **pcsig, ClassIndex *pcnum,
       
   199                 char **pmname, char **pmsig, char **psname, jint *plineno)
       
   200 {
       
   201     jmethodID method;
       
   202     jlocation location;
       
   203     jint      lineno;
       
   204 
       
   205     HPROF_ASSERT(frame_index!=0);
       
   206     *pmname = NULL;
       
   207     *pmsig = NULL;
       
   208     *pcsig = NULL;
       
   209     if ( psname != NULL ) {
       
   210         *psname = NULL;
       
   211     }
       
   212     if ( plineno != NULL ) {
       
   213         *plineno = -1;
       
   214     }
       
   215     if ( pcnum != NULL ) {
       
   216         *pcnum = 0;
       
   217     }
       
   218     frame_get_location(frame_index, frame_serial_num, &method, &location, &lineno);
       
   219     if ( plineno != NULL ) {
       
   220         *plineno = lineno;
       
   221     }
       
   222     WITH_LOCAL_REFS(env, 1) {
       
   223         jclass klass;
       
   224 
       
   225         getMethodClass(method, &klass);
       
   226         getClassSignature(klass, pcsig, NULL);
       
   227         if ( pcnum != NULL ) {
       
   228             LoaderIndex loader_index;
       
   229             jobject     loader;
       
   230 
       
   231             loader = getClassLoader(klass);
       
   232             loader_index = loader_find_or_create(env, loader);
       
   233             *pcnum = class_find_or_create(*pcsig, loader_index);
       
   234              (void)class_new_classref(env, *pcnum, klass);
       
   235         }
       
   236         if ( psname != NULL ) {
       
   237             getSourceFileName(klass, psname);
       
   238         }
       
   239     } END_WITH_LOCAL_REFS;
       
   240     getMethodName(method, pmname, pmsig);
       
   241 }
       
   242 
       
   243 /* Write out a stack trace.  */
       
   244 static void
       
   245 output_trace(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
       
   246 {
       
   247     TraceKey *key;
       
   248     TraceInfo *info;
       
   249     SerialNumber serial_num;
       
   250     SerialNumber thread_serial_num;
       
   251     jint n_frames;
       
   252     JNIEnv *env;
       
   253     int i;
       
   254     char *phase_str;
       
   255     struct FrameNames {
       
   256         SerialNumber serial_num;
       
   257         char * sname;
       
   258         char * csig;
       
   259         char * mname;
       
   260         int    lineno;
       
   261     } *finfo;
       
   262 
       
   263     info = (TraceInfo*)info_ptr;
       
   264     if ( info->status != 0 ) {
       
   265         return;
       
   266     }
       
   267 
       
   268     env = (JNIEnv*)arg;
       
   269 
       
   270     key = (TraceKey*)key_ptr;
       
   271     thread_serial_num = key->thread_serial_num;
       
   272     serial_num = info->serial_num;
       
   273     info->status = 1;
       
   274     finfo = NULL;
       
   275 
       
   276     n_frames = (jint)key->n_frames;
       
   277     if ( n_frames > 0 ) {
       
   278         finfo = (struct FrameNames *)HPROF_MALLOC(n_frames*(int)sizeof(struct FrameNames));
       
   279 
       
   280         /* Write frames, but save information for trace later */
       
   281         for (i = 0; i < n_frames; i++) {
       
   282             FrameIndex frame_index;
       
   283             char *msig;
       
   284             ClassIndex cnum;
       
   285 
       
   286             frame_index = key->frames[i];
       
   287             get_frame_details(env, frame_index, &finfo[i].serial_num,
       
   288                         &finfo[i].csig, &cnum,
       
   289                         &finfo[i].mname, &msig, &finfo[i].sname, &finfo[i].lineno);
       
   290 
       
   291             if (frame_get_status(frame_index) == 0) {
       
   292                 io_write_frame(frame_index, finfo[i].serial_num,
       
   293                                finfo[i].mname, msig,
       
   294                                finfo[i].sname, class_get_serial_number(cnum),
       
   295                                finfo[i].lineno);
       
   296                 frame_set_status(frame_index, 1);
       
   297             }
       
   298             jvmtiDeallocate(msig);
       
   299         }
       
   300     }
       
   301 
       
   302     /* Find phase string */
       
   303     if ( key->phase == JVMTI_PHASE_LIVE ) {
       
   304         phase_str = NULL; /* Normal trace, no phase annotation */
       
   305     } else {
       
   306         phase_str =  phaseString(key->phase);
       
   307     }
       
   308 
       
   309     io_write_trace_header(serial_num, thread_serial_num, n_frames, phase_str);
       
   310 
       
   311     for (i = 0; i < n_frames; i++) {
       
   312         io_write_trace_elem(serial_num, key->frames[i], finfo[i].serial_num,
       
   313                             finfo[i].csig,
       
   314                             finfo[i].mname, finfo[i].sname, finfo[i].lineno);
       
   315         jvmtiDeallocate(finfo[i].csig);
       
   316         jvmtiDeallocate(finfo[i].mname);
       
   317         jvmtiDeallocate(finfo[i].sname);
       
   318     }
       
   319 
       
   320     io_write_trace_footer(serial_num, thread_serial_num, n_frames);
       
   321 
       
   322     if ( finfo != NULL ) {
       
   323         HPROF_FREE(finfo);
       
   324     }
       
   325 }
       
   326 
       
   327 /* Output a specific list of traces. */
       
   328 static void
       
   329 output_list(JNIEnv *env, TraceIndex *list, jint count)
       
   330 {
       
   331     rawMonitorEnter(gdata->data_access_lock); {
       
   332         int i;
       
   333 
       
   334         for ( i = 0; i < count ; i++ ) {
       
   335             TraceIndex index;
       
   336             TraceInfo  *info;
       
   337             void *      pkey;
       
   338             int         key_len;
       
   339 
       
   340             index = list[i];
       
   341             table_get_key(gdata->trace_table, index, &pkey, &key_len);
       
   342             info = get_info(index);
       
   343             output_trace(index, pkey, key_len, info, (void*)env);
       
   344         }
       
   345     } rawMonitorExit(gdata->data_access_lock);
       
   346 }
       
   347 
       
   348 static void
       
   349 collect_iterator(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
       
   350 {
       
   351     TraceInfo *info;
       
   352     IterateInfo      *iterate;
       
   353 
       
   354     HPROF_ASSERT(key_ptr!=NULL);
       
   355     HPROF_ASSERT(key_len>0);
       
   356     HPROF_ASSERT(arg!=NULL);
       
   357     HPROF_ASSERT(info_ptr!=NULL);
       
   358     iterate = (IterateInfo *)arg;
       
   359     info = (TraceInfo *)info_ptr;
       
   360     iterate->traces[iterate->count++] = index;
       
   361     iterate->grand_total_cost += info->self_cost;
       
   362 }
       
   363 
       
   364 static int
       
   365 qsort_compare_cost(const void *p_trace1, const void *p_trace2)
       
   366 {
       
   367     TraceIndex          trace1;
       
   368     TraceIndex          trace2;
       
   369     TraceInfo * info1;
       
   370     TraceInfo * info2;
       
   371 
       
   372     HPROF_ASSERT(p_trace1!=NULL);
       
   373     HPROF_ASSERT(p_trace2!=NULL);
       
   374     trace1 = *(TraceIndex *)p_trace1;
       
   375     trace2 = *(TraceIndex *)p_trace2;
       
   376     info1 = get_info(trace1);
       
   377     info2 = get_info(trace2);
       
   378     /*LINTED*/
       
   379     return (int)(info2->self_cost - info1->self_cost);
       
   380 }
       
   381 
       
   382 static int
       
   383 qsort_compare_num_hits(const void *p_trace1, const void *p_trace2)
       
   384 {
       
   385     TraceIndex          trace1;
       
   386     TraceIndex          trace2;
       
   387     TraceInfo * info1;
       
   388     TraceInfo * info2;
       
   389 
       
   390     HPROF_ASSERT(p_trace1!=NULL);
       
   391     HPROF_ASSERT(p_trace2!=NULL);
       
   392     trace1 = *(TraceIndex *)p_trace1;
       
   393     trace2 = *(TraceIndex *)p_trace2;
       
   394     info1 = get_info(trace1);
       
   395     info2 = get_info(trace2);
       
   396     return info2->num_hits - info1->num_hits;
       
   397 }
       
   398 
       
   399 /* External interfaces. */
       
   400 
       
   401 void
       
   402 trace_init(void)
       
   403 {
       
   404     gdata->trace_table = table_initialize("Trace",
       
   405                             256, 256, 511, (int)sizeof(TraceInfo));
       
   406 }
       
   407 
       
   408 void
       
   409 trace_list(void)
       
   410 {
       
   411     debug_message(
       
   412         "--------------------- Trace Table ------------------------\n");
       
   413     table_walk_items(gdata->trace_table, &list_item, NULL);
       
   414     debug_message(
       
   415         "----------------------------------------------------------\n");
       
   416 }
       
   417 
       
   418 void
       
   419 trace_cleanup(void)
       
   420 {
       
   421     table_cleanup(gdata->trace_table, NULL, NULL);
       
   422     gdata->trace_table = NULL;
       
   423 }
       
   424 
       
   425 SerialNumber
       
   426 trace_get_serial_number(TraceIndex index)
       
   427 {
       
   428     TraceInfo *info;
       
   429 
       
   430     if ( index == 0 ) {
       
   431         return 0;
       
   432     }
       
   433     info = get_info(index);
       
   434     return info->serial_num;
       
   435 }
       
   436 
       
   437 void
       
   438 trace_increment_cost(TraceIndex index, jint num_hits, jlong self_cost, jlong total_cost)
       
   439 {
       
   440     TraceInfo *info;
       
   441 
       
   442     table_lock_enter(gdata->trace_table); {
       
   443         info              = get_info(index);
       
   444         info->num_hits   += num_hits;
       
   445         info->self_cost  += self_cost;
       
   446         info->total_cost += total_cost;
       
   447     } table_lock_exit(gdata->trace_table);
       
   448 }
       
   449 
       
   450 TraceIndex
       
   451 trace_find_or_create(SerialNumber thread_serial_num, jint n_frames, FrameIndex *frames, jvmtiFrameInfo *jframes_buffer)
       
   452 {
       
   453     return find_or_create(thread_serial_num, n_frames, frames, getPhase(),
       
   454                                 (TraceKey*)jframes_buffer);
       
   455 }
       
   456 
       
   457 /* We may need to ask for more frames than the user asked for */
       
   458 static int
       
   459 get_real_depth(int depth, jboolean skip_init)
       
   460 {
       
   461     int extra_frames;
       
   462 
       
   463     extra_frames = 0;
       
   464     /* This is only needed if we are doing BCI */
       
   465     if ( gdata->bci && depth > 0 ) {
       
   466         /* Account for Java and native Tracker methods */
       
   467         extra_frames = 2;
       
   468         if ( skip_init ) {
       
   469             /* Also allow for ignoring the java.lang.Object.<init> method */
       
   470             extra_frames += 1;
       
   471         }
       
   472     }
       
   473     return depth + extra_frames;
       
   474 }
       
   475 
       
   476 /* Fill in FrameIndex array from jvmtiFrameInfo array, return n_frames */
       
   477 static int
       
   478 fill_frame_buffer(int depth, int real_depth,
       
   479                  int frame_count, jboolean skip_init,
       
   480                  jvmtiFrameInfo *jframes_buffer, FrameIndex *frames_buffer)
       
   481 {
       
   482     int  n_frames;
       
   483     jint topframe;
       
   484 
       
   485     /* If real_depth is 0, just return 0 */
       
   486     if ( real_depth == 0 ) {
       
   487         return 0;
       
   488     }
       
   489 
       
   490     /* Assume top frame index is 0 for now */
       
   491     topframe = 0;
       
   492 
       
   493     /* Possible top frames belong to the hprof Tracker class, remove them */
       
   494     if ( gdata->bci ) {
       
   495         while ( ( ( frame_count - topframe ) > 0 ) &&
       
   496                 ( topframe < (real_depth-depth) ) &&
       
   497                 ( tracker_method(jframes_buffer[topframe].method) ||
       
   498                   ( skip_init
       
   499                     && jframes_buffer[topframe].method==gdata->object_init_method ) )
       
   500              ) {
       
   501             topframe++;
       
   502         }
       
   503     }
       
   504 
       
   505     /* Adjust count to match depth request */
       
   506     if ( ( frame_count - topframe ) > depth ) {
       
   507         frame_count =  depth + topframe;
       
   508     }
       
   509 
       
   510     /* The actual frame count we will process */
       
   511     n_frames = frame_count - topframe;
       
   512     if ( n_frames > 0 ) {
       
   513         int i;
       
   514 
       
   515         for (i = 0; i < n_frames; i++) {
       
   516             jmethodID method;
       
   517             jlocation location;
       
   518 
       
   519             method = jframes_buffer[i+topframe].method;
       
   520             location = jframes_buffer[i+topframe].location;
       
   521             frames_buffer[i] = frame_find_or_create(method, location);
       
   522         }
       
   523     }
       
   524     return n_frames;
       
   525 }
       
   526 
       
   527 /* Get the trace for the supplied thread */
       
   528 TraceIndex
       
   529 trace_get_current(jthread thread, SerialNumber thread_serial_num,
       
   530                         int depth, jboolean skip_init,
       
   531                         FrameIndex *frames_buffer,
       
   532                         jvmtiFrameInfo *jframes_buffer)
       
   533 {
       
   534     TraceIndex index;
       
   535     jint       frame_count;
       
   536     int        real_depth;
       
   537     int        n_frames;
       
   538 
       
   539     HPROF_ASSERT(thread!=NULL);
       
   540     HPROF_ASSERT(frames_buffer!=NULL);
       
   541     HPROF_ASSERT(jframes_buffer!=NULL);
       
   542 
       
   543     /* We may need to ask for more frames than the user asked for */
       
   544     real_depth = get_real_depth(depth, skip_init);
       
   545 
       
   546     /* Get the stack trace for this one thread */
       
   547     frame_count = 0;
       
   548     if ( real_depth > 0 ) {
       
   549         getStackTrace(thread, jframes_buffer, real_depth, &frame_count);
       
   550     }
       
   551 
       
   552     /* Create FrameIndex's */
       
   553     n_frames = fill_frame_buffer(depth, real_depth, frame_count, skip_init,
       
   554                                  jframes_buffer, frames_buffer);
       
   555 
       
   556     /* Lookup or create new TraceIndex */
       
   557     index = find_or_create(thread_serial_num, n_frames, frames_buffer,
       
   558                 getPhase(), (TraceKey*)jframes_buffer);
       
   559     return index;
       
   560 }
       
   561 
       
   562 /* Get traces for all threads in list (traces[i]==0 if thread not running) */
       
   563 void
       
   564 trace_get_all_current(jint thread_count, jthread *threads,
       
   565                       SerialNumber *thread_serial_nums,
       
   566                       int depth, jboolean skip_init,
       
   567                       TraceIndex *traces, jboolean always_care)
       
   568 {
       
   569     jvmtiStackInfo *stack_info;
       
   570     int             nbytes;
       
   571     int             real_depth;
       
   572     int             i;
       
   573     FrameIndex     *frames_buffer;
       
   574     TraceKey       *trace_key_buffer;
       
   575     jvmtiPhase      phase;
       
   576 
       
   577     HPROF_ASSERT(threads!=NULL);
       
   578     HPROF_ASSERT(thread_serial_nums!=NULL);
       
   579     HPROF_ASSERT(traces!=NULL);
       
   580     HPROF_ASSERT(thread_count > 0);
       
   581 
       
   582     /* Find out what the phase is for all these traces */
       
   583     phase = getPhase();
       
   584 
       
   585     /* We may need to ask for more frames than the user asked for */
       
   586     real_depth = get_real_depth(depth, skip_init);
       
   587 
       
   588     /* Get the stack traces for all the threads */
       
   589     getThreadListStackTraces(thread_count, threads, real_depth, &stack_info);
       
   590 
       
   591     /* Allocate a frames_buffer and trace key buffer */
       
   592     nbytes = (int)sizeof(FrameIndex)*real_depth;
       
   593     frames_buffer = (FrameIndex*)HPROF_MALLOC(nbytes);
       
   594     nbytes += (int)sizeof(TraceKey);
       
   595     trace_key_buffer = (TraceKey*)HPROF_MALLOC(nbytes);
       
   596 
       
   597     /* Loop over the stack traces we have for these 'thread_count' threads */
       
   598     for ( i = 0 ; i < thread_count ; i++ ) {
       
   599         int n_frames;
       
   600 
       
   601         /* Assume 0 at first (no trace) */
       
   602         traces[i] = 0;
       
   603 
       
   604         /* If thread has frames, is runnable, and isn't suspended, we care */
       
   605         if ( always_care ||
       
   606              ( stack_info[i].frame_count > 0
       
   607                && (stack_info[i].state & JVMTI_THREAD_STATE_RUNNABLE)!=0
       
   608                && (stack_info[i].state & JVMTI_THREAD_STATE_SUSPENDED)==0
       
   609                && (stack_info[i].state & JVMTI_THREAD_STATE_INTERRUPTED)==0 )
       
   610             ) {
       
   611 
       
   612             /* Create FrameIndex's */
       
   613             n_frames = fill_frame_buffer(depth, real_depth,
       
   614                                          stack_info[i].frame_count,
       
   615                                          skip_init,
       
   616                                          stack_info[i].frame_buffer,
       
   617                                          frames_buffer);
       
   618 
       
   619             /* Lookup or create new TraceIndex */
       
   620             traces[i] = find_or_create(thread_serial_nums[i],
       
   621                            n_frames, frames_buffer, phase, trace_key_buffer);
       
   622         }
       
   623     }
       
   624 
       
   625     /* Make sure we free the space */
       
   626     HPROF_FREE(frames_buffer);
       
   627     HPROF_FREE(trace_key_buffer);
       
   628     jvmtiDeallocate(stack_info);
       
   629 }
       
   630 
       
   631 /* Increment the trace costs for all the threads (for cpu=samples) */
       
   632 void
       
   633 trace_increment_all_sample_costs(jint thread_count, jthread *threads,
       
   634                       SerialNumber *thread_serial_nums,
       
   635                       int depth, jboolean skip_init)
       
   636 {
       
   637     TraceIndex *traces;
       
   638     int         nbytes;
       
   639 
       
   640     HPROF_ASSERT(threads!=NULL);
       
   641     HPROF_ASSERT(thread_serial_nums!=NULL);
       
   642     HPROF_ASSERT(thread_count > 0);
       
   643     HPROF_ASSERT(depth >= 0);
       
   644 
       
   645     if ( depth == 0 ) {
       
   646         return;
       
   647     }
       
   648 
       
   649     /* Allocate a traces array */
       
   650     nbytes = (int)sizeof(TraceIndex)*thread_count;
       
   651     traces = (TraceIndex*)HPROF_MALLOC(nbytes);
       
   652 
       
   653     /* Get all the current traces for these threads */
       
   654     trace_get_all_current(thread_count, threads, thread_serial_nums,
       
   655                       depth, skip_init, traces, JNI_FALSE);
       
   656 
       
   657     /* Increment the cpu=samples cost on these traces */
       
   658     table_lock_enter(gdata->trace_table); {
       
   659         int i;
       
   660 
       
   661         for ( i = 0 ; i < thread_count ; i++ ) {
       
   662             /* Each trace gets a hit and an increment of it's total cost */
       
   663             if ( traces[i] != 0 ) {
       
   664                 TraceInfo *info;
       
   665 
       
   666                 info              = get_info(traces[i]);
       
   667                 info->num_hits   += 1;
       
   668                 info->self_cost  += (jlong)1;
       
   669                 info->total_cost += (jlong)1;
       
   670             }
       
   671         }
       
   672     } table_lock_exit(gdata->trace_table);
       
   673 
       
   674     /* Free up the memory allocated */
       
   675     HPROF_FREE(traces);
       
   676 }
       
   677 
       
   678 void
       
   679 trace_output_unmarked(JNIEnv *env)
       
   680 {
       
   681     rawMonitorEnter(gdata->data_access_lock); {
       
   682         table_walk_items(gdata->trace_table, &output_trace, (void*)env);
       
   683     } rawMonitorExit(gdata->data_access_lock);
       
   684 }
       
   685 
       
   686 /* output info on the cost associated with traces  */
       
   687 void
       
   688 trace_output_cost(JNIEnv *env, double cutoff)
       
   689 {
       
   690     IterateInfo iterate;
       
   691     int i, trace_table_size, n_items;
       
   692     double accum;
       
   693     int n_entries;
       
   694 
       
   695     rawMonitorEnter(gdata->data_access_lock); {
       
   696 
       
   697         n_entries = table_element_count(gdata->trace_table);
       
   698         iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
       
   699         iterate.count = 0;
       
   700         iterate.grand_total_cost = 0;
       
   701         table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
       
   702 
       
   703         trace_table_size = iterate.count;
       
   704 
       
   705         /* sort all the traces according to the cost */
       
   706         qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
       
   707                     &qsort_compare_cost);
       
   708 
       
   709         n_items = 0;
       
   710         for (i = 0; i < trace_table_size; i++) {
       
   711             TraceInfo *info;
       
   712             TraceIndex trace_index;
       
   713             double percent;
       
   714 
       
   715             trace_index = iterate.traces[i];
       
   716             info = get_info(trace_index);
       
   717             /* As soon as a trace with zero hits is seen, we need no others */
       
   718             if (info->num_hits == 0 ) {
       
   719                 break;
       
   720             }
       
   721             percent = (double)info->self_cost / (double)iterate.grand_total_cost;
       
   722             if (percent < cutoff) {
       
   723                 break;
       
   724             }
       
   725             n_items++;
       
   726         }
       
   727 
       
   728         /* Now write all trace we might refer to. */
       
   729         output_list(env, iterate.traces, n_items);
       
   730 
       
   731         io_write_cpu_samples_header(iterate.grand_total_cost, n_items);
       
   732 
       
   733         accum = 0;
       
   734 
       
   735         for (i = 0; i < n_items; i++) {
       
   736             SerialNumber frame_serial_num;
       
   737             TraceInfo *info;
       
   738             TraceKey *key;
       
   739             TraceIndex trace_index;
       
   740             double percent;
       
   741             char *csig;
       
   742             char *mname;
       
   743             char *msig;
       
   744 
       
   745             trace_index = iterate.traces[i];
       
   746             info = get_info(trace_index);
       
   747             key = get_pkey(trace_index);
       
   748             percent = ((double)info->self_cost / (double)iterate.grand_total_cost) * 100.0;
       
   749             accum += percent;
       
   750 
       
   751             csig = NULL;
       
   752             mname = NULL;
       
   753             msig  = NULL;
       
   754 
       
   755             if (key->n_frames > 0) {
       
   756                 get_frame_details(env, key->frames[0], &frame_serial_num,
       
   757                         &csig, NULL, &mname, &msig, NULL, NULL);
       
   758             }
       
   759 
       
   760             io_write_cpu_samples_elem(i+1, percent, accum, info->num_hits,
       
   761                         (jint)info->self_cost, info->serial_num,
       
   762                         key->n_frames, csig, mname);
       
   763 
       
   764             jvmtiDeallocate(csig);
       
   765             jvmtiDeallocate(mname);
       
   766             jvmtiDeallocate(msig);
       
   767         }
       
   768 
       
   769         io_write_cpu_samples_footer();
       
   770 
       
   771         HPROF_FREE(iterate.traces);
       
   772 
       
   773     } rawMonitorExit(gdata->data_access_lock);
       
   774 
       
   775 }
       
   776 
       
   777 /* output the trace cost in old prof format */
       
   778 void
       
   779 trace_output_cost_in_prof_format(JNIEnv *env)
       
   780 {
       
   781     IterateInfo iterate;
       
   782     int i, trace_table_size;
       
   783     int n_entries;
       
   784 
       
   785     rawMonitorEnter(gdata->data_access_lock); {
       
   786 
       
   787         n_entries = table_element_count(gdata->trace_table);
       
   788         iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
       
   789         iterate.count = 0;
       
   790         iterate.grand_total_cost = 0;
       
   791         table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
       
   792 
       
   793         trace_table_size = iterate.count;
       
   794 
       
   795         /* sort all the traces according to the number of hits */
       
   796         qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
       
   797                     &qsort_compare_num_hits);
       
   798 
       
   799         io_write_oldprof_header();
       
   800 
       
   801         for (i = 0; i < trace_table_size; i++) {
       
   802             SerialNumber frame_serial_num;
       
   803             TraceInfo *info;
       
   804             TraceKey *key;
       
   805             TraceIndex trace_index;
       
   806             int num_frames;
       
   807             int num_hits;
       
   808             char *csig_callee;
       
   809             char *mname_callee;
       
   810             char *msig_callee;
       
   811             char *csig_caller;
       
   812             char *mname_caller;
       
   813             char *msig_caller;
       
   814 
       
   815             trace_index = iterate.traces[i];
       
   816             key = get_pkey(trace_index);
       
   817             info = get_info(trace_index);
       
   818             num_hits = info->num_hits;
       
   819 
       
   820             if (num_hits == 0) {
       
   821                 break;
       
   822             }
       
   823 
       
   824             csig_callee  = NULL;
       
   825             mname_callee = NULL;
       
   826             msig_callee  = NULL;
       
   827             csig_caller  = NULL;
       
   828             mname_caller = NULL;
       
   829             msig_caller  = NULL;
       
   830 
       
   831             num_frames = (int)key->n_frames;
       
   832 
       
   833             if (num_frames >= 1) {
       
   834                 get_frame_details(env, key->frames[0], &frame_serial_num,
       
   835                         &csig_callee, NULL,
       
   836                         &mname_callee, &msig_callee, NULL, NULL);
       
   837             }
       
   838 
       
   839             if (num_frames > 1) {
       
   840                 get_frame_details(env, key->frames[1], &frame_serial_num,
       
   841                         &csig_caller, NULL,
       
   842                         &mname_caller, &msig_caller, NULL, NULL);
       
   843             }
       
   844 
       
   845             io_write_oldprof_elem(info->num_hits, num_frames,
       
   846                                     csig_callee, mname_callee, msig_callee,
       
   847                                     csig_caller, mname_caller, msig_caller,
       
   848                                     (int)info->total_cost);
       
   849 
       
   850             jvmtiDeallocate(csig_callee);
       
   851             jvmtiDeallocate(mname_callee);
       
   852             jvmtiDeallocate(msig_callee);
       
   853             jvmtiDeallocate(csig_caller);
       
   854             jvmtiDeallocate(mname_caller);
       
   855             jvmtiDeallocate(msig_caller);
       
   856         }
       
   857 
       
   858         io_write_oldprof_footer();
       
   859 
       
   860         HPROF_FREE(iterate.traces);
       
   861 
       
   862     } rawMonitorExit(gdata->data_access_lock);
       
   863 }
       
   864 
       
   865 void
       
   866 trace_clear_cost(void)
       
   867 {
       
   868     table_walk_items(gdata->trace_table, &clear_cost, NULL);
       
   869 }