author | sla |
Tue, 26 Aug 2014 07:55:08 +0200 | |
changeset 26201 | 40a873d21081 |
parent 25859 | jdk/src/demo/share/jvmti/hprof/hprof_tls.c@3317bb8137f4 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
14342
8435a30053c1
7197491: update copyright year to match last edit in jdk8 jdk repository
alanb
parents:
10292
diff
changeset
|
2 |
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
* |
|
5506 | 15 |
* - Neither the name of Oracle nor the names of its |
2 | 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 |
||
10292
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
32 |
/* |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
33 |
* This source code is provided to illustrate the usage of a given feature |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
34 |
* or technique and has been deliberately simplified. Additional steps |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
35 |
* required for a production-quality application, such as security checks, |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
36 |
* input validation and proper error handling, might not be present in |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
37 |
* this sample code. |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
38 |
*/ |
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
39 |
|
ed7db6a12c2a
7067811: Update demo/sample code to state it should not be used for production
nloodin
parents:
5506
diff
changeset
|
40 |
|
2 | 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 |
} |