Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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/

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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 - 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.

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 EclipseCon.jfc true 500 ms true 100 ms true 100 ms true true true 10 ms Path allows subset of events to be captured Can also specify whether to capture stackTrace or in some cases threshold

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Found the culprit 496259

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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?

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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)

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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[]

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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+

Slide 66

Slide 66 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 String.intern?

Slide 67

Slide 67 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Isn't that an anti-pattern?

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Questions

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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); } }

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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.

Slide 77

Slide 77 text

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.

Slide 78

Slide 78 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Custom Events • Added to JFC for enabling specific event types ...> true 0 ms

Slide 79

Slide 79 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame Graph • Generate FlameGraph events from JFR private static SortedSet readRecording(File recordingFile) throws IOException { TreeSet flameEvents = new TreeSet(); 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; } }

Slide 80

Slide 80 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame Graph • Generate FlameGraph events from JFR private static void writeFlameEvents(SortedSet flameEvents, File outputFile) throws IOException { try (FileWriter out = new FileWriter(outputFile)) { Stack stacks = new Stack(); Iterator 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(); } }

Slide 81

Slide 81 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame Graph • Generate FlameGraph events from JFR private static void write(Stack stack, Writer out) throws IOException { FlameEvent topEvent = stack.peek(); long time = topEvent.getAdjustedDuration(); Iterator 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()); }

Slide 82

Slide 82 text

Copyright (c) 2016, Alex Blewitt, Bandlem Ltd EclipseCon 2016 Flame Graph • Generate FlameGraph events from JFR private static void writeBefore(Stack 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 flameEvents = writeBefore(recordingFile); writeFlameEvents(flameEvents, outputFile); }

Slide 83

Slide 83 text

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(); }

Slide 84

Slide 84 text

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() {...} }

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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