{"id":513,"date":"2014-02-12T02:32:51","date_gmt":"2014-02-12T01:32:51","guid":{"rendered":"http:\/\/hirt.se\/blog\/?p=513"},"modified":"2014-02-12T02:32:51","modified_gmt":"2014-02-12T01:32:51","slug":"using-the-jvm-performance-counters","status":"publish","type":"post","link":"https:\/\/hirt.se\/blog\/?p=513","title":{"rendered":"Using the JVM Performance Counters"},"content":{"rendered":"<p>So, in JRockit there was this neat little dynamic MBean from which you could access all the JVM performance counters as attributes. Tonight I ended up in an e-mail thread leading me to think about how to retrieve the HotSpot ones. This is of course all very unsupported, and counter names\/content and even the very API is subject to change at any given release. I am providing this information mostly as a reminder to myself. Who knows, someone might find this useful. <\/p>\n<p>I will now go ahead and show how something similar to the PerformanceCounters MBean available in JRockit can be built. I recommend against doing this in any kind of production scenario, as the PerformanceCounter API is totally unsupported. Please don\u2019t ask me what a certain counter means &#8211; you probably shouldn\u2019t be using these in the first place. This is all for lolz. \ud83d\ude42<\/p>\n<p>Here comes the usual disclaimer:<\/p>\n<blockquote>\n<p><span style=\"background-color: #ffffff\">The following blog entry will describe <strong><span style=\"color: #ff0000\">UNSUPPORTED <\/span><\/strong>functionality. This means that relying on the described APIs or functionality may <span style=\"color: #ff0000\"><strong>BREAK <\/strong><\/span><span style=\"color: #000000\">your code\/plugin with any given update of the JDK and\/or Mission Control. <\/span><\/span><\/p>\n<\/blockquote>\n<h2>Performance Counter Hello World<\/h2>\n<p>If you ever used JRockit, you may fondly remember the old <font size=\"5\" face=\"Cordia New\">jrcmd<\/font> utility, which now exists in a HotSpot incarnation as <font size=\"3\" face=\"Courier New\">jcmd<\/font>. Well, jrcmd had an option, \u2013l, which would list all the the performance counters in the target JVM. The following code will let you implement something similar to the jrcmd \u2013l command. Note that the PerformanceCounter API resides in a package most IDEs will restrict access to. You will need to change your project settings accordingly for the following to compile. <\/p>\n<p>Anyways, here is a hack to list all the performance counters for a particular PID:<\/p>\n<p><font size=\"2\" face=\"Courier New\">import java.io.IOException;<br \/>import java.nio.ByteBuffer; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">import sun.management.counter.Counter;<br \/>import sun.management.counter.perf.PerfInstrumentation;<br \/>import sun.misc.Perf; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">public class PerfCounterTest { <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws IOException {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (args.length != 1) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;Usage: PerfCounterTest &lt;PID&gt;&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.exit(2);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perf p = Perf.getPerf();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteBuffer buffer = p.attach(Integer.parseInt(args[0]), &#8220;r&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PerfInstrumentation perfInstrumentation = new PerfInstrumentation(buffer);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Counter counter : perfInstrumentation.getAllCounters()) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(String.format(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;%s = %s [Variability: %s, Units: %s]&#8221;, counter.getName(),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String.valueOf(counter.getValue()),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter.getVariability(), counter.getUnits()));<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; }<br \/>}<\/font> <\/p>\n<p>Note that you will need the \u201csun.misc.Perf.getPerf\u201d permission to be able to access the Perf instance when running with a security manager.<\/p>\n<p>From here to a fully functional Dynamic MBean, the step is pretty short.<\/p>\n<h2>PerformanceCounterMBean \u00e1 la JRockit for HotSpot<\/h2>\n<p>Here is an example of how code exposing the Performance Counters as a Dynamic MBean can look like:<\/p>\n<p><font size=\"2\" face=\"Courier New\">import java.io.IOException;<br \/>import java.nio.ByteBuffer;<br \/>import java.util.ArrayList;<br \/>import java.util.Collection;<br \/>import java.util.HashMap;<br \/>import java.util.List;<br \/>import java.util.Map; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">import javax.management.Attribute;<br \/>import javax.management.AttributeList;<br \/>import javax.management.AttributeNotFoundException;<br \/>import javax.management.DynamicMBean;<br \/>import javax.management.InvalidAttributeValueException;<br \/>import javax.management.MBeanAttributeInfo;<br \/>import javax.management.MBeanException;<br \/>import javax.management.MBeanInfo;<br \/>import javax.management.MalformedObjectNameException;<br \/>import javax.management.ObjectName;<br \/>import javax.management.ReflectionException;<br \/>import javax.management.RuntimeOperationsException; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">import sun.misc.Perf;<br \/>import sun.management.counter.Counter;<br \/>import sun.management.counter.perf.PerfInstrumentation; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">public class PerfCounters implements DynamicMBean {<br \/>&nbsp;&nbsp;&nbsp; public final static ObjectName MBEAN_OBJECT_NAME;<br \/>&nbsp;&nbsp;&nbsp; public final Map&lt;String, Counter&gt; counterMap;<br \/>&nbsp;&nbsp;&nbsp; private final MBeanInfo info; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; static {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MBEAN_OBJECT_NAME = createObjectName(&#8220;se.hirt.management:type=PerfCounters&#8221;);<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; public PerfCounters() {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counterMap = setUpCounters();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info = createMBeanInfo();<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public Object getAttribute(String attribute)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws AttributeNotFoundException, MBeanException,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReflectionException {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (attribute == null) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new RuntimeOperationsException(new IllegalArgumentException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;The attribute name cannot be null.&#8221;),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Cannot invoke getAttribute on &#8221; + MBEAN_OBJECT_NAME<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &#8221; with null as attribute name.&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Counter c = counterMap.get(attribute);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == null) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new AttributeNotFoundException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Could not find the attribute &#8221; + attribute);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return c.getValue();<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public void setAttribute(Attribute attribute)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws AttributeNotFoundException, InvalidAttributeValueException,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MBeanException, ReflectionException {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (attribute == null) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new RuntimeOperationsException(new IllegalArgumentException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;The attribute name cannot be null.&#8221;),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Cannot invoke setAttribute on &#8221; + MBEAN_OBJECT_NAME<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &#8221; with null as attribute name.&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Counter c = counterMap.get(attribute);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == null) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new AttributeNotFoundException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Could not find the attribute &#8221; + attribute + &#8220;.&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new RuntimeOperationsException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new UnsupportedOperationException(),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;All attributes on the PerfCounters MBean are read only.&#8221;);<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public AttributeList getAttributes(String[] attributes) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AttributeList attributeList = new AttributeList();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (String attribute : attributes) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributeList.add(new Attribute(attribute,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getAttribute(attribute)));<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (AttributeNotFoundException | MBeanException<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | ReflectionException e) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Seems this one is not supposed to throw exceptions. Try to<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ get as many as possible.<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return attributeList;<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public AttributeList setAttributes(AttributeList attributes) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Seems this one is not supposed to throw exceptions.<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Just ignore.<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public Object invoke(String actionName, Object[] params, String[] signature)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws MBeanException, ReflectionException {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new MBeanException(new UnsupportedOperationException(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MBEAN_OBJECT_NAME + &#8221; does not have any operations.&#8221;));<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; @Override<br \/>&nbsp;&nbsp;&nbsp; public MBeanInfo getMBeanInfo() {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return info;<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; private static ObjectName createObjectName(String name) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new ObjectName(name);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (MalformedObjectNameException e) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ This will not happen &#8211; known to be wellformed.<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; private Map&lt;String, Counter&gt; setUpCounters() {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map&lt;String, Counter&gt; counters = new HashMap&lt;&gt;();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perf p = Perf.getPerf();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteBuffer buffer = p.attach(0, &#8220;r&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PerfInstrumentation perfInstrumentation = new PerfInstrumentation(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Counter counter : perfInstrumentation.getAllCounters()) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counters.put(counter.getName(), counter);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IllegalArgumentException | IOException e) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(&#8220;Failed to access performance counters. No counters will be available!&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return counters;<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; private MBeanInfo createMBeanInfo() {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collection&lt;Counter&gt; counters = counterMap.values();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;MBeanAttributeInfo&gt; attributes = new ArrayList&lt;&gt;(counters.size());<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Counter c : counters) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!c.isVector()) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String typeName = &#8220;java.lang.String&#8221;;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (c) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object value = c.getValue();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (value != null) {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeName = value.getClass().getName();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributes.add(new MBeanAttributeInfo(c.getName(), typeName,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String.format(&#8220;%s [%s,%s]&#8221;, c.getName(), c.getUnits(),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.getVariability()), true, false, false));<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MBeanAttributeInfo[] attributesArray = attributes.toArray(new MBeanAttributeInfo[attributes.size()]);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new MBeanInfo(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.getClass().getName(),<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;An MBean exposing the available JVM Performance Counters as attributes.&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributesArray, null, null, null);<br \/>&nbsp;&nbsp;&nbsp; }<br \/>}<\/font> <\/p>\n<p>And here is a little test application that registers the MBean with the platform MBean server and then waits around, giving you an opportunity to hook up with Mission Control and try it out: <\/p>\n<p><font size=\"2\" face=\"Courier New\">import java.io.IOException;<br \/>import java.lang.management.ManagementFactory; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">import javax.management.InstanceAlreadyExistsException;<br \/>import javax.management.MBeanRegistrationException;<br \/>import javax.management.NotCompliantMBeanException; <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">public class PerfCounterMBeanRunner { <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, IOException {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ManagementFactory.getPlatformMBeanServer().registerMBean(new PerfCounters(), PerfCounters.MBEAN_OBJECT_NAME);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8220;Press enter to quit!&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.in.read();<br \/>&nbsp;&nbsp;&nbsp; } <\/font> <\/p>\n<p><font size=\"2\" face=\"Courier New\">}<\/font> <\/p>\n<p>If you use the JMX Console to connect to a JVM where the PerfCounters MBean is registered, you should be able to find the PerfCounters MBean using the MBean Browser. There should be quite a few performance counters available:<\/p>\n<p><a href=\"https:\/\/hirt.se\/blog\/wp-content\/uploads\/2014\/02\/JMC_perf_counters.png\"><img loading=\"lazy\" decoding=\"async\" title=\"JMC_perf_counters\" style=\"border-top: 0px;border-right: 0px;border-bottom: 0px;border-left: 0px\" border=\"0\" alt=\"JMC_perf_counters\" src=\"https:\/\/hirt.se\/blog\/wp-content\/uploads\/2014\/02\/JMC_perf_counters_thumb.png\" width=\"644\" height=\"353\"><\/a> <\/p>\n<h2>Conclusion<\/h2>\n<p>Sample code for using the proprietary JVM performance counter API was provided, as well as example code on how to implement a version of the old <font size=\"2\" face=\"Courier New\">jrcmd \u2013l <\/font>command, as well as the old PerformanceCounter MBean of JRockit. Again, these examples are using proprietary APIs that may break at any given release. Use responsibly!<\/p>\n<p><a href=\"https:\/\/hirt.se\/blog\/wp-content\/uploads\/2014\/02\/jrockit_duke_love.png\"><img loading=\"lazy\" decoding=\"async\" title=\"jrockit_duke_love\" style=\"border-top: 0px;border-right: 0px;border-bottom: 0px;border-left: 0px\" border=\"0\" alt=\"jrockit_duke_love\" src=\"https:\/\/hirt.se\/blog\/wp-content\/uploads\/2014\/02\/jrockit_duke_love_thumb.png\" width=\"244\" height=\"229\"><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, in JRockit there was this neat little dynamic MBean from which you could access all the JVM performance counters as attributes. Tonight I ended up in an e-mail thread leading me to think about how to retrieve the HotSpot ones. This is of course all very unsupported, and counter names\/content and even the very [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-513","post","type-post","status-publish","format-standard","hentry","category-java-mission-control-fair-dj"],"_links":{"self":[{"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/posts\/513","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=513"}],"version-history":[{"count":1,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/posts\/513\/revisions"}],"predecessor-version":[{"id":514,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=\/wp\/v2\/posts\/513\/revisions\/514"}],"wp:attachment":[{"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hirt.se\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}