Pro Yearly is on sale from $80 to $50! »

Optimising Eclipse Plug-ins

B3d3a2cce932eca144b8c13a63966404?s=47 alblue
October 27, 2016

Optimising Eclipse Plug-ins

An overview of profiling and optimisation tools that can be used to optimise Eclipse plug-ins, along with sample code and configurations that can be used to make Eclipse faster. Presented at EclipseCon Europe 2016 in Ludwigsburg, Germany. A screencast recording of this is available at https://vimeo.com/alblue/optimising-eclipse-plug-ins
Creative

B3d3a2cce932eca144b8c13a63966404?s=128

alblue

October 27, 2016
Tweet

Transcript

  1. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Optimising

    Eclipse Plug-ins Alex Blewitt @alblue https://alblue.bandlem.com
  2. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 –Donald

    Knuth “Optimisation is the root of all evil”
  3. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 –Donald

    Knuth “Optimisation is the root of all evil”
  4. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Optimising

    Memory CPU Code size Latency http://www.brendangregg.com/usemethod.html USE method * Utilisation * Saturation * Errors
  5. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flight

    Recorder • Oracle's addition to OpenJDK to allow high-performance recording • Commercial feature, payable in production • -XX:+UnlockCommericalFeatures • -XX:+FlightRecorder • Writes out timestamped events to .jfr file • Selectively enable events with default.jfc or profile.jfc
  6. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control • Bundled with Oracle JDK in order to read .jfr files • Built on Eclipse, or can be installed into an existing Eclipse • Can trigger flight recording from an existing process • Can connect to non-Oracle JVMs for MBean overview • Run with jmc from JAVA_HOME http://download.oracle.com/technology/products/missioncontrol/updatesites/base/5.5.0/eclipse/
  7. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control Usage in high water mark
  8. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control Install Apache Aries JMX and register PlatformMBeanServer for osgi.core beans
  9. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control Press once for snapshot, twice for delta Different pool sizes
  10. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control Updates once per second
  11. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Mission Control Different colour icons indicate how much presure it causes the VM
  12. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JCmd

    • Command line tool for diagnostic commands, uses Java ID (pid) • jcmd - show a list of all Java processes on the local host • jcmd 1234 help - shows a list of commands or help for cmds • jcmd 1234 GC.run - runs the garbage collector System.gc() • jcmd 1234 GC.heap_dump <file> - generate hprof heap dump • jcmd 1234 GC.class_histogram - dump the heap histogram • jcmd 1234 Thread.print - take a stack dump Replacement for jps, jstat, jmap etc.
  13. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flight

    Recorder • Can record from startup, for a specific time, or on demand • -XX:StartFlightRecording=
 settings=profile | default | /path/to/something.jfc
 filename=/path/to/out.jfr
 [ dumponexit=false | true ]
 [ duration=0 | 60s | 10m | 5h | 3d ... ]
 [ delay=0 | 60s | 10m | 5h | 3d ... ]
 [ maxage=0 | 60s | 10m | 5h | 3d ...]
 [ maxsize=0 | 1k | 2m | 3g ... ] Default settings are loaded from
 JAVA_HOME/jre/ib/jfr -XX:+UnlockCommercialFeatures -XX:StartFlightRecording=
 settings=/tmp/EclipseCon.jfc,dumponexit=true,filename=/tmp/neon.jfr
  14. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flight

    Recorder Settings • Saved as an XML file Thread dump period must be >= 10ms
  15. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 EclipseCon.jfc

    <?xml version="1.0" encoding="UTF-8"?> <configuration version="1.0" name="EclipseCon" description="Demo for EclipseCon" provider="Alex Blewitt"> <producer uri="http://www.oracle.com/hotspot/jvm/" label="Oracle JDK"> <event path="os/processor/cpu_load"> <setting name="enabled">true</setting> <setting name="period">500 ms</setting> </event> <event path="java/statistics/class_loading"> <setting name="enabled">true</setting> <setting name="period">100 ms</setting> </event> <event path="java/statistics/threads"> <setting name="enabled">true</setting> <setting name="period">100 ms</setting> </event> <event path="vm/class/load"> <setting name="enabled">true</setting> <setting name="stackTrace">true</setting> </event> <event path="vm/runtime/thread_dump"> <setting name="enabled">true</setting> <setting name="period">10 ms</setting> </event> </producer> </configuration> Path allows subset of events to be captured Can also specify whether to capture stackTrace or in some cases threshold
  16. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Viewing

    a JFR file Make sure synchronise selection is enabled Ensure event types are selected from Events page Shows number of events by producer Shows events filtered by event types (not all captured) This is a capture from an Eclipse 4.6 application startup and shutdown
  17. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 CPU

    utilisation ? Nothing seems to be happening here ... Rest of program never reaches 100% CPU Splash appears Eclipse running Shutdown
  18. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Zooming

    in Drag to zoom in events bar Or drag in the CPU usage
  19. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Found

    the culprit 496259
  20. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Profiling

    with YourKit Thanks to YourKit for providing me with a license for this presentation
  21. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 GC

    analysis with Censum Thanks to JClarity for providing me with a license for this presentation
  22. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Concurrency

    Most class loads are on main thread Loading 10,000 takes time, even if class isn't complicated - reducing classes will speed this up
  23. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Concurrency

    Most class loads are on main thread
  24. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Problems

    seen so far • Massively single threaded operation with main thread • Activator, IStartup, (and next, Workbench.initialize) • Limited use of Declarative Services (Component Resolve Thread) • Delay with DNS lookup at start, quiet point in CPU utilisation mid-way • No observable memory issues at this point (GC looks fine) • Where are we spending execution time?
  25. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • Events can be generated programmatically com.oracle.jrockit.jfr • Subclass of InstantEvent, DurationEvent or TimedEvent • Events can have associated metadata, and capture stack/thread • Associated with a producer and a path for selective enablement • Events have a start(), end() and are dumped with commit() • No way of reporting a specific time; start/end automatic • Example: register a bundle listener to find when activator starts/stops Renamed to jdk.jfr or jdk.internal.jfr in Java 9
  26. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events DNS delay No classloading or activator? Startup complete We can record custom events, like timing for activators
  27. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events DNS delay No classloading or activator? Startup complete We can record custom events, like timing for activators
  28. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events
  29. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events Device.getFontList() Workbench.initializeFonts() FontRegistry.getFontData() ½ second 22 fonts
  30. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events
  31. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events
  32. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events
  33. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graphs • Brendan Gregg's Flame Graph generator • Fn;NestedFn;NestedFn time - generate from JFR file • Convert with flamegraph.pl < neon.flame > neon.svg eclipse;org.eclipse.equinox.common 12354587 eclipse;org.eclipse.equinox.ds 29975629 eclipse;org.eclipse.equinox.util 5484913 eclipse;org.eclipse.e4.core.di 46453 eclipse;org.eclipse.e4.core.di.extensions 38247 eclipse;org.eclipse.equinox.event 390380 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime;org.eclipse.core.contenttype;org.eclipse.equinox.preferences 16893735 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime;org.eclipse.core.contenttype;org.eclipse.equinox.registry 64136326 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime;org.eclipse.core.contenttype 6180006 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime;org.eclipse.core.jobs 11617533 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime;org.eclipse.equinox.app 31330246 eclipse;org.eclipse.ui.trace;org.eclipse.core.runtime 15737669 eclipse;org.eclipse.ui.trace 6264739 eclipse;org.eclipse.update.configurator 58846819 https://github.com/brendangregg/FlameGraph
  34. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graphs • Left-to-right order unimportant • Relative width shows time and nesting shows values
  35. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graphs • Can interactively navigate SVG graph • Can search for specific types
  36. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graphs • Can also intermix other types e.g. class load • See which class loader triggered bundle startup
  37. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Plug-in

    optimisations • Declarative Services solves most problems • Avoids the need for BundleActivator classes • Avoids the need for IStartup implementations • Avoids the need for ServiceTracker • ServiceTracker.open() is a blocking call • ServiceTracker.open() results in DS activating services
  38. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Plug-in

    optimisations • Declarative Services has some issues to note • Methods are called using reflection rather than interface type • class.getDeclaredMethods() results in many class loads • All argument, return types, and exceptions are loaded • Including traversing the inheritance hierarchy • (Spring has the same problem)
  39. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Plug-in

    optimisations • Declarative Services has some issues to note • Methods are called using reflection rather than interface type • class.getDeclaredMethods() results in many class loads • All argument, return types, and exceptions are loaded • Including traversing the inheritance hierarchy • (Spring has the same problem) @Component(immediate=true) public class MyService implements MyInterface { @Activate public void activate() { // starting things here } private X doSomethingWith(Y y) throws Z { // unrelated method in the same class // DS calling 'activate' will load X, Y, Z } @Override public void myServiceMethod() { } } PDE can now generate service components for a project Project > Plug-in Development > DS Annotations Activating will load (but not initialize) X, Y, Z And any supertypes as well
  40. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Best

    practices • Use a separate interface from the implementation • Preferably in separate bundles - that way client is decoupled • Use (declarative) services to wire components together • Use Require-Capability: osgi-extender to require DS • Prefer Import-Package to Require-Bundle • Activator/IStartup/ServiceTracker -> DS immediate components
  41. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Reducing

    memory usage • Eclipse MAT can be used to find where the objects come from
  42. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Reducing

    memory usage • Platform references String String + char[]
  43. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 URLs

    are bad! • Incredibly inefficient way of storing data • "http://eclipsecon.org" - 88 bytes • new URL("http://eclipsecon.org") - 224+ bytes - 3x! • As if that wasn't bad enough, there is a DNS lookup in hashCode! • URL.hashCode() -> • URLStreamHandler.hashCode(url) -> • InetAddress.getByName(url.getHost()) URIs are actually worse 472 bytes in this example
  44. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Object Layout • jol is an OpenJDK tool that can show • internals – how the object is laid out • footprint – how much memory it takes $ java -jar jol-cli.jar internals java.lang.String java.lang.String object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) c2 02 00 f8 12 4 char[] String.value [] 16 4 int String.hash 0 20 4 (loss due to the next object alignment) org.openjdk.jol jol-cli 0.6 jol-cli-0.6-full.jar
  45. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Object Layout • jol is an OpenJDK tool that can show • internals – how the object is laid out • footprint – how much memory it takes $ java -jar jol-cli.jar footprint java.lang.String java.lang.String@6842775dd footprint: COUNT AVG SUM DESCRIPTION 1 16 16 [C 1 24 24 java.lang.String 2 40 (total) org.openjdk.jol jol-cli 0.6 jol-cli-0.6-full.jar
  46. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Java

    Object Layout • Uses the default constructor of the class being tested • If the class has no (sensible) default constructor • Create a wrapper class • In default constructor, instantiate/store type • Run jol-cli.jar footprint on wrapper class
  47. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 •

    Uses the default constructor of the class being tested • If the class has no (sensible) default constructor • Create a wrapper class • In default constructor, instantiate/store type • Run jol-cli.jar footprint on wrapper class Java Object Layout public class Wrapper { public final URI uri; public Wrapper() throws Exception { uri = new URI("http://eclipsecon.org"); } } $ java -cp jol-cli.jar:. org.openjdk.jol.Main footprint Wrapper Wrapper@574caa3fd footprint: COUNT AVG SUM DESCRIPTION 1 16 16 Wrapper 6 41 248 [C 6 24 144 java.lang.String 1 80 80 java.net.URI 14 488 (total) 488 – 16 = 472
  48. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Suggested

    fixes • Fix URLImageDescriptor to store String instead of URL • Convert to a URL on demand for e.g. stream contents • Most uses won't need the additional URL fields • Fix the rampant layer violation in MenuHelper as well ... • If you must use URLs (e.g. through API contracts) then cache • P2 URL cache fixed 442915
  49. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Primitive

    wrapper classes • There are still a non-trivial number of wrapper creations • new Boolean(true) -> Boolean.TRUE • new Boolean(x) -> Boolean.valueOf(x) • Smaller code footprint • new Boolean(x) - 8 bytes • Boolean.valueOf(x) - 3 bytes • Using transformer agent shows few k savings in JDT 489706 489697 491825 476814 476724 Constructors are deprecated in Java 9
  50. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Memory

    and GC • Java's garbage collection is best suited for • Short lived objects, which get GC'd quickly • Long lived objects, which stay around for ever • Different GC strategies have changed over years • Some Eclipse code is written for JVMs before J2SE • Allocation is not as 'expensive' as it used to be
  51. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Generational

    GC Survivor 0 Survivor 1 Eden Tenured Young Generation Old Generation Minor GC Major/Full GC Survivor space is copied and flipped on each minor GC Tenured objects are promoted at tenuring threshold Objects are created in Eden PermGen Meta space
  52. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JVisual

    VM • Provides a view into a JVM's state • Run jvisualvm from JAVA_HOME • Connects to local or remote JVMs • Install Tools > Plugins > Visual GC for more • Present in OracleJDK but can connect to non-OracleJDKs
  53. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JVisual

    VM (max, current): occupancy Young gen column Old gen column Off heap column Slope shows allocation rate Minor GCs
  54. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 G1

    GC Tenured Tenured H ug e Tenured Eden Survivor Survivor Tenured Eden Tenured -XX:+UseG1GC 1..32Mb 2048+ regions
  55. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 G1

    GC Tenured Tenured H ug e Tenured Eden Survivor Tenured Tenured -XX:+UseG1GC 1..32Mb 2048+ regions
  56. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 G1

    GC Tenured Tenured H ug e Tenured Tenured Eden Survivor -XX:+UseG1GC 1..32Mb 2048+ regions
  57. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 12

    bytes 4 8 12 bytes 4 4 4 Header A, l, e, x length Header *char[] hash pad Strings in Java String char[] "Alex" 24 bytes 24 bytes 48 bytes
  58. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Java String char[] "Alex"
  59. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Java String char[] "Alex" String String String String String String "Alex" "Alex" "Alex" "Alex" "Alex" char[] char[] char[] char[] char[] "Alex" char[]
  60. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Java String char[] "Alex" String String String String String "Alex" "Alex" "Alex" "Alex" "Alex" char[] char[] char[] char[] char[] -XX:+UseG1GC -XX:+UseStringDeduplication 48 bytes 48 bytes 48 bytes 48 bytes 48 bytes 48 bytes 288 bytes
  61. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Java String char[] "Alex" String String String String String "Alex" "Alex" "Alex" "Alex" "Alex" -XX:+UseG1GC -XX:+UseStringDeduplication 48 bytes 24 bytes 24 bytes 24 bytes 24 bytes 24 bytes 168 bytes 490341
  62. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 "Alex"

    "Alex" "Alex" "Alex" "Alex" String String String String String Strings in Java String char[] "Alex" String.intern() 48 bytes 24 bytes 24 bytes 24 bytes 24 bytes 24 bytes 168 bytes
  63. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Java String char[] "Alex" String.intern() 48 bytes
  64. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Strings

    in Eclipse String char[] "Alex""objectClass" String char[] 0 8512 bytes 133 "MenuItem" String char[] 10512 bytes 219 26880 bytes 560 "platform" String char[] 36960 bytes 660 String "false" char[] 42960 bytes 895 String "true" char[] 48 bytes 48 bytes 64 bytes 56 bytes 48 bytes intern() 5280 bytes 3232 bytes 13464 bytes 15827 bytes 21504 bytes -XX+UseDedup
  65. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Suggested

    fixes • Registry and E4 model use many, many, many String values • true, false, MenuItem, View, ColorDefinition, defaultAccelerator • Intern String values in implementations in: • (registry) ConfigurationElement.propertiesAndValues • (css.swt.dom) WidgetElement.localName • (e4.model.basic) PartImpl.tags Saves 2Mb+
  66. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 String.intern?

  67. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Isn't

    that an anti-pattern?
  68. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 String.intern()

    • Used to be a problem • Strings stored in (write-only) PermGen • Couldn't be garbage collected • Bucket size was fixed to a small number (1009) • Used to be avoided 6
  69. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 String.intern()

    • These problems have all gone away, since Java 7 • Strings no longer stored in PermGen (and no more PermGen!) • Strings are stored on heap and so can be garbage collected • Bucket size increased to 60013 (-XX:StringTableSize=60013) • Use it wherever you have large volumes of small Strings • -XX:+UseStringDeduplication helps but doesn't solve problem 7 8
  70. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Performance

    recommendations • Avoid networking lookups or I/O on the main/blocking thread • Remove BundleActivator and IStartup code • Move startup of services from Activator to Declarative Services Components • Migrate data structures from load-at-start to load-on-demand • Reduce the number of classes (move inner classes to method references) • Avoid using URL or URI to store data, and avoid usage in APIs • Use String.intern() for long-lived and limited sized String references • Measure with flame graphs or profile with JMH where appropriate
  71. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Go

    forth and make Eclipse fast!
  72. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Questions

  73. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Appendix

  74. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • An EclipseActivatorEvent can be used to record activator time @EventDefinition(name = "EclipseActivator", description="Eclipse Activator", path="eclipse/activator", stacktrace = true, thread = true) public class EclipseActivatorEvent extends TimedEvent { @ValueDefinition(id = "bundleName", name = "bundleName", description = "Name") private String bundleName; public String getBundleName() { return bundleName; } public void setBundleName(String bundleName) { this.bundleName = bundleName; } public EclipseActivatorEvent() { super(EclipseTokens.EclipseActivatorEventToken); } }
  75. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • Tokens are used by the runtime to associate event types public class EclipseTokens { private static final String URI = "http://www.eclipsecon.org/2016/jfr/"; public static final EventToken EclipseActivatorEventToken; public static final EventToken EclipseAnotherEventToken; static { try { Producer producer = new Producer("Eclipse", "EclipseCon Demo of JFR", URI); EclipseActivatorEventToken= producer.addEvent(EclipseActivatorEvent.class); EclipseAnotherEventToken = producer.addEvent(EclipseAnotherEvent.class); producer.register(); } catch (Exception e) { throw new RuntimeException(e); } } } This is Java 8; changes in Java 9 JFR
  76. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • Can register a SynchronousBundleListener to measure time public final class JFRBundleListener implements SynchronousBundleListener { public void bundleChanged(BundleEvent bundleEvent) { Bundle bundle = bundleEvent.getBundle(); int type = bundleEvent.getType(); EclipseActivatorEvent event = Activator.events[(int) id]; String name = bundle.getSymbolicName(); if (type == BundleEvent.STARTING && event != null) { event.begin(); } else if (type == BundleEvent.STARTED && event != null) { event.end(); event.setBundleSymbolicName(name); event.commit(); } } } Needs to be registered/started ahead of DS, simpleconfigurator etc.
  77. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • Can register a SynchronousBundleListener to measure time public class Activator implements BundleActivator { static final int MAX_BUNDLES = 1000; static EclipseActivatorEvent[] events = new EclipseActivatorEvent[MAX_BUNDLES]; public void start(BundleContext context) throws Exception { for (int i = 0; i < events.length; i++) { events[i] = new EclipseActivatorEvent(); } context.addBundleListener(new JFRBundleListener()); } public void stop(BundleContext context) throws Exception { } } Needs to be registered/started ahead of DS, simpleconfigurator etc.
  78. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom

    Events • Added to JFC for enabling specific event types <?xml version="1.0" encoding="UTF-8"?> <configuration version="1.0" name="EclipseCon" description="Demo of settings for EclipseCon" provider="Alex Blewitt"> <producer uri="http://www.oracle.com/hotspot/jvm/" label="Oracle JDK">...</> <producer uri="http://www.eclipsecon.org/2016/jfr/" label="EclipseConJFRDemo"> <event path="eclipse/activator"> <setting name="enabled">true</setting> <setting name="threshold">0 ms</setting> </event> </producer> </configuration>
  79. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graph • Generate FlameGraph events from JFR private static SortedSet<FlameEvent> readRecording(File recordingFile) throws IOException { TreeSet<FlameEvent> flameEvents = new TreeSet<FlameEvent>(); Parser parser = new Parser(recordingFile); for (ChunkParser chunkParser : parser) { for (FLREvent event : chunkParser) { if ("vm/class/load".equals(event.getPath())) { FLRStruct resolvedValue = (FLRStruct) event.getResolvedValue("loadedClass"); String message = (String) resolvedValue.getResolvedValue("name").toString(); FlameEvent flameEvent = new FlameEvent(event.getStartTime(), event.getTimestamp(), message); flameEvents.add(flameEvent); } if ("eclipse/activator".equals(event.getPath())) { String message = (String) event.getResolvedValue("bundleSymbolicName"); FlameEvent flameEvent = new FlameEvent(event.getStartTime(), event.getTimestamp(), message); flameEvents.add(flameEvent); } } parser.close(); return flameEvents; } }
  80. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graph • Generate FlameGraph events from JFR private static void writeFlameEvents(SortedSet<FlameEvent> flameEvents, File outputFile) throws IOException { try (FileWriter out = new FileWriter(outputFile)) { Stack<FlameEvent> stacks = new Stack<FlameEvent>(); Iterator<FlameEvent> it = flameEvents.iterator(); while (it.hasNext()) { FlameEvent otherFlameEvent = (FlameEvent) it.next(); writeBefore(stacks, otherFlameEvent.getStart(), out); if (!stacks.isEmpty()) stacks.peek().addDelta(otherFlameEvent.getDuration()); stacks.push(otherFlameEvent); } writeBefore(stacks, Long.MAX_VALUE, out); out.flush(); } }
  81. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graph • Generate FlameGraph events from JFR private static void write(Stack<FlameEvent> stack, Writer out) throws IOException { FlameEvent topEvent = stack.peek(); long time = topEvent.getAdjustedDuration(); Iterator<FlameEvent> it = stack.iterator(); StringBuffer buffer = new StringBuffer("eclipse"); while (it.hasNext()) { buffer.append(';'); FlameEvent type = (FlameEvent) it.next(); buffer.append(type.getMessage()); } buffer.append(" " + time); out.write(buffer.toString()); }
  82. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame

    Graph • Generate FlameGraph events from JFR private static void writeBefore(Stack<FlameEvent> stack, long before, Writer out) throws IOException { if (!stack.isEmpty() && stack.peek().getEnd() < before) { write(stack, out); stack.pop(); writeBefore(stack, before, out); } } public static void main(String[] args) throws IOException { File recordingFile = new File(args[0]); File outputFile = new File(args[1]); SortedSet<FlameEvent> flameEvents = writeBefore(recordingFile); writeFlameEvents(flameEvents, outputFile); }
  83. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    • Java Microbenchmark Harness • Add a @Benchmark annotation to methods under test // 18 bytecode instructions @Benchmark public String chain() { return new StringBuffer().append(a).append(b).toString(); } // 24 bytecode instructions @Benchmark public String sequence() { StringBuilder sb = new StringBuilder(); sb.append(a); sb.append(b); return sb.toString(); }
  84. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    • Java Microbenchmark Harness • Wrap in a @State(Scope.Benchmark) class with @Param @State(Scope.Benchmark) public class StringBuilderBenchmark { @Param({ "Hello", "Goodbye" }) private String a; @Param({ "World", "EclipseCon" }) private String b; @Benchmark public String sequence() {...} @Benchmark public String chain() {...} }
  85. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    • Java Microbenchmark Harness • Build and run -wi 5 -tu ns -f 1 -bm avgt # JMH 1.15 (released 22 days ago) # VM version: JDK 1.8.0_102, VM 25.102-b14 # VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java Benchmark (a) (b) Mode Cnt Score Error Units StringBuilderBenchmark.chain Hello World avgt 20 15.038 ± 0.083 ns/op StringBuilderBenchmark.chain Hello EclipseCon avgt 20 15.935 ± 0.129 ns/op StringBuilderBenchmark.chain Goodbye World avgt 20 15.380 ± 0.128 ns/op StringBuilderBenchmark.chain Goodbye EclipseCon avgt 20 16.574 ± 0.130 ns/op StringBuilderBenchmark.sequence Hello World avgt 20 28.993 ± 0.524 ns/op StringBuilderBenchmark.sequence Hello EclipseCon avgt 20 28.354 ± 0.262 ns/op StringBuilderBenchmark.sequence Goodbye World avgt 20 29.354 ± 0.208 ns/op StringBuilderBenchmark.sequence Goodbye EclipseCon avgt 20 50.103 ± 0.582 ns/op Average time Warmups Time unit
  86. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    • Java Microbenchmark Harness • Build and run -wi 5 -tu ns -f 1 -bm avgt -prof gc # JMH 1.15 (released 22 days ago) # VM version: JDK 1.8.0_102, VM 25.102-b14 # VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java Benchmark (a) (b) Mode Cnt Score Error Units ..chain:·gc.alloc.rate.norm Hello World avgt 20 64 ± 0.001 B/op ..chain:·gc.alloc.rate.norm Hello EclipseCon avgt 20 72 ± 0.001 B/op ..chain:·gc.alloc.rate.norm Goodbye World avgt 20 64 ± 0.001 B/op ..chain:·gc.alloc.rate.norm Goodbye EclipseCon avgt 20 80 ± 0.001 B/op ..sequence:·gc.alloc.rate.norm Hello World avgt 20 112 ± 0.001 B/op ..sequence:·gc.alloc.rate.norm Hello EclipseCon avgt 20 120 ± 0.001 B/op ..sequence:·gc.alloc.rate.norm Goodbye World avgt 20 112 ± 0.001 B/op ..sequence:·gc.alloc.rate.norm Goodbye EclipseCon avgt 20 216 ± 0.001 B/op Average time Warmups Time unit Profile GC Other profilers exist, like perfasm
  87. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • It is possible to use Eclipse's annotation profiler to test JMH projects
  88. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • Factory path needs jmh-generator-annprocess and jmh-core
  89. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • Turn off warnings in generated code
  90. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • It's possible to configure annotation processing in Eclipse for JMH
  91. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • It's possible to configure annotation processing in Eclipse for JMH
  92. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMH

    in Eclipse • It's possible to configure annotation processing in Eclipse for JMH
  93. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 StringBuffer

    and StringBuilder • StringBuffer is synchronized; StringBuilder is not • Chaining is more efficient than sequencing • Custom HotSpot code for chained calls -XX:+OptimizeStringConcat public static String chain(String a, String b) { return new StringBuffer().append(a).append(b).toString(); } // 18 bytecode instructions public static String sequence(String a, String b) { StringBuilder sb = new StringBuilder(); sb.append(a); sb.append(b); return sb.toString(); } // 24 bytecode instructions https://alblue.bandlem.com/2016/04/jmh-stringbuffer-stringbuilder.html 492200 492230
  94. Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 JMX

    beans in OSGi • Supported with Apache Aries JMX • Install org.apache.aries.{jmx,util}, org.osgi.service.cm // Import-Package: javax.management,org.osgi.framework public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer(); context.registerService(MBeanServer.class.getName(), pmbs, null); } public void stop(BundleContext context) throws Exception { } } Don't forget javax.management on Equinox