1 # Mission Control
   2 
   3 Mission Control is an open source production time profiling and diagnostics tool for Java.
   4 
   5 Builds of Mission Control can currently be found in the Oracle JDK on supported platforms and in the Eclipse marketplace. 
   6 
   7 For more information on Mission Control, see http://www.oracle.com/missioncontrol.
   8 
   9 ### Core API Features
  10 
  11 * Core APIs for parsing and processing Java flight recordings 
  12 
  13 * Core API can *read* recordings from JDK 7 and above
  14 
  15 * Core API can *run* on JDK 7 and above
  16 
  17 * Core API contains a framework for handling units of measurement and physical quantities
  18 
  19 * Core API supports headless analysis of Java flight recordings
  20 
  21 
  22 ### Application Features
  23 
  24 * An application supporting framework for hosting various useful Java tools 
  25 
  26 * A tool for visualizing the contents of Java flight recordings, and the results of an automated analysis of the contents
  27 
  28 * A JMX Console 
  29 
  30 * A tool for heap waste analysis
  31 
  32 
  33 ### Core API Example
  34 
  35 Example for producing an HTML report from the command line:
  36 
  37 ```bash
  38 java -cp <the built core jars> org.openjdk.jmc.flightrecorder.rules.report.html.JfrHtmlRulesReport <file> [<outputfile>]
  39 ```
  40 
  41 
  42 Example for finding the standard deviation for the java monitor events in a recording:
  43 
  44 ```java
  45 import java.io.File;
  46  
  47 import org.openjdk.jmc.common.IDisplayable;
  48 import org.openjdk.jmc.common.item.Aggregators;
  49 import org.openjdk.jmc.common.item.IItemCollection;
  50 import org.openjdk.jmc.common.item.ItemFilters;
  51 import org.openjdk.jmc.common.unit.IQuantity;
  52 import org.openjdk.jmc.flightrecorder.JfrAttributes;
  53 import org.openjdk.jmc.flightrecorder.JfrLoaderToolkit;
  54 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  55  
  56 /**
  57  * Finds out the standard deviation for the java monitor enter events.
  58  */
  59 public class LoadRecording {
  60     public static void main(String[] args) throws Exception {         
  61         IItemCollection events = JfrLoaderToolkit.loadEvents(new File(args[0]));
  62         IQuantity aggregate = events.apply(ItemFilters.type(JdkTypeIDs.MONITOR_ENTER))
  63                 .getAggregate(Aggregators.stddev(JfrAttributes.DURATION));
  64          
  65         System.out.println("The standard deviation for the Java monitor enter events was "
  66                 + aggregate.displayUsing(IDisplayable.AUTO));
  67     }
  68 }
  69 ```
  70 
  71 
  72 Example for programmatically running the rules:
  73 
  74 ```java
  75 import java.io.File;
  76 import java.util.concurrent.RunnableFuture;
  77  
  78 import org.example.util.DemoToolkit;
  79 import org.openjdk.jmc.common.item.IItemCollection;
  80 import org.openjdk.jmc.common.util.IPreferenceValueProvider;
  81 import org.openjdk.jmc.flightrecorder.JfrLoaderToolkit;
  82 import org.openjdk.jmc.flightrecorder.rules.IRule;
  83 import org.openjdk.jmc.flightrecorder.rules.Result;
  84 import org.openjdk.jmc.flightrecorder.rules.RuleRegistry;
  85  
  86 public class RunRulesOnFileSimple {
  87     public static void main(String[] args) throws Exception {
  88         File recording = DemoToolkit.verifyRecordingArgument(RunRulesOnFileSimple.class, args);
  89         IItemCollection events = JfrLoaderToolkit.loadEvents(recording);
  90          
  91         for (IRule rule : RuleRegistry.getRules()) {
  92             RunnableFuture<Result> future = rule.evaluate(events, IPreferenceValueProvider.DEFAULT_VALUES);
  93             future.run();
  94             Result result = future.get();
  95             if (result.getScore() > 50) {
  96                 System.out.println(String.format("[Score: %3.0f] Rule ID: %s, Rule name: %s, Short description: %s",
  97                         result.getScore(), result.getRule().getId(), result.getRule().getName(),
  98                         result.getShortDescription()));
  99             }
 100         }
 101     }
 102 }
 103 ```
 104 
 105 
 106 Example for programmatically running rules in parallel (requires JDK8):
 107 
 108 ```java
 109 import java.io.File;
 110 import java.util.List;
 111 import java.util.concurrent.ExecutionException;
 112 import java.util.concurrent.Executor;
 113 import java.util.concurrent.Executors;
 114 import java.util.concurrent.RunnableFuture;
 115 import java.util.stream.Collectors;
 116 import java.util.stream.Stream;
 117  
 118 import org.openjdk.jmc.common.item.IItemCollection;
 119 import org.openjdk.jmc.common.util.IPreferenceValueProvider;
 120 import org.openjdk.jmc.flightrecorder.JfrLoaderToolkit;
 121 import org.openjdk.jmc.flightrecorder.rules.IRule;
 122 import org.openjdk.jmc.flightrecorder.rules.Result;
 123 import org.openjdk.jmc.flightrecorder.rules.RuleRegistry;
 124  
 125 /**
 126  * Runs the rules on the events in the specified file in parallel, then prints
 127  * them in order of descending score.
 128  */
 129 public class RunRulesOnFile {
 130     private final static Executor EXECUTOR = Executors
 131             .newFixedThreadPool(Runtime.getRuntime().availableProcessors() - 1);
 132     private static int limit;
 133  
 134     public static void main(String[] args) throws Exception {
 135         if (args.length == 0) {
 136             System.out.println(
 137                     "Usage: RunRulesOnFile <recording file> [<limit>]\n\tThe recording file must be a flight recording from JDK 7 or above. The limit, if set, will only report rules triggered with a score higher or equal than the limit.");
 138             System.exit(2);
 139         }
 140         IItemCollection events = JfrLoaderToolkit.loadEvents(new File(args[0]));
 141         if (args.length > 1) {
 142             limit = Integer.parseInt(args[1]);
 143         }
 144         Stream<RunnableFuture<Result>> resultFutures = RuleRegistry.getRules().stream()
 145                 .map((IRule r) -> evaluate(r, events));
 146         List<Result> results = resultFutures.parallel().map((RunnableFuture<Result> runnable) -> get(runnable))
 147                 .collect(Collectors.toList());
 148         results.sort((Result r1, Result r2) -> Double.compare(r2.getScore(), r1.getScore()));
 149         results.stream().forEach(RunRulesOnFile::printResult);
 150     }
 151  
 152     public static RunnableFuture<Result> evaluate(IRule rule, IItemCollection events) {
 153         RunnableFuture<Result> evaluation = rule.evaluate(events, IPreferenceValueProvider.DEFAULT_VALUES);
 154         EXECUTOR.execute(evaluation);
 155         return evaluation;
 156     }
 157  
 158     public static Result get(RunnableFuture<Result> resultFuture) {
 159         try {
 160             return resultFuture.get();
 161         } catch (InterruptedException | ExecutionException e) {
 162             e.printStackTrace();
 163         }
 164         return null;
 165     }
 166  
 167     private static void printResult(Result result) {
 168         if (result.getScore() >= limit) {
 169             System.out.printf("(%.0f) [%s]: %s\nDetails:\n%s\n============<End of Result>============\n",
 170                     result.getScore(), result.getRule().getId(), result.getShortDescription(),
 171                     result.getLongDescription() == null ? "<no description>" : result.getLongDescription());
 172         }
 173     }
 174 }
 175 ```
 176 
 177 ## Building Mission Control from Source
 178 
 179 Prerequisites for building Mission Control:
 180 1. Install JDK 8, and make sure it is the JDK in use (java -version)
 181 
 182 2. Install Maven (version 3.3.x. or above)
 183 
 184 First get third party dependencies into a local p2 repo and make it available on localhost:
 185 
 186 ```bash
 187 cd missioncontrolfolder/releng/third-party
 188 mvn p2:site
 189 mvn jetty:run
 190 ```
 191 
 192 Then in another terminal (in the project root):
 193 
 194 ```bash
 195 mvn package
 196 ```
 197 Note that you may need to define proxy settings if you happen to be behind a firewall. In your ~/.m2/settings.xml file (if you have none, simply create one), add:
 198 
 199 ```xml
 200 <settings>
 201   <proxies>
 202     <proxy>
 203       <id>http-proxy</id>
 204       <active>true</active>
 205       <protocol>http</protocol>
 206       <host>my.proxy.example.org</host>
 207       <port>80</port>
 208       <nonProxyHosts>localhost|*.example.org</nonProxyHosts>
 209     </proxy>
 210     <proxy>
 211       <id>https-proxy</id>
 212       <active>true</active>
 213       <protocol>https</protocol>
 214       <host>my.proxy.example.org</host>
 215       <port>80</port>
 216       <nonProxyHosts>localhost|*.example.org</nonProxyHosts>
 217     </proxy>
 218   </proxies>
 219 </settings>
 220 
 221 ```
 222 
 223 ## Running Tests
 224 To run the unit tests:
 225 
 226 ```bash
 227 mvn verify
 228 ```
 229 
 230 To run the UI tests:
 231 
 232 > Currently, in order to run UI tests you need to supply the Jemmy UI testing libraries yourself. These can be built from source available at the mercurial repository at http://hg.openjdk.java.net/code-tools/jemmy/v3/.
 233 
 234 >1. Create a directory on your local drive where you wish to build the Jemmy libraries.
 235 >2. In a terminal, when in the newly created directory, issue `hg clone http://hg.openjdk.java.net/code-tools/jemmy/v3/`. If you don't have a Mercurial client you can download the code from http://hg.openjdk.java.net/code-tools/jemmy/v3/archive/tip.zip (or .gz or .bz2).
 236 >3. Build Jemmy by issuing `mvn clean package`. Adding `-DskipTests` makes sure that UI tests that might fail won't stop the packaging.
 237 >4. Copy the resulting jar files from core/JemmyCore/target, core/JemmyAWTInput/target, core/JemmyBrowser/target and SWT/JemmySWT/target to \[jmc_repo_dir\]/application/uitests/org.openjdk.jmc.test.jemmy/lib/ (create the lib directory first if it does not exist).
 238 
 239 >(As soon as Jemmy is published on Maven Central, this manual build step will be removed.)
 240 
 241 ```bash
 242 mvn verify -P uitests
 243 ```
 244 Note that the UI tests will take some time to run, and that you need to stop interacting with your computer for the duration of the tests.
 245 
 246 Spotbugs can take some time to run. If you are only interested in the test results, you can skip running spotbugs by setting `-Dspotbugs.skip=true`.
 247 
 248 For example:
 249 
 250 ```bash
 251 mvn verify -P uitests -Dspotbugs.skip=true
 252 ```
 253 
 254 ## Filtering Test Runs
 255 Aside from the from the simple -test Maven flag test classes that should be run/not run can be specified by means of the system properties "test.includes" and/or "test.excludes". Multiple patterns can be specified by comma separation.
 256 
 257 For example:
 258 
 259 ```bash
 260 mvn verify -Dtest.includes=**/*TestRulesWithJfr*,**/*StacktraceModelTest*
 261 ```
 262 
 263 When specifying both test.includes and "test.excludes" the test.excludes takes precedence and filters out tests that also are matched by "test.includes".
 264 
 265 For example:
 266 
 267 ```bash
 268 mvn verify -P uitests -Dtest.includes=**/*SystemTabTest*,**/*TestRulesWithJfr*,**/*StacktraceModelTest* -Dtest.excludes=**/*ModelTest*
 269 ```
 270 
 271 The above will not run StacktraceModelTest, as that is also matched by "test.excludes".
 272 
 273 Note that if UI-tests are supposed to be part of the filtered run the "uitests" profile needs to be specified as well. Otherwise the UI won't start up and so the tests fail.
 274 
 275 ## Running the Locally Built JMC
 276 The built JMC will end up in the `target` folder in the root. To run it, go to `target/products/org.openjdk.jmc/<platform>` to find the launcher. Don't forget to override the vm flag with the JVM you wish to use for running JMC.
 277 
 278 Here is an example for Mac OS X:
 279 
 280 ```bash
 281 target/products/org.openjdk.jmc/macosx/cocoa/x86_64/JDK\ Mission\ Control.app/Contents/MacOS/jmc -vm $JAVA_HOME/bin
 282 ```
 283 
 284 Here is an Linux example:
 285 
 286 ```bash
 287 target/products/org.openjdk.jmc/linux/gtk/x86_64/jmc -vm $JAVA_HOME/bin
 288 ```
 289 
 290 And here is an example for Windows x64:
 291 
 292 ```bash
 293 missioncontrol\target\products\org.openjdk.jmc\win32\win32\x86_64\jmc.exe -vm %JAVA_HOME%\bin
 294 ```
 295 
 296 ## Setting Up for Development and Launching in Eclipse
 297 First make sure that you have installed the Mercurial Plug-in for Eclipse (MercurialEclipse). It can be installed from the Eclipse Marketplace (Help | Eclipse Marketplace...). At the time of writing, version 2.2 was the most recent one.
 298 
 299 1. First ensure that you have started the jetty server in the first step of building JMC.
 300 2. Next open (File | Open...) the Eclipse target platform of interest, for example releng/platform-definitions/platform-definition-photon/platform.target
 301 3. In the upper right corner of the platform editor that opens, click the link "Set as Active Target Platform"
 302 4. Import the projects you are interested in (core and/or application) into a recent Eclipse.
 303 5. If importing the application projects, make sure you create a user library (Preferences | Java/Build Path/User Libraries) named JMC_JDK, and add (Add External JARs...) the following JARs from a JDK 8 (u40 or above) to the User Library:
 304  - tools.jar (<JDK>/lib/tools.jar)
 305  - jconsole.jar (<JDK>/lib/jconsole.jar)
 306  - jfxswt.jar (<JDK>/jre/lib/jfxswt.jar)
 307  - jfxrt.jar (<JDK>/jre/lib/ext/jfxrt.jar)
 308 
 309 Note that importing configuration/ide/eclipse as an Eclipse project should automatically make the development launchers available to you.
 310 
 311 ## License
 312 The Mission Control source code is made available under the Universal Permissive License (UPL), Version 1.0 or a BSD-style license, alternatively. The full open source license text is available at license/LICENSE.txt in the JMC project.
 313 
 314 ## About
 315 Mission Control is an open source project of the [OpenJDK](http://openjdk.java.net/).
 316 The Mission Control project originated from the JRockit JVM project.