Lines 67-74
Link Here
|
67 |
protected static char[] objectSize; |
67 |
protected static char[] objectSize; |
68 |
protected static short samplingInterval; |
68 |
protected static short samplingInterval; |
69 |
protected static int samplingDepth; |
69 |
protected static int samplingDepth; |
70 |
private static int stackDepth; |
|
|
71 |
private static int[] stackFrameIds; |
72 |
private static Map classIdMap; |
70 |
private static Map classIdMap; |
73 |
|
71 |
|
74 |
// -------------------------------------- Miscellaneous support routines ------------------------------------------ |
72 |
// -------------------------------------- Miscellaneous support routines ------------------------------------------ |
Lines 84-92
Link Here
|
84 |
if (aic == null) { |
82 |
if (aic == null) { |
85 |
allocatedInstThreshold = null; |
83 |
allocatedInstThreshold = null; |
86 |
objectSize = null; |
84 |
objectSize = null; |
87 |
stackFrameIds = null; |
|
|
88 |
Stacks.clearNativeStackFrameBuffer(); |
89 |
|
90 |
return; |
85 |
return; |
91 |
} else if (allocatedInstArrayLength < aic.length) { |
86 |
} else if (allocatedInstArrayLength < aic.length) { |
92 |
short[] oldThresh = (allocatedInstThreshold != null) ? allocatedInstThreshold : null; |
87 |
short[] oldThresh = (allocatedInstThreshold != null) ? allocatedInstThreshold : null; |
Lines 117-124
Link Here
|
117 |
if (val > MAX_STACK_FRAMES) { |
112 |
if (val > MAX_STACK_FRAMES) { |
118 |
val = MAX_STACK_FRAMES; |
113 |
val = MAX_STACK_FRAMES; |
119 |
} |
114 |
} |
120 |
} else { |
|
|
121 |
stackDepth = 0; |
122 |
} |
115 |
} |
123 |
|
116 |
|
124 |
samplingDepth = val; |
117 |
samplingDepth = val; |
Lines 165-170
Link Here
|
165 |
|
158 |
|
166 |
if (!ti.isInitialized()) { |
159 |
if (!ti.isInitialized()) { |
167 |
ti.initialize(true); |
160 |
ti.initialize(true); |
|
|
161 |
ti.useEventBuffer(); |
162 |
ti.useStackBuffer(MAX_STACK_FRAMES); |
168 |
} |
163 |
} |
169 |
|
164 |
|
170 |
ti.inProfilingRuntimeMethod++; |
165 |
ti.inProfilingRuntimeMethod++; |
Lines 201-235
Link Here
|
201 |
// ------------------------------------------ Stack trace obtaining ----------------------------------------------- |
196 |
// ------------------------------------------ Stack trace obtaining ----------------------------------------------- |
202 |
|
197 |
|
203 |
/** This is used in Object Allocation profiling mode */ |
198 |
/** This is used in Object Allocation profiling mode */ |
204 |
protected static synchronized void getAndSendCurrentStackTrace(char classId, long objSize) { |
199 |
protected static void getAndSendCurrentStackTrace(ThreadInfo ti, char classId, long objSize) { |
|
|
200 |
int stackDepth = 0; |
201 |
|
202 |
if (eventBuffer == null) { |
203 |
return; // Chances are that instrumentation has been removed while we were executing instrumentation code |
204 |
} |
205 |
|
206 |
if (samplingDepth != 0) { |
207 |
stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, ti.stackFrameIds); |
208 |
} |
209 |
|
210 |
writeObjAllocStackTraceEvent(ti, classId, objSize, stackDepth); |
211 |
} |
212 |
|
213 |
/** This is used in Object Liveness profiling mode */ |
214 |
protected static void getAndSendCurrentStackTrace(ThreadInfo ti, char classId, char epoch, int objCount, long objSize) { |
215 |
int stackDepth = 0; |
216 |
|
205 |
if (eventBuffer == null) { |
217 |
if (eventBuffer == null) { |
206 |
return; // Chances are that instrumentation has been removed while we were executing instrumentation code |
218 |
return; // Chances are that instrumentation has been removed while we were executing instrumentation code |
207 |
} |
219 |
} |
208 |
|
220 |
|
209 |
synchronized (eventBuffer) { // Note that we have to use synchronization here due to the static stackFrameIds[] array |
221 |
if (samplingDepth != 0) { |
210 |
|
222 |
stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, ti.stackFrameIds); |
211 |
if (samplingDepth != 0) { |
|
|
212 |
stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, stackFrameIds); |
213 |
} |
214 |
|
215 |
writeObjAllocStackTraceEvent(classId, objSize); |
216 |
} |
217 |
} |
218 |
|
219 |
/** This is used in Object Liveness profiling mode */ |
220 |
protected static synchronized void getAndSendCurrentStackTrace(char classId, char epoch, int objCount, long objSize) { |
221 |
if (eventBuffer == null) { |
222 |
return; // Chances are that instrumentation has been removed while we were executing instrumentation code |
223 |
} |
223 |
} |
224 |
|
224 |
|
225 |
synchronized (eventBuffer) { // Note that we have to use synchronization here due to the static stackFrameIds[] array |
225 |
writeObjLivenessStackTraceEvent(ti, classId, epoch, objCount, objSize, stackDepth); |
226 |
|
|
|
227 |
if (samplingDepth != 0) { |
228 |
stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, stackFrameIds); |
229 |
} |
230 |
|
231 |
writeObjLivenessStackTraceEvent(classId, epoch, objCount, objSize); |
232 |
} |
233 |
} |
226 |
} |
234 |
|
227 |
|
235 |
protected static long getCachedObjectSize(char classId, Object object) { |
228 |
protected static long getCachedObjectSize(char classId, Object object) { |
Lines 263-276
Link Here
|
263 |
protected static void clearDataStructures() { |
256 |
protected static void clearDataStructures() { |
264 |
ProfilerRuntime.clearDataStructures(); |
257 |
ProfilerRuntime.clearDataStructures(); |
265 |
allocatedInstancesCount = null; |
258 |
allocatedInstancesCount = null; |
266 |
stackFrameIds = null; |
|
|
267 |
Stacks.clearNativeStackFrameBuffer(); |
268 |
} |
259 |
} |
269 |
|
260 |
|
270 |
protected static void createNewDataStructures() { |
261 |
protected static void createNewDataStructures() { |
271 |
ProfilerRuntime.createNewDataStructures(); |
262 |
ProfilerRuntime.createNewDataStructures(); |
272 |
stackFrameIds = new int[MAX_STACK_FRAMES]; |
263 |
Stacks.setStackFrameBufferSize(MAX_STACK_FRAMES); |
273 |
Stacks.createNativeStackFrameBuffer(MAX_STACK_FRAMES); |
|
|
274 |
classIdMap = new HashMap(); |
264 |
classIdMap = new HashMap(); |
275 |
} |
265 |
} |
276 |
|
266 |
|
Lines 323-330
Link Here
|
323 |
|
313 |
|
324 |
// ---------------------------------------- Writing profiler events ----------------------------------------- |
314 |
// ---------------------------------------- Writing profiler events ----------------------------------------- |
325 |
|
315 |
|
326 |
/** Note that there is no synchronized(eventBuffer) in this method, since synchronization is already required by its callers */ |
316 |
protected static void writeObjAllocStackTraceEvent(ThreadInfo ti, char classId, long objSize, int stackDepth) { |
327 |
protected static void writeObjAllocStackTraceEvent(char classId, long objSize) { |
|
|
328 |
if (eventBuffer == null) { |
317 |
if (eventBuffer == null) { |
329 |
return; // Instrumentation removal happened when we were in instrumentation |
318 |
return; // Instrumentation removal happened when we were in instrumentation |
330 |
} |
319 |
} |
Lines 337-361
Link Here
|
337 |
ProfilerServer.notifyClientOnResultsAvailability(); |
326 |
ProfilerServer.notifyClientOnResultsAvailability(); |
338 |
} |
327 |
} |
339 |
|
328 |
|
340 |
int curPos = globalEvBufPos; |
329 |
int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment |
341 |
|
330 |
|
342 |
if ((curPos + 16 + (stackDepth * 4)) > globalEvBufPosThreshold) { // Dump the buffer |
331 |
if (curPos + 18 + (stackDepth * 4) > ThreadInfo.evBufPosThreshold) { |
343 |
externalActionsHandler.handleEventBufferDump(eventBuffer, 0, curPos); |
332 |
copyLocalBuffer(ti); |
344 |
curPos = 0; |
333 |
curPos = ti.evBufPos; |
345 |
} |
334 |
} |
346 |
|
335 |
|
347 |
eventBuffer[curPos++] = OBJ_ALLOC_STACK_TRACE; |
336 |
byte[] evBuf = ti.evBuf; |
348 |
eventBuffer[curPos++] = (byte) ((classId >> 8) & 0xFF); |
337 |
if (!ti.isInitialized()) return; // Reset collectors performed when we were already executing instrumentation code |
349 |
eventBuffer[curPos++] = (byte) ((classId) & 0xFF); |
|
|
350 |
|
338 |
|
351 |
eventBuffer[curPos++] = (byte) ((objSize >> 32) & 0xFF); |
339 |
evBuf[curPos++] = OBJ_ALLOC_STACK_TRACE; |
352 |
eventBuffer[curPos++] = (byte) ((objSize >> 24) & 0xFF); |
340 |
evBuf[curPos++] = (byte) ((classId >> 8) & 0xFF); |
353 |
eventBuffer[curPos++] = (byte) ((objSize >> 16) & 0xFF); |
341 |
evBuf[curPos++] = (byte) ((classId) & 0xFF); |
354 |
eventBuffer[curPos++] = (byte) ((objSize >> 8) & 0xFF); |
|
|
355 |
eventBuffer[curPos++] = (byte) (objSize & 0xFF); |
356 |
|
342 |
|
357 |
curPos = writeStack(curPos); |
343 |
evBuf[curPos++] = (byte) ((objSize >> 32) & 0xFF); |
358 |
globalEvBufPos = curPos; |
344 |
evBuf[curPos++] = (byte) ((objSize >> 24) & 0xFF); |
|
|
345 |
evBuf[curPos++] = (byte) ((objSize >> 16) & 0xFF); |
346 |
evBuf[curPos++] = (byte) ((objSize >> 8) & 0xFF); |
347 |
evBuf[curPos++] = (byte) (objSize & 0xFF); |
348 |
|
349 |
curPos = writeStack(evBuf, curPos, ti, stackDepth); |
350 |
ti.evBufPos = curPos; |
359 |
} |
351 |
} |
360 |
|
352 |
|
361 |
protected static void writeObjGCEvent(long objectId) { |
353 |
protected static void writeObjGCEvent(long objectId) { |
Lines 384-391
Link Here
|
384 |
} |
376 |
} |
385 |
} |
377 |
} |
386 |
|
378 |
|
387 |
/** Note that there is no synchronized(eventBuffer) in this method, since synchronization is already required by its callers */ |
379 |
protected static void writeObjLivenessStackTraceEvent(ThreadInfo ti, char classId, char epoch, int objCount, long objSize, int stackDepth) { |
388 |
protected static void writeObjLivenessStackTraceEvent(char classId, char epoch, int objCount, long objSize) { |
|
|
389 |
if (eventBuffer == null) { |
380 |
if (eventBuffer == null) { |
390 |
return; // Instrumentation removal happened when we were in instrumentation |
381 |
return; // Instrumentation removal happened when we were in instrumentation |
391 |
} |
382 |
} |
Lines 398-434
Link Here
|
398 |
ProfilerServer.notifyClientOnResultsAvailability(); |
389 |
ProfilerServer.notifyClientOnResultsAvailability(); |
399 |
} |
390 |
} |
400 |
|
391 |
|
401 |
int curPos = globalEvBufPos; |
392 |
int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment |
402 |
|
393 |
|
403 |
if ((curPos + 24 + (stackDepth * 4)) > globalEvBufPosThreshold) { // Dump the buffer |
394 |
if (curPos + 24 + (stackDepth * 4) > ThreadInfo.evBufPosThreshold) { |
404 |
externalActionsHandler.handleEventBufferDump(eventBuffer, 0, curPos); |
395 |
copyLocalBuffer(ti); |
405 |
curPos = 0; |
396 |
curPos = ti.evBufPos; |
406 |
} |
397 |
} |
407 |
|
398 |
|
408 |
eventBuffer[curPos++] = OBJ_LIVENESS_STACK_TRACE; |
399 |
byte[] evBuf = ti.evBuf; |
409 |
eventBuffer[curPos++] = (byte) ((classId >> 8) & 0xFF); |
400 |
if (!ti.isInitialized()) return; // Reset collectors performed when we were already executing instrumentation code |
410 |
eventBuffer[curPos++] = (byte) ((classId) & 0xFF); |
|
|
411 |
eventBuffer[curPos++] = (byte) ((epoch >> 8) & 0xFF); |
412 |
eventBuffer[curPos++] = (byte) ((epoch) & 0xFF); |
413 |
eventBuffer[curPos++] = (byte) ((objCount >> 24) & 0xFF); |
414 |
eventBuffer[curPos++] = (byte) ((objCount >> 16) & 0xFF); |
415 |
eventBuffer[curPos++] = (byte) ((objCount >> 8) & 0xFF); |
416 |
eventBuffer[curPos++] = (byte) ((objCount) & 0xFF); |
417 |
|
401 |
|
418 |
eventBuffer[curPos++] = (byte) ((objSize >> 32) & 0xFF); |
402 |
evBuf[curPos++] = OBJ_LIVENESS_STACK_TRACE; |
419 |
eventBuffer[curPos++] = (byte) ((objSize >> 24) & 0xFF); |
403 |
evBuf[curPos++] = (byte) ((classId >> 8) & 0xFF); |
420 |
eventBuffer[curPos++] = (byte) ((objSize >> 16) & 0xFF); |
404 |
evBuf[curPos++] = (byte) ((classId) & 0xFF); |
421 |
eventBuffer[curPos++] = (byte) ((objSize >> 8) & 0xFF); |
405 |
evBuf[curPos++] = (byte) ((epoch >> 8) & 0xFF); |
422 |
eventBuffer[curPos++] = (byte) (objSize & 0xFF); |
406 |
evBuf[curPos++] = (byte) ((epoch) & 0xFF); |
|
|
407 |
evBuf[curPos++] = (byte) ((objCount >> 24) & 0xFF); |
408 |
evBuf[curPos++] = (byte) ((objCount >> 16) & 0xFF); |
409 |
evBuf[curPos++] = (byte) ((objCount >> 8) & 0xFF); |
410 |
evBuf[curPos++] = (byte) ((objCount) & 0xFF); |
423 |
|
411 |
|
424 |
curPos = writeStack(curPos); |
412 |
evBuf[curPos++] = (byte) ((objSize >> 32) & 0xFF); |
425 |
globalEvBufPos = curPos; |
413 |
evBuf[curPos++] = (byte) ((objSize >> 24) & 0xFF); |
|
|
414 |
evBuf[curPos++] = (byte) ((objSize >> 16) & 0xFF); |
415 |
evBuf[curPos++] = (byte) ((objSize >> 8) & 0xFF); |
416 |
evBuf[curPos++] = (byte) (objSize & 0xFF); |
417 |
|
418 |
curPos = writeStack(evBuf, curPos, ti, stackDepth); |
419 |
ti.evBufPos = curPos; |
426 |
} |
420 |
} |
427 |
|
421 |
|
428 |
private static int writeStack(int curPos) { |
422 |
protected static void copyLocalBuffer(ThreadInfo ti) { |
429 |
eventBuffer[curPos++] = (byte) ((stackDepth >> 16) & 0xFF); |
423 |
// Copy the local buffer into the main buffer - however avoid doing that if we have already reset profiler collectors |
430 |
eventBuffer[curPos++] = (byte) ((stackDepth >> 8) & 0xFF); |
424 |
if (eventBuffer == null) { |
431 |
eventBuffer[curPos++] = (byte) ((stackDepth) & 0xFF); |
425 |
return; |
|
|
426 |
} |
427 |
|
428 |
synchronized (eventBuffer) { |
429 |
if (!ti.isInitialized()) { |
430 |
return; // Reset collectors performed when we were already executing instrumentation code |
431 |
} |
432 |
|
433 |
int curPos = ti.evBufPos; |
434 |
|
435 |
// First check if the global buffer itself needs to be dumped |
436 |
int evBufDumpLastPos = ti.evBufDumpLastPos; |
437 |
|
438 |
if (((globalEvBufPos + curPos) - evBufDumpLastPos) > globalEvBufPosThreshold) { |
439 |
sendingBuffer = true; |
440 |
|
441 |
externalActionsHandler.handleEventBufferDump(eventBuffer, 0, globalEvBufPos); |
442 |
globalEvBufPos = 0; |
443 |
sendingBuffer = false; |
444 |
} |
445 |
|
446 |
// Finally copy the local buffer into the global one |
447 |
eventBuffer[globalEvBufPos++] = SET_FOLLOWING_EVENTS_THREAD; |
448 |
eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId >> 8) & 0xFF); |
449 |
eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId) & 0xFF); |
450 |
System.arraycopy(ti.evBuf, evBufDumpLastPos, eventBuffer, globalEvBufPos, curPos - evBufDumpLastPos); |
451 |
globalEvBufPos += (curPos - evBufDumpLastPos); |
452 |
ti.evBufPos = 0; |
453 |
ti.evBufDumpLastPos = 0; |
454 |
} |
455 |
} |
456 |
|
457 |
|
458 |
private static int writeStack(byte[] evBuf, int curPos, ThreadInfo ti, int stackDepth) { |
459 |
evBuf[curPos++] = (byte) ((stackDepth >> 16) & 0xFF); |
460 |
evBuf[curPos++] = (byte) ((stackDepth >> 8) & 0xFF); |
461 |
evBuf[curPos++] = (byte) ((stackDepth) & 0xFF); |
432 |
|
462 |
|
433 |
/// A variant when we send non-reversed call graph |
463 |
/// A variant when we send non-reversed call graph |
434 |
//int base = depth + NO_OF_PROFILER_FRAMES - 1; |
464 |
//int base = depth + NO_OF_PROFILER_FRAMES - 1; |
Lines 437-448
Link Here
|
437 |
// eventBuffer[curPos++] = (char) ((stackFrameIds[base-i]) & 0xFFFF); |
467 |
// eventBuffer[curPos++] = (char) ((stackFrameIds[base-i]) & 0xFFFF); |
438 |
//} |
468 |
//} |
439 |
int frameIdx = NO_OF_PROFILER_FRAMES; |
469 |
int frameIdx = NO_OF_PROFILER_FRAMES; |
440 |
|
470 |
int[] frames = ti.stackFrameIds; |
|
|
471 |
|
441 |
for (int i = 0; i < stackDepth; i++) { |
472 |
for (int i = 0; i < stackDepth; i++) { |
442 |
eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 24) & 0xFF); |
473 |
evBuf[curPos++] = (byte) ((frames[frameIdx] >> 24) & 0xFF); |
443 |
eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 16) & 0xFF); |
474 |
evBuf[curPos++] = (byte) ((frames[frameIdx] >> 16) & 0xFF); |
444 |
eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 8) & 0xFF); |
475 |
evBuf[curPos++] = (byte) ((frames[frameIdx] >> 8) & 0xFF); |
445 |
eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx]) & 0xFF); |
476 |
evBuf[curPos++] = (byte) ((frames[frameIdx]) & 0xFF); |
446 |
frameIdx++; |
477 |
frameIdx++; |
447 |
} |
478 |
} |
448 |
|
479 |
|