--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.hprof.agent/share/native/libhprof/hprof_trace.c Tue Aug 26 07:55:08 2014 +0200
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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 Oracle 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.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+
+/* Trace table. */
+
+/*
+ * A trace is an optional thread serial number plus N frames.
+ *
+ * The thread serial number is added to the key only if the user asks for
+ * threads in traces, which will cause many more traces to be created.
+ * Without it all threads share the traces.
+ *
+ * This is a variable length Key, depending on the number of frames.
+ * The frames are FrameIndex values into the frame table.
+ *
+ * It is important that the thread serial number is used and not the
+ * TlsIndex, threads come and go, and TlsIndex values are re-used
+ * but the thread serial number is unique per thread.
+ *
+ * The cpu=times and cpu=samples dumps rely heavily on traces, the trace
+ * dump preceeds the cpu information and uses the trace information.
+ * Depending on the cpu= request, different sorts are applied to the
+ * traces that are dumped.
+ *
+ */
+
+#include "hprof.h"
+
+typedef struct TraceKey {
+ SerialNumber thread_serial_num; /* Thread serial number */
+ short n_frames; /* Number of frames that follow. */
+ jvmtiPhase phase : 8; /* Makes some traces unique */
+ FrameIndex frames[1]; /* Variable length */
+} TraceKey;
+
+typedef struct TraceInfo {
+ SerialNumber serial_num; /* Trace serial number */
+ jint num_hits; /* Number of hits this trace has */
+ jlong total_cost; /* Total cost associated with trace */
+ jlong self_cost; /* Total cost without children cost */
+ jint status; /* Status of dump of trace */
+} TraceInfo;
+
+typedef struct IterateInfo {
+ TraceIndex* traces;
+ int count;
+ jlong grand_total_cost;
+} IterateInfo;
+
+/* Private internal functions. */
+
+static TraceKey*
+get_pkey(TraceIndex index)
+{
+ void * pkey;
+ int key_len;
+
+ table_get_key(gdata->trace_table, index, &pkey, &key_len);
+ HPROF_ASSERT(pkey!=NULL);
+ HPROF_ASSERT(key_len>=(int)sizeof(TraceKey));
+ HPROF_ASSERT(((TraceKey*)pkey)->n_frames<=1?key_len==(int)sizeof(TraceKey) :
+ key_len==(int)sizeof(TraceKey)+
+ (int)sizeof(FrameIndex)*(((TraceKey*)pkey)->n_frames-1));
+ return (TraceKey*)pkey;
+}
+
+static TraceInfo *
+get_info(TraceIndex index)
+{
+ TraceInfo * info;
+
+ info = (TraceInfo*)table_get_info(gdata->trace_table, index);
+ return info;
+}
+
+static TraceIndex
+find_or_create(SerialNumber thread_serial_num, jint n_frames,
+ FrameIndex *frames, jvmtiPhase phase, TraceKey *trace_key_buffer)
+{
+ TraceInfo * info;
+ TraceKey * pkey;
+ int key_len;
+ TraceIndex index;
+ jboolean new_one;
+ static TraceKey empty_key;
+
+ HPROF_ASSERT(frames!=NULL);
+ HPROF_ASSERT(trace_key_buffer!=NULL);
+ key_len = (int)sizeof(TraceKey);
+ if ( n_frames > 1 ) {
+ key_len += (int)((n_frames-1)*(int)sizeof(FrameIndex));
+ }
+ pkey = trace_key_buffer;
+ *pkey = empty_key;
+ pkey->thread_serial_num = (gdata->thread_in_traces ? thread_serial_num : 0);
+ pkey->n_frames = (short)n_frames;
+ pkey->phase = phase;
+ if ( n_frames > 0 ) {
+ (void)memcpy(pkey->frames, frames, (n_frames*(int)sizeof(FrameIndex)));
+ }
+
+ new_one = JNI_FALSE;
+ index = table_find_or_create_entry(gdata->trace_table,
+ pkey, key_len, &new_one, NULL);
+ if ( new_one ) {
+ info = get_info(index);
+ info->serial_num = gdata->trace_serial_number_counter++;
+ }
+ return index;
+}
+
+static void
+list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ TraceInfo *info;
+ TraceKey *key;
+ int i;
+
+ HPROF_ASSERT(key_ptr!=NULL);
+ HPROF_ASSERT(key_len>0);
+ HPROF_ASSERT(info_ptr!=NULL);
+ key = (TraceKey*)key_ptr;
+ info = (TraceInfo *)info_ptr;
+
+ debug_message( "Trace 0x%08x: SN=%u, threadSN=%u, n_frames=%d, frames=(",
+ index,
+ info->serial_num,
+ key->thread_serial_num,
+ key->n_frames);
+ for ( i = 0 ; i < key->n_frames ; i++ ) {
+ debug_message( "0x%08x, ", key->frames[i]);
+ }
+ debug_message( "), traceSN=%u, num_hits=%d, self_cost=(%d,%d), "
+ "total_cost=(%d,%d), status=0x%08x\n",
+ info->serial_num,
+ info->num_hits,
+ jlong_high(info->self_cost),
+ jlong_low(info->self_cost),
+ jlong_high(info->total_cost),
+ jlong_low(info->total_cost),
+ info->status);
+}
+
+static void
+clear_cost(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ TraceInfo *info;
+
+ HPROF_ASSERT(key_ptr!=NULL);
+ HPROF_ASSERT(key_len>0);
+ HPROF_ASSERT(info_ptr!=NULL);
+ info = (TraceInfo *)info_ptr;
+ info->num_hits = 0;
+ info->total_cost = 0;
+ info->self_cost = 0;
+}
+
+/* Get the names for a frame in order to dump it. */
+static void
+get_frame_details(JNIEnv *env, FrameIndex frame_index,
+ SerialNumber *frame_serial_num, char **pcsig, ClassIndex *pcnum,
+ char **pmname, char **pmsig, char **psname, jint *plineno)
+{
+ jmethodID method;
+ jlocation location;
+ jint lineno;
+
+ HPROF_ASSERT(frame_index!=0);
+ *pmname = NULL;
+ *pmsig = NULL;
+ *pcsig = NULL;
+ if ( psname != NULL ) {
+ *psname = NULL;
+ }
+ if ( plineno != NULL ) {
+ *plineno = -1;
+ }
+ if ( pcnum != NULL ) {
+ *pcnum = 0;
+ }
+ frame_get_location(frame_index, frame_serial_num, &method, &location, &lineno);
+ if ( plineno != NULL ) {
+ *plineno = lineno;
+ }
+ WITH_LOCAL_REFS(env, 1) {
+ jclass klass;
+
+ getMethodClass(method, &klass);
+ getClassSignature(klass, pcsig, NULL);
+ if ( pcnum != NULL ) {
+ LoaderIndex loader_index;
+ jobject loader;
+
+ loader = getClassLoader(klass);
+ loader_index = loader_find_or_create(env, loader);
+ *pcnum = class_find_or_create(*pcsig, loader_index);
+ (void)class_new_classref(env, *pcnum, klass);
+ }
+ if ( psname != NULL ) {
+ getSourceFileName(klass, psname);
+ }
+ } END_WITH_LOCAL_REFS;
+ getMethodName(method, pmname, pmsig);
+}
+
+/* Write out a stack trace. */
+static void
+output_trace(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ TraceKey *key;
+ TraceInfo *info;
+ SerialNumber serial_num;
+ SerialNumber thread_serial_num;
+ jint n_frames;
+ JNIEnv *env;
+ int i;
+ char *phase_str;
+ struct FrameNames {
+ SerialNumber serial_num;
+ char * sname;
+ char * csig;
+ char * mname;
+ int lineno;
+ } *finfo;
+
+ info = (TraceInfo*)info_ptr;
+ if ( info->status != 0 ) {
+ return;
+ }
+
+ env = (JNIEnv*)arg;
+
+ key = (TraceKey*)key_ptr;
+ thread_serial_num = key->thread_serial_num;
+ serial_num = info->serial_num;
+ info->status = 1;
+ finfo = NULL;
+
+ n_frames = (jint)key->n_frames;
+ if ( n_frames > 0 ) {
+ finfo = (struct FrameNames *)HPROF_MALLOC(n_frames*(int)sizeof(struct FrameNames));
+
+ /* Write frames, but save information for trace later */
+ for (i = 0; i < n_frames; i++) {
+ FrameIndex frame_index;
+ char *msig;
+ ClassIndex cnum;
+
+ frame_index = key->frames[i];
+ get_frame_details(env, frame_index, &finfo[i].serial_num,
+ &finfo[i].csig, &cnum,
+ &finfo[i].mname, &msig, &finfo[i].sname, &finfo[i].lineno);
+
+ if (frame_get_status(frame_index) == 0) {
+ io_write_frame(frame_index, finfo[i].serial_num,
+ finfo[i].mname, msig,
+ finfo[i].sname, class_get_serial_number(cnum),
+ finfo[i].lineno);
+ frame_set_status(frame_index, 1);
+ }
+ jvmtiDeallocate(msig);
+ }
+ }
+
+ /* Find phase string */
+ if ( key->phase == JVMTI_PHASE_LIVE ) {
+ phase_str = NULL; /* Normal trace, no phase annotation */
+ } else {
+ phase_str = phaseString(key->phase);
+ }
+
+ io_write_trace_header(serial_num, thread_serial_num, n_frames, phase_str);
+
+ for (i = 0; i < n_frames; i++) {
+ io_write_trace_elem(serial_num, key->frames[i], finfo[i].serial_num,
+ finfo[i].csig,
+ finfo[i].mname, finfo[i].sname, finfo[i].lineno);
+ jvmtiDeallocate(finfo[i].csig);
+ jvmtiDeallocate(finfo[i].mname);
+ jvmtiDeallocate(finfo[i].sname);
+ }
+
+ io_write_trace_footer(serial_num, thread_serial_num, n_frames);
+
+ if ( finfo != NULL ) {
+ HPROF_FREE(finfo);
+ }
+}
+
+/* Output a specific list of traces. */
+static void
+output_list(JNIEnv *env, TraceIndex *list, jint count)
+{
+ rawMonitorEnter(gdata->data_access_lock); {
+ int i;
+
+ for ( i = 0; i < count ; i++ ) {
+ TraceIndex index;
+ TraceInfo *info;
+ void * pkey;
+ int key_len;
+
+ index = list[i];
+ table_get_key(gdata->trace_table, index, &pkey, &key_len);
+ info = get_info(index);
+ output_trace(index, pkey, key_len, info, (void*)env);
+ }
+ } rawMonitorExit(gdata->data_access_lock);
+}
+
+static void
+collect_iterator(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
+{
+ TraceInfo *info;
+ IterateInfo *iterate;
+
+ HPROF_ASSERT(key_ptr!=NULL);
+ HPROF_ASSERT(key_len>0);
+ HPROF_ASSERT(arg!=NULL);
+ HPROF_ASSERT(info_ptr!=NULL);
+ iterate = (IterateInfo *)arg;
+ info = (TraceInfo *)info_ptr;
+ iterate->traces[iterate->count++] = index;
+ iterate->grand_total_cost += info->self_cost;
+}
+
+static int
+qsort_compare_cost(const void *p_trace1, const void *p_trace2)
+{
+ TraceIndex trace1;
+ TraceIndex trace2;
+ TraceInfo * info1;
+ TraceInfo * info2;
+
+ HPROF_ASSERT(p_trace1!=NULL);
+ HPROF_ASSERT(p_trace2!=NULL);
+ trace1 = *(TraceIndex *)p_trace1;
+ trace2 = *(TraceIndex *)p_trace2;
+ info1 = get_info(trace1);
+ info2 = get_info(trace2);
+ /*LINTED*/
+ return (int)(info2->self_cost - info1->self_cost);
+}
+
+static int
+qsort_compare_num_hits(const void *p_trace1, const void *p_trace2)
+{
+ TraceIndex trace1;
+ TraceIndex trace2;
+ TraceInfo * info1;
+ TraceInfo * info2;
+
+ HPROF_ASSERT(p_trace1!=NULL);
+ HPROF_ASSERT(p_trace2!=NULL);
+ trace1 = *(TraceIndex *)p_trace1;
+ trace2 = *(TraceIndex *)p_trace2;
+ info1 = get_info(trace1);
+ info2 = get_info(trace2);
+ return info2->num_hits - info1->num_hits;
+}
+
+/* External interfaces. */
+
+void
+trace_init(void)
+{
+ gdata->trace_table = table_initialize("Trace",
+ 256, 256, 511, (int)sizeof(TraceInfo));
+}
+
+void
+trace_list(void)
+{
+ debug_message(
+ "--------------------- Trace Table ------------------------\n");
+ table_walk_items(gdata->trace_table, &list_item, NULL);
+ debug_message(
+ "----------------------------------------------------------\n");
+}
+
+void
+trace_cleanup(void)
+{
+ table_cleanup(gdata->trace_table, NULL, NULL);
+ gdata->trace_table = NULL;
+}
+
+SerialNumber
+trace_get_serial_number(TraceIndex index)
+{
+ TraceInfo *info;
+
+ if ( index == 0 ) {
+ return 0;
+ }
+ info = get_info(index);
+ return info->serial_num;
+}
+
+void
+trace_increment_cost(TraceIndex index, jint num_hits, jlong self_cost, jlong total_cost)
+{
+ TraceInfo *info;
+
+ table_lock_enter(gdata->trace_table); {
+ info = get_info(index);
+ info->num_hits += num_hits;
+ info->self_cost += self_cost;
+ info->total_cost += total_cost;
+ } table_lock_exit(gdata->trace_table);
+}
+
+TraceIndex
+trace_find_or_create(SerialNumber thread_serial_num, jint n_frames, FrameIndex *frames, jvmtiFrameInfo *jframes_buffer)
+{
+ return find_or_create(thread_serial_num, n_frames, frames, getPhase(),
+ (TraceKey*)jframes_buffer);
+}
+
+/* We may need to ask for more frames than the user asked for */
+static int
+get_real_depth(int depth, jboolean skip_init)
+{
+ int extra_frames;
+
+ extra_frames = 0;
+ /* This is only needed if we are doing BCI */
+ if ( gdata->bci && depth > 0 ) {
+ /* Account for Java and native Tracker methods */
+ extra_frames = 2;
+ if ( skip_init ) {
+ /* Also allow for ignoring the java.lang.Object.<init> method */
+ extra_frames += 1;
+ }
+ }
+ return depth + extra_frames;
+}
+
+/* Fill in FrameIndex array from jvmtiFrameInfo array, return n_frames */
+static int
+fill_frame_buffer(int depth, int real_depth,
+ int frame_count, jboolean skip_init,
+ jvmtiFrameInfo *jframes_buffer, FrameIndex *frames_buffer)
+{
+ int n_frames;
+ jint topframe;
+
+ /* If real_depth is 0, just return 0 */
+ if ( real_depth == 0 ) {
+ return 0;
+ }
+
+ /* Assume top frame index is 0 for now */
+ topframe = 0;
+
+ /* Possible top frames belong to the hprof Tracker class, remove them */
+ if ( gdata->bci ) {
+ while ( ( ( frame_count - topframe ) > 0 ) &&
+ ( topframe < (real_depth-depth) ) &&
+ ( tracker_method(jframes_buffer[topframe].method) ||
+ ( skip_init
+ && jframes_buffer[topframe].method==gdata->object_init_method ) )
+ ) {
+ topframe++;
+ }
+ }
+
+ /* Adjust count to match depth request */
+ if ( ( frame_count - topframe ) > depth ) {
+ frame_count = depth + topframe;
+ }
+
+ /* The actual frame count we will process */
+ n_frames = frame_count - topframe;
+ if ( n_frames > 0 ) {
+ int i;
+
+ for (i = 0; i < n_frames; i++) {
+ jmethodID method;
+ jlocation location;
+
+ method = jframes_buffer[i+topframe].method;
+ location = jframes_buffer[i+topframe].location;
+ frames_buffer[i] = frame_find_or_create(method, location);
+ }
+ }
+ return n_frames;
+}
+
+/* Get the trace for the supplied thread */
+TraceIndex
+trace_get_current(jthread thread, SerialNumber thread_serial_num,
+ int depth, jboolean skip_init,
+ FrameIndex *frames_buffer,
+ jvmtiFrameInfo *jframes_buffer)
+{
+ TraceIndex index;
+ jint frame_count;
+ int real_depth;
+ int n_frames;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(frames_buffer!=NULL);
+ HPROF_ASSERT(jframes_buffer!=NULL);
+
+ /* We may need to ask for more frames than the user asked for */
+ real_depth = get_real_depth(depth, skip_init);
+
+ /* Get the stack trace for this one thread */
+ frame_count = 0;
+ if ( real_depth > 0 ) {
+ getStackTrace(thread, jframes_buffer, real_depth, &frame_count);
+ }
+
+ /* Create FrameIndex's */
+ n_frames = fill_frame_buffer(depth, real_depth, frame_count, skip_init,
+ jframes_buffer, frames_buffer);
+
+ /* Lookup or create new TraceIndex */
+ index = find_or_create(thread_serial_num, n_frames, frames_buffer,
+ getPhase(), (TraceKey*)jframes_buffer);
+ return index;
+}
+
+/* Get traces for all threads in list (traces[i]==0 if thread not running) */
+void
+trace_get_all_current(jint thread_count, jthread *threads,
+ SerialNumber *thread_serial_nums,
+ int depth, jboolean skip_init,
+ TraceIndex *traces, jboolean always_care)
+{
+ jvmtiStackInfo *stack_info;
+ int nbytes;
+ int real_depth;
+ int i;
+ FrameIndex *frames_buffer;
+ TraceKey *trace_key_buffer;
+ jvmtiPhase phase;
+
+ HPROF_ASSERT(threads!=NULL);
+ HPROF_ASSERT(thread_serial_nums!=NULL);
+ HPROF_ASSERT(traces!=NULL);
+ HPROF_ASSERT(thread_count > 0);
+
+ /* Find out what the phase is for all these traces */
+ phase = getPhase();
+
+ /* We may need to ask for more frames than the user asked for */
+ real_depth = get_real_depth(depth, skip_init);
+
+ /* Get the stack traces for all the threads */
+ getThreadListStackTraces(thread_count, threads, real_depth, &stack_info);
+
+ /* Allocate a frames_buffer and trace key buffer */
+ nbytes = (int)sizeof(FrameIndex)*real_depth;
+ frames_buffer = (FrameIndex*)HPROF_MALLOC(nbytes);
+ nbytes += (int)sizeof(TraceKey);
+ trace_key_buffer = (TraceKey*)HPROF_MALLOC(nbytes);
+
+ /* Loop over the stack traces we have for these 'thread_count' threads */
+ for ( i = 0 ; i < thread_count ; i++ ) {
+ int n_frames;
+
+ /* Assume 0 at first (no trace) */
+ traces[i] = 0;
+
+ /* If thread has frames, is runnable, and isn't suspended, we care */
+ if ( always_care ||
+ ( stack_info[i].frame_count > 0
+ && (stack_info[i].state & JVMTI_THREAD_STATE_RUNNABLE)!=0
+ && (stack_info[i].state & JVMTI_THREAD_STATE_SUSPENDED)==0
+ && (stack_info[i].state & JVMTI_THREAD_STATE_INTERRUPTED)==0 )
+ ) {
+
+ /* Create FrameIndex's */
+ n_frames = fill_frame_buffer(depth, real_depth,
+ stack_info[i].frame_count,
+ skip_init,
+ stack_info[i].frame_buffer,
+ frames_buffer);
+
+ /* Lookup or create new TraceIndex */
+ traces[i] = find_or_create(thread_serial_nums[i],
+ n_frames, frames_buffer, phase, trace_key_buffer);
+ }
+ }
+
+ /* Make sure we free the space */
+ HPROF_FREE(frames_buffer);
+ HPROF_FREE(trace_key_buffer);
+ jvmtiDeallocate(stack_info);
+}
+
+/* Increment the trace costs for all the threads (for cpu=samples) */
+void
+trace_increment_all_sample_costs(jint thread_count, jthread *threads,
+ SerialNumber *thread_serial_nums,
+ int depth, jboolean skip_init)
+{
+ TraceIndex *traces;
+ int nbytes;
+
+ HPROF_ASSERT(threads!=NULL);
+ HPROF_ASSERT(thread_serial_nums!=NULL);
+ HPROF_ASSERT(thread_count > 0);
+ HPROF_ASSERT(depth >= 0);
+
+ if ( depth == 0 ) {
+ return;
+ }
+
+ /* Allocate a traces array */
+ nbytes = (int)sizeof(TraceIndex)*thread_count;
+ traces = (TraceIndex*)HPROF_MALLOC(nbytes);
+
+ /* Get all the current traces for these threads */
+ trace_get_all_current(thread_count, threads, thread_serial_nums,
+ depth, skip_init, traces, JNI_FALSE);
+
+ /* Increment the cpu=samples cost on these traces */
+ table_lock_enter(gdata->trace_table); {
+ int i;
+
+ for ( i = 0 ; i < thread_count ; i++ ) {
+ /* Each trace gets a hit and an increment of it's total cost */
+ if ( traces[i] != 0 ) {
+ TraceInfo *info;
+
+ info = get_info(traces[i]);
+ info->num_hits += 1;
+ info->self_cost += (jlong)1;
+ info->total_cost += (jlong)1;
+ }
+ }
+ } table_lock_exit(gdata->trace_table);
+
+ /* Free up the memory allocated */
+ HPROF_FREE(traces);
+}
+
+void
+trace_output_unmarked(JNIEnv *env)
+{
+ rawMonitorEnter(gdata->data_access_lock); {
+ table_walk_items(gdata->trace_table, &output_trace, (void*)env);
+ } rawMonitorExit(gdata->data_access_lock);
+}
+
+/* output info on the cost associated with traces */
+void
+trace_output_cost(JNIEnv *env, double cutoff)
+{
+ IterateInfo iterate;
+ int i, trace_table_size, n_items;
+ double accum;
+ int n_entries;
+
+ rawMonitorEnter(gdata->data_access_lock); {
+
+ n_entries = table_element_count(gdata->trace_table);
+ iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
+ iterate.count = 0;
+ iterate.grand_total_cost = 0;
+ table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
+
+ trace_table_size = iterate.count;
+
+ /* sort all the traces according to the cost */
+ qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
+ &qsort_compare_cost);
+
+ n_items = 0;
+ for (i = 0; i < trace_table_size; i++) {
+ TraceInfo *info;
+ TraceIndex trace_index;
+ double percent;
+
+ trace_index = iterate.traces[i];
+ info = get_info(trace_index);
+ /* As soon as a trace with zero hits is seen, we need no others */
+ if (info->num_hits == 0 ) {
+ break;
+ }
+ percent = (double)info->self_cost / (double)iterate.grand_total_cost;
+ if (percent < cutoff) {
+ break;
+ }
+ n_items++;
+ }
+
+ /* Now write all trace we might refer to. */
+ output_list(env, iterate.traces, n_items);
+
+ io_write_cpu_samples_header(iterate.grand_total_cost, n_items);
+
+ accum = 0;
+
+ for (i = 0; i < n_items; i++) {
+ SerialNumber frame_serial_num;
+ TraceInfo *info;
+ TraceKey *key;
+ TraceIndex trace_index;
+ double percent;
+ char *csig;
+ char *mname;
+ char *msig;
+
+ trace_index = iterate.traces[i];
+ info = get_info(trace_index);
+ key = get_pkey(trace_index);
+ percent = ((double)info->self_cost / (double)iterate.grand_total_cost) * 100.0;
+ accum += percent;
+
+ csig = NULL;
+ mname = NULL;
+ msig = NULL;
+
+ if (key->n_frames > 0) {
+ get_frame_details(env, key->frames[0], &frame_serial_num,
+ &csig, NULL, &mname, &msig, NULL, NULL);
+ }
+
+ io_write_cpu_samples_elem(i+1, percent, accum, info->num_hits,
+ (jint)info->self_cost, info->serial_num,
+ key->n_frames, csig, mname);
+
+ jvmtiDeallocate(csig);
+ jvmtiDeallocate(mname);
+ jvmtiDeallocate(msig);
+ }
+
+ io_write_cpu_samples_footer();
+
+ HPROF_FREE(iterate.traces);
+
+ } rawMonitorExit(gdata->data_access_lock);
+
+}
+
+/* output the trace cost in old prof format */
+void
+trace_output_cost_in_prof_format(JNIEnv *env)
+{
+ IterateInfo iterate;
+ int i, trace_table_size;
+ int n_entries;
+
+ rawMonitorEnter(gdata->data_access_lock); {
+
+ n_entries = table_element_count(gdata->trace_table);
+ iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
+ iterate.count = 0;
+ iterate.grand_total_cost = 0;
+ table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
+
+ trace_table_size = iterate.count;
+
+ /* sort all the traces according to the number of hits */
+ qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
+ &qsort_compare_num_hits);
+
+ io_write_oldprof_header();
+
+ for (i = 0; i < trace_table_size; i++) {
+ SerialNumber frame_serial_num;
+ TraceInfo *info;
+ TraceKey *key;
+ TraceIndex trace_index;
+ int num_frames;
+ int num_hits;
+ char *csig_callee;
+ char *mname_callee;
+ char *msig_callee;
+ char *csig_caller;
+ char *mname_caller;
+ char *msig_caller;
+
+ trace_index = iterate.traces[i];
+ key = get_pkey(trace_index);
+ info = get_info(trace_index);
+ num_hits = info->num_hits;
+
+ if (num_hits == 0) {
+ break;
+ }
+
+ csig_callee = NULL;
+ mname_callee = NULL;
+ msig_callee = NULL;
+ csig_caller = NULL;
+ mname_caller = NULL;
+ msig_caller = NULL;
+
+ num_frames = (int)key->n_frames;
+
+ if (num_frames >= 1) {
+ get_frame_details(env, key->frames[0], &frame_serial_num,
+ &csig_callee, NULL,
+ &mname_callee, &msig_callee, NULL, NULL);
+ }
+
+ if (num_frames > 1) {
+ get_frame_details(env, key->frames[1], &frame_serial_num,
+ &csig_caller, NULL,
+ &mname_caller, &msig_caller, NULL, NULL);
+ }
+
+ io_write_oldprof_elem(info->num_hits, num_frames,
+ csig_callee, mname_callee, msig_callee,
+ csig_caller, mname_caller, msig_caller,
+ (int)info->total_cost);
+
+ jvmtiDeallocate(csig_callee);
+ jvmtiDeallocate(mname_callee);
+ jvmtiDeallocate(msig_callee);
+ jvmtiDeallocate(csig_caller);
+ jvmtiDeallocate(mname_caller);
+ jvmtiDeallocate(msig_caller);
+ }
+
+ io_write_oldprof_footer();
+
+ HPROF_FREE(iterate.traces);
+
+ } rawMonitorExit(gdata->data_access_lock);
+}
+
+void
+trace_clear_cost(void)
+{
+ table_walk_items(gdata->trace_table, &clear_cost, NULL);
+}