Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_trace.c
38829 views
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
}
870
871