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.server.system.Timers;
044: import java.lang.reflect.Method;
045:
046: /**
047: * This class contains the functionality that is common for all CPU profiling methods available in JFluid.
048: *
049: * @author Tomas Hurka
050: * @author Misha Dmitriev
051: */
052: public class ProfilerRuntimeCPU extends ProfilerRuntime {
053: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
054:
055: private static final boolean DEBUG = false;
056: private static int nProfiledThreadsLimit;
057: protected static int nProfiledThreadsAllowed;
058:
059: // The following flag is used to prevent deadlock inside getThreadInfo() by forcing immediate return from methodEntry() etc.
060: // in case methodEntry() (typically when it's injected in some core class method) is executed on behalf of some profiler server thread,
061: // when all target app threads are suspended. In that case, some thread may be suspended within getThreadInfo(), holding the lock.
062: // It is also used to disable instrumentation to be on the safe side when we e.g. detach from a running multithreaded application -
063: // it looks as if in this case de-instrumentation may not immediately propagate everywhere.
064: protected static volatile boolean recursiveInstrumentationDisabled = false;
065:
066: // ------------------------------------------ Timers -----------------------------------------------
067: protected static boolean absoluteTimerOn;
068:
069: // ------------------------------------------ Timers -----------------------------------------------
070: protected static boolean threadCPUTimerOn;
071:
072: // ---------------------------------- Profile Data Acquisition --------------------------------------
073: protected static boolean[] instrMethodInvoked;
074: private static boolean javaLangReflectMethodInvokeInterceptEnabled = false;
075: private static Method getRequestedSessionIdMethod;
076: private static Method getMethodMethod;
077: private static Method getServletPathMethod;
078:
079: //~ Methods ------------------------------------------------------------------------------------------------------------------
080:
081: // See the comment in writeTimeStampedEvent() below, marked with (***)
082: // On all OSes except Linux, the upper byte of value returned by Timers.getCurrentTimeInCounts() will be zero - timer
083: // calculates time from program start or from machine start. But on Linux it seems to be timeofday or something. We have
084: // to take measures here to return time in the same format as used for collected data.
085: public static long getAbsTimeStampInCollectedFormat() {
086: return Timers.getCurrentTimeInCounts() & 72057594037927935L; //0xFFFFFFFFFFFFFF, i.e. 7 bytes
087: }
088:
089: public static void setInstrMethodsInvoked(boolean[] methodInvoked) {
090: instrMethodInvoked = methodInvoked;
091: }
092:
093: public static void setJavaLangReflectMethodInvokeInterceptEnabled(
094: boolean v) {
095: javaLangReflectMethodInvokeInterceptEnabled = v;
096: }
097:
098: public static void setNProfiledThreadsLimit(int num) {
099: nProfiledThreadsLimit = nProfiledThreadsAllowed = num;
100: }
101:
102: public static void setTimerTypes(boolean absolute, boolean threadCPU) {
103: if (threadCPU != threadCPUTimerOn) {
104: String osName = System.getProperty("os.name"); // NOI18N
105:
106: if (osName.startsWith("SunOS")
107: || osName.startsWith("Solaris")) {
108: Timers.enableMicrostateAccounting(threadCPU); // NOI18N
109: }
110: }
111:
112: absoluteTimerOn = absolute;
113: threadCPUTimerOn = threadCPU;
114: }
115:
116: // This is currently used only when calibrating the profiler, to pre-create a ThreadInfo before calling methodEntry/Exit.
117: // It is done to prevent the system attempting to send a "new thread created" message to the client.
118: public static void createThreadInfoForCurrentThread() {
119: ThreadInfo ti = ThreadInfo.getThreadInfo();
120: ti.initialize();
121: ti.useEventBuffer();
122: ti.inCallGraph = false; // Important: this is a correct initial value when ti is used in calibration
123: }
124:
125: public static void handleJavaLangReflectMethodInvoke(Method method) {
126: if (!javaLangReflectMethodInvokeInterceptEnabled) {
127: return;
128: }
129:
130: if (recursiveInstrumentationDisabled) {
131: return;
132: }
133:
134: ThreadInfo ti = ThreadInfo.getThreadInfo();
135:
136: if (!ti.isInitialized() || !ti.inCallGraph) {
137: return; // ti == null may happen if instrumentation has been removed or data collectors reset
138: }
139:
140: if (ti.inProfilingRuntimeMethod > 0) {
141: return;
142: }
143:
144: ti.inProfilingRuntimeMethod++;
145:
146: externalActionsHandler.handleReflectiveInvoke(method);
147:
148: ti.inProfilingRuntimeMethod--;
149: }
150:
151: public static void handleServletDoMethod(Object request) {
152: if (recursiveInstrumentationDisabled) {
153: return;
154: }
155:
156: ThreadInfo ti = ThreadInfo.getThreadInfo();
157:
158: if (!ti.isInitialized()) {
159: System.out.println("No thread for servlet request"); // NOI18N
160:
161: return;
162: }
163:
164: ti.inProfilingRuntimeMethod++;
165: servletDoMethodHook(ti, request);
166: ti.inProfilingRuntimeMethod--;
167: }
168:
169: public static void resetProfilerCollectors() {
170: nProfiledThreadsAllowed = nProfiledThreadsLimit;
171: }
172:
173: public static void resumeCurrentThreadTimer() {
174: ThreadInfo ti = ThreadInfo.getThreadInfo();
175:
176: if (!ti.isInitialized() || !ti.inCallGraph) {
177: return;
178: }
179:
180: writeAdjustTimeEvent(ti, ti.absEntryTime, ti.threadEntryTime);
181: ti.inProfilingRuntimeMethod--;
182: }
183:
184: // This is currently called in class load hook, to stop counting the time and emitting method entry/exit events while the
185: // hook and other Java code that it may call are active.
186: public static ThreadInfo suspendCurrentThreadTimer() {
187: ThreadInfo ti = ThreadInfo.getThreadInfo();
188:
189: if (!ti.isInitialized() || !ti.inCallGraph) {
190: return ti;
191: }
192:
193: ti.inProfilingRuntimeMethod++;
194:
195: // those timestamps are taken here, as opposed to earlier in this method, because we need to make sure we do not
196: // profile the Timer.get... calls, by increasing the ti.inProfilingRuntimeMethod
197: // see issue 65614 for a possible impact of this
198: // http://profiler.netbeans.org/issues/show_bug.cgi?id=65614
199: long absTimeStamp = Timers.getCurrentTimeInCounts();
200: long threadTimeStamp = Timers.getThreadCPUTimeInNanos();
201: ti.absEntryTime = absTimeStamp;
202: ti.threadEntryTime = threadTimeStamp;
203:
204: return ti;
205: }
206:
207: protected static void clearDataStructures() {
208: ProfilerRuntime.clearDataStructures();
209: nProfiledThreadsAllowed = nProfiledThreadsLimit;
210: }
211:
212: protected static void copyLocalBuffer(ThreadInfo ti) {
213: long absTimeStamp = 0;
214: long threadTimeStamp = 0;
215:
216: // Copy the local buffer into the main buffer - however avoid doing that if we have already reset profiler collectors
217: if (eventBuffer == null) {
218: return;
219: }
220:
221: boolean needToAdjustTime = false;
222:
223: if (sendingBuffer) { // Some other thread is already sending the buffer contents
224: absTimeStamp = Timers.getCurrentTimeInCounts();
225: threadTimeStamp = Timers.getThreadCPUTimeInNanos();
226:
227: synchronized (eventBuffer) { // Wait on the lock. When it's free, buffer has been sent and reset
228:
229: if (sendingBuffer) {
230: System.err
231: .println("*** Sanity check failed - sendingBuffer where should have been already sent"); // NOI18N
232: }
233:
234: needToAdjustTime = true;
235: }
236: }
237:
238: synchronized (eventBuffer) {
239: if (!ti.isInitialized()) {
240: return; // Reset collectors performed when we were already executing instrumentation code
241: }
242:
243: int curPos = ti.evBufPos;
244:
245: // First check if the global buffer itself needs to be dumped
246: int evBufDumpLastPos = ti.evBufDumpLastPos;
247:
248: if (((globalEvBufPos + curPos) - evBufDumpLastPos) > globalEvBufPosThreshold) {
249: sendingBuffer = true;
250:
251: if (!needToAdjustTime) {
252: absTimeStamp = Timers.getCurrentTimeInCounts();
253: threadTimeStamp = Timers.getThreadCPUTimeInNanos();
254: needToAdjustTime = true;
255: }
256:
257: externalActionsHandler.handleEventBufferDump(
258: eventBuffer, 0, globalEvBufPos);
259: globalEvBufPos = 0;
260: sendingBuffer = false;
261: }
262:
263: // Finally copy the local buffer into the global one
264: eventBuffer[globalEvBufPos++] = SET_FOLLOWING_EVENTS_THREAD;
265: eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId >> 8) & 0xFF);
266: eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId) & 0xFF);
267: System.arraycopy(ti.evBuf, evBufDumpLastPos, eventBuffer,
268: globalEvBufPos, curPos - evBufDumpLastPos);
269: globalEvBufPos += (curPos - evBufDumpLastPos);
270: ti.evBufPos = 0;
271: ti.evBufDumpLastPos = 0;
272:
273: // Now, if we previously spent time waiting for another thread to dump the global buffer, or doing that
274: // ourselves, write the ADJUST_TIME event into the local buffer
275: if (needToAdjustTime) {
276: writeAdjustTimeEvent(ti, absTimeStamp, threadTimeStamp);
277: }
278: }
279: }
280:
281: protected static long currentTimeInCounts() {
282: return Timers.getCurrentTimeInCounts();
283: }
284:
285: protected static void enableProfiling(boolean v) {
286: recursiveInstrumentationDisabled = !v;
287:
288: // Doesn't call clearDataStructures() since this is an "abstract" class
289: }
290:
291: // ---------------------------------- Handling wait/sleep/monitor times ----------------------------
292: protected static void monitorEntryCPU(Thread t, Object monitor) {
293: if (recursiveInstrumentationDisabled) {
294: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
295: }
296:
297: ThreadInfo ti = ThreadInfo.getThreadInfo(t);
298:
299: if (ti.isInitialized() && ti.inCallGraph) {
300: if (ti.inProfilingRuntimeMethod > 0) {
301: return;
302: }
303:
304: ti.inProfilingRuntimeMethod++;
305: //System.out.println("++++++monitorEntry, depth = " + ti.stackDepth);
306: writeWaitTimeEvent(METHOD_ENTRY_MONITOR, ti);
307: ti.inProfilingRuntimeMethod--;
308: }
309: }
310:
311: protected static void monitorExitCPU(Thread t, Object monitor) {
312: if (recursiveInstrumentationDisabled) {
313: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
314: }
315:
316: ThreadInfo ti = ThreadInfo.getThreadInfo(t);
317:
318: if (ti.isInitialized() && ti.inCallGraph) {
319: if (ti.inProfilingRuntimeMethod > 0) {
320: return;
321: }
322:
323: ti.inProfilingRuntimeMethod++;
324: //System.out.println("++++++monitorExit, depth = " + ti.stackDepth);
325: writeWaitTimeEvent(METHOD_EXIT_MONITOR, ti);
326: ti.inProfilingRuntimeMethod--;
327: }
328: }
329:
330: protected static void sleepEntryCPU() {
331: if (recursiveInstrumentationDisabled) {
332: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
333: }
334:
335: ThreadInfo ti = ThreadInfo.getThreadInfo();
336:
337: if (ti.isInitialized() && ti.inCallGraph) {
338: if (ti.inProfilingRuntimeMethod > 0) {
339: return;
340: }
341:
342: ti.inProfilingRuntimeMethod++;
343: //System.out.println("++++++sleepEntry, depth = " + ti.stackDepth);
344: writeWaitTimeEvent(METHOD_ENTRY_SLEEP, ti);
345: ti.inProfilingRuntimeMethod--;
346: }
347: }
348:
349: protected static void sleepExitCPU() {
350: if (recursiveInstrumentationDisabled) {
351: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
352: }
353:
354: ThreadInfo ti = ThreadInfo.getThreadInfo();
355:
356: if (ti.isInitialized() && ti.inCallGraph) {
357: if (ti.inProfilingRuntimeMethod > 0) {
358: return;
359: }
360:
361: ti.inProfilingRuntimeMethod++;
362: //System.out.println("++++++sleepExit, depth = " + ti.stackDepth);
363: writeWaitTimeEvent(METHOD_EXIT_SLEEP, ti);
364: ti.inProfilingRuntimeMethod--;
365: }
366: }
367:
368: protected static void waitEntryCPU() {
369: if (recursiveInstrumentationDisabled) {
370: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
371: }
372:
373: ThreadInfo ti = ThreadInfo.getThreadInfo();
374:
375: if (ti.isInitialized() && ti.inCallGraph) {
376: if (ti.inProfilingRuntimeMethod > 0) {
377: return;
378: }
379:
380: ti.inProfilingRuntimeMethod++;
381: //System.out.println("++++++waitEntry, depth = " + ti.stackDepth);
382: writeWaitTimeEvent(METHOD_ENTRY_WAIT, ti);
383: ti.inProfilingRuntimeMethod--;
384: }
385: }
386:
387: protected static void waitExitCPU() {
388: if (recursiveInstrumentationDisabled) {
389: return; // See the comment at the recursiveInstrumentationDisabled variable declaration
390: }
391:
392: ThreadInfo ti = ThreadInfo.getThreadInfo();
393:
394: if (ti.isInitialized() && ti.inCallGraph) {
395: if (ti.inProfilingRuntimeMethod > 0) {
396: return;
397: }
398:
399: ti.inProfilingRuntimeMethod++;
400: //System.out.println("++++++waitExit, depth = " + ti.stackDepth);
401: writeWaitTimeEvent(METHOD_EXIT_WAIT, ti);
402: ti.inProfilingRuntimeMethod--;
403: }
404: }
405:
406: static void writeAdjustTimeEvent(ThreadInfo ti, long absTimeStamp,
407: long threadTimeStamp) {
408: //if (printEvents) System.out.println("*** Writing ADJUST_TIME event, metodId = " + (int)methodId + ", ts = " + timeStamp);
409: byte[] evBuf = ti.evBuf;
410: int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment
411:
412: // Check if the local buffer is about to overflow. We initially didn't have this code here, assuming that writeAdjustTimeEvent()
413: // cannot be called more than 1-2 times in a row. However, later we recognized that actually a large number of this calls can be
414: // made sequentially by classLoadHook() if many classes are loaded in a row. So we need to perform all checks for overflow;
415: // however we take some advantage of the fact that we don't need to take intermediate time stamps etc.
416: if (curPos > ThreadInfo.evBufPosThreshold) {
417: // Copy the local buffer into the main buffer - however avoid doing that if we have already reset profiler collectors
418: if (eventBuffer == null) {
419: return;
420: }
421:
422: synchronized (eventBuffer) {
423: curPos = ti.evBufPos;
424:
425: boolean globalBufNeedsDump = false;
426:
427: // First check if the global buffer itself needs to be dumped
428: int evBufDumpLastPos = ti.evBufDumpLastPos;
429:
430: if (((globalEvBufPos + curPos) - evBufDumpLastPos) > globalEvBufPosThreshold) {
431: globalBufNeedsDump = true;
432: sendingBuffer = true;
433: externalActionsHandler.handleEventBufferDump(
434: eventBuffer, 0, globalEvBufPos);
435: globalEvBufPos = 0;
436: sendingBuffer = false;
437: }
438:
439: // Finally copy the local buffer into the global one
440: eventBuffer[globalEvBufPos++] = SET_FOLLOWING_EVENTS_THREAD;
441: eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId >> 8) & 0xFF);
442: eventBuffer[globalEvBufPos++] = (byte) ((ti.threadId) & 0xFF);
443: System.arraycopy(evBuf, evBufDumpLastPos, eventBuffer,
444: globalEvBufPos, curPos - evBufDumpLastPos);
445: globalEvBufPos += (curPos - evBufDumpLastPos);
446: ti.evBufPos = 0;
447: ti.evBufDumpLastPos = 0;
448: }
449: }
450:
451: curPos = ti.evBufPos;
452: evBuf[curPos++] = ADJUST_TIME;
453:
454: long absInterval = Timers.getCurrentTimeInCounts()
455: - absTimeStamp;
456: evBuf[curPos++] = (byte) ((absInterval >> 48) & 0xFF);
457: evBuf[curPos++] = (byte) ((absInterval >> 40) & 0xFF);
458: evBuf[curPos++] = (byte) ((absInterval >> 32) & 0xFF);
459: evBuf[curPos++] = (byte) ((absInterval >> 24) & 0xFF);
460: evBuf[curPos++] = (byte) ((absInterval >> 16) & 0xFF);
461: evBuf[curPos++] = (byte) ((absInterval >> 8) & 0xFF);
462: evBuf[curPos++] = (byte) ((absInterval) & 0xFF);
463:
464: long threadInterval = Timers.getThreadCPUTimeInNanos()
465: - threadTimeStamp;
466: evBuf[curPos++] = (byte) ((threadInterval >> 48) & 0xFF);
467: evBuf[curPos++] = (byte) ((threadInterval >> 40) & 0xFF);
468: evBuf[curPos++] = (byte) ((threadInterval >> 32) & 0xFF);
469: evBuf[curPos++] = (byte) ((threadInterval >> 24) & 0xFF);
470: evBuf[curPos++] = (byte) ((threadInterval >> 16) & 0xFF);
471: evBuf[curPos++] = (byte) ((threadInterval >> 8) & 0xFF);
472: evBuf[curPos++] = (byte) ((threadInterval) & 0xFF);
473:
474: ti.evBufPos = curPos;
475: }
476:
477: static void writeServletDoMethod(ThreadInfo ti, String method,
478: String servletPath, String sessionId) {
479: int fullInfoLen = 1 + 1 + (servletPath.length() * 2) + 4;
480: int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment
481:
482: if ((curPos + fullInfoLen) > ThreadInfo.evBufPosThreshold) {
483: copyLocalBuffer(ti);
484: curPos = ti.evBufPos;
485: }
486:
487: byte[] evBuf = ti.evBuf;
488: byte methodId = -1;
489: int sessionHash = -1;
490:
491: if ("GET".equals(method)) { // NOI18N
492: methodId = 1;
493: } else if ("POST".equals(method)) { // NOI18N
494: methodId = 2;
495: } else if ("PUT".equals(method)) { // NOI18N
496: methodId = 3;
497: } else if ("DELETE".equals(method)) { // NOI18N
498: methodId = 4;
499: }
500:
501: if (sessionId != null) {
502: sessionHash = sessionId.hashCode();
503: }
504:
505: evBuf[curPos++] = SERVLET_DO_METHOD;
506: evBuf[curPos++] = methodId;
507:
508: byte[] name = servletPath.getBytes();
509: int len = name.length;
510: evBuf[curPos++] = (byte) ((len >> 8) & 0xFF);
511: evBuf[curPos++] = (byte) ((len) & 0xFF);
512: System.arraycopy(name, 0, evBuf, curPos, len);
513: curPos += len;
514: evBuf[curPos++] = (byte) ((sessionHash >> 24) & 0xFF);
515: evBuf[curPos++] = (byte) ((sessionHash >> 16) & 0xFF);
516: evBuf[curPos++] = (byte) ((sessionHash >> 8) & 0xFF);
517: evBuf[curPos++] = (byte) ((sessionHash) & 0xFF);
518: ti.evBufPos = curPos;
519: }
520:
521: static void writeThreadCreationEvent(ThreadInfo ti) {
522: Thread thread = ti.thread;
523: String threadName = thread.getName();
524: String threadClassName = thread.getClass().getName();
525: int fullInfoLen = ((threadName.length() + threadClassName
526: .length()) * 2) + 7;
527:
528: synchronized (eventBuffer) {
529: if ((globalEvBufPos + fullInfoLen) > globalEvBufPosThreshold) {
530: sendingBuffer = true;
531: externalActionsHandler.handleEventBufferDump(
532: eventBuffer, 0, globalEvBufPos);
533: globalEvBufPos = 0;
534: sendingBuffer = false;
535: }
536:
537: eventBuffer[globalEvBufPos++] = NEW_THREAD;
538:
539: int threadId = ti.getThreadId();
540: eventBuffer[globalEvBufPos++] = (byte) ((threadId >> 8) & 0xFF);
541: eventBuffer[globalEvBufPos++] = (byte) ((threadId) & 0xFF);
542:
543: byte[] name = threadName.getBytes();
544: int len = name.length;
545: eventBuffer[globalEvBufPos++] = (byte) ((len >> 8) & 0xFF);
546: eventBuffer[globalEvBufPos++] = (byte) ((len) & 0xFF);
547: System.arraycopy(name, 0, eventBuffer, globalEvBufPos, len);
548: globalEvBufPos += len;
549: name = threadClassName.getBytes();
550: len = name.length;
551: eventBuffer[globalEvBufPos++] = (byte) ((len >> 8) & 0xFF);
552: eventBuffer[globalEvBufPos++] = (byte) ((len) & 0xFF);
553: System.arraycopy(name, 0, eventBuffer, globalEvBufPos, len);
554: globalEvBufPos += len;
555: }
556: }
557:
558: // ---------------------------------- Writing profiler events --------------------------------------
559: static void writeTimeStampedEvent(byte eventType, ThreadInfo ti,
560: char methodId) {
561: int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment
562:
563: if (curPos > ThreadInfo.evBufPosThreshold) {
564: copyLocalBuffer(ti);
565: curPos = ti.evBufPos;
566: }
567:
568: byte[] evBuf = ti.evBuf;
569:
570: evBuf[curPos++] = eventType;
571: evBuf[curPos++] = (byte) ((methodId >> 8) & 0xFF);
572: evBuf[curPos++] = (byte) ((methodId) & 0xFF);
573:
574: // Note that in the code below, we write only the 7 low bytes of the 64-bit timestamp. The justification is that this saves
575: // us some performance and memory, and 2^55 == 36028797018963968 ns == 36028797 sec == 10008 hr == 416 days is a sufficent
576: // representation range for the foreseeable usages of our tool. (***)
577: if (absoluteTimerOn || (eventType < TWO_TIMESTAMP_EVENTS)) {
578: long absTimeStamp = Timers.getCurrentTimeInCounts();
579: evBuf[curPos++] = (byte) ((absTimeStamp >> 48) & 0xFF);
580: evBuf[curPos++] = (byte) ((absTimeStamp >> 40) & 0xFF);
581: evBuf[curPos++] = (byte) ((absTimeStamp >> 32) & 0xFF);
582: evBuf[curPos++] = (byte) ((absTimeStamp >> 24) & 0xFF);
583: evBuf[curPos++] = (byte) ((absTimeStamp >> 16) & 0xFF);
584: evBuf[curPos++] = (byte) ((absTimeStamp >> 8) & 0xFF);
585: evBuf[curPos++] = (byte) ((absTimeStamp) & 0xFF);
586:
587: if (DEBUG) {
588: System.out
589: .println("ProfilerRuntimeCPU.DEBUG: Writing event (Abs) type = "
590: + eventType
591: + ", metodId = "
592: + (int) methodId
593: + ", timestamp: "
594: + absTimeStamp); // NOI18N
595: }
596: }
597:
598: if (threadCPUTimerOn || (eventType < TWO_TIMESTAMP_EVENTS)) {
599: long threadTimeStamp = Timers.getThreadCPUTimeInNanos();
600: evBuf[curPos++] = (byte) ((threadTimeStamp >> 48) & 0xFF);
601: evBuf[curPos++] = (byte) ((threadTimeStamp >> 40) & 0xFF);
602: evBuf[curPos++] = (byte) ((threadTimeStamp >> 32) & 0xFF);
603: evBuf[curPos++] = (byte) ((threadTimeStamp >> 24) & 0xFF);
604: evBuf[curPos++] = (byte) ((threadTimeStamp >> 16) & 0xFF);
605: evBuf[curPos++] = (byte) ((threadTimeStamp >> 8) & 0xFF);
606: evBuf[curPos++] = (byte) ((threadTimeStamp) & 0xFF);
607:
608: if (DEBUG) {
609: System.out
610: .println("ProfilerRuntimeCPU.DEBUG: Writing event (CPU) type = "
611: + eventType
612: + ", metodId = "
613: + (int) methodId
614: + ", timestamp: "
615: + threadTimeStamp); // NOI18N
616: }
617: }
618:
619: ti.evBufPos = curPos;
620: }
621:
622: static void writeWaitTimeEvent(byte eventType, ThreadInfo ti) {
623: // if (printEvents) System.out.println("*** Writing event " + eventType + ", metodId = " + (int)methodId);
624: int curPos = ti.evBufPos; // It's important to use a local copy for evBufPos, so that evBufPos is at event boundary at any moment
625:
626: if (curPos > ThreadInfo.evBufPosThreshold) {
627: copyLocalBuffer(ti);
628: curPos = ti.evBufPos;
629: }
630:
631: byte[] evBuf = ti.evBuf;
632:
633: evBuf[curPos++] = eventType;
634:
635: // Note that in the code below, we write only the 7 low bytes of the 64-bit value. The justification is that this saves
636: // us some performance and memory, and 2^55 == 36028797018963968 ns == 36028797 sec == 10008 hr == 416 days is a sufficent
637: // representation range for the foreseeable usages of our tool. (***)
638: long absTimeStamp = Timers.getCurrentTimeInCounts();
639:
640: if (DEBUG) {
641: System.out
642: .println("ProfilerRuntimeCPU.DEBUG: Writing waitTime event type = "
643: + eventType
644: + ", timestamp: "
645: + absTimeStamp); // NOI18N
646: }
647:
648: evBuf[curPos++] = (byte) ((absTimeStamp >> 48) & 0xFF);
649: evBuf[curPos++] = (byte) ((absTimeStamp >> 40) & 0xFF);
650: evBuf[curPos++] = (byte) ((absTimeStamp >> 32) & 0xFF);
651: evBuf[curPos++] = (byte) ((absTimeStamp >> 24) & 0xFF);
652: evBuf[curPos++] = (byte) ((absTimeStamp >> 16) & 0xFF);
653: evBuf[curPos++] = (byte) ((absTimeStamp >> 8) & 0xFF);
654: evBuf[curPos++] = (byte) ((absTimeStamp) & 0xFF);
655:
656: ti.evBufPos = curPos;
657: }
658:
659: private static void servletDoMethodHook(ThreadInfo ti,
660: Object request) {
661: String servletPath = null;
662: String method = null;
663: String requestedSessionId = null;
664:
665: if (getRequestedSessionIdMethod == null) {
666: try {
667: Class requestClass = request.getClass();
668: getRequestedSessionIdMethod = requestClass.getMethod(
669: "getRequestedSessionId", null); // NOI18N
670: getMethodMethod = requestClass.getMethod("getMethod",
671: null); // NOI18N
672: getServletPathMethod = requestClass.getMethod(
673: "getServletPath", null); // NOI18N
674: } catch (Exception ex) {
675: ex.printStackTrace();
676:
677: return;
678: }
679: }
680:
681: try {
682: requestedSessionId = (String) getRequestedSessionIdMethod
683: .invoke(request, null);
684: method = (String) getMethodMethod.invoke(request, null);
685: servletPath = (String) getServletPathMethod.invoke(request,
686: null);
687: } catch (Exception ex) {
688: ex.printStackTrace();
689:
690: return;
691: }
692:
693: writeServletDoMethod(ti, method, servletPath,
694: requestedSessionId);
695: }
696: }
|