001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.server;
042:
043: import org.netbeans.lib.profiler.global.CommonConstants;
044: import org.netbeans.lib.profiler.global.ProfilingPointServerHandler;
045: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
046: import java.lang.reflect.Method;
047: import java.util.*;
048:
049: /**
050: * This is a base class, containing common functionality for classes that contain instrumentation methods.
051: *
052: * @author Tomas Hurka
053: * @author Misha Dmitriev
054: */
055: public class ProfilerRuntime implements CommonConstants {
056: //~ Inner Interfaces ---------------------------------------------------------------------------------------------------------
057:
058: // ------------- Handling operations that should be performed outside ProfilerRuntime --------------
059: public static interface ExternalActionsHandler {
060: //~ Methods --------------------------------------------------------------------------------------------------------------
061:
062: public void handleEventBufferDump(byte[] eventBuffer,
063: int startPos, int curPtrPos);
064:
065: public void handleFirstTimeMethodInvoke(int methodId);
066:
067: public int handleFirstTimeVMObjectAlloc(String className,
068: int classLoaderId);
069:
070: public void handleReflectiveInvoke(Method method);
071: }
072:
073: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
074:
075: protected static ExternalActionsHandler externalActionsHandler;
076:
077: // ---------------------------------- Writing profiler events --------------------------------------
078: protected static byte[] eventBuffer;
079: protected static int globalEvBufPos;
080: protected static int globalEvBufPosThreshold;
081: protected static volatile boolean sendingBuffer;
082: private static boolean printEvents; // For debugging
083:
084: //~ Methods ------------------------------------------------------------------------------------------------------------------
085:
086: public static void createEventBuffer(int bufSize) {
087: eventBuffer = new byte[bufSize];
088: globalEvBufPosThreshold = bufSize
089: - (3 * ThreadInfo.MAX_EVENT_SIZE) - 1;
090: globalEvBufPos = 0;
091: }
092:
093: // Asynchronous event buffer dump
094: public static void dumpEventBuffer() {
095: if (eventBuffer == null) {
096: return; // Just in case somebody calls it with null eventBuffer
097: }
098:
099: if (sendingBuffer) {
100: return; // No need (and may cause a deadlock in tool) if forced dump is requested while
101: // a routine dump is already in progress
102: }
103:
104: synchronized (eventBuffer) {
105: sendingBuffer = true;
106:
107: // Dump the info from all thread-local buffers (if they are not null) into the global buffer
108: ThreadInfo[] tis = ThreadInfo.getThreadInfos();
109:
110: for (int i = 0; i < tis.length; i++) {
111: ThreadInfo ti = tis[i];
112:
113: if ((ti == null) || (ti.evBuf == null)
114: || !ti.isInitialized()) {
115: continue;
116: }
117:
118: int curPos = ti.evBufPos; // Guaranteed to be at event boundary
119:
120: if (((globalEvBufPos + curPos) - ti.evBufDumpLastPos) > globalEvBufPosThreshold) {
121: break; // We don't try to perform more than one global buffer dumps yet
122: }
123:
124: int evBufSize = curPos - ti.evBufDumpLastPos;
125:
126: if (evBufSize > 0) {
127: eventBuffer[globalEvBufPos++] = SET_FOLLOWING_EVENTS_THREAD;
128: eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId >> 8) & 0xFF);
129: eventBuffer[globalEvBufPos++] = (byte) (ti.threadId & 0xFF);
130: System.arraycopy(ti.evBuf, ti.evBufDumpLastPos,
131: eventBuffer, globalEvBufPos, evBufSize);
132: globalEvBufPos += evBufSize;
133: ti.evBufDumpLastPos = curPos;
134: }
135: }
136:
137: externalActionsHandler.handleEventBufferDump(eventBuffer,
138: 0, globalEvBufPos);
139: globalEvBufPos = 0;
140: sendingBuffer = false;
141: }
142: }
143:
144: public static void init(ExternalActionsHandler h) {
145: externalActionsHandler = h;
146: }
147:
148: // ------------- Handling wait/sleep/monitors entry/exit -------------------------------------------
149: public static void monitorEntry(Thread t, Object monitor) {
150: if (ThreadInfo.profilingSuspended()
151: || ThreadInfo.isProfilerServerThread(t)) {
152: // nothing done for profiler own threads or if in instrumentation
153: return;
154: }
155:
156: ProfilingSessionStatus status = ProfilerServer
157: .getProfilingSessionStatus();
158:
159: if (status != null) {
160: switch (status.currentInstrType) {
161: case INSTR_RECURSIVE_FULL:
162: case INSTR_RECURSIVE_SAMPLED:
163: ProfilerRuntimeCPU.monitorEntryCPU(t, monitor);
164:
165: break;
166: case INSTR_CODE_REGION:
167: ProfilerRuntimeCPUCodeRegion.monitorEntryRegion(t,
168: monitor);
169:
170: break;
171: }
172: }
173:
174: // TODO: use for thread monitoring
175: }
176:
177: public static void monitorExit(Thread t, Object monitor) {
178: if (ThreadInfo.profilingSuspended()
179: || ThreadInfo.isProfilerServerThread(t)) {
180: // nothing done for profiler own threads or if in instrumentation
181: return;
182: }
183:
184: ProfilingSessionStatus status = ProfilerServer
185: .getProfilingSessionStatus();
186:
187: if (status != null) {
188: switch (status.currentInstrType) {
189: case INSTR_RECURSIVE_FULL:
190: case INSTR_RECURSIVE_SAMPLED:
191: ProfilerRuntimeCPU.monitorExitCPU(t, monitor);
192:
193: break;
194: case INSTR_CODE_REGION:
195: ProfilerRuntimeCPUCodeRegion.monitorExitRegion(t,
196: monitor);
197:
198: break;
199: }
200: }
201:
202: // TODO: use for thread monitoring
203: }
204:
205: public static void profilePointHit(char id) {
206: if (ThreadInfo.profilingSuspended()
207: || ThreadInfo.isCurrentThreadProfilerServerThread()) {
208: return;
209: }
210:
211: if (eventBuffer == null) {
212: return; // Instrumentation removal happened when we were in instrumentation
213: }
214:
215: ThreadInfo ti = ThreadInfo.getThreadInfo();
216:
217: if (ti.inProfilingRuntimeMethod > 0) {
218: return;
219: }
220:
221: ti.inProfilingRuntimeMethod++;
222:
223: int[] ids = ProfilerServer.getProfilingSessionStatus().profilingPointIDs;
224: int idx = Arrays.binarySearch(ids, id);
225:
226: if (idx >= 0) {
227: ProfilingPointServerHandler method = ProfilerServer
228: .getProfilingSessionStatus().profilingPointHandlers[idx];
229:
230: try {
231: method.profilingPointHit(id);
232: } catch (Exception e) {
233: e.printStackTrace(System.err);
234: }
235: }
236:
237: ti.inProfilingRuntimeMethod--;
238: }
239:
240: public static boolean profiledTargetAppThreadsExist() {
241: return (ThreadInfo.getNProfiledAppThreads() > 0);
242: }
243:
244: // ------------------------------ Common setup functionality ---------------------------------------
245: public static void resetProfilerCollectors(int instrType) {
246: if ((instrType != INSTR_CODE_REGION) && (eventBuffer != null)) {
247: synchronized (eventBuffer) {
248: doResetProfilerCollectors(instrType);
249: }
250: } else {
251: doResetProfilerCollectors(instrType);
252: }
253: }
254:
255: public static void sleepEntry() {
256: if (ThreadInfo.profilingSuspended()
257: || ThreadInfo.isCurrentThreadProfilerServerThread()) {
258: // nothing done for profiler own threads or if in instrumentation
259: return;
260: }
261:
262: ProfilingSessionStatus status = ProfilerServer
263: .getProfilingSessionStatus();
264:
265: if (status != null) {
266: switch (status.currentInstrType) {
267: case INSTR_RECURSIVE_FULL:
268: case INSTR_RECURSIVE_SAMPLED:
269: ProfilerRuntimeCPU.sleepEntryCPU();
270:
271: break;
272: case INSTR_CODE_REGION:
273: ProfilerRuntimeCPUCodeRegion.sleepEntryRegion();
274:
275: break;
276: }
277: }
278:
279: // TODO: use for thread monitoring
280: }
281:
282: public static void sleepExit() {
283: if (ThreadInfo.profilingSuspended()
284: || ThreadInfo.isCurrentThreadProfilerServerThread()) {
285: // nothing done for profiler own threads or if in instrumentation
286: return;
287: }
288:
289: ProfilingSessionStatus status = ProfilerServer
290: .getProfilingSessionStatus();
291:
292: if (status != null) {
293: switch (status.currentInstrType) {
294: case INSTR_RECURSIVE_FULL:
295: case INSTR_RECURSIVE_SAMPLED:
296: ProfilerRuntimeCPU.sleepExitCPU();
297:
298: break;
299: case INSTR_CODE_REGION:
300: ProfilerRuntimeCPUCodeRegion.sleepExitRegion();
301:
302: break;
303: }
304: }
305:
306: // TODO: use for thread monitoring
307: }
308:
309: public static void waitEntry() {
310: if (ThreadInfo.profilingSuspended()
311: || ThreadInfo.isCurrentThreadProfilerServerThread()) {
312: // nothing done for profiler own threads or if in instrumentation
313: return;
314: }
315:
316: ProfilingSessionStatus status = ProfilerServer
317: .getProfilingSessionStatus();
318:
319: if (status != null) {
320: switch (status.currentInstrType) {
321: case INSTR_RECURSIVE_FULL:
322: case INSTR_RECURSIVE_SAMPLED:
323: ProfilerRuntimeCPU.waitEntryCPU();
324:
325: break;
326: case INSTR_CODE_REGION:
327: ProfilerRuntimeCPUCodeRegion.waitEntryRegion();
328:
329: break;
330: }
331: }
332:
333: // TODO: use for thread monitoring
334: }
335:
336: public static void waitExit() {
337: if (ThreadInfo.profilingSuspended()
338: || ThreadInfo.isCurrentThreadProfilerServerThread()) {
339: // nothing done for profiler own threads or if in instrumentation
340: return;
341: }
342:
343: ProfilingSessionStatus status = ProfilerServer
344: .getProfilingSessionStatus();
345:
346: if (status != null) {
347: switch (status.currentInstrType) {
348: case INSTR_RECURSIVE_FULL:
349: case INSTR_RECURSIVE_SAMPLED:
350: ProfilerRuntimeCPU.waitExitCPU();
351:
352: break;
353: case INSTR_CODE_REGION:
354: ProfilerRuntimeCPUCodeRegion.waitExitRegion();
355:
356: break;
357: }
358: }
359:
360: // TODO: use for thread monitoring
361: }
362:
363: public static void writeProfilingPointHitEvent(int id,
364: long absTimeStamp) {
365: ThreadInfo ti = ThreadInfo.getThreadInfo();
366: int tid = ti.threadId;
367:
368: if (ti.evBuf == null) { // memory profilimg use global event buffer
369:
370: synchronized (eventBuffer) {
371: int curPos = globalEvBufPos;
372:
373: if (curPos > globalEvBufPosThreshold) { // Dump the buffer
374: dumpEventBuffer();
375: curPos = 0;
376: }
377:
378: curPos = writePPointHitToBuffer(eventBuffer,
379: absTimeStamp, curPos, id, tid);
380: globalEvBufPos = curPos;
381: }
382: } else { // CPU profiling write to thread event buffer
383:
384: int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment
385:
386: if (curPos > ThreadInfo.evBufPosThreshold) {
387: ProfilerRuntimeCPU.copyLocalBuffer(ti); // ugly I know :-(
388: curPos = ti.evBufPos;
389: }
390:
391: byte[] evBuf = ti.evBuf;
392: ti.evBufPos = writePPointHitToBuffer(evBuf, absTimeStamp,
393: curPos, id, tid);
394: }
395: }
396:
397: // -------------------------------- Thread-related stuff ------------------------------------------
398: protected static void changeAllThreadsInProfRuntimeMethodStatus(
399: int val) {
400: ThreadInfo.changeAllThreadsInProfRuntimeMethodStatus(val);
401: }
402:
403: protected static void clearDataStructures() {
404: eventBuffer = null;
405: globalEvBufPos = 0;
406: ThreadInfo.resetThreadInfoTable();
407: }
408:
409: protected static void createNewDataStructures() {
410: ThreadInfo.resetThreadInfoTable(); // Despite the name, it effectively creates some data
411: }
412:
413: private static void doResetProfilerCollectors(int instrType) {
414: ThreadInfo.resetThreadInfoTable();
415: globalEvBufPos = 0;
416:
417: if (eventBuffer != null) {
418: eventBuffer[globalEvBufPos++] = RESET_COLLECTORS;
419: }
420:
421: switch (instrType) {
422: case INSTR_RECURSIVE_FULL:
423: case INSTR_RECURSIVE_SAMPLED:
424: ProfilerRuntimeCPU.resetProfilerCollectors();
425:
426: break;
427: case INSTR_CODE_REGION:
428: ProfilerRuntimeCPUCodeRegion.resetProfilerCollectors();
429:
430: break;
431: case INSTR_OBJECT_ALLOCATIONS:
432: case INSTR_OBJECT_LIVENESS:
433: ProfilerRuntimeMemory.resetProfilerCollectors(instrType);
434:
435: break;
436: }
437: }
438:
439: private static int writePPointHitToBuffer(byte[] buf,
440: final long absTimeStamp, int curPos, final int id,
441: final int tid) {
442: buf[curPos++] = BUFFEREVENT_PROFILEPOINT_HIT;
443: buf[curPos++] = (byte) ((id >> 8) & 0xFF);
444: buf[curPos++] = (byte) (id & 0xFF);
445: buf[curPos++] = (byte) ((absTimeStamp >> 48) & 0xFF);
446: buf[curPos++] = (byte) ((absTimeStamp >> 40) & 0xFF);
447: buf[curPos++] = (byte) ((absTimeStamp >> 32) & 0xFF);
448: buf[curPos++] = (byte) ((absTimeStamp >> 24) & 0xFF);
449: buf[curPos++] = (byte) ((absTimeStamp >> 16) & 0xFF);
450: buf[curPos++] = (byte) ((absTimeStamp >> 8) & 0xFF);
451: buf[curPos++] = (byte) ((absTimeStamp) & 0xFF);
452: buf[curPos++] = (byte) ((tid >> 8) & 0xFF);
453: buf[curPos++] = (byte) ((tid) & 0xFF);
454:
455: return curPos;
456: }
457: }
|