Source Code Cross Referenced for ProfilerInterface.java in  » IDE-Netbeans » cvsclient » org » netbeans » lib » profiler » server » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » cvsclient » org.netbeans.lib.profiler.server 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         * The Original Software is NetBeans. The Initial Developer of the Original
0026:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0027:         * Microsystems, Inc. All Rights Reserved.
0028:         *
0029:         * If you wish your version of this file to be governed by only the CDDL
0030:         * or only the GPL Version 2, indicate your decision by adding
0031:         * "[Contributor] elects to include this software in this distribution
0032:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0033:         * single choice of license, a recipient has the option to distribute
0034:         * your version of this file under either the CDDL, the GPL Version 2 or
0035:         * to extend the choice of license to its licensees as provided above.
0036:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0037:         * Version 2 license, then the option applies only if the new code is
0038:         * made subject to such option by the copyright holder.
0039:         */
0040:
0041:        package org.netbeans.lib.profiler.server;
0042:
0043:        import org.netbeans.lib.profiler.global.CommonConstants;
0044:        import org.netbeans.lib.profiler.global.Platform;
0045:        import org.netbeans.lib.profiler.global.ProfilingPointServerHandler;
0046:        import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
0047:        import org.netbeans.lib.profiler.global.TransactionalSupport;
0048:        import org.netbeans.lib.profiler.server.system.*;
0049:        import org.netbeans.lib.profiler.wireprotocol.*;
0050:        import java.io.File;
0051:        import java.io.FileOutputStream;
0052:        import java.io.IOException;
0053:        import java.lang.reflect.Method;
0054:        import java.text.MessageFormat;
0055:        import java.util.ResourceBundle;
0056:        import java.util.WeakHashMap;
0057:
0058:        /**
0059:         * Main interface to the target VM side introspection functionality.
0060:         *
0061:         * @author Tomas Hurka
0062:         * @author Misha Dmitriev
0063:         * @author Adrian Mos
0064:         * @author Ian Formanek
0065:         */
0066:        public class ProfilerInterface implements  CommonConstants {
0067:            //~ Inner Classes ------------------------------------------------------------------------------------------------------------
0068:
0069:            private static class HFIRIThread extends Thread {
0070:                //~ Constructors ---------------------------------------------------------------------------------------------------------
0071:
0072:                HFIRIThread() {
0073:                    ThreadInfo.addProfilerServerThread(this );
0074:                    this .setName(PROFILER_SPECIAL_EXEC_THREAD_NAME + " 1"); // NOI18N
0075:                    setDaemon(true);
0076:                }
0077:
0078:                //~ Methods --------------------------------------------------------------------------------------------------------------
0079:
0080:                public void run() {
0081:                    RootClassLoadedCommand cmd = new RootClassLoadedCommand(
0082:                            new String[] { "*FAKE_CLASS_1*", "*FAKE_CLASS_2*" },
0083:                            new int[] { 0, 0 }, null, 2, new int[] { -1 }, ""); // NOI18N
0084:                    profilerServer.sendComplexCmdToClient(cmd);
0085:
0086:                    InstrumentMethodGroupResponse imgr = (InstrumentMethodGroupResponse) profilerServer
0087:                            .getLastResponse();
0088:                    ThreadInfo.removeProfilerServerThread(this );
0089:                }
0090:            }
0091:
0092:            private static class InitiateInstThread extends Thread {
0093:                //~ Instance fields ------------------------------------------------------------------------------------------------------
0094:
0095:                private InitiateInstrumentationCommand cmd;
0096:                private boolean targetAppRunning;
0097:
0098:                //~ Constructors ---------------------------------------------------------------------------------------------------------
0099:
0100:                InitiateInstThread(InitiateInstrumentationCommand cmd,
0101:                        boolean targetAppRunning) {
0102:                    ThreadInfo.addProfilerServerThread(this );
0103:                    this .setName(PROFILER_SPECIAL_EXEC_THREAD_NAME + " 2"); // NOI18N
0104:                    this .cmd = cmd;
0105:                    this .targetAppRunning = targetAppRunning;
0106:                }
0107:
0108:                //~ Methods --------------------------------------------------------------------------------------------------------------
0109:
0110:                public void run() {
0111:                    // We take a serialClientOperationsLock, then turn class load hook on, to prevent possible class loads, that
0112:                    // will neither get into loadedClassesArray nor be intercepted properly and reported to client by classLoadHook.
0113:                    // In other words, classes that are loaded before this point get into loadedClassesArray; classes loaded
0114:                    // afterwards should be individually intercepted and reported to client.
0115:                    serialClientOperationsLock.beginTrans(true);
0116:
0117:                    try {
0118:                        initInstrumentationThread = Thread.currentThread();
0119:
0120:                        int instrType = cmd.getInstrType();
0121:                        setCurrentInstrType(instrType);
0122:                        rootClassNames = cmd.getRootClassNames();
0123:                        status.startProfilingPointsActive = cmd
0124:                                .isStartProfilingPointsActive();
0125:
0126:                        status.profilingPointIDs = cmd.getProfilingPointIDs();
0127:
0128:                        String[] handlers = cmd.getProfilingPointHandlers();
0129:                        String[] infos = cmd.getProfilingPointInfos();
0130:                        status.profilingPointHandlers = ProfilingPointServerHandler
0131:                                .getInstances(handlers, infos);
0132:                        computeRootWildcard();
0133:                        rootClassLoaded = false;
0134:
0135:                        // the following code is needed to avoid issue 59660: Remote profiling can cause the agent to hang if CPU
0136:                        // or Code Fragment profiling is used
0137:                        // see http://profiler.netbeans.org/issues/show_bug.cgi?id=59660
0138:                        // and http://profiler.netbeans.org/issues/show_bug.cgi?id=61968
0139:                        try {
0140:                            Class.forName("java.util.LinkedHashMap"); // NOI18N
0141:                            Class
0142:                                    .forName("java.util.LinkedHashMap$LinkedHashIterator"); // NOI18N
0143:                            Class
0144:                                    .forName("java.util.LinkedHashMap$KeyIterator"); // NOI18N
0145:                            // for take heap dump
0146:
0147:                            Class
0148:                                    .forName("java.lang.reflect.InvocationTargetException"); // NOI18N
0149:                            Class.forName("java.lang.InterruptedException");
0150:                        } catch (ClassNotFoundException e) {
0151:                            e.printStackTrace(System.err);
0152:                        }
0153:
0154:                        // The following code is needed to enforce native method bind for Thread.sleep before instrumentation, so
0155:                        // that the NativeMethodBind it can be disabled as first thing in instrumentation
0156:                        // this is needed as a workaround for JDK bug:
0157:                        // CR 6318850 Updated P3 hotspot/jvmti RedefineClasses() and NativeMethodBind event crash
0158:                        try {
0159:                            Thread.sleep(1);
0160:                        } catch (InterruptedException e) {
0161:                        } // ignore
0162:
0163:                        synchronized (this ) {
0164:                            try {
0165:                                wait(1);
0166:                            } catch (InterruptedException e) {
0167:                            } // ignore
0168:                        }
0169:
0170:                        Classes.enableClassLoadHook();
0171:
0172:                        boolean instrSpawnedThreads = cmd
0173:                                .getInstrSpawnedThreads();
0174:
0175:                        if (targetAppRunning
0176:                                || hasAnyCoreClassNames(cmd.getRootClassNames())
0177:                                || instrSpawnedThreads
0178:                                || (instrType == INSTR_OBJECT_ALLOCATIONS)
0179:                                || (instrType == INSTR_OBJECT_LIVENESS)) {
0180:                            getLoadedClasses(); // Init loadedClassesArray
0181:
0182:                            boolean loadedRootClassesExist = false;
0183:
0184:                            switch (instrType) {
0185:                            case INSTR_RECURSIVE_FULL:
0186:                            case INSTR_RECURSIVE_SAMPLED:
0187:                                // This will look into loadedClassesArray to check if there are any root classes already loaded
0188:                                loadedRootClassesExist = instrSpawnedThreads ? true
0189:                                        : checkForLoadedRootClasses();
0190:
0191:                                break;
0192:                            case INSTR_CODE_REGION:
0193:                                loadedRootClassesExist = checkForLoadedRootClasses();
0194:
0195:                                break;
0196:                            case INSTR_OBJECT_ALLOCATIONS:
0197:                            case INSTR_OBJECT_LIVENESS:
0198:                                loadedRootClassesExist = true;
0199:
0200:                                break;
0201:                            }
0202:
0203:                            if (loadedRootClassesExist) { // Root class(es) has been loaded or none is needed - start
0204:                                // instrumentation-related operations right away
0205:                                sendRootClassLoadedCommand(false);
0206:
0207:                                if (!getAndInstrumentClasses(true)) {
0208:                                    disableProfilerHooks();
0209:                                }
0210:
0211:                                rootClassLoaded = true; // See the comment in classLoadHook why it's worth setting rootClassLoaded
0212:                                // to true after the first instrumentation, not before
0213:                            }
0214:                        }
0215:
0216:                        initInstrumentationThread = null;
0217:                    } finally {
0218:                        serialClientOperationsLock.endTrans();
0219:                    }
0220:
0221:                    ThreadInfo.removeProfilerServerThread(this );
0222:                }
0223:
0224:                private static void computeRootWildcard() {
0225:                    rootClassNameWildcard = new boolean[rootClassNames.length];
0226:
0227:                    for (int i = 0; i < rootClassNames.length; i++) {
0228:                        int nameLen = rootClassNames[i].length();
0229:                        rootClassNameWildcard[i] = (nameLen == 0) // default package wildcard
0230:                                || (rootClassNames[i].charAt(nameLen - 1) == '.'); // ends with "." // NOI18N
0231:                    }
0232:                }
0233:            }
0234:
0235:            //~ Static fields/initializers -----------------------------------------------------------------------------------------------
0236:
0237:            // -----
0238:            // I18N String constants
0239:            // !!! Warning - do not use ResourceBundle.getBundle here, won't work in context of direct/dynamic attach !!!
0240:            // Default EN messages initialized here, will be replaced by localized messages in static initializer
0241:            private static String INTERNAL_ERROR_MSG = "Internal error:\nExpected InstrumentMethodGroupResponse, got response of class {0},\nvalue = {1}\nAll instrumentation will be removed"; // NOI18N
0242:            private static String UNEXPECTED_EXCEPTION_MSG = "Unexpected exception caught when trying to instrument classes.\nOriginal exception:\n{0}\nStack trace:\n\n{1}"; // NOI18N
0243:            private static String INSTRUMENTATION_SUCCESSFUL_MSG = "Deferred instrumentation performed successfully"; // NOI18N
0244:            // -----
0245:
0246:            static {
0247:                ResourceBundle messages = ProfilerServer
0248:                        .getProfilerServerResourceBundle();
0249:
0250:                if (messages != null) {
0251:                    INTERNAL_ERROR_MSG = messages
0252:                            .getString("ProfilerInterface_InternalErrorMsg"); // NOI18N
0253:                    UNEXPECTED_EXCEPTION_MSG = messages
0254:                            .getString("ProfilerInterface_UnexpectedExceptionMsg"); // NOI18N
0255:                    INSTRUMENTATION_SUCCESSFUL_MSG = messages
0256:                            .getString("ProfilerInterface_InstrumentationSuccessfulMsg"); // NOI18N
0257:                }
0258:            }
0259:
0260:            // TODO [release]: change value to FALSE to remove the print code below entirely by compiler
0261:            private static final boolean DEBUG = System
0262:                    .getProperty("org.netbeans.lib.profiler.server.ProfilerInterface.classLoadHook") != null; // NOI18N
0263:
0264:            // The lock used to serialize requests from server to client. May be used outside this class.
0265:            public static TransactionalSupport serialClientOperationsLock = new TransactionalSupport();
0266:            private static ProfilerServer profilerServer;
0267:            private static ProfilingSessionStatus status;
0268:            private static EventBufferManager evBufManager;
0269:            private static Class[] loadedClassesArray; // Temporary array, used to send all loaded class names to client
0270:            // on instrumentation initiation.
0271:            private static int[] loadedClassesLoaders; // Ditto, for loaders
0272:            private static WeakHashMap reflectMethods; // Cache of methods called using reflection
0273:            private static boolean targetAppSuspended = false;
0274:            private static boolean instrumentReflection = false;
0275:            private static int[] packedArrayOffsets;
0276:            private static int nSystemThreads;
0277:            private static Thread initInstrumentationThread;
0278:            private static String[] rootClassNames;
0279:            private static boolean[] rootClassNameWildcard;
0280:
0281:            // For statistics
0282:            static int nClassLoads;
0283:
0284:            // For statistics
0285:            static int nFirstMethodInvocations;
0286:
0287:            // For statistics
0288:            static int nEmptyInstrMethodGroupResponses;
0289:            static int nNonEmptyInstrMethodGroupResponses;
0290:            static int nSingleMethodInstrMethodGroupResponses;
0291:            static int nTotalInstrMethods;
0292:            static long totalHotswappingTime;
0293:            static long minHotswappingTime = 10000000000L;
0294:            static long maxHotswappingTime;
0295:            static long clientInstrStartTime;
0296:            static long clientInstrTime;
0297:            static long clientDataProcStartTime;
0298:            static long clientDataProcTime;
0299:
0300:            //----------------------------------------- Private implementation --------------------------------------------------
0301:            private static boolean rootClassLoaded; // has root class been loaded?
0302:
0303:            // The following variable addresses the issue of classLoadHook called for a class, that is already registered as
0304:            // loaded, (through getAllLoadedClasses) but is actually initialized only when extendConstantPool() is called on it.
0305:            // Initialization would cause classLoadHook invocation on this class, and subsequent "second class load event"
0306:            // messages in client (which is just confusing). But this may also cause more subtle deadlock bug due to
0307:            // classLoadHook() trying to record adjustTime event, while serialClientOperationsLock is held by an outer invocation
0308:            // of classLoadHook() or methodInvokedFirstTime(). To avoid all these problems we use this simple way to avoid
0309:            // unnecessary classLoadHook() invocations.
0310:            private static volatile Thread instrumentMethodGroupCallThread;
0311:
0312:            //~ Methods ------------------------------------------------------------------------------------------------------------------
0313:
0314:            public static CodeRegionCPUResultsResponse getCodeRegionCPUResults() {
0315:                CodeRegionCPUResultsResponse resp = new CodeRegionCPUResultsResponse(
0316:                        ProfilerRuntimeCPUCodeRegion.getProfilingResults());
0317:
0318:                return resp;
0319:            }
0320:
0321:            public static void setCurrentInstrType(int type) {
0322:                boolean isMemoryProfiling = (type == INSTR_OBJECT_ALLOCATIONS)
0323:                        || (type == INSTR_OBJECT_LIVENESS);
0324:
0325:                status.currentInstrType = type;
0326:                Classes.setVMObjectAllocEnabled(isMemoryProfiling);
0327:            }
0328:
0329:            public static int getCurrentInstrType() {
0330:                return status.currentInstrType;
0331:            }
0332:
0333:            public static ThreadLivenessStatusResponse getCurrentThreadLivenessStatus() {
0334:                ThreadLivenessStatusResponse resp = new ThreadLivenessStatusResponse(
0335:                        ThreadInfo.getCurrentLivenessStatus());
0336:
0337:                return resp;
0338:            }
0339:
0340:            public static void setInstrumentReflection(boolean v) {
0341:                if (status.targetAppRunning) {
0342:                    ProfilerRuntimeCPU
0343:                            .setJavaLangReflectMethodInvokeInterceptEnabled(v);
0344:                } else {
0345:                    instrumentReflection = v;
0346:                }
0347:            }
0348:
0349:            public static MethodNamesResponse getMethodNamesForJMethodIds(
0350:                    int[] methodIds) {
0351:                int nMethods = methodIds.length;
0352:                int len = nMethods * 3;
0353:                packedArrayOffsets = new int[len];
0354:
0355:                System.gc(); // To avoid as much as possible a GC that happens concurrently while the call below is in progress
0356:                // (though I am not sure now it's a real problem)
0357:
0358:                byte[] packedData = Stacks.getMethodNamesForJMethodIds(
0359:                        nMethods, methodIds, packedArrayOffsets);
0360:                MethodNamesResponse resp = new MethodNamesResponse(packedData,
0361:                        packedArrayOffsets);
0362:
0363:                return resp;
0364:            }
0365:
0366:            public static int getNPrerecordedSystemThreads() {
0367:                return nSystemThreads;
0368:            }
0369:
0370:            public static ObjectAllocationResultsResponse getObjectAllocationResults() {
0371:                status.beginTrans(false);
0372:
0373:                try {
0374:                    ObjectAllocationResultsResponse resp = new ObjectAllocationResultsResponse(
0375:                            status.getAllocatedInstancesCount(), status
0376:                                    .getNInstrClasses());
0377:
0378:                    return resp;
0379:                } finally {
0380:                    status.endTrans();
0381:                }
0382:            }
0383:
0384:            public static void setProfilerServer(ProfilerServer server) {
0385:                profilerServer = server;
0386:            }
0387:
0388:            /**
0389:             * This method cleans up the data structures managed by this class, but not by various ProfilerRuntimeXXX classes.
0390:             * The latter are cleaned up separately, by the following deactivateInjectedCode() method.
0391:             */
0392:            public static void clearProfilerDataStructures() {
0393:                //loadedClassesArray = null;
0394:                //loadedClassesCPLengths = null;
0395:                //loadedClassesLoaders = null;
0396:                //ClassLoaderManager.reset();
0397:                //packedArrayOffsets = null;
0398:                reflectMethods = null;
0399:
0400:                //evBufManager.freeBufferFile();
0401:            }
0402:
0403:            public static boolean cpuResultsExist() {
0404:                return ProfilerRuntime.profiledTargetAppThreadsExist();
0405:            }
0406:
0407:            /**
0408:             * Deactivate the injected code for the current instrumentation type, and clean up all the supporting data structures
0409:             * maintained by the corresponding ProfilerRuntimeXXX class.
0410:             */
0411:            public static void deactivateInjectedCode() {
0412:                int instrType = getCurrentInstrType();
0413:
0414:                if (instrType == INSTR_NONE) {
0415:                    return;
0416:                }
0417:
0418:                disableProfilerHooks();
0419:
0420:                switch (instrType) {
0421:                case INSTR_CODE_REGION:
0422:                    ProfilerRuntimeCPUCodeRegion.enableProfiling(false);
0423:
0424:                    if (rootClassNames != null) {
0425:                        rootClassNames = null;
0426:                    }
0427:
0428:                    break;
0429:                case INSTR_RECURSIVE_FULL:
0430:                    ProfilerRuntimeCPUFullInstr.enableProfiling(false);
0431:                    ProfilerRuntimeCPU.setTimerTypes(false, false); // Mainly to clean up microstate accounting on Solaris
0432:
0433:                    break;
0434:                case INSTR_RECURSIVE_SAMPLED:
0435:                    ProfilerRuntimeCPUSampledInstr.enableProfiling(false);
0436:                    ProfilerRuntimeCPU.setTimerTypes(false, false);
0437:
0438:                    break;
0439:                case INSTR_OBJECT_ALLOCATIONS:
0440:                    ProfilerRuntimeObjAlloc.enableProfiling(false);
0441:
0442:                    break;
0443:                case INSTR_OBJECT_LIVENESS:
0444:                    ProfilerRuntimeObjLiveness.enableProfiling(false);
0445:
0446:                    break;
0447:                }
0448:
0449:                status.resetInstrClassAndMethodInfo();
0450:                setCurrentInstrType(INSTR_NONE);
0451:            }
0452:
0453:            public static void disableProfilerHooks() {
0454:                Classes.disableClassLoadHook();
0455:                ProfilerRuntimeCPU
0456:                        .setJavaLangReflectMethodInvokeInterceptEnabled(false);
0457:                ClassLoaderManager.setNotifyToolAboutUnloadedClasses(false);
0458:            }
0459:
0460:            public static void dumpExistingResults(boolean live) {
0461:                if (!live && (getCurrentInstrType() == INSTR_OBJECT_LIVENESS)
0462:                        && ProfilerRuntimeObjLiveness.getRunGCOnGetResults()) {
0463:                    GC.runGC();
0464:
0465:                    try {
0466:                        Thread.sleep(500);
0467:
0468:                        // Give WeakReference collector thread a chance to register some (hopefully most of) object GCs
0469:                    } catch (Exception ex) {
0470:                    }
0471:
0472:                    ;
0473:                }
0474:
0475:                ProfilerRuntime.dumpEventBuffer();
0476:            }
0477:
0478:            /**
0479:             * This method initializes the internal data structures, and also records the profiler's own thread(s), so that
0480:             * they are not affected by our suspend/resume operations. If we run in the normal mode, i.e. the target JVM was
0481:             * started by the client, specialThread is the current thread, which will then become the target app main thread.
0482:             * It should be excluded from the list of the profiler's own threads. If we run in the attached mode, specialThread
0483:             * is the only thread that we can reliably characterize as the profiler's own.
0484:             */
0485:            public static void initProfilerInterface(
0486:                    ProfilingSessionStatus status, Thread specialThread) {
0487:                Timers.initialize();
0488:                Classes.initialize();
0489:                GC.initialize();
0490:                Stacks.initialize();
0491:                Threads.initialize();
0492:                HeapDump
0493:                        .initialize(Platform.getJDKVersionNumber() == Platform.JDK_15);
0494:                ClassLoaderManager.initialize(profilerServer);
0495:                ClassLoaderManager
0496:                        .addLoader(ClassLoader.getSystemClassLoader());
0497:                reflectMethods = new WeakHashMap();
0498:
0499:                evBufManager = new EventBufferManager(profilerServer);
0500:                ProfilerInterface.status = status;
0501:
0502:                // Check that all profiler's own threads are running, and then record them internally, so that target app threads
0503:                // are accounted for properly.
0504:                while (!Monitors.monitorThreadsStarted()) {
0505:                    try {
0506:                        Thread.sleep(50);
0507:                    } catch (Exception ex) {
0508:                    }
0509:
0510:                    ;
0511:                }
0512:
0513:                if (status.runningInAttachedMode) {
0514:                    Threads.recordProfilerOwnThreads(false, specialThread);
0515:                    nSystemThreads = -1; // Indicates that we really don't know how many of these threads
0516:                    // are VM-own, or system, threads
0517:                } else {
0518:                    nSystemThreads = Threads.recordProfilerOwnThreads(true,
0519:                            specialThread);
0520:                }
0521:
0522:                ProfilerRuntime
0523:                        .init(new ProfilerRuntime.ExternalActionsHandler() {
0524:                            public void handleFirstTimeMethodInvoke(int methodId) {
0525:                                firstTimeMethodInvokeHook(methodId);
0526:                            }
0527:
0528:                            public void handleReflectiveInvoke(Method method) {
0529:                                reflectiveMethodInvokeHook(method);
0530:                            }
0531:
0532:                            public int handleFirstTimeVMObjectAlloc(
0533:                                    String className, int classLoaderId) {
0534:                                return firstTimeVMObjectAlloc(className,
0535:                                        classLoaderId);
0536:                            }
0537:
0538:                            public void handleEventBufferDump(
0539:                                    byte[] eventBuffer, int startPos,
0540:                                    int curPtrPos) {
0541:                                serialClientOperationsLock.beginTrans(true);
0542:
0543:                                try { // So that this event does not interfere with class
0544:                                    // loads / method invocations
0545:                                    clientDataProcStartTime = Timers
0546:                                            .getCurrentTimeInCounts();
0547:                                    evBufManager.eventBufferDumpHook(
0548:                                            eventBuffer, startPos, curPtrPos);
0549:                                    clientDataProcTime += (Timers
0550:                                            .getCurrentTimeInCounts() - clientDataProcStartTime);
0551:                                } finally {
0552:                                    serialClientOperationsLock.endTrans();
0553:                                }
0554:                            }
0555:                        });
0556:            }
0557:
0558:            public static void initiateInstrumentation(
0559:                    final InitiateInstrumentationCommand cmd,
0560:                    final boolean targetAppRunning) throws Exception {
0561:                int instrType = cmd.getInstrType();
0562:                String instrClassName = cmd.getRootClassName();
0563:
0564:                if (instrClassName.equals("*FAKE_CLASS_FOR_INTERNAL_TEST*")) { // NOI18N
0565:                    handleFakeInitRecursiveInstrumentationCommand(); // To initialize certain internal classes, see comments
0566:                    // in handleFake... method
0567:
0568:                    return;
0569:                }
0570:
0571:                switch (instrType) {
0572:                case INSTR_RECURSIVE_FULL:
0573:                case INSTR_RECURSIVE_SAMPLED:
0574:                case INSTR_OBJECT_ALLOCATIONS:
0575:                case INSTR_OBJECT_LIVENESS:
0576:                    evBufManager.openBufferFile(EVENT_BUFFER_SIZE_IN_BYTES);
0577:                    ProfilerRuntime
0578:                            .createEventBuffer(EVENT_BUFFER_SIZE_IN_BYTES);
0579:                    status.resetInstrClassAndMethodInfo();
0580:
0581:                    if ((instrType == INSTR_OBJECT_ALLOCATIONS)
0582:                            || (instrType == INSTR_OBJECT_LIVENESS)) {
0583:                        ClassLoaderManager
0584:                                .setNotifyToolAboutUnloadedClasses(true);
0585:                    } else {
0586:                        ClassLoaderManager
0587:                                .setNotifyToolAboutUnloadedClasses(false);
0588:                    }
0589:
0590:                    break;
0591:                case INSTR_CODE_REGION:
0592:                    ProfilerRuntimeCPUCodeRegion.resetProfilerCollectors();
0593:
0594:                    break;
0595:                }
0596:
0597:                // We have to perform the following operations in a separate thread, since they may involve further dialog with
0598:                // the tool (client), whereas this thread has to return quickly to send the "OK" response to the tool.
0599:                new InitiateInstThread(cmd, targetAppRunning).start();
0600:            }
0601:
0602:            public static void instrumentMethods(
0603:                    InstrumentMethodGroupCommand cmd) throws Exception {
0604:                if (!cmd.isEmpty()) {
0605:                    try {
0606:                        instrumentMethodGroupNow(cmd.getBase());
0607:                    } catch (Exception ex) {
0608:                        deactivateInjectedCode();
0609:                        setCurrentInstrType(INSTR_NONE);
0610:                        throw ex;
0611:                    }
0612:                }
0613:
0614:                setCurrentInstrType(cmd.getInstrType());
0615:            }
0616:
0617:            public static void resetProfilerCollectors() {
0618:                ProfilerRuntime.resetProfilerCollectors(getCurrentInstrType());
0619:                reflectMethods = new WeakHashMap(); // So that methods that are possibly holding unreachable classes are
0620:                // removed and classes allowed to be GCed
0621:            }
0622:
0623:            public static void resumeTargetApp() {
0624:                if (getCurrentInstrType() == INSTR_RECURSIVE_FULL) {
0625:                    ProfilerRuntimeCPUFullInstr.resumeActiveTimers();
0626:                }
0627:
0628:                Threads.resumeTargetAppThreads(null);
0629:                targetAppSuspended = false;
0630:            }
0631:
0632:            public static void suspendTargetApp() {
0633:                Threads.suspendTargetAppThreads(null);
0634:
0635:                if (getCurrentInstrType() == INSTR_RECURSIVE_FULL) {
0636:                    ProfilerRuntimeCPUFullInstr.suspendActiveTimers();
0637:                }
0638:
0639:                targetAppSuspended = true;
0640:            }
0641:
0642:            private static boolean getAndInstrumentClasses(
0643:                    boolean rootClassInstrumentation) {
0644:                Response r = profilerServer.getLastResponse();
0645:
0646:                if (!(r instanceof  InstrumentMethodGroupResponse)) { // This is an internal error which, hopefully, has been fixed.
0647:
0648:                    String msg = MessageFormat.format(INTERNAL_ERROR_MSG,
0649:                            new Object[] { r.getClass(), r });
0650:                    deactivateInjectedCode();
0651:                    profilerServer
0652:                            .sendComplexCmdToClient(new AsyncMessageCommand(
0653:                                    false, msg));
0654:
0655:                    return false;
0656:                }
0657:
0658:                InstrumentMethodGroupResponse imgr = (InstrumentMethodGroupResponse) r;
0659:                clientInstrTime += (Timers.getCurrentTimeInCounts() - clientInstrStartTime);
0660:
0661:                if (!imgr.isOK()) {
0662:                    return false;
0663:                }
0664:
0665:                if (imgr.isEmpty()) {
0666:                    nEmptyInstrMethodGroupResponses++;
0667:
0668:                    // Don't return immediately, because may have rootClassInstrumentation == true (see above)
0669:                } else {
0670:                    // Do the following update before instrumentation, since if we do this after it, chances are some instrumented
0671:                    // method in another thread enters e.g. methodEntry() and hits the not-yet-updated invocation array before
0672:                    // updating has been completed.
0673:                    updateInstrClassAndMethodNames(imgr.getBase(), true);
0674:
0675:                    if (rootClassInstrumentation
0676:                            && (getCurrentInstrType() == INSTR_OBJECT_LIVENESS)) {
0677:                        // Create a ThreadInfo for the current thread immediately to avoid recursion with trace object allocation calls
0678:                        ThreadInfo.getThreadInfo();
0679:                    }
0680:
0681:                    try {
0682:                        instrumentMethodGroupNow(imgr.getBase());
0683:                    } catch (Exception ex) {
0684:                        //deactivateInjectedCode();   // It looks like it often makes more sense to proceed and get at least some info
0685:                        profilerServer
0686:                                .sendComplexCmdToClient(new AsyncMessageCommand(
0687:                                        false, ex.getMessage()));
0688:
0689:                        return true; // Used to be "return false" (but see comment above).
0690:                    }
0691:                }
0692:
0693:                if (rootClassInstrumentation) {
0694:                    switch (getCurrentInstrType()) {
0695:                    case INSTR_RECURSIVE_FULL:
0696:
0697:                        if (instrumentReflection) {
0698:                            ProfilerRuntimeCPU
0699:                                    .setJavaLangReflectMethodInvokeInterceptEnabled(true);
0700:                        }
0701:
0702:                        ProfilerRuntimeCPUFullInstr.enableProfiling(true);
0703:
0704:                        break;
0705:                    case INSTR_RECURSIVE_SAMPLED:
0706:
0707:                        if (instrumentReflection) {
0708:                            ProfilerRuntimeCPU
0709:                                    .setJavaLangReflectMethodInvokeInterceptEnabled(true);
0710:                        }
0711:
0712:                        ProfilerRuntimeCPUSampledInstr.enableProfiling(true);
0713:
0714:                        break;
0715:                    case INSTR_CODE_REGION:
0716:                        ProfilerRuntimeCPUCodeRegion.enableProfiling(true);
0717:
0718:                        break;
0719:                    case INSTR_OBJECT_ALLOCATIONS:
0720:                        ProfilerRuntimeObjAlloc.enableProfiling(true);
0721:
0722:                        break;
0723:                    case INSTR_OBJECT_LIVENESS:
0724:                        ProfilerRuntimeObjLiveness.enableProfiling(true);
0725:
0726:                        break;
0727:                    }
0728:                }
0729:
0730:                return true;
0731:            }
0732:
0733:            private static boolean isCoreClassName(String name) {
0734:                name = name.replace('.', '/'); // NOI18N
0735:
0736:                return (name.startsWith("java/") || name.startsWith("sun/") || name
0737:                        .startsWith("javax/")); // NOI18N
0738:            }
0739:
0740:            private static void getLoadedClasses() {
0741:                Class[] nonSystemClasses;
0742:                int nonSystemIndex = 0;
0743:
0744:                loadedClassesArray = Classes.getAllLoadedClasses();
0745:                nonSystemClasses = new Class[loadedClassesArray.length]; // classes loaded by classloaders other that bootstrap and system
0746:                loadedClassesLoaders = new int[loadedClassesArray.length];
0747:
0748:                for (int i = 0; i < loadedClassesArray.length; i++) {
0749:                    Class clazz = loadedClassesArray[i];
0750:                    loadedClassesLoaders[i] = ClassLoaderManager
0751:                            .registerLoader(clazz);
0752:
0753:                    if (loadedClassesLoaders[i] > 0) { // bootstrap classloader has index -1 and system classloader has index 0
0754:                        nonSystemClasses[nonSystemIndex++] = clazz;
0755:                    }
0756:                }
0757:
0758:                if (nonSystemIndex > 0) {
0759:                    Classes
0760:                            .cacheLoadedClasses(nonSystemClasses,
0761:                                    nonSystemIndex);
0762:                }
0763:            }
0764:
0765:            private static boolean isRootClass(String className) {
0766:                for (int i = 0; i < rootClassNames.length; i++) {
0767:                    String rootName = rootClassNames[i];
0768:
0769:                    if (rootClassNameWildcard[i]) {
0770:                        if (className.startsWith(rootName)) {
0771:                            if (className.indexOf('.', rootName.length()) == -1) { // not a subpackage
0772:
0773:                                return true;
0774:                            }
0775:                        }
0776:                    } else if (rootName.equals(className)) {
0777:                        return true;
0778:                    }
0779:                }
0780:
0781:                return false;
0782:            }
0783:
0784:            private static void appendTypeName(StringBuffer sb, Class type) {
0785:                if (type.isArray()) {
0786:                    do {
0787:                        sb.append('['); // NOI18N
0788:                        type = type.getComponentType();
0789:                    } while (type.isArray());
0790:                }
0791:
0792:                if (type == Integer.TYPE) {
0793:                    sb.append('I'); // NOI18N
0794:                } else if (type == Boolean.TYPE) {
0795:                    sb.append('Z'); // NOI18N
0796:                } else if (type == Byte.TYPE) {
0797:                    sb.append('B'); // NOI18N
0798:                } else if (type == Character.TYPE) {
0799:                    sb.append('C'); // NOI18N
0800:                } else if (type == Long.TYPE) {
0801:                    sb.append('J'); // NOI18N
0802:                } else if (type == Float.TYPE) {
0803:                    sb.append('F'); // NOI18N
0804:                } else if (type == Double.TYPE) {
0805:                    sb.append('D'); // NOI18N
0806:                } else if (type == Void.TYPE) {
0807:                    sb.append('V'); // NOI18N
0808:                } else {
0809:                    sb.append('L'); // NOI18N
0810:                    sb.append(type.getName().replace('.', '/')); // NOI18N
0811:                    sb.append(';'); // NOI18N
0812:                }
0813:            }
0814:
0815:            private static boolean checkForLoadedRootClasses() {
0816:                for (int i = 0; i < loadedClassesArray.length; i++) {
0817:                    if (isRootClass(loadedClassesArray[i].getName())) {
0818:                        return true;
0819:                    }
0820:                }
0821:
0822:                return false;
0823:            }
0824:
0825:            /** Called on CLASS_PREPARE JVMTI event */
0826:            private static void classLoadHook(Class clazz) {
0827:                ThreadInfo threadInfo = ThreadInfo.getThreadInfo();
0828:
0829:                threadInfo.inProfilingRuntimeMethod++;
0830:
0831:                try {
0832:                    String className = clazz.getName();
0833:
0834:                    if (instrumentMethodGroupCallThread == Thread
0835:                            .currentThread()
0836:                            || internalClassName(className)) { // See comment at inInstrumentMethodGroupCall
0837:                        ClassLoaderManager.registerLoader(clazz); // Still register the loader, for reasons related with
0838:                        // management of jmethodIds
0839:
0840:                        return;
0841:                    }
0842:
0843:                    Thread currentThread = Thread.currentThread();
0844:
0845:                    if (PROFILER_SERVER_THREAD_NAME.equals(currentThread
0846:                            .getName())) {
0847:                        System.err.println(ENGINE_WARNING + "class "
0848:                                + className + " loaded by "
0849:                                + PROFILER_SERVER_THREAD_NAME); // NOI18N
0850:
0851:                        return;
0852:                    }
0853:
0854:                    if ((initInstrumentationThread != null)
0855:                            && (currentThread == initInstrumentationThread)) {
0856:                        // Looks like on rare occasions we can get this problem - class load hook called when it shouldn't.
0857:                        // If we are already here, we can't (easily at least) fix this problem, but at least we can warn the user.
0858:                        System.err
0859:                                .println(ENGINE_WARNING
0860:                                        + "class load hook invoked at inappropriate time for " // NOI18N
0861:                                        + className + ", loader = "
0862:                                        + clazz.getClassLoader()); // NOI18N
0863:                        System.err
0864:                                .println("*** This class will not be instrumented unless you re-run the instrumentation command"); // NOI18N
0865:                        System.err.println(PLEASE_REPORT_PROBLEM);
0866:                        System.err
0867:                                .println("=============================== Stack trace ====================="); // NOI18N
0868:                        Thread.dumpStack();
0869:                        System.err
0870:                                .println("=============================== End stack trace ================="); // NOI18N
0871:
0872:                        return;
0873:                    }
0874:
0875:                    //System.out.println("+++ Class load hook invoked for " + className + ", loader = " + clazz.getClassLoader());
0876:                    int classLoaderId = ClassLoaderManager
0877:                            .registerLoader(clazz);
0878:                    boolean resumeTimer = false;
0879:
0880:                    if (DEBUG) {
0881:                        System.err
0882:                                .println("ProfilerInterface.classLoadHook.DEBUG: "
0883:                                        + className
0884:                                        + ", classLoaderId: "
0885:                                        + classLoaderId); // NOI18N
0886:                    }
0887:
0888:                    serialClientOperationsLock.beginTrans(true);
0889:
0890:                    try {
0891:                        boolean rootInstrumented = false;
0892:                        String excMessage = null;
0893:                        int instrType = getCurrentInstrType();
0894:
0895:                        if (instrType == INSTR_NONE) {
0896:                            return; // Instrumentation was turned off in the mean time
0897:                        }
0898:
0899:                        // bugfix for issue http://profiler.netbeans.org/issues/show_bug.cgi?id=65968
0900:                        boolean resumeProfiling = false;
0901:
0902:                        if (ThreadInfo.profilingSuspended()) {
0903:                            ThreadInfo.suspendProfiling();
0904:                            resumeProfiling = true;
0905:                        }
0906:
0907:                        try {
0908:                            if (rootClassLoaded) { // if yes, it means instrumentation has been started
0909:                                // [ian] why the following if???
0910:
0911:                                if ((instrType != INSTR_RECURSIVE_FULL)
0912:                                        && (instrType != INSTR_RECURSIVE_SAMPLED)
0913:                                        && (instrType != INSTR_OBJECT_ALLOCATIONS)
0914:                                        && (instrType != INSTR_OBJECT_LIVENESS)) {
0915:                                    if (!((instrType == INSTR_CODE_REGION) && className
0916:                                            .equals(rootClassNames[ProfilingSessionStatus.CODE_REGION_CLASS_IDX]))) {
0917:                                        return; // Nothing to do
0918:                                    }
0919:                                }
0920:
0921:                                ThreadInfo ti = null;
0922:
0923:                                if ((instrType == INSTR_RECURSIVE_FULL)
0924:                                        || (instrType == INSTR_RECURSIVE_SAMPLED)) {
0925:                                    nClassLoads++;
0926:                                    ti = ProfilerRuntimeCPU
0927:                                            .suspendCurrentThreadTimer(); // start blackout period
0928:                                    clientInstrStartTime = Timers
0929:                                            .getCurrentTimeInCounts();
0930:                                    // We'll be unable to call resumeCurrentThreadTimer() right here, since here we are holding serialClientOperationsLock.
0931:                                    // The same lock is acquired when we dump the event buffer. So if here we call resumeTimer(), which calls writeEvent(),
0932:                                    // we can get into a deadlock if some other thread at this time is dumping the event buffer and tries to acquire that lock.
0933:                                    resumeTimer = true; // resume blackout period at the end
0934:                                }
0935:
0936:                                // Get cached class file bytes if they are available, i.e. if the class is loaded by a custom classloader
0937:                                // If remote profiling is used, get these class file bytes from system classpath
0938:                                // classLoaderId = 0 means that it is a system or bootstrap classloader
0939:                                byte[] classFileBytes = (classLoaderId > 0) ? Classes
0940:                                        .getCachedClassFileBytes(clazz)
0941:                                        : (status.remoteProfiling ? ClassBytesLoader
0942:                                                .getClassFileBytes(className)
0943:                                                : null);
0944:
0945:                                // send request to tool to instrument the bytecode
0946:                                ClassLoadedCommand cmd = new ClassLoadedCommand(
0947:                                        className,
0948:                                        ClassLoaderManager
0949:                                                .getThisAndParentLoaderData(classLoaderId),
0950:                                        classFileBytes, (ti != null) ? ti
0951:                                                .isInCallGraph() : false);
0952:                                profilerServer.sendComplexCmdToClient(cmd);
0953:
0954:                                // read response from tool that should contain the instrumented bytecode, and redefine the methods/classes
0955:                                if (!getAndInstrumentClasses(false)) {
0956:                                    disableProfilerHooks();
0957:
0958:                                    return;
0959:                                }
0960:                            } else {
0961:                                // in total inst scheme for CPU profiling we instrument everything
0962:                                boolean rootWasLoaded = ((instrType == INSTR_RECURSIVE_FULL) || (instrType == INSTR_RECURSIVE_SAMPLED))
0963:                                        && (status.instrScheme == CommonConstants.INSTRSCHEME_TOTAL);
0964:
0965:                                // No root classes have been loaded - check if it's one of them
0966:                                if (!rootWasLoaded && !isRootClass(className)) {
0967:                                    return;
0968:                                }
0969:
0970:                                // This is a root class - proceed with requesting client for instrumented code.
0971:                                nClassLoads++;
0972:                                clientInstrStartTime = Timers
0973:                                        .getCurrentTimeInCounts();
0974:                                sendRootClassLoadedCommand(true);
0975:
0976:                                if (!getAndInstrumentClasses(true)) {
0977:                                    disableProfilerHooks();
0978:
0979:                                    return;
0980:                                }
0981:
0982:                                // Note: it is important to have 'rootClassLoaded = true' here, i.e. *after* (not before) the call to getAndInstrumentClasses().
0983:                                // It looks like some classes returned by getAllLoadedClasses() may be not completely initialized, and thus when we finally
0984:                                // load them properly in instrumentMethodGroup() before intrumenting, they get initialized and classLoadHook is called for each
0985:                                // of them. If rootClassLoaded is true, then for each such class a request is sent to the client, which wonders why it got a
0986:                                // second class load event for the same class. Having rootClassLoaded not set until all such classes are loaded eliminates this
0987:                                // issue. WARNING: may it happen that some really new class is loaded as a side effect of initializing of the classes described
0988:                                // above? If so, it will be effectively lost. Need to try to come up with a test to confirm or prove this worry wrong.
0989:                                rootInstrumented = true;
0990:                                rootClassLoaded = true;
0991:
0992:                                // This is done to avoid counting the time spent in instrumentation etc. upon root class load, but before our app (or actually
0993:                                // data recording) started. That's because we use this internal statistics to calculate/verify the gross run time of the app.
0994:                                ProfilerCalibrator
0995:                                        .resetInternalStatsCollectors();
0996:                            }
0997:
0998:                            if (rootInstrumented || (excMessage != null)) {
0999:                                AsyncMessageCommand cmd = null;
1000:
1001:                                if (excMessage == null) {
1002:                                    cmd = new AsyncMessageCommand(true,
1003:                                            INSTRUMENTATION_SUCCESSFUL_MSG); // NOI18N
1004:                                } else {
1005:                                    cmd = new AsyncMessageCommand(false,
1006:                                            excMessage);
1007:                                }
1008:
1009:                                profilerServer.sendComplexCmdToClient(cmd);
1010:                            }
1011:                        } finally {
1012:                            if (resumeProfiling) {
1013:                                ThreadInfo.resumeProfiling();
1014:                            }
1015:                        }
1016:                    } finally { // end of synchronized(serialClientOperationsLock)
1017:                        serialClientOperationsLock.endTrans();
1018:                    }
1019:
1020:                    if (resumeTimer) {
1021:                        int instrType = getCurrentInstrType();
1022:
1023:                        if ((instrType == INSTR_RECURSIVE_FULL)
1024:                                || (instrType == INSTR_RECURSIVE_SAMPLED)) {
1025:                            ProfilerRuntimeCPU.resumeCurrentThreadTimer();
1026:                        }
1027:                    }
1028:                } finally {
1029:                    threadInfo.inProfilingRuntimeMethod--;
1030:                }
1031:            }
1032:
1033:            private static void firstTimeMethodInvokeHook(int methodId) {
1034:                serialClientOperationsLock.beginTrans(true);
1035:
1036:                try {
1037:                    int instrType = getCurrentInstrType();
1038:
1039:                    if ((instrType != INSTR_RECURSIVE_FULL)
1040:                            && (instrType != INSTR_RECURSIVE_SAMPLED)) {
1041:                        return; // Chances are that instrumentation is already stopped
1042:                    }
1043:
1044:                    clientInstrStartTime = Timers.getCurrentTimeInCounts();
1045:
1046:                    MethodInvokedFirstTimeCommand cmd = new MethodInvokedFirstTimeCommand(
1047:                            methodId);
1048:                    profilerServer.sendComplexCmdToClient(cmd);
1049:
1050:                    if (!getAndInstrumentClasses(false)) {
1051:                        disableProfilerHooks();
1052:
1053:                        return;
1054:                    }
1055:
1056:                    // The following reset is done to avoid counting the time spent in instrumentation before data recording started.
1057:                    if (nFirstMethodInvocations == 0) {
1058:                        ProfilerCalibrator.resetInternalStatsCollectors();
1059:                    }
1060:
1061:                    nFirstMethodInvocations++;
1062:                } finally {
1063:                    serialClientOperationsLock.endTrans();
1064:                }
1065:            }
1066:
1067:            private static int firstTimeVMObjectAlloc(String className,
1068:                    int classLoaderId) {
1069:                if (internalClassName(className)) {
1070:                    return -1;
1071:                }
1072:
1073:                serialClientOperationsLock.beginTrans(true);
1074:
1075:                try {
1076:                    if (classLoaderId > 0) { // neither bootstrap nor system class loader
1077:                        // get defining classloader 
1078:                        classLoaderId = ClassLoaderManager
1079:                                .getDefiningLoaderForClass(className,
1080:                                        classLoaderId);
1081:                    }
1082:
1083:                    GetClassIdCommand cmd = new GetClassIdCommand(className,
1084:                            classLoaderId);
1085:                    profilerServer.sendComplexCmdToClient(cmd);
1086:
1087:                    GetClassIdResponse resp = (GetClassIdResponse) profilerServer
1088:                            .getLastResponse();
1089:
1090:                    if (resp.isOK()) {
1091:                        return resp.getClassId();
1092:                    }
1093:
1094:                    return -1;
1095:                } finally {
1096:                    serialClientOperationsLock.endTrans();
1097:                }
1098:            }
1099:
1100:            private static void handleFakeInitRecursiveInstrumentationCommand() {
1101:                // Send a fake RootClassLoadedCommand to the client and get a reply from it. This is done to force initialization
1102:                // of all classes related to this operation. If this happens later, it can cause deadlock due to classLoadHook called upon
1103:                // loading of some of these classes, when classLoadHook is already locked to "serialize" class load events.
1104:                new HFIRIThread().start();
1105:            }
1106:
1107:            /**
1108:             *  support for multiple roots needed by EJB work
1109:             *  will check each class to see if it is a candidate to be a core class
1110:             */
1111:            private static boolean hasAnyCoreClassNames(String[] classes) {
1112:                if (!(classes.length > 0)) {
1113:                    return false;
1114:                }
1115:
1116:                for (int i = 0; i < classes.length; i++) {
1117:                    if (isCoreClassName(classes[i])) {
1118:                        return true;
1119:                    }
1120:                }
1121:
1122:                return false; //none found...
1123:            }
1124:
1125:            private static void instrumentMethodGroupNow(
1126:                    InstrumentMethodGroupData imgb) throws Exception {
1127:                try {
1128:                    instrumentMethodGroupCallThread = Thread.currentThread();
1129:
1130:                    int res = 0;
1131:                    long time = Timers.getCurrentTimeInCounts();
1132:                    nNonEmptyInstrMethodGroupResponses++;
1133:
1134:                    int nClasses = imgb.getNClasses();
1135:                    String[] instrClassNames = imgb.getMethodClasses();
1136:                    int[] instrClassLoaders = imgb.getClassLoaderIds();
1137:                    int nMethods = imgb.getNMethods();
1138:
1139:                    Class[] clazzes = new Class[nClasses];
1140:                    byte[][] b = imgb.getReplacementClassFileBytes();
1141:                    int k = 0;
1142:
1143:                    for (int i = 0; i < nClasses; i++) {
1144:                        clazzes[k] = ClassLoaderManager.getLoadedClass(
1145:                                instrClassNames[i], instrClassLoaders[i]);
1146:
1147:                        if (clazzes[k] != null) {
1148:                            if (b[k] == null) {
1149:                                // An optimization to avoid overhead of creating and sending original class file bytes from client
1150:                                // to server
1151:                                if (instrClassLoaders[i] == 0) {
1152:                                    b[k] = ClassBytesLoader
1153:                                            .getClassFileBytes(instrClassNames[i]);
1154:                                } else {
1155:                                    b[k] = Classes
1156:                                            .getCachedClassFileBytes(clazzes[k]);
1157:                                }
1158:                            }
1159:
1160:                            k++;
1161:                        } else {
1162:                            reportUnloadedClass(instrClassNames[i]);
1163:
1164:                            int classesToMove = nClasses - k - 1;
1165:                            System.arraycopy(clazzes, k + 1, clazzes, k,
1166:                                    classesToMove);
1167:                            System.arraycopy(b, k + 1, b, k, classesToMove);
1168:                        }
1169:                    }
1170:
1171:                    if (k < nClasses) {
1172:                        Class[] oldClazzes = clazzes;
1173:                        clazzes = new Class[k];
1174:                        System.arraycopy(oldClazzes, 0, clazzes, 0, k);
1175:                    }
1176:
1177:                    Classes.redefineClasses(clazzes, imgb
1178:                            .getReplacementClassFileBytes());
1179:
1180:                    time = Timers.getCurrentTimeInCounts() - time;
1181:                    totalHotswappingTime += time;
1182:
1183:                    if (time < minHotswappingTime) {
1184:                        minHotswappingTime = time;
1185:                    } else if (time > maxHotswappingTime) {
1186:                        maxHotswappingTime = time;
1187:                    }
1188:
1189:                    instrumentMethodGroupCallThread = null;
1190:                } catch (Throwable t) {
1191:                    if (t instanceof  Classes.RedefineException) {
1192:                        int nClasses = imgb.getNClasses();
1193:                        String[] instrClassNames = imgb.getMethodClasses();
1194:                        System.err
1195:                                .println("Profiler Agent Error: Redefinition failed for classes:"); // NOI18N
1196:
1197:                        for (int i = 0; i < nClasses; i++) {
1198:                            System.err.println(instrClassNames[i]);
1199:                        }
1200:
1201:                        System.err
1202:                                .println("Profiler Agent Error: with message: "
1203:                                        + ((Classes.RedefineException) t)
1204:                                                .getMessage()); // NOI18N
1205:
1206:                        byte[][] newBytes = imgb.getReplacementClassFileBytes();
1207:
1208:                        for (int i = 0; i < nClasses; i++) {
1209:                            String name = instrClassNames[i];
1210:                            File outFile = new File(name + ".class"); // NOI18N
1211:                            System.err.println("Debug: writing class file: "
1212:                                    + name + ", into file: "
1213:                                    + outFile.getPath()); // NOI18N
1214:
1215:                            try {
1216:                                FileOutputStream fos = new FileOutputStream(
1217:                                        outFile);
1218:                                fos.write(newBytes[i]);
1219:                                fos.close();
1220:                            } catch (IOException exc) {
1221:                                System.err.println("error: " + exc
1222:                                        + " writing class file: "
1223:                                        + outFile.getPath()); // NOI18N
1224:                            }
1225:                        }
1226:
1227:                        throw ((Classes.RedefineException) t);
1228:                    } else {
1229:                        java.io.StringWriter sw = new java.io.StringWriter();
1230:                        java.io.PrintWriter pw = new java.io.PrintWriter(sw);
1231:                        t.printStackTrace(pw);
1232:                        throw new Exception(MessageFormat.format(
1233:                                UNEXPECTED_EXCEPTION_MSG, new Object[] { t,
1234:                                        sw.toString() }));
1235:                    }
1236:                } finally {
1237:                    instrumentMethodGroupCallThread = null;
1238:                }
1239:            }
1240:
1241:            private static boolean internalClassName(String name) {
1242:                return (name.startsWith(PROFILER_DOTTED_CLASS_PREFIX) || // WARNING: sun.reflect.* are not really internal classes, but they may create too many problems by being loaded unexpectedly
1243:                        // by our internal code and causing classLoadHook to be invoked recursively. At least we need sun.reflect.Generated* to be
1244:                        // dismissed. Others could probably be less of a problem if ClassLoaderManager didn't use reflection.
1245:                        (name.startsWith("sun.reflect.")
1246:                                && !name
1247:                                        .startsWith("sun.reflect.GeneratedSerializationConstructorAccessor") && !name
1248:                                .startsWith("sun.reflect.GeneratedConstructorAccessor")) // NOI18N
1249:                        || name.startsWith("sun.instrument.") // NOI18N
1250:                // FIXME: below is a (hopefully temporary) fix to the strange problem showing up as ClassCircularityError when
1251:                // we try to profile PetStore with eager instrumentation scheme on Sun ONE AS 7. This makes the problem go away,
1252:                // but its root cause is still unclear to me.
1253:                || name.equals("com.sun.enterprise.J2EESecurityManager") // NOI18N
1254:                );
1255:            }
1256:
1257:            private static void reflectiveMethodInvokeHook(Method method) {
1258:                serialClientOperationsLock.beginTrans(true);
1259:
1260:                try {
1261:                    if (reflectMethods.containsKey(method)) {
1262:                        return;
1263:                    }
1264:
1265:                    ProfilerRuntimeCPU.suspendCurrentThreadTimer();
1266:
1267:                    reflectMethods.put(method, null);
1268:
1269:                    Class clazz = method.getDeclaringClass();
1270:                    String className = clazz.getName();
1271:                    String methodName = method.getName();
1272:                    Class[] paramTypes = method.getParameterTypes();
1273:                    StringBuffer sb = new StringBuffer();
1274:                    sb.append('(');
1275:
1276:                    for (int i = 0; i < paramTypes.length; i++) {
1277:                        appendTypeName(sb, paramTypes[i]);
1278:                    }
1279:
1280:                    sb.append(')');
1281:                    appendTypeName(sb, method.getReturnType());
1282:
1283:                    String methodSignature = sb.toString();
1284:
1285:                    clientInstrStartTime = Timers.getCurrentTimeInCounts();
1286:
1287:                    MethodLoadedCommand cmd = new MethodLoadedCommand(
1288:                            className,
1289:                            ClassLoaderManager.registerLoader(clazz),
1290:                            methodName, methodSignature);
1291:                    profilerServer.sendComplexCmdToClient(cmd);
1292:
1293:                    if (!getAndInstrumentClasses(false)) {
1294:                        disableProfilerHooks();
1295:
1296:                        return;
1297:                    }
1298:
1299:                    ProfilerRuntimeCPU.resumeCurrentThreadTimer();
1300:                } finally {
1301:                    serialClientOperationsLock.endTrans();
1302:                }
1303:            }
1304:
1305:            private static void reportUnloadedClass(String className) {
1306:                System.err.println(ENGINE_WARNING
1307:                        + "target VM cannot load class to instrument "
1308:                        + className); // NOI18N
1309:                System.err
1310:                        .println("*** probably it has been unloaded recently"); // NOI18N
1311:            }
1312:
1313:            private static void sendRootClassLoadedCommand(
1314:                    boolean doGetLoadedClasses) {
1315:                if (doGetLoadedClasses) {
1316:                    getLoadedClasses(); // Otherwise we know loadedClassesArray has already been initialized
1317:                }
1318:
1319:                int len = loadedClassesArray.length;
1320:                String[] loadedClassNames = new String[len];
1321:                int[] loaders = new int[len];
1322:                byte[][] cachedClassFileBytes = new byte[len][];
1323:                int idx = 0;
1324:
1325:                for (int i = 0; i < loadedClassesArray.length; i++) {
1326:                    String name = loadedClassesArray[i].getName();
1327:
1328:                    if (name.startsWith("[") || internalClassName(name)) { // NOI18N
1329:
1330:                        continue; // NOI18N
1331:                    }
1332:
1333:                    loadedClassNames[idx] = name;
1334:                    loaders[idx] = loadedClassesLoaders[i];
1335:
1336:                    if (loaders[idx] > 0) {
1337:                        cachedClassFileBytes[idx] = Classes
1338:                                .getCachedClassFileBytes(loadedClassesArray[i]);
1339:                    } else if (status.remoteProfiling) { // When we profile remotely, we need to send all available classes to the tool
1340:                        cachedClassFileBytes[idx] = ClassBytesLoader
1341:                                .getClassFileBytes(loadedClassesArray[i]
1342:                                        .getName());
1343:                    }
1344:
1345:                    idx++;
1346:                }
1347:
1348:                String bufferFileName = ((getCurrentInstrType() == INSTR_RECURSIVE_FULL)
1349:                        || (getCurrentInstrType() == INSTR_RECURSIVE_SAMPLED)
1350:                        || (getCurrentInstrType() == INSTR_OBJECT_ALLOCATIONS) || (getCurrentInstrType() == INSTR_OBJECT_LIVENESS)) ? evBufManager
1351:                        .getBufferFileName()
1352:                        : " "; // NOI18N
1353:
1354:                RootClassLoadedCommand cmd = new RootClassLoadedCommand(
1355:                        loadedClassNames, loaders, cachedClassFileBytes, idx,
1356:                        ClassLoaderManager.getParentLoaderIdTable(),
1357:                        bufferFileName);
1358:                profilerServer.sendComplexCmdToClient(cmd);
1359:                loadedClassesArray = null; // Free memory
1360:                loadedClassesLoaders = null; // Ditto
1361:            }
1362:
1363:            private static void updateInstrClassAndMethodNames(
1364:                    InstrumentMethodGroupData imgb, boolean firstTime) {
1365:                status.beginTrans(false);
1366:
1367:                try {
1368:                    switch (getCurrentInstrType()) {
1369:                    case INSTR_RECURSIVE_FULL:
1370:                    case INSTR_RECURSIVE_SAMPLED:
1371:                        status.updateInstrMethodsInfo(imgb.getNClasses(), imgb
1372:                                .getNMethods(), null, null, null, null, null,
1373:                                imgb.getInstrMethodLeaf());
1374:                        ProfilerRuntimeCPU.setInstrMethodsInvoked(status
1375:                                .getInstrMethodInvoked());
1376:
1377:                        break;
1378:                    case INSTR_OBJECT_ALLOCATIONS:
1379:                    case INSTR_OBJECT_LIVENESS:
1380:                        status.updateAllocatedInstancesCountInfoInServer(imgb
1381:                                .getAddInfo());
1382:                        ProfilerRuntimeMemory
1383:                                .setAllocatedInstancesCountArray(status
1384:                                        .getAllocatedInstancesCount());
1385:
1386:                        break;
1387:                    }
1388:                } finally {
1389:                    status.endTrans();
1390:                }
1391:            }
1392:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.