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_tls.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
#include "hprof.h"
42
43
/* Thread Local Storage Table and method entry/exit handling. */
44
45
/*
46
* The tls table items have a key of it's serial number, but may be
47
* searched via a walk of the table looking for a jthread match.
48
* This isn't a performance
49
* issue because the table index should normally be stored in the
50
* Thread Local Storage for the thread. The table is only searched
51
* when the jthread is seen before the Thread Local Storage is set
52
* (e.g. before VM_INIT or the ThreadStart).
53
* The key is only used when we need to lookup a tls table entry by
54
* way of it's serial number, which should be unique per thread.
55
*
56
* Each active thread that we have seen should have a unique TlsIndex
57
* which is an index into this table.
58
*
59
* For cpu=times, each table entry will have a stack to hold the method
60
* that have been called, effectively keeping an active stack trace
61
* for the thread. As each method exits, the statistics for the trace
62
* associated with the current stack contents is updated.
63
*
64
* For cpu=samples, each thread is checked to see if it's runnable,
65
* and not suspended, and has a stack associated with it, and then
66
* that stack trace is updated with an additional 'hit'.
67
*
68
* This file also contains the dump logic for owned monitors, and for
69
* threads.
70
*
71
*/
72
73
/*
74
* Initial number of stack elements to track per thread. This
75
* value should be set to a reasonable guess as to the number of
76
* methods deep a thread calls. This stack doubles in size for each
77
* reallocation and does not shrink.
78
*/
79
80
#define INITIAL_THREAD_STACK_LIMIT 64
81
82
typedef struct StackElement {
83
FrameIndex frame_index; /* Frame (method/location(-1)) */
84
jmethodID method; /* Method ID */
85
jlong method_start_time; /* method start time */
86
jlong time_in_callees; /* time in callees */
87
} StackElement;
88
89
typedef struct TlsInfo {
90
jint sample_status; /* Thread status for cpu sampling */
91
jboolean agent_thread; /* Is thread our own agent thread? */
92
jthread globalref; /* Global reference for thread */
93
Stack *stack; /* Stack of StackElements entry/exit */
94
MonitorIndex monitor_index; /* last contended mon */
95
jint tracker_status; /* If we are inside Tracker class */
96
FrameIndex *frames_buffer; /* Buffer used to create TraceIndex */
97
jvmtiFrameInfo *jframes_buffer; /* Buffer used to create TraceIndex */
98
int buffer_depth; /* Frames allowed in buffer */
99
TraceIndex last_trace; /* Last trace for this thread */
100
ObjectIndex thread_object_index;/* If heap=dump */
101
jlong monitor_start_time; /* Start time for monitor */
102
jint in_heap_dump; /* If we are an object in the dump */
103
} TlsInfo;
104
105
typedef struct SearchData {
106
JNIEnv *env;
107
jthread thread;
108
TlsIndex found;
109
} SearchData;
110
111
typedef struct IterateInfo {
112
TlsIndex * ptls_index;
113
jthread * pthreads;
114
jint count;
115
} IterateInfo;
116
117
typedef struct ThreadList {
118
jthread *threads;
119
SerialNumber *serial_nums;
120
TlsInfo **infos;
121
jint count;
122
JNIEnv *env;
123
} ThreadList;
124
125
typedef struct SampleData {
126
ObjectIndex thread_object_index;
127
jint sample_status;
128
} SampleData;
129
130
/* Private internal functions. */
131
132
static SerialNumber
133
get_key(TlsIndex index)
134
{
135
SerialNumber *pkey;
136
int key_len;
137
138
if ( index == 0 ) {
139
return 0;
140
}
141
pkey = NULL;
142
key_len = 0;
143
table_get_key(gdata->tls_table, index, (void**)&pkey, &key_len);
144
HPROF_ASSERT(pkey!=NULL);
145
HPROF_ASSERT(key_len==(int)sizeof(SerialNumber));
146
return *pkey;
147
}
148
149
static TlsInfo *
150
get_info(TlsIndex index)
151
{
152
return (TlsInfo*)table_get_info(gdata->tls_table, index);
153
}
154
155
static void
156
delete_globalref(JNIEnv *env, TlsInfo *info)
157
{
158
jthread ref;
159
160
HPROF_ASSERT(env!=NULL);
161
HPROF_ASSERT(info!=NULL);
162
ref = info->globalref;
163
info->globalref = NULL;
164
if ( ref != NULL ) {
165
deleteWeakGlobalReference(env, ref);
166
}
167
}
168
169
static void
170
clean_info(TlsInfo *info)
171
{
172
/* Free up any allocated space in this TlsInfo structure */
173
if ( info->stack != NULL ) {
174
stack_term(info->stack);
175
info->stack = NULL;
176
}
177
if ( info->frames_buffer != NULL ) {
178
HPROF_FREE(info->frames_buffer);
179
info->frames_buffer = NULL;
180
}
181
if ( info->jframes_buffer != NULL ) {
182
HPROF_FREE(info->jframes_buffer);
183
info->jframes_buffer = NULL;
184
}
185
}
186
187
static void
188
cleanup_item(TableIndex index, void *key_ptr, int key_len,
189
void *info_ptr, void *arg)
190
{
191
TlsInfo * info;
192
193
info = (TlsInfo*)info_ptr;
194
clean_info(info);
195
}
196
197
static void
198
delete_ref_item(TableIndex index, void *key_ptr, int key_len,
199
void *info_ptr, void *arg)
200
{
201
delete_globalref((JNIEnv*)arg, (TlsInfo*)info_ptr);
202
}
203
204
static void
205
list_item(TableIndex index, void *key_ptr, int key_len,
206
void *info_ptr, void *arg)
207
{
208
TlsInfo *info;
209
210
HPROF_ASSERT(info_ptr!=NULL);
211
212
info = (TlsInfo*)info_ptr;
213
debug_message( "Tls 0x%08x: SN=%u, sample_status=%d, agent=%d, "
214
"thread=%p, monitor=0x%08x, "
215
"tracker_status=%d\n",
216
index,
217
*(SerialNumber*)key_ptr,
218
info->sample_status,
219
info->agent_thread,
220
(void*)info->globalref,
221
info->monitor_index,
222
info->tracker_status);
223
}
224
225
static void
226
search_item(TableIndex index, void *key_ptr, int key_len,
227
void *info_ptr, void *arg)
228
{
229
TlsInfo *info;
230
SearchData *data;
231
jobject lref;
232
233
HPROF_ASSERT(info_ptr!=NULL);
234
HPROF_ASSERT(arg!=NULL);
235
info = (TlsInfo*)info_ptr;
236
data = (SearchData*)arg;
237
lref = newLocalReference(data->env, info->globalref);
238
if ( lref != NULL ) {
239
if ( isSameObject(data->env, data->thread, lref) ) {
240
HPROF_ASSERT(data->found==0); /* Did we find more than one? */
241
data->found = index;
242
}
243
deleteLocalReference(data->env, lref);
244
}
245
}
246
247
static TlsIndex
248
search(JNIEnv *env, jthread thread)
249
{
250
SearchData data;
251
252
HPROF_ASSERT(env!=NULL);
253
HPROF_ASSERT(thread!=NULL);
254
255
data.env = env;
256
data.thread = thread;
257
data.found = 0;
258
table_walk_items(gdata->tls_table, &search_item, (void*)&data);
259
return data.found;
260
}
261
262
static void
263
garbage_collect_item(TableIndex index, void *key_ptr, int key_len,
264
void *info_ptr, void *arg)
265
{
266
TlsInfo *info;
267
JNIEnv *env;
268
jobject lref;
269
270
HPROF_ASSERT(info_ptr!=NULL);
271
HPROF_ASSERT(arg!=NULL);
272
info = (TlsInfo*)info_ptr;
273
env = (JNIEnv*)arg;
274
lref = newLocalReference(env, info->globalref);
275
if ( lref == NULL ) {
276
delete_globalref(env, info);
277
clean_info(info);
278
table_free_entry(gdata->tls_table, index);
279
} else {
280
deleteLocalReference(env, lref);
281
}
282
}
283
284
void
285
tls_garbage_collect(JNIEnv *env)
286
{
287
HPROF_ASSERT(env!=NULL);
288
rawMonitorEnter(gdata->data_access_lock); {
289
table_walk_items(gdata->tls_table, &garbage_collect_item, (void*)env);
290
} rawMonitorExit(gdata->data_access_lock);
291
}
292
293
static void
294
sum_sample_status_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
295
{
296
TlsInfo *info;
297
298
HPROF_ASSERT(info_ptr!=NULL);
299
info = (TlsInfo*)info_ptr;
300
if ( !info->agent_thread ) {
301
(*(jint*)arg) += info->sample_status;
302
}
303
}
304
305
static void
306
setup_trace_buffers(TlsInfo *info, int max_depth)
307
{
308
int nbytes;
309
int max_frames;
310
311
if ( info->frames_buffer != NULL && info->buffer_depth >= max_depth ) {
312
return;
313
}
314
if ( info->frames_buffer != NULL ) {
315
HPROF_FREE(info->frames_buffer);
316
}
317
if ( info->jframes_buffer != NULL ) {
318
HPROF_FREE(info->jframes_buffer);
319
}
320
info->buffer_depth = max_depth;
321
max_frames = max_depth + 4; /* Allow for BCI & <init> */
322
nbytes = (int)sizeof(FrameIndex)*(max_frames+1);
323
info->frames_buffer = HPROF_MALLOC(nbytes);
324
nbytes = (int)sizeof(jvmtiFrameInfo)*(max_frames+1);
325
info->jframes_buffer = HPROF_MALLOC(nbytes);
326
}
327
328
static TraceIndex
329
get_trace(jthread thread, SerialNumber thread_serial_num,
330
int depth, jboolean skip_init,
331
FrameIndex *frames_buffer, jvmtiFrameInfo *jframes_buffer)
332
{
333
TraceIndex trace_index;
334
335
trace_index = gdata->system_trace_index;
336
if ( thread != NULL ) {
337
trace_index = trace_get_current(thread,
338
thread_serial_num, depth, skip_init,
339
frames_buffer, jframes_buffer);
340
}
341
return trace_index;
342
}
343
344
/* Find thread with certain object index */
345
static void
346
sample_setter(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
347
{
348
TlsInfo *info;
349
350
HPROF_ASSERT(info_ptr!=NULL);
351
352
info = (TlsInfo*)info_ptr;
353
if ( info->globalref != NULL && !info->agent_thread ) {
354
SampleData *data;
355
356
data = (SampleData*)arg;
357
if ( data->thread_object_index == info->thread_object_index ) {
358
info->sample_status = data->sample_status;
359
}
360
}
361
}
362
363
/* Get various lists on known threads */
364
static void
365
get_thread_list(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
366
{
367
SerialNumber thread_serial_num;
368
TlsInfo *info;
369
ThreadList *list;
370
jthread thread;
371
372
HPROF_ASSERT(key_ptr!=NULL);
373
HPROF_ASSERT(info_ptr!=NULL);
374
375
thread_serial_num = *(SerialNumber*)key_ptr;
376
info = (TlsInfo*)info_ptr;
377
list = (ThreadList*)arg;
378
thread = newLocalReference(list->env, info->globalref);
379
if ( thread != NULL && info->sample_status != 0 && !info->agent_thread ) {
380
if ( list->infos != NULL ) {
381
list->infos[list->count] = info;
382
}
383
if ( list->serial_nums != NULL ) {
384
list->serial_nums[list->count] = thread_serial_num;
385
}
386
list->threads[list->count] = thread;
387
list->count++;
388
/* Local reference gets freed by caller */
389
} else {
390
/* If we don't use the local reference, delete it now */
391
if ( thread != NULL ) {
392
deleteLocalReference(list->env, thread);
393
}
394
}
395
}
396
397
static void
398
adjust_stats(jlong total_time, jlong self_time, TraceIndex trace_index,
399
StackElement *parent)
400
{
401
if ( total_time > 0 && parent != NULL ) { /* if a caller exists */
402
parent->time_in_callees += total_time;
403
}
404
trace_increment_cost(trace_index, 1, self_time, total_time);
405
}
406
407
static void
408
push_method(Stack *stack, jlong method_start_time, jmethodID method)
409
{
410
StackElement new_element;
411
FrameIndex frame_index;
412
413
HPROF_ASSERT(method!=NULL);
414
HPROF_ASSERT(stack!=NULL);
415
416
frame_index = frame_find_or_create(method, -1);
417
HPROF_ASSERT(frame_index != 0);
418
new_element.frame_index = frame_index;
419
new_element.method = method;
420
new_element.method_start_time= method_start_time;
421
new_element.time_in_callees = (jlong)0;
422
stack_push(stack, &new_element);
423
}
424
425
static Stack *
426
insure_method_on_stack(jthread thread, TlsInfo *info, jlong current_time,
427
FrameIndex frame_index, jmethodID method)
428
{
429
StackElement element;
430
void *p;
431
int depth;
432
int count;
433
int fcount;
434
int i;
435
Stack *new_stack;
436
Stack *stack;
437
438
stack = info->stack;
439
440
HPROF_ASSERT(method!=NULL);
441
442
/* If this method is on the stack, just return */
443
depth = stack_depth(stack);
444
p = stack_top(stack);
445
if ( p != NULL ) {
446
element = *(StackElement*)p;
447
if ( element.frame_index == frame_index ) {
448
return stack;
449
}
450
}
451
for ( i = 0 ; i < depth ; i++ ) {
452
p = stack_element(stack, i);
453
element = *(StackElement*)p;
454
if ( element.frame_index == frame_index ) {
455
return stack;
456
}
457
}
458
459
/* It wasn't found, create a new stack */
460
getFrameCount(thread, &count);
461
if ( count <= 0 ) {
462
HPROF_ERROR(JNI_FALSE, "no frames, method can't be on stack");
463
}
464
setup_trace_buffers(info, count);
465
getStackTrace(thread, info->jframes_buffer, count, &fcount);
466
HPROF_ASSERT(count==fcount);
467
468
/* Create a new stack */
469
new_stack = stack_init(INITIAL_THREAD_STACK_LIMIT,
470
INITIAL_THREAD_STACK_LIMIT,
471
(int)sizeof(StackElement));
472
for ( i = count-1; i >= 0 ; i-- ) {
473
push_method(new_stack, current_time, info->jframes_buffer[i].method);
474
}
475
if ( depth > 0 ) {
476
for ( i = depth-1 ; i >= 0; i-- ) {
477
stack_push(new_stack, stack_element(stack, i));
478
}
479
}
480
stack_term(stack);
481
return new_stack;
482
}
483
484
static void
485
pop_method(TlsIndex index, jlong current_time, jmethodID method, FrameIndex frame_index)
486
{
487
SerialNumber thread_serial_num;
488
TlsInfo * info;
489
StackElement element;
490
void *p;
491
int depth;
492
int trace_depth;
493
jlong total_time;
494
jlong self_time;
495
int i;
496
TraceIndex trace_index;
497
498
HPROF_ASSERT(method!=NULL);
499
HPROF_ASSERT(frame_index!=0);
500
501
thread_serial_num = get_key(index);
502
info = get_info(index);
503
HPROF_ASSERT(info!=NULL);
504
HPROF_ASSERT(info->stack!=NULL);
505
depth = stack_depth(info->stack);
506
p = stack_pop(info->stack);
507
if (p == NULL) {
508
HPROF_ERROR(JNI_FALSE, "method return tracked, but stack is empty");
509
return;
510
}
511
element = *(StackElement*)p;
512
HPROF_ASSERT(element.frame_index!=0);
513
514
/* The depth of frames we should keep track for reporting */
515
if (gdata->prof_trace_depth > depth) {
516
trace_depth = depth;
517
} else {
518
trace_depth = gdata->prof_trace_depth;
519
}
520
521
/* Create a trace entry */
522
HPROF_ASSERT(info->frames_buffer!=NULL);
523
HPROF_ASSERT(info->jframes_buffer!=NULL);
524
setup_trace_buffers(info, trace_depth);
525
info->frames_buffer[0] = element.frame_index;
526
for (i = 1; i < trace_depth; i++) {
527
StackElement e;
528
529
e = *(StackElement*)stack_element(info->stack, (depth - i) - 1);
530
info->frames_buffer[i] = e.frame_index;
531
HPROF_ASSERT(e.frame_index!=0);
532
}
533
trace_index = trace_find_or_create(thread_serial_num,
534
trace_depth, info->frames_buffer, info->jframes_buffer);
535
536
/* Calculate time spent */
537
total_time = current_time - element.method_start_time;
538
if ( total_time < 0 ) {
539
total_time = 0;
540
self_time = 0;
541
} else {
542
self_time = total_time - element.time_in_callees;
543
}
544
545
/* Update stats */
546
p = stack_top(info->stack);
547
if ( p != NULL ) {
548
adjust_stats(total_time, self_time, trace_index, (StackElement*)p);
549
} else {
550
adjust_stats(total_time, self_time, trace_index, NULL);
551
}
552
}
553
554
static void
555
dump_thread_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
556
{
557
SerialNumber thread_serial_num;
558
TlsInfo *info;
559
jthread thread;
560
JNIEnv *env;
561
562
HPROF_ASSERT(key_ptr!=NULL);
563
HPROF_ASSERT(info_ptr!=NULL);
564
env = (JNIEnv*)arg;
565
thread_serial_num = *(SerialNumber*)key_ptr;
566
info = (TlsInfo*)info_ptr;
567
thread = newLocalReference(env, info->globalref);
568
if ( thread != NULL ) {
569
jint threadState;
570
SerialNumber trace_serial_num;
571
572
getThreadState(thread, &threadState);
573
/* A 0 trace at this time means the thread is in unknown territory.
574
* The trace serial number MUST be a valid serial number, so we use
575
* the system trace (empty) just so it has a valid trace.
576
*/
577
if ( info->last_trace == 0 ) {
578
trace_serial_num = trace_get_serial_number(gdata->system_trace_index);
579
} else {
580
trace_serial_num = trace_get_serial_number(info->last_trace);
581
}
582
io_write_monitor_dump_thread_state(thread_serial_num,
583
trace_serial_num, threadState);
584
deleteLocalReference(env, thread);
585
}
586
}
587
588
static SerialNumber
589
get_serial_number(JNIEnv *env, jthread thread)
590
{
591
TlsIndex index;
592
593
if ( thread == NULL ) {
594
return gdata->unknown_thread_serial_num;
595
}
596
HPROF_ASSERT(env!=NULL);
597
index = tls_find_or_create(env, thread);
598
return get_key(index);
599
}
600
601
static void
602
dump_monitor_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
603
{
604
TlsInfo *info;
605
jthread thread;
606
JNIEnv *env;
607
608
HPROF_ASSERT(info_ptr!=NULL);
609
env = (JNIEnv*)arg;
610
info = (TlsInfo*)info_ptr;
611
thread = newLocalReference(env, info->globalref);
612
if ( thread != NULL ) {
613
jobject *objects;
614
jint ocount;
615
int i;
616
617
getOwnedMonitorInfo(thread, &objects, &ocount);
618
if ( ocount > 0 ) {
619
for ( i = 0 ; i < ocount ; i++ ) {
620
jvmtiMonitorUsage usage;
621
SerialNumber *waiter_nums;
622
SerialNumber *notify_waiter_nums;
623
int t;
624
char * sig;
625
626
WITH_LOCAL_REFS(env, 1) {
627
jclass clazz;
628
629
clazz = getObjectClass(env, objects[i]);
630
getClassSignature(clazz, &sig, NULL);
631
} END_WITH_LOCAL_REFS;
632
633
getObjectMonitorUsage(objects[i], &usage);
634
waiter_nums = HPROF_MALLOC(usage.waiter_count*
635
(int)sizeof(SerialNumber)+1);
636
for ( t = 0 ; t < usage.waiter_count ; t++ ) {
637
waiter_nums[t] =
638
get_serial_number(env, usage.waiters[t]);
639
}
640
notify_waiter_nums = HPROF_MALLOC(usage.notify_waiter_count*
641
(int)sizeof(SerialNumber)+1);
642
for ( t = 0 ; t < usage.notify_waiter_count ; t++ ) {
643
notify_waiter_nums[t] =
644
get_serial_number(env, usage.notify_waiters[t]);
645
}
646
io_write_monitor_dump_state(sig,
647
get_serial_number(env, usage.owner),
648
usage.entry_count,
649
waiter_nums, usage.waiter_count,
650
notify_waiter_nums, usage.notify_waiter_count);
651
jvmtiDeallocate(sig);
652
jvmtiDeallocate(usage.waiters);
653
jvmtiDeallocate(usage.notify_waiters);
654
HPROF_FREE(waiter_nums);
655
HPROF_FREE(notify_waiter_nums);
656
}
657
}
658
jvmtiDeallocate(objects);
659
deleteLocalReference(env, thread);
660
}
661
}
662
663
static jlong
664
monitor_time(void)
665
{
666
jlong mtime;
667
668
mtime = md_get_timemillis(); /* gettimeofday() */
669
return mtime;
670
}
671
672
static jlong
673
method_time(void)
674
{
675
jlong method_time;
676
677
method_time = md_get_thread_cpu_timemillis(); /* thread CPU time */
678
return method_time;
679
}
680
681
/* External interfaces */
682
683
TlsIndex
684
tls_find_or_create(JNIEnv *env, jthread thread)
685
{
686
SerialNumber thread_serial_num;
687
static TlsInfo empty_info;
688
TlsInfo info;
689
TlsIndex index;
690
691
HPROF_ASSERT(env!=NULL);
692
HPROF_ASSERT(thread!=NULL);
693
694
/*LINTED*/
695
index = (TlsIndex)(ptrdiff_t)getThreadLocalStorage(thread);
696
if ( index != 0 ) {
697
HPROF_ASSERT(isSameObject(env, thread, get_info(index)->globalref));
698
return index;
699
}
700
index = search(env, thread);
701
if ( index != 0 ) {
702
setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);
703
return index;
704
}
705
thread_serial_num = gdata->thread_serial_number_counter++;
706
info = empty_info;
707
info.monitor_index = 0;
708
info.sample_status = 1;
709
info.agent_thread = JNI_FALSE;
710
info.stack = stack_init(INITIAL_THREAD_STACK_LIMIT,
711
INITIAL_THREAD_STACK_LIMIT,
712
(int)sizeof(StackElement));
713
setup_trace_buffers(&info, gdata->max_trace_depth);
714
info.globalref = newWeakGlobalReference(env, thread);
715
index = table_create_entry(gdata->tls_table, &thread_serial_num, (int)sizeof(SerialNumber), (void*)&info);
716
setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);
717
HPROF_ASSERT(search(env,thread)==index);
718
return index;
719
}
720
721
/* Mark a new or existing entry as being an agent thread */
722
void
723
tls_agent_thread(JNIEnv *env, jthread thread)
724
{
725
TlsIndex index;
726
TlsInfo *info;
727
728
index = tls_find_or_create(env, thread);
729
info = get_info(index);
730
info->agent_thread = JNI_TRUE;
731
}
732
733
void
734
tls_init(void)
735
{
736
gdata->tls_table = table_initialize("TLS",
737
16, 16, 16, (int)sizeof(TlsInfo));
738
}
739
740
void
741
tls_list(void)
742
{
743
debug_message(
744
"--------------------- TLS Table ------------------------\n");
745
table_walk_items(gdata->tls_table, &list_item, NULL);
746
debug_message(
747
"----------------------------------------------------------\n");
748
}
749
750
jint
751
tls_sum_sample_status(void)
752
{
753
jint sample_status_total;
754
755
sample_status_total = 0;
756
table_walk_items(gdata->tls_table, &sum_sample_status_item, (void*)&sample_status_total);
757
return sample_status_total;
758
}
759
760
void
761
tls_set_sample_status(ObjectIndex object_index, jint sample_status)
762
{
763
SampleData data;
764
765
data.thread_object_index = object_index;
766
data.sample_status = sample_status;
767
table_walk_items(gdata->tls_table, &sample_setter, (void*)&data);
768
}
769
770
jint
771
tls_get_tracker_status(JNIEnv *env, jthread thread, jboolean skip_init,
772
jint **ppstatus, TlsIndex* pindex,
773
SerialNumber *pthread_serial_num, TraceIndex *ptrace_index)
774
{
775
TlsInfo *info;
776
TlsIndex index;
777
SerialNumber thread_serial_num;
778
jint status;
779
780
index = tls_find_or_create(env, thread);
781
info = get_info(index);
782
*ppstatus = &(info->tracker_status);
783
status = **ppstatus;
784
thread_serial_num = get_key(index);
785
786
if ( pindex != NULL ) {
787
*pindex = index;
788
}
789
if ( status != 0 ) {
790
return status;
791
}
792
if ( ptrace_index != NULL ) {
793
setup_trace_buffers(info, gdata->max_trace_depth);
794
*ptrace_index = get_trace(thread, thread_serial_num,
795
gdata->max_trace_depth, skip_init,
796
info->frames_buffer, info->jframes_buffer);
797
}
798
if ( pthread_serial_num != NULL ) {
799
*pthread_serial_num = thread_serial_num;
800
}
801
return status;
802
}
803
804
MonitorIndex
805
tls_get_monitor(TlsIndex index)
806
{
807
TlsInfo *info;
808
809
info = get_info(index);
810
return info->monitor_index;
811
}
812
813
void
814
tls_set_thread_object_index(TlsIndex index, ObjectIndex thread_object_index)
815
{
816
TlsInfo *info;
817
818
info = get_info(index);
819
info->thread_object_index = thread_object_index;
820
}
821
822
SerialNumber
823
tls_get_thread_serial_number(TlsIndex index)
824
{
825
return get_key(index);
826
}
827
828
void
829
tls_set_monitor(TlsIndex index, MonitorIndex monitor_index)
830
{
831
TlsInfo *info;
832
833
info = get_info(index);
834
info->monitor_index = monitor_index;
835
}
836
837
void
838
tls_cleanup(void)
839
{
840
table_cleanup(gdata->tls_table, &cleanup_item, NULL);
841
gdata->tls_table = NULL;
842
}
843
844
void
845
tls_delete_global_references(JNIEnv *env)
846
{
847
table_walk_items(gdata->tls_table, &delete_ref_item, (void*)env);
848
}
849
850
void
851
tls_thread_ended(JNIEnv *env, TlsIndex index)
852
{
853
HPROF_ASSERT(env!=NULL);
854
855
/* Sample thread stack for last time, do NOT free the entry yet. */
856
table_lock_enter(gdata->tls_table); {
857
SerialNumber thread_serial_num;
858
TlsInfo *info;
859
jthread thread;
860
861
thread_serial_num = get_key(index);
862
info = get_info(index);
863
thread = newLocalReference(env, info->globalref);
864
if (gdata->heap_dump && thread!=NULL) {
865
setup_trace_buffers(info, gdata->max_trace_depth);
866
info->last_trace = get_trace(thread, thread_serial_num,
867
gdata->max_trace_depth, JNI_FALSE,
868
info->frames_buffer, info->jframes_buffer);
869
}
870
if ( thread != NULL ) {
871
deleteLocalReference(env, thread);
872
}
873
} table_lock_exit(gdata->tls_table);
874
875
}
876
877
/* Sample ALL threads and update the trace costs */
878
void
879
tls_sample_all_threads(JNIEnv *env)
880
{
881
ThreadList list;
882
jthread *threads;
883
SerialNumber *serial_nums;
884
885
table_lock_enter(gdata->tls_table); {
886
int max_count;
887
int nbytes;
888
int i;
889
890
/* Get buffers to hold thread list and serial number list */
891
max_count = table_element_count(gdata->tls_table);
892
nbytes = (int)sizeof(jthread)*max_count;
893
threads = (jthread*)HPROF_MALLOC(nbytes);
894
nbytes = (int)sizeof(SerialNumber)*max_count;
895
serial_nums = (SerialNumber*)HPROF_MALLOC(nbytes);
896
897
/* Get list of threads and serial numbers */
898
list.threads = threads;
899
list.infos = NULL;
900
list.serial_nums = serial_nums;
901
list.count = 0;
902
list.env = env;
903
table_walk_items(gdata->tls_table, &get_thread_list, (void*)&list);
904
905
/* Increment the cost on the traces for these threads */
906
trace_increment_all_sample_costs(list.count, threads, serial_nums,
907
gdata->max_trace_depth, JNI_FALSE);
908
909
/* Loop over local refs and free them */
910
for ( i = 0 ; i < list.count ; i++ ) {
911
if ( threads[i] != NULL ) {
912
deleteLocalReference(env, threads[i]);
913
}
914
}
915
916
} table_lock_exit(gdata->tls_table);
917
918
/* Free up allocated space */
919
HPROF_FREE(threads);
920
HPROF_FREE(serial_nums);
921
922
}
923
924
void
925
tls_push_method(TlsIndex index, jmethodID method)
926
{
927
jlong method_start_time;
928
TlsInfo *info;
929
930
HPROF_ASSERT(method!=NULL);
931
info = get_info(index);
932
HPROF_ASSERT(info!=NULL);
933
method_start_time = method_time();
934
HPROF_ASSERT(info->stack!=NULL);
935
push_method(info->stack, method_start_time, method);
936
}
937
938
void
939
tls_pop_exception_catch(TlsIndex index, jthread thread, jmethodID method)
940
{
941
TlsInfo *info;
942
StackElement element;
943
void *p;
944
FrameIndex frame_index;
945
jlong current_time;
946
947
HPROF_ASSERT(method!=NULL);
948
frame_index = frame_find_or_create(method, -1);
949
HPROF_ASSERT(frame_index != 0);
950
951
info = get_info(index);
952
953
HPROF_ASSERT(info!=NULL);
954
HPROF_ASSERT(info->stack!=NULL);
955
HPROF_ASSERT(frame_index!=0);
956
current_time = method_time();
957
info->stack = insure_method_on_stack(thread, info, current_time,
958
frame_index, method);
959
p = stack_top(info->stack);
960
if (p == NULL) {
961
HPROF_ERROR(JNI_FALSE, "expection pop, nothing on stack");
962
return;
963
}
964
element = *(StackElement*)p;
965
HPROF_ASSERT(element.frame_index!=0);
966
while ( element.frame_index != frame_index ) {
967
pop_method(index, current_time, element.method, frame_index);
968
p = stack_top(info->stack);
969
if ( p == NULL ) {
970
break;
971
}
972
element = *(StackElement*)p;
973
}
974
if (p == NULL) {
975
HPROF_ERROR(JNI_FALSE, "exception pop stack empty");
976
}
977
}
978
979
void
980
tls_pop_method(TlsIndex index, jthread thread, jmethodID method)
981
{
982
TlsInfo *info;
983
StackElement element;
984
void *p;
985
FrameIndex frame_index;
986
jlong current_time;
987
988
HPROF_ASSERT(method!=NULL);
989
frame_index = frame_find_or_create(method, -1);
990
HPROF_ASSERT(frame_index != 0);
991
992
info = get_info(index);
993
HPROF_ASSERT(info!=NULL);
994
HPROF_ASSERT(info->stack!=NULL);
995
current_time = method_time();
996
HPROF_ASSERT(frame_index!=0);
997
info->stack = insure_method_on_stack(thread, info, current_time,
998
frame_index, method);
999
p = stack_top(info->stack);
1000
HPROF_ASSERT(p!=NULL);
1001
element = *(StackElement*)p;
1002
while ( element.frame_index != frame_index ) {
1003
pop_method(index, current_time, element.method, frame_index);
1004
p = stack_top(info->stack);
1005
if ( p == NULL ) {
1006
break;
1007
}
1008
element = *(StackElement*)p;
1009
}
1010
pop_method(index, current_time, method, frame_index);
1011
}
1012
1013
/* For all TLS entries, update the last_trace on all threads */
1014
static void
1015
update_all_last_traces(JNIEnv *env)
1016
{
1017
jthread *threads;
1018
TlsInfo **infos;
1019
SerialNumber *serial_nums;
1020
TraceIndex *traces;
1021
1022
if ( gdata->max_trace_depth == 0 ) {
1023
return;
1024
}
1025
1026
table_lock_enter(gdata->tls_table); {
1027
1028
ThreadList list;
1029
int max_count;
1030
int nbytes;
1031
int i;
1032
1033
/* Get buffers to hold thread list and serial number list */
1034
max_count = table_element_count(gdata->tls_table);
1035
nbytes = (int)sizeof(jthread)*max_count;
1036
threads = (jthread*)HPROF_MALLOC(nbytes);
1037
nbytes = (int)sizeof(SerialNumber)*max_count;
1038
serial_nums = (SerialNumber*)HPROF_MALLOC(nbytes);
1039
nbytes = (int)sizeof(TlsInfo*)*max_count;
1040
infos = (TlsInfo**)HPROF_MALLOC(nbytes);
1041
1042
/* Get list of threads, serial numbers, and info pointers */
1043
list.threads = threads;
1044
list.serial_nums = serial_nums;
1045
list.infos = infos;
1046
list.count = 0;
1047
list.env = env;
1048
table_walk_items(gdata->tls_table, &get_thread_list, (void*)&list);
1049
1050
/* Get all stack trace index's for all these threadss */
1051
nbytes = (int)sizeof(TraceIndex)*max_count;
1052
traces = (TraceIndex*)HPROF_MALLOC(nbytes);
1053
trace_get_all_current(list.count, threads, serial_nums,
1054
gdata->max_trace_depth, JNI_FALSE,
1055
traces, JNI_TRUE);
1056
1057
/* Loop over traces and update last_trace's */
1058
for ( i = 0 ; i < list.count ; i++ ) {
1059
if ( threads[i] != NULL ) {
1060
deleteLocalReference(env, threads[i]);
1061
}
1062
infos[i]->last_trace = traces[i];
1063
}
1064
1065
} table_lock_exit(gdata->tls_table);
1066
1067
/* Free up all allocated space */
1068
HPROF_FREE(threads);
1069
HPROF_FREE(serial_nums);
1070
HPROF_FREE(infos);
1071
HPROF_FREE(traces);
1072
1073
}
1074
1075
void
1076
tls_dump_traces(JNIEnv *env)
1077
{
1078
rawMonitorEnter(gdata->data_access_lock); {
1079
update_all_last_traces(env);
1080
trace_output_unmarked(env);
1081
} rawMonitorExit(gdata->data_access_lock);
1082
}
1083
1084
void
1085
tls_dump_monitor_state(JNIEnv *env)
1086
{
1087
HPROF_ASSERT(env!=NULL);
1088
1089
rawMonitorEnter(gdata->data_access_lock); {
1090
tls_dump_traces(env);
1091
io_write_monitor_dump_header();
1092
table_walk_items(gdata->tls_table, &dump_thread_state, (void*)env);
1093
table_walk_items(gdata->tls_table, &dump_monitor_state, (void*)env);
1094
io_write_monitor_dump_footer();
1095
} rawMonitorExit(gdata->data_access_lock);
1096
}
1097
1098
void
1099
tls_monitor_start_timer(TlsIndex index)
1100
{
1101
TlsInfo *info;
1102
1103
info = get_info(index);
1104
HPROF_ASSERT(info!=NULL);
1105
HPROF_ASSERT(info->globalref!=NULL);
1106
info->monitor_start_time = monitor_time();
1107
}
1108
1109
jlong
1110
tls_monitor_stop_timer(TlsIndex index)
1111
{
1112
TlsInfo *info;
1113
jlong t;
1114
1115
info = get_info(index);
1116
HPROF_ASSERT(info!=NULL);
1117
t = monitor_time() - info->monitor_start_time;
1118
info->monitor_start_time = 0;
1119
return t;
1120
}
1121
1122
TraceIndex
1123
tls_get_trace(TlsIndex index, JNIEnv *env, int depth, jboolean skip_init)
1124
{
1125
SerialNumber thread_serial_num;
1126
TraceIndex trace_index;
1127
TlsInfo *info;
1128
jthread thread;
1129
1130
thread_serial_num = get_key(index);
1131
info = get_info(index);
1132
HPROF_ASSERT(info!=NULL);
1133
setup_trace_buffers(info, depth);
1134
thread = newLocalReference(env, info->globalref);
1135
if ( thread != NULL ) {
1136
trace_index = get_trace(thread, thread_serial_num, depth, skip_init,
1137
info->frames_buffer, info->jframes_buffer);
1138
deleteLocalReference(env, thread);
1139
} else {
1140
trace_index = gdata->system_trace_index;
1141
}
1142
return trace_index;
1143
}
1144
1145
void
1146
tls_set_in_heap_dump(TlsIndex index, jint in_heap_dump)
1147
{
1148
TlsInfo *info;
1149
1150
info = get_info(index);
1151
info->in_heap_dump = in_heap_dump;
1152
}
1153
1154
jint
1155
tls_get_in_heap_dump(TlsIndex index)
1156
{
1157
TlsInfo *info;
1158
1159
info = get_info(index);
1160
return info->in_heap_dump;
1161
}
1162
1163
static void
1164
clean_in_heap_dump(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
1165
{
1166
TlsInfo *info;
1167
1168
HPROF_ASSERT(info_ptr!=NULL);
1169
info = (TlsInfo*)info_ptr;
1170
info->in_heap_dump = 0;
1171
}
1172
1173
void
1174
tls_clear_in_heap_dump(void)
1175
{
1176
table_walk_items(gdata->tls_table, &clean_in_heap_dump, NULL);
1177
}
1178
1179
TlsIndex
1180
tls_find(SerialNumber thread_serial_num)
1181
{
1182
TlsIndex index;
1183
1184
if ( thread_serial_num == 0 ) {
1185
return 0;
1186
}
1187
index = table_find_entry(gdata->tls_table,
1188
(void*)&thread_serial_num, (int)sizeof(SerialNumber));
1189
return index;
1190
}
1191
1192