diff -r 5696f3be43db lib.profiler/native/src-jdk15/Stacks.c --- a/lib.profiler/native/src-jdk15/Stacks.c Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/native/src-jdk15/Stacks.c Fri Sep 14 09:29:20 2012 +0200 @@ -82,8 +82,7 @@ #define MAX_FRAMES 100 -static jvmtiFrameInfo *_stack_frames_buffer = NULL; -static jint *_stack_id_buffer = NULL; +static jint stackSizeInFrames = 0; static jclass threadType = NULL; static jclass intArrType = NULL; static long base_addresses[NO_OF_BASE_ADDRESS]={-1L,-1L,-1L,-1L}; @@ -148,35 +147,13 @@ * Method: createNativeStackFrameBuffer * Signature: (I)V */ -JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_createNativeStackFrameBuffer +JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_setStackFrameBufferSize (JNIEnv *env, jclass clz, jint sizeInFrames) { - if (_stack_frames_buffer != NULL) { - Java_org_netbeans_lib_profiler_server_system_Stacks_clearNativeStackFrameBuffer(env, clz); - } - _stack_frames_buffer = calloc(sizeInFrames, sizeof(jvmtiFrameInfo)); - _stack_id_buffer = calloc(sizeInFrames, sizeof(jint)); + stackSizeInFrames = sizeInFrames; } -/* - * Class: org_netbeans_lib_profiler_server_system_Stacks - * Method: clearNativeStackFrameBuffer - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_clearNativeStackFrameBuffer - (JNIEnv *env, jclass clz) -{ - if (_stack_frames_buffer != NULL) { - free(_stack_frames_buffer); - } - if (_stack_id_buffer != NULL) { - free(_stack_id_buffer); - } - _stack_frames_buffer = NULL; - _stack_id_buffer = NULL; -} - /* * Class: org_netbeans_lib_profiler_server_system_Stacks @@ -187,17 +164,19 @@ (JNIEnv *env, jclass clz, jthread jni_thread, jint depth, jintArray ret) { jint i, count; - if (_stack_frames_buffer == NULL) { - /* Can happen if profiling stopped concurrently */ - return 0; - } + jvmtiFrameInfo *_stack_frames_buffer; + jint *_stack_id_buffer; + _stack_frames_buffer = calloc(stackSizeInFrames, sizeof(jvmtiFrameInfo)); + _stack_id_buffer = calloc(stackSizeInFrames, sizeof(jint)); (*_jvmti)->GetStackTrace(_jvmti, jni_thread, 0, depth, _stack_frames_buffer, &count); for (i = 0; i < count; i++) { _stack_id_buffer[i] = convert_jmethodID_to_jint(_stack_frames_buffer[i].method); } (*env)->SetIntArrayRegion(env, ret, 0, count, _stack_id_buffer); + free(_stack_frames_buffer); + free(_stack_id_buffer); return count; } diff -r 5696f3be43db lib.profiler/native/src-jdk15/org_netbeans_lib_profiler_server_system_Stacks.h --- a/lib.profiler/native/src-jdk15/org_netbeans_lib_profiler_server_system_Stacks.h Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/native/src-jdk15/org_netbeans_lib_profiler_server_system_Stacks.h Fri Sep 14 09:29:20 2012 +0200 @@ -84,18 +84,10 @@ /* * Class: org_netbeans_lib_profiler_server_system_Stacks - * Method: clearNativeStackFrameBuffer - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_clearNativeStackFrameBuffer - (JNIEnv *, jclass); - -/* - * Class: org_netbeans_lib_profiler_server_system_Stacks * Method: createNativeStackFrameBuffer * Signature: (I)V */ -JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_createNativeStackFrameBuffer +JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Stacks_setStackFrameBufferSize (JNIEnv *, jclass, jint); #ifdef __cplusplus diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/results/memory/MemoryDataFrameProcessor.java --- a/lib.profiler/src/org/netbeans/lib/profiler/results/memory/MemoryDataFrameProcessor.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/results/memory/MemoryDataFrameProcessor.java Fri Sep 14 09:29:20 2012 +0200 @@ -54,6 +54,9 @@ * @author Jaroslav Bachorik */ public class MemoryDataFrameProcessor extends AbstractDataFrameProcessor { + //~ Instance fields ---------------------------------------------------------------------------------------------------------- + + private volatile int currentThreadId = -1; //~ Methods ------------------------------------------------------------------------------------------------------------------ public void doProcessDataFrame(byte[] buffer) { @@ -166,6 +169,15 @@ break; } + case CommonConstants.SET_FOLLOWING_EVENTS_THREAD: { + if (LOGGER.isLoggable(Level.FINEST)) { + LOGGER.log(Level.FINEST, "Change current thread , tId={0}", currentThreadId); // NOI18N + } + + currentThreadId = (char) ((((int) buffer[curPos++] & 0xFF) << 8) | ((int) buffer[curPos++] & 0xFF)); + + break; + } default: { LOGGER.severe("*** Profiler Engine: internal error: got unknown event type in MemoryDataFrameProcessor: " // NOI18N + (int) eventType diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeMemory.java --- a/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeMemory.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeMemory.java Fri Sep 14 09:29:20 2012 +0200 @@ -67,8 +67,6 @@ protected static char[] objectSize; protected static short samplingInterval; protected static int samplingDepth; - private static int stackDepth; - private static int[] stackFrameIds; private static Map classIdMap; // -------------------------------------- Miscellaneous support routines ------------------------------------------ @@ -84,9 +82,6 @@ if (aic == null) { allocatedInstThreshold = null; objectSize = null; - stackFrameIds = null; - Stacks.clearNativeStackFrameBuffer(); - return; } else if (allocatedInstArrayLength < aic.length) { short[] oldThresh = (allocatedInstThreshold != null) ? allocatedInstThreshold : null; @@ -117,8 +112,6 @@ if (val > MAX_STACK_FRAMES) { val = MAX_STACK_FRAMES; } - } else { - stackDepth = 0; } samplingDepth = val; @@ -165,6 +158,8 @@ if (!ti.isInitialized()) { ti.initialize(true); + ti.useEventBuffer(); + ti.useStackBuffer(MAX_STACK_FRAMES); } ti.inProfilingRuntimeMethod++; @@ -201,35 +196,33 @@ // ------------------------------------------ Stack trace obtaining ----------------------------------------------- /** This is used in Object Allocation profiling mode */ - protected static synchronized void getAndSendCurrentStackTrace(char classId, long objSize) { + protected static void getAndSendCurrentStackTrace(ThreadInfo ti, char classId, long objSize) { + int stackDepth = 0; + + if (eventBuffer == null) { + return; // Chances are that instrumentation has been removed while we were executing instrumentation code + } + + if (samplingDepth != 0) { + stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, ti.stackFrameIds); + } + + writeObjAllocStackTraceEvent(ti, classId, objSize, stackDepth); + } + + /** This is used in Object Liveness profiling mode */ + protected static void getAndSendCurrentStackTrace(ThreadInfo ti, char classId, char epoch, int objCount, long objSize) { + int stackDepth = 0; + if (eventBuffer == null) { return; // Chances are that instrumentation has been removed while we were executing instrumentation code } - synchronized (eventBuffer) { // Note that we have to use synchronization here due to the static stackFrameIds[] array - - if (samplingDepth != 0) { - stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, stackFrameIds); - } - - writeObjAllocStackTraceEvent(classId, objSize); - } - } - - /** This is used in Object Liveness profiling mode */ - protected static synchronized void getAndSendCurrentStackTrace(char classId, char epoch, int objCount, long objSize) { - if (eventBuffer == null) { - return; // Chances are that instrumentation has been removed while we were executing instrumentation code + if (samplingDepth != 0) { + stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, ti.stackFrameIds); } - synchronized (eventBuffer) { // Note that we have to use synchronization here due to the static stackFrameIds[] array - - if (samplingDepth != 0) { - stackDepth = Stacks.getCurrentStackFrameIds(Thread.currentThread(), samplingDepth, stackFrameIds); - } - - writeObjLivenessStackTraceEvent(classId, epoch, objCount, objSize); - } + writeObjLivenessStackTraceEvent(ti, classId, epoch, objCount, objSize, stackDepth); } protected static long getCachedObjectSize(char classId, Object object) { @@ -263,14 +256,11 @@ protected static void clearDataStructures() { ProfilerRuntime.clearDataStructures(); allocatedInstancesCount = null; - stackFrameIds = null; - Stacks.clearNativeStackFrameBuffer(); } protected static void createNewDataStructures() { ProfilerRuntime.createNewDataStructures(); - stackFrameIds = new int[MAX_STACK_FRAMES]; - Stacks.createNativeStackFrameBuffer(MAX_STACK_FRAMES); + Stacks.setStackFrameBufferSize(MAX_STACK_FRAMES); classIdMap = new HashMap(); } @@ -323,8 +313,7 @@ // ---------------------------------------- Writing profiler events ----------------------------------------- - /** Note that there is no synchronized(eventBuffer) in this method, since synchronization is already required by its callers */ - protected static void writeObjAllocStackTraceEvent(char classId, long objSize) { + protected static void writeObjAllocStackTraceEvent(ThreadInfo ti, char classId, long objSize, int stackDepth) { if (eventBuffer == null) { return; // Instrumentation removal happened when we were in instrumentation } @@ -337,25 +326,28 @@ ProfilerServer.notifyClientOnResultsAvailability(); } - int curPos = globalEvBufPos; + int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment - if ((curPos + 16 + (stackDepth * 4)) > globalEvBufPosThreshold) { // Dump the buffer - externalActionsHandler.handleEventBufferDump(eventBuffer, 0, curPos); - curPos = 0; + if (curPos + 18 + (stackDepth * 4) > ThreadInfo.evBufPosThreshold) { + copyLocalBuffer(ti); + curPos = ti.evBufPos; } - eventBuffer[curPos++] = OBJ_ALLOC_STACK_TRACE; - eventBuffer[curPos++] = (byte) ((classId >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((classId) & 0xFF); + byte[] evBuf = ti.evBuf; + if (!ti.isInitialized()) return; // Reset collectors performed when we were already executing instrumentation code - eventBuffer[curPos++] = (byte) ((objSize >> 32) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 24) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 16) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) (objSize & 0xFF); + evBuf[curPos++] = OBJ_ALLOC_STACK_TRACE; + evBuf[curPos++] = (byte) ((classId >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((classId) & 0xFF); - curPos = writeStack(curPos); - globalEvBufPos = curPos; + evBuf[curPos++] = (byte) ((objSize >> 32) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 24) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 16) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 8) & 0xFF); + evBuf[curPos++] = (byte) (objSize & 0xFF); + + curPos = writeStack(evBuf, curPos, ti, stackDepth); + ti.evBufPos = curPos; } protected static void writeObjGCEvent(long objectId) { @@ -384,8 +376,7 @@ } } - /** Note that there is no synchronized(eventBuffer) in this method, since synchronization is already required by its callers */ - protected static void writeObjLivenessStackTraceEvent(char classId, char epoch, int objCount, long objSize) { + protected static void writeObjLivenessStackTraceEvent(ThreadInfo ti, char classId, char epoch, int objCount, long objSize, int stackDepth) { if (eventBuffer == null) { return; // Instrumentation removal happened when we were in instrumentation } @@ -398,37 +389,76 @@ ProfilerServer.notifyClientOnResultsAvailability(); } - int curPos = globalEvBufPos; + int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment - if ((curPos + 24 + (stackDepth * 4)) > globalEvBufPosThreshold) { // Dump the buffer - externalActionsHandler.handleEventBufferDump(eventBuffer, 0, curPos); - curPos = 0; + if (curPos + 24 + (stackDepth * 4) > ThreadInfo.evBufPosThreshold) { + copyLocalBuffer(ti); + curPos = ti.evBufPos; } - eventBuffer[curPos++] = OBJ_LIVENESS_STACK_TRACE; - eventBuffer[curPos++] = (byte) ((classId >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((classId) & 0xFF); - eventBuffer[curPos++] = (byte) ((epoch >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((epoch) & 0xFF); - eventBuffer[curPos++] = (byte) ((objCount >> 24) & 0xFF); - eventBuffer[curPos++] = (byte) ((objCount >> 16) & 0xFF); - eventBuffer[curPos++] = (byte) ((objCount >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((objCount) & 0xFF); + byte[] evBuf = ti.evBuf; + if (!ti.isInitialized()) return; // Reset collectors performed when we were already executing instrumentation code - eventBuffer[curPos++] = (byte) ((objSize >> 32) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 24) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 16) & 0xFF); - eventBuffer[curPos++] = (byte) ((objSize >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) (objSize & 0xFF); + evBuf[curPos++] = OBJ_LIVENESS_STACK_TRACE; + evBuf[curPos++] = (byte) ((classId >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((classId) & 0xFF); + evBuf[curPos++] = (byte) ((epoch >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((epoch) & 0xFF); + evBuf[curPos++] = (byte) ((objCount >> 24) & 0xFF); + evBuf[curPos++] = (byte) ((objCount >> 16) & 0xFF); + evBuf[curPos++] = (byte) ((objCount >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((objCount) & 0xFF); - curPos = writeStack(curPos); - globalEvBufPos = curPos; + evBuf[curPos++] = (byte) ((objSize >> 32) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 24) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 16) & 0xFF); + evBuf[curPos++] = (byte) ((objSize >> 8) & 0xFF); + evBuf[curPos++] = (byte) (objSize & 0xFF); + + curPos = writeStack(evBuf, curPos, ti, stackDepth); + ti.evBufPos = curPos; } - private static int writeStack(int curPos) { - eventBuffer[curPos++] = (byte) ((stackDepth >> 16) & 0xFF); - eventBuffer[curPos++] = (byte) ((stackDepth >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((stackDepth) & 0xFF); + protected static void copyLocalBuffer(ThreadInfo ti) { + // Copy the local buffer into the main buffer - however avoid doing that if we have already reset profiler collectors + if (eventBuffer == null) { + return; + } + + synchronized (eventBuffer) { + if (!ti.isInitialized()) { + return; // Reset collectors performed when we were already executing instrumentation code + } + + int curPos = ti.evBufPos; + + // First check if the global buffer itself needs to be dumped + int evBufDumpLastPos = ti.evBufDumpLastPos; + + if (((globalEvBufPos + curPos) - evBufDumpLastPos) > globalEvBufPosThreshold) { + sendingBuffer = true; + + externalActionsHandler.handleEventBufferDump(eventBuffer, 0, globalEvBufPos); + globalEvBufPos = 0; + sendingBuffer = false; + } + + // Finally copy the local buffer into the global one + eventBuffer[globalEvBufPos++] = SET_FOLLOWING_EVENTS_THREAD; + eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId >> 8) & 0xFF); + eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId) & 0xFF); + System.arraycopy(ti.evBuf, evBufDumpLastPos, eventBuffer, globalEvBufPos, curPos - evBufDumpLastPos); + globalEvBufPos += (curPos - evBufDumpLastPos); + ti.evBufPos = 0; + ti.evBufDumpLastPos = 0; + } + } + + + private static int writeStack(byte[] evBuf, int curPos, ThreadInfo ti, int stackDepth) { + evBuf[curPos++] = (byte) ((stackDepth >> 16) & 0xFF); + evBuf[curPos++] = (byte) ((stackDepth >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((stackDepth) & 0xFF); /// A variant when we send non-reversed call graph //int base = depth + NO_OF_PROFILER_FRAMES - 1; @@ -437,12 +467,13 @@ // eventBuffer[curPos++] = (char) ((stackFrameIds[base-i]) & 0xFFFF); //} int frameIdx = NO_OF_PROFILER_FRAMES; - + int[] frames = ti.stackFrameIds; + for (int i = 0; i < stackDepth; i++) { - eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 24) & 0xFF); - eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 16) & 0xFF); - eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx] >> 8) & 0xFF); - eventBuffer[curPos++] = (byte) ((stackFrameIds[frameIdx]) & 0xFF); + evBuf[curPos++] = (byte) ((frames[frameIdx] >> 24) & 0xFF); + evBuf[curPos++] = (byte) ((frames[frameIdx] >> 16) & 0xFF); + evBuf[curPos++] = (byte) ((frames[frameIdx] >> 8) & 0xFF); + evBuf[curPos++] = (byte) ((frames[frameIdx]) & 0xFF); frameIdx++; } diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjAlloc.java --- a/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjAlloc.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjAlloc.java Fri Sep 14 09:29:20 2012 +0200 @@ -100,6 +100,8 @@ if (!ti.isInitialized()) { ti.initialize(true); + ti.useEventBuffer(); + ti.useStackBuffer(MAX_STACK_FRAMES); } ti.inProfilingRuntimeMethod++; @@ -113,7 +115,7 @@ if (allocatedInstThreshold[classId] <= 0) { long objSize = getCachedObjectSize(classId, object); - getAndSendCurrentStackTrace(classId, objSize); + getAndSendCurrentStackTrace(ti, classId, objSize); allocatedInstThreshold[classId] = nextRandomizedInterval(); } diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjLiveness.java --- a/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjLiveness.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/server/ProfilerRuntimeObjLiveness.java Fri Sep 14 09:29:20 2012 +0200 @@ -250,6 +250,8 @@ if (!ti.isInitialized()) { ti.initialize(true); + ti.useEventBuffer(); + ti.useStackBuffer(MAX_STACK_FRAMES); } if (ti.inProfilingRuntimeMethod > 0) { @@ -278,7 +280,7 @@ long objSize = getCachedObjectSize(classId, object); - getAndSendCurrentStackTrace(classId, epoch, objCount, objSize); + getAndSendCurrentStackTrace(ti, classId, epoch, objCount, objSize); allocatedInstThreshold[classId] = nextRandomizedInterval(); } diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/server/ThreadInfo.java --- a/lib.profiler/src/org/netbeans/lib/profiler/server/ThreadInfo.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/server/ThreadInfo.java Fri Sep 14 09:29:20 2012 +0200 @@ -83,6 +83,7 @@ Thread thread; // Thread object for this ThreadInfo byte[] evBuf; // Thread-local event (rough profiling data) buffer. Currently used in CPU profiling only. + int[] stackFrameIds; // used im memory profiling to store allocation stacktrace boolean inCallGraph; // Indicates whether the thread is currently in the profiled subgraph boolean sampleDue; // In sampled instrumentation mode, indicates that next sampling should be done int evBufDumpLastPos; // Used to avoid synchronization in writeEvent() and yet to allow for asynchronous event buffer dumps. @@ -247,6 +248,10 @@ evBuf = new byte[evBufSize]; } + final void useStackBuffer(int bufferSize) { + stackFrameIds = new int[bufferSize]; + } + static int getNProfiledAppThreads() { return nProfiledAppThreads; } @@ -349,6 +354,7 @@ ProfilerRuntimeCPU.copyLocalBuffer(ti); } ti.evBuf = null; // release results buffer + ti.stackFrameIds = null; // release also srackFrameIds buffer } ti.thread = null; // release dead thread hasDeadThreads = true; @@ -445,5 +451,6 @@ rootMethodStackDepth = stackDepth = 0; inCallGraph = sampleDue = false; evBuf = null; + stackFrameIds = null; } } diff -r 5696f3be43db lib.profiler/src/org/netbeans/lib/profiler/server/system/Stacks.java --- a/lib.profiler/src/org/netbeans/lib/profiler/server/system/Stacks.java Fri Sep 14 05:25:50 2012 +0200 +++ b/lib.profiler/src/org/netbeans/lib/profiler/server/system/Stacks.java Fri Sep 14 09:29:20 2012 +0200 @@ -84,17 +84,10 @@ */ public static native void getAllStackTraces(Thread[][] threads, int[][] states, int[][][] frames); - /** Clear the above stack frame buffer permanently. */ - public static native void clearNativeStackFrameBuffer(); - /** - * Creates the internal, C-level stack frame buffer, used for intermediate storage of data obtained using - * getCurrentStackFrameIds. Since just a single buffer is used, getCurrentStackFrameIds is obviously not - * multithread-safe. The code that uses this stuff has to use a single lock - so far not a problem for memory - * profiling where we use it, since normally it collects data for just every 10th object, thus the probability - * of contention is not very high. + * Sets maximum stack size */ - public static native void createNativeStackFrameBuffer(int sizeInFrames); + public static native void setStackFrameBufferSize(int sizeInFrames); /** Should be called at earliest possible time */ public static void initialize() {