Tuesday Feb 17, 2015

Welcome Raspberry Pi 2!

Having surpassed 4 million units shipped and clearly establishing itself as a de facto reference platform, the folks at the Raspberry Pi Foundation are not resting on their laurels.  Earlier this month (February 2015), they introduced the Raspberry Pi 2 Model B:

Compared to its predecessor, the Raspberry Pi B+, this newer model is packaged with a Broadcom BCM2836 SoC at 900MHz.  It is not only superior in performance to the original single core BCM2835 processor on core-by-core basis, it now brings the added benefit of including 4 cores.  Add to that a doubling of RAM from 512MB to 1GB and it should be no mystery that this new platform can handle more serious workloads.  Later on down, a chart compares the SPECjvm2008 benchmark performance of the original Raspberry Pi Model B with the new Raspberry Pi 2 Model B.

In addition to the substantial performance bump, major kudos are to be given to the Raspberry Pi Foundation engineers for their focus on hardware and software compatibility:

  • The Pi2 maintains the same physical form factor as the Raspberry Pi B+, meaning that all of the previous accessories (USB power cable, serial console cable, microSD card ...) all work perfectly well with the new version.  That also includes any Raspberry Pi B+ enclosures you may have too.
  • The ARMv7-based BCM2836 processor is backwards-compatible with the original ARMv6 version.  In order to maintain binary compatibility, the latest version of the Raspbian distribution will boot either the new or old versions of the Raspberry Pi.  Note that in this mode, applications will not be able to take full advantage of the ARMv7 enhancements.  Alternate OS distributions may provide the extra performance boost at the expense of breaking backwards compatibility.
  • Perhaps best of all, the Raspberry Pi maintains its appeal to the masses.  At approximately £23/$35, no price increase comes along with this upgrade.

A Brief Look at Performance

The chart that follows examines Raspberry Pi Java performance via the SPECjvm2008 benchmark.  Both original and Raspberry Pi 2 systems ran the latest available Raspbian Image (2015-02-02) and the latest available Java 7 JDK (Java 7 update 72)1.  The four vertical bars (blue, red, green, purple) represent four separate runs of the benchmark:

  1. Blue: Raspberry Pi Model B.  Invoked with JVM argument -Xmx400m specifying a maximum heap of 400MB.
  2. Red: Raspberry Pi 2, single threaded.  Invoked with JVM argument -Xmx400m specifying a maximum heap of 400MB, and application argument -bt 1 instructing the SPECjvm2008 test harness to run the benchmark tests with a single thread.  This is meant to approximate an apples-to-apples comparison of single core performance between the two Raspberry Pi systems.
  3. Green: Raspberry Pi 2, multithreaded (default).  Invoked with JVM argument -Xmx600m specifying a maximum heap of 600MB2.
  4. Purple: Raspberry Pi 2, multithreaded (default), larger heap.  Invoked with JVM argument -Xmx900m specifying a maximum heap of 900MB3.


The larger the measurement (ops/min), the faster the result, the single core performance of the Raspberry Pi 2 is a big improvement over its predecessor.  As the SPECjvm2008 suite does include a healthy dose of mutithreaded code, enabling the test harness to take advantage of the 4 hardware threads available to the Pi 2 added another huge jump in performance.  And finally utilizing the extra RAM (in the form of a larger heap) provided for by the Raspberry Pi 2 yields only a very modest gain in throughput.  In particular, 2 of the 11 component tests (compress, xml) show an improvement with the extra heap.  For more detailed results, you can view this spreadsheet.

The added horsepower that the Raspberry Pi 2 brings solidifies the Raspberry Pi family as an important reference platform in the present as well as the future for companies like Oracle.  As the Internet of Things phenomena plays out and more processing is brought to the edge, the new Raspberry Pi is better suited to handle the increased workload that applications like Oracle Event Processing for Oracle Java Embedded and others require.

Notes

1 The latest Raspbian distro includes a recent version of Oracle's Java 8 JDK.  Unfortunately the somewhat dated SPECjvm2008 benchmark has a dependency that requires Java 1.7 or earlier, so for these benchmarks, we needed to use a Java 7 JDK.  The latest available, 7u72, was used for these tests.

2 With 4 cores, the SPECjvm2008 test suite would produce an OutOfMemoryError when run with the initial max heap size argument of -Xmx400m.  Increasing the max heap size to 600MB (-Xmx600m) enabled the tests to complete.  Evidently SPECjvm2008 requires more heap space as more hardware threads are configured in.

3 In order to utilize the full amount of RAM (1GB) available with the Raspberry Pi 2, a firmware upgrade may be required.  If necessary, you can invoke 'sudo rpi-update'  from a linux shell on the Raspberry Pi 2 to accomplish this task.

Wednesday Jan 14, 2015

Managing Java Flight Recorder Enabled JVMs with SSL

One advantage Java Flight Recorder enjoys is that its event collection and profiling framework is built right into the JDK, allowing instrumented JVM instances to operate with near-zero overhead.  At arguably negligible expense, would it then make sense to consider enabling Java Flight Recorder on production applications?  We say absolutely!

You can google around to search for how this framework can be configured to monitor remote JVMs, and nearly all of the reference material will help you get up to speed quickly.  However, you'll find that these examples favor simplicity over security.  They generally disable authentication and encryption leaving the remote application vulnerable to anyone who knows or can guess its host name and port number.  In the real world, if you wanted to monitor a production application remotely, you'd need to carefully consider the security ramifications.

Not finding much in the way of instruction here, we thought it might be helpful to document, by example, how a sample remote Java application can be more securely instrumented and managed with Java Flight Recorder and Java Mission Control.  What follows are the steps necessary to enable monitoring over a connection that is secured using Secure Sockets Layer (SSL).

For the remainder of this article, we'll refer to the instrumented JVM as the remote side of the solution.  To demonstrate the ubiquity of the Java SE platform, our remote JVM will actually reside on a Raspberry Pi.  As Java SE and Java SE Embedded runtime environments both now bundle the Java Flight Recorder feature set, it doesn't really matter what type of remote JVM instance we have.  The location where the Java Mission Control application runs will be referred to as the client side.  For this example we'll use an Ubuntu-based system.  In reality, the client could have run on any of the alternative supported Java clients like Windows or MacOS.

On the remote side (hostname pi1):

Remote side, step 0: Create a directory to house the signed digital certificates required for SSL communication.  Moreover, it should have minimal access.

pi1$ mkdir $HOME/.certs
pi1$ chmod 700 $HOME/.certs

Remote side, step 1: Create a self-signed cryptographic key pair with the JDK keytool(1) utility.  The are many alternatives to creating (and requesting) cryptographic keys.  The method we'll use for this example is the most straightforward, as keytool is part of the JDK, not to mention the least expensive too!

pi1$ keytool -genkey -alias jfrremote -keyalg RSA -validity 730 \
-keystore $HOME/.certs/jfrremoteKeyStore
Enter keystore password: changeit
Re-enter new password: changeit
What is your first and last name?
[Unknown]:  Joe Schmo
What is the name of your organizational unit?
  [Unknown]:  Acme Corp
What is the name of your organization?
  [Unknown]:  Skunkworks
What is the name of your City or Locality?
  [Unknown]:  New York
What is the name of your State or Province?
  [Unknown]:  NY
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US correct?
  [no]:  yes

Enter key password for <jfrremote>
        (RETURN if same as keystore password):

Remote side, step 2: Restrict the access of the newly created jfrremoteKeyStore file.

pi1$ chmod 600 $HOME/.certs/jfrremoteKeyStore

Remote side, step 3: Verify that the keystore contains our newly created key:

pi1$ keytool -keystore $HOME/.certs/jfrremoteKeyStore -list -v
Enter keystore password: changeit

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: jfrremote
Creation date: 13-Jan-2015
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Issuer: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Serial number: 258d7624
Valid from: Tue Jan 13 17:32:51 UTC 2015 until: Thu Jan 12 17:32:51 UTC 2017
Certificate fingerprints:
         MD5:  2E:AD:5F:85:61:21:8D:1A:4B:ED:02:7C:67:26:8B:95
         SHA1: 82:12:D6:A0:4C:20:E4:7F:C5:C1:C7:BC:AD:C7:D1:E8:47:76:F2:A6
         SHA256: AF:E1:D8:7F:67:F3:DA:F1:22:58:42:B9:A5:50:37:6A:BA:49:76:BC:15:5F:11:9D:F0:1E:13:15:39:BB:9F:C4
         Signature algorithm name: SHA256withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 5E EC 1E F8 D5 33 F4 E6   29 06 B6 65 39 85 68 05  ^....3..)..e9.h.
0010: F7 19 B3 AF                                        ....
]
]


*******************************************
*******************************************

Remote side, step 4: Export the certificate associated with the recently generated key pair. This will be used by the remote JVM instance and also has to be imported into the trust store of the client application (Java Mission Control or jmc).

pi1$ keytool -export -alias jfrremote -keystore \
$HOME/.certs/jfrremoteKeyStore -rfc -file jfrremote.cer
Enter keystore password: changeit
Certificate stored in file <jfrremote.cer>

Remote side, step 5: Securely transfer the certificate stored in the jfrremote.cer file over to the system where the Java Mission Control client (jmc) will be run

Switching over to the client side (hostname R840):

Client side, step 0: Create a directory to house the signed digital certificates required for SSL communication, with minimal access.

R840$ mkdir $HOME/.certs
R840$ chmod 700 $HOME/.certs

Client  side, step 1: Import the certificate, represented by the jfrremote.cer file, into the client's trust store.

R840$ keytool -importcert -keystore $HOME/.certs/jfrremoteTrustStore \
-alias jfrremote -file jfrremote.cer
Enter keystore password: changeit
Re-enter new password: changeit
Owner: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Issuer: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Serial number: 4fec928c
Valid from: Tue Jan 13 08:41:48 EST 2015 until: Thu Jan 12 08:41:48 EST 2017
Certificate fingerprints:
        MD5:  3D:81:45:16:49:13:85:38:E8:E9:90:50:4A:59:F5:5E
         SHA1: 6E:FA:63:D7:9A:58:26:A4:22:94:33:9F:AA:1A:6C:B6:E4:16:2C:DE
         SHA256: 58:EB:F0:C9:DD:F9:D4:F7:FD:95:4B:2B:61:4C:88:6D:57:E3:87:9F:71:F5:BD:25:67:FB:3C:C0:05:0B:C6:0F
         Signature algorithm name: SHA256withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: D9 A6 A2 0E CE D2 F7 9D   FA 96 9C B9 9A 32 E2 3A  .............2.:
0010: 98 ED A7 5F                                        ..._
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Client side, step 2: Restrict the access of the newly created jfrremoteTrustStore file.

R840$ chmod 600 $HOME/.certs/jfrremoteTrustStore

Client side, step 3: Create a self-signed cryptographic key pair with the JDK keytool(1) utility.  This represents the certificate for the client-side Java Mission Control (jmc) application.

R840$ keytool -genkey -alias jmc -keyalg RSA -validity 730 \
-keystore $HOME/.certs/jmcKeyStore
Enter keystore password: changeit
Re-enter new password: changeit
What is your first and last name?
  [Unknown]:  Joe Schmo
What is the name of your organizational unit?
  [Unknown]:  Acme Corp
What is the name of your organization?
  [Unknown]:  Skunkworks
What is the name of your City or Locality?
  [Unknown]:  New York
What is the name of your State or Province?
  [Unknown]:  NY
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US correct?
  [no]:  yes

Enter key password for <jmc>
        (RETURN if same as keystore password):

Client side, step 4: Restrict the access of the newly created jmcKeyStore file.

R840$ chmod 600 $HOME/.certs/jmcKeyStore

Client side, step 5: Export the certificate associated with the recently generated key pair. This will be used by the Java Mission Control application and also has to be imported into the trust store of the remote JVM instance.

R840$ keytool -export -alias jmc -keystore $HOME/.certs/jmcKeyStore \
-rfc -file jmc.cer
Enter keystore password: changeit
Certificate stored in file <jmc.cer>

Client side, step 6: Securely transfer the certificate stored in the jmc.cer file over to the system where the remote JVM instance will be run

Returning to the remote side (hostname pi1):

Remote side, step 6: Import the certificate, represented by the jmc.cer file, into the remote JVM instance's trust store.

pi1$ keytool -import -alias jmc -file jmc.cer \
-keystore $HOME/.certs/jmcTrustStore
Enter keystore password: changeit
Re-enter new password: changeit
Owner: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Issuer: CN=Joe Schmo, OU=Acme Corp, O=Skunkworks, L=New York, ST=NY, C=US
Serial number: 860e0e4
Valid from: Tue Jan 13 20:15:33 UTC 2015 until: Thu Jan 12 20:15:33 UTC 2017
Certificate fingerprints:
        MD5:  7B:D7:F3:9D:71:52:F9:35:03:3A:68:BF:02:C2:52:51
         SHA1: 38:95:6D:2F:DE:FC:99:D6:63:55:00:A8:57:E2:31:FF:53:35:18:F7
         SHA256: 7D:87:87:01:E5:21:58:02:67:0E:7E:2F:14:77:86:12:9D:52:CD:11:A4:B1:C5:D3:32:D8:05:30:61:7B:F5:3E
         Signature algorithm name: SHA256withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 0A E8 E3 5E 0A 3C 48 FF   D4 DB 10 A8 62 31 1E F9  ...^.<H.....b1..
0010: 55 D8 4C 7A                                        U.Lz
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Remote side, step 7: Restrict the access of the newly created jmcTrustStore file.

pi1$ chmod 600 $HOME/.certs/jmcTrustStore

Putting it All Together

With key stores and trust stores set up on both sides, we can now start up both components.  Our sample application is a very simple one called Allocator.java. Download it onto your remote system and compile it with the javac program.  When ready, you can start up an SSL-enabled remote JVM instance of the Allocator program in continuous flight recorder mode with the following invocation:

pi1$ java \
-Dcom.sun.management.jmxremote.port=7091\
-Dcom.sun.management.jmxremote.ssl=true \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djavax.net.ssl.keyStore=$HOME/.certs/jfrremoteKeyStore \
-Djavax.net.ssl.keyStorePassword=changeit \
-Djava.rmi.server.hostname=pi1 \
-XX:+UnlockCommercialFeatures \
-XX:+FlightRecorder \
-XX:FlightRecorderOptions=defaultrecording=true \
Allocator

On the client side, Java Mission Control is started in the following way:

R840$ jmc -vmargs \
-Djavax.net.ssl.trustStore=$HOME/.certs/jfrremoteTrustStore \
-Djavax.net.ssl.trustStorePassword=changeit \
-Djavax.net.ssl.keyStore=$HOME/.certs/jmcKeyStore\
-Djavax.net.ssl.keyStorePassword=changeit

Once Java Mission Control has started, we connect to the VM instance on host pi1 as shown in the screenshots that follow.  First off, we select "Connect..." from the File menu.

A "New Connection" window appears.  Select "Create a new connection" and click the "Next>" button.

In the next window that appears, "pi1" is selected as the host and "7091" as the port.  Clicking the "Finish" button continues the process.


 And here's a screenshot of the MBean Server window for the JVM running on host pi1.

Conclusion

To assist in this repetitive and potentially error-prone task, a series of shell scripts have been created which just might be of use.  Download this tarball, and check out the README files found in the two directories, one for the remote side of the equation, the other for the client.

For further edification, please check out these links:

Marcus Hirt's blog for all things related to Java Flight Recorder and Java Mission Control
http://hirt.se/blog/

If you run into SSL handshake problems, this link may prove helpful.
How to Anazyze Java SSL Errors:
http://java.dzone.com/articles/how-analyze-java-ssl-errors

Erik Costlow's article on Self-signed certificates for a known community:
https://blogs.oracle.com/java-platform-group/entry/self_signed_certificates_for_a



Friday Oct 31, 2014

USB Device Access for Java SE and OSGi

One of the challenges in creating the content for the Java One 2014 Java SE Embedded Internet of Things Hands-on-Lab concerned interacting, via Java and OSGi, with a USB temperature sensor.   Unfortunately a USB communications API is not part of the Java SE standard (as of this post: Halloween 2014).  So the question is, how can Java/USB communication be established, and furthermore and how does this work within the OSGi framework?

In looking around at some of the available options, we chose the javahidapi as the basis for this connectivity.  As a Java/JNI wrapper around the C/C++ HID API for Linux, MacOS X and Windows, the appeal behind this API is that using it does not require the use of a custom driver for each device on each platform.

In order to operate within an OSGi framework (in this case Apache Felix 4.4), javahidapi's open source code has been slightly modified/enhanced. The end result is that an OSGi bundle is available that can be dropped into standard OSGi frameworks to support USB communication for HID devices.  It does contain a native component, and for the sake of simplicity, we've decided to include a separate jar file for each supported architecture.  For the OSGi enthusiast, here's what the generated MANIFEST.MF file looks like for the Linux/armhf (suitable for the Raspberry Pi) architecture:

Manifest-Version: 1.0
Bnd-LastModified: 1415889978962
Build-Jdk: 1.7.0_51
Built-By: jtconnor
Bundle-Activator: com.codeminders.hidapi.Activator
Bundle-ManifestVersion: 2
Bundle-Name: hidapi OSGi Bundle for Linux/armhf
Bundle-NativeCode: native/linux/armv6l/libhidapi-jni-32.so; osname=Linux; processor=armv6l
Bundle-SymbolicName: com.codeminders.hidapi-armhf
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: com.codeminders.hidapi;uses:="org.osgi.framework";version="1.0.0"
Import-Package: org.osgi.framework;version="[1.6,2)"
Tool: Bnd-1.50.0

Here are some pre-built hidapi OSGi bundles for popular Linux platforms:

To get a feel for the changes made to the original source, here's what was done:

  1. A NetBeans project was created under the Maven->OSGi Bundle category
  2. The Java source code for javahidapi was placed in the project's src/main/java/com/codeminders/hidapi directory
  3. The architecture specific native library was placed in the project's src/main/resources/native/linux/architecture directory.  For example, the Linux/x86 version of the project places the libhidapi-jni-32.so file in the src/main/resources/native/linux/x86 directory.
  4. An Activator.java class was added in the project's src/main/java/com/codeminders/hidapi directory.  In OSGi, the start() method in this class gets called when this bundle is activated.  It is specified in the bundle's MANIFEST.MF file.
  5. The original ClassPathLibraryLoader.java file was simplified and is currently only appropriate for Linux deployments.
  6. As this is a Maven-based project, the project's pom.xml file was edited (here's what the x86 version looks like), such that at build time it will generate a MANIFEST.MF file similar to the one referenced above.

And here are the associated NetBeans Projects which can be used to build the 4 bundles referenced above.

If you'd like to extend this template to include OSGi bundles for additional architectures, you can start with one of the projects above, clone it, and make the appropriate changes for your new environment.  If the native javahidapi component for your new platform is not available, you'll have to pull down the source for hidapi and build it for inclusion into your project.  If anyone is interested in going through this exercise, I'd be glad to post the fruits of their labor here.

Tuesday Aug 26, 2014

Java SE Embedded IoT Hands On Lab Returns for Java One 2014

After a one year hiatus, a Hands On Lab featuring Java SE for Embedded devices will return for The Java One 2014 Conference.  Entitled HOL2097 Java SE Embedded IoT Hands On Lab, students who attend this lab will:

  • Have their own individual embedded device to gain valuable hands on experience
  • Learn how to create Java 8 Compact Profiles using the eJDK jrecreate tool.  Students will use and deploy those Compact Profiles on their individual device.
  • Learn about profile-aware tools available both at the JDK and IDE (NetBeans) level that aid developers in creating Java applications suitable for specific Compact Profiles.
  • Learn about and utilize OSGi, an important Java-based modular service platform ideal for dynamically managing the lifecycle of software components, especially suited for gateway devices.
  • Attach a sensor to the gateway device and deploy a Java/OSGi bundle on the device to capture data from the sensor.
  • Build and deploy a Java/OSGi web service bundle on the gateway device that publishes data captured by the sensor.  Students will be able to remotely access this web service to retrieve the sensor data in standard JSON format.

For those attending the Java One 2014 Conference, seating for this lab is limited.  So reserve your spot early.  We could also conceivably host a smaller workshop at a customer location effectively duplicating this lab.  If you're interested, you can drop me a line at james.connors@oracle.com.

Friday Jun 20, 2014

Java Serial Communications Revisited

Last touched upon in this article dated August 2011, it's high time to revisit the state of Java serial port communications options for the following reasons:

  • As the hype around Internet of Things continues to ratchet up, serial communications are a requirement for a certain class of IoT sensors and devices.
  • RxTx, the platform with arguably the most history, cannot be built with the recently released Java 8 JDK without some modifications.
  • For some time now the website hosting the RxTx project: http://rxtx.qbang.org/wiki/index.php/Main_Page has not been available.
  • Building support for additional specifications like RS-485 and parallel is available in RxTx but was never addressed in the previous serial communications article.
  • An alternative framework called jSSC is gaining in popularity and is worth further discussion.
  • Work in the OpenJDK Device I/O Project is progressing. Among the goals of this project is support for serial communications.

RxTx

In my customer experiences, RxTx, despite its age, still gets mentioned most when considering serial communications with Java.  For whatever reasons, the RxTx project has gone off line, and access to the project source code is not readily available.  Fortunately, we have a copy, and have made a few enhancements such that:

  • The source can now be compiled with a JDK versions 6, 7 and 8.
  • The original article discussed only enough modifications to build the  librxtxSerial.so shared object required for traditional serial communications.  The librxtxParallel.so, librxtxRaw.so, librxtxI2C.so and librxtxRS485.so shared objects could not be built.  With some very slight modifications, these can successfully be built too.  I make absolutely no promises as to their usefulness, but they do compile. :)

The source code is based upon the original 2.1-7r2 version and in this instance is now called 2.1.7r2-Java8.  You can download the source here.  If you want to get a feel for the changes made, take a look at this file:  JAVA8_MODS.txt which can be found in the main directory of the source code.  To build RxTx on your native platform:

   $ tar xvf 2.1.7r2-Java8.tar.gz
   $ cd 2.1.7r2-Java8/
   $ ./configure
   $ make

jSSC

The Java Simple Serial Connector, or jSSC for short, is another open source project that can be found here: http://code.google.com/p/java-simple-serial-connector/.  It is available for a host of processor/OS combinations and, in addition to source availability, comes bundled in binary form too.  Here's a list of supported platforms for its current 2.6.0 release:

Win32 Win64 Linux_x86 Linux_x86_64 Linux_ARM Solaris_x86 Solaris_x86_64 MacOSX_x86 MacOSX_x86_64 MacOSX_PPC MacOSX_PPC64

Like RxTx, it contains a native component but is packaged in a nice transparent fashion.  The one potential challenge here may be in trying to figure out how to support a new platform that isn't on this list.  I didn't have a whole lot of success finding out how to build the binary, and admittedly didn't spend an inordinate amount of time trying to figure it out either.  Nonetheless, this project is gaining in popularity and has a dedicated individual supporting the software.

OpenJDK Device I/O

Finally, a project is underway to treat serial communication and device I/O in general as a first class citizen for the Java SE standard. The wiki can be found here: https://wiki.openjdk.java.net/display/dio/Main. It is based on the work done to provide device I/O to the Java ME 8 platform.  Further solidifying the universality theme of Java 8, the ultimate goal would be to have a consistent device I/O API across both Java SE and Java ME.  If you want to further understand what those APIs look like you can view them here: http://docs.oracle.com/javame/8.0/api/dio/api/index.html.

In conclusion, support for serial communications in Java SE is -- albeit slowly -- progressing.  There are multiple open source projects and commercial alternatives too.  Ideally, it will be great to see a formal API supported by the Java SE Standard.

Monday Mar 17, 2014

An Embedded Java 8 Lambda Expression Microbenchmark

It's been a long road, but Java 8 has finally arrived.  Much has been written and said about all the new features contained in this release, perhaps the most important of these is the introduction of Lambda Expressions.  Lambdas are now intimately integrated into the Java platform and they have the potential to aid developers in the traditionally tricky realm of parallel programming.

Following closely behind, Compact Profiles promise to open up the tremendous benefits of Java Standard Edition compatibility to embedded platforms previously thought to be too small.  Can you see where this is heading?  It might be interesting to use these two technologies simultaneously and see how well they work together.  What follows is the description of a small program and its performance measurements -- a microbenchmark if you will -- that aims to highlight how programming with the new Lambda Expression paradigm can be beneficial not only for typical desktops and servers, but also for a growing number of embedded platforms too.

The Hardware/OS Platform(s)

Of primary interest for this article is the Boundary Devices BD-SL-i.MX6 single board computer.  It is a quad-core ARM® Cortex™-A9 based system with 1GB RAM running an armhf  Debian Linux distribution.  At the time of this article's publication, its list price is US $199.

imx6q_sabrelite_top1

What makes it more interesting is that we'll not only run Java 8 Lambda Expressions on device, we'll do it within the confines of the new Java 8 Compact1 profile.  The static footprint of this Java runtime environment is 10½ MB.

A second system, altogether different in capability and capacity from our embedded device will be used as a means to compare and contrast execution behavior across disparate hardware and OS environments.  The system in question is a Toshiba Tecra R840 laptop running Windows 7/64-bit.  It has a dual-core Intel® Core™ i5-2520M processor with 8GB RAM and will use the standard Java 8 Runtime Environment (JRE) for Windows 64-bit.

The Application

Looking for a sample dataset as the basis for our rudimentary application, this link provides an ideal (and fictional) database of employee records.  Among the available formats, a comma-delimited CSV file is supplied with approximately 300,000 entries.  Our sample application will read this file and store the employee records into a LinkedList<EmployeeRec>.  The EmployeeRec has the following  fields:

public class EmployeeRec {
    private String id;
    private String birthDate;
    private String lastName;
    private String firstName;
    private String gender;
    private String hireDate;
    ...
}

With this data structure initialized, our application is asked to perform one simple task:  calculate the average age of all male employees.

Old School

First off let's perform this calculation in a way that predates the availability of Lambda Expressions.  We'll call this version OldSchool.  The code performing the "average age of all male employees" calculation looks like this:

double sumAge = 0;
long numMales = 0;
for (EmployeeRec emp : employeeList) {
    if (emp.getGender().equals("M")) {
        sumAge += emp.getAge();
        numMales += 1;
    }
}
double avgAge = sumAge / numMales;

Lamba Expression Version 1

Our second variation will use a Lambda expression to perform the identical calculation.  We'll call this version Lamba stream().  The key statement in Java 8 looks like this:

double avgAge = employeeList.stream()
                .filter(s -> s.getGender().equals("M"))
                .mapToDouble(s -> s.getAge())
                .average()
                .getAsDouble();

Lambda Expression Version 2

Our final variation uses the preceding Lambda Expression with one slight modification: it replaces the stream() method call with the parallelStream() method, offering the potential to split the task into smaller units running on separate threads.  We'll call this version Lambda parallelStream(). The Java 8 statement looks as follows:

double avgAge = employeeList.parallelStream()
                .filter(s -> s.getGender().equals("M"))
                .mapToDouble(s -> s.getAge())
                .average()
                .getAsDouble();

Initial Test Results

The charts that follow display execution times of the sample problem solved via our three aforementioned variations.  The left chart represents times recorded on the ARM Cortex-A9 processor while the right chart shows recorded times for the Intel Core-i5.  The smaller the result, the faster, both examples indicate that there is some overhead to utilizing a serial Lambda stream() over and above the old school pre-Lambda solution.  As far as parallelStream() goes, it's a mixed bag.  For the Cortex-A9, the parallelStream() operation is negligibly faster than the old school solution, whereas for the Core-i5, the overhead incurred by parallelStream() actually makes the solution slower.

Without any further investigation, one might conclude that parallel streams may not be worth the effort. But what if performing a trivial calculation on a list of 300,000 employees simply isn't enough work to show the benefits of parallelization?  For this next series of tests, we'll increase the computational load to see how performance might be effected.

Adding More Work to the Test

For this version of the test, we'll solve the same problem, that is to say, calculate the average age of all males, but add a varying amount of intermediate computation.  We can variably increase the number of required compute cycles by introducing the following identity method to our programs:

/*
 * Rube Goldberg way of calculating identity of 'val',
 * assuming number is positive
 */
private static double identity(double val) {
    double result = 0;
    for (int i=0; i < loopCount; i++) {
        result += Math.sqrt(Math.abs(Math.pow(val, 2)));    
    }
    return result / loopCount;

}

As this method takes the square root of the square of a number, it is in essence an expensive identity function. By changing the value of loopCount (this is done via command-line option), we can change the number of times this loop executes per identity() invocation.  This method is inserted into our code, for example with the Lambda ParallelStream() version, as follows:

double avgAge = employeeList.parallelStream()
                .filter(s -> s.getGender().equals("M"))
                .mapToDouble(s -> identity(s.getAge()))
                .average()
                .getAsDouble();

A modification identical to what is highlighted in red above is also applied to both Old School and Lambda Stream() variations.  The charts that follow display execution times for three separate runs of our microbenchmark, each with a different value assigned to the internal loopCount variable in our Rube Goldberg identity() function.

For the Cortex-A9, you can clearly see the performance advantage of parallelStream() when the loop count is set to 100, and it becomes even more striking when the loop count is increased to 500.  For the Core-i5, it takes a lot more work to realize the benefits of parallelStream().  Not until the loop count is set to 50,000 do the performance advantages become apparent.  The Core-i5 is so much faster and only has two cores; consequently the amount of effort needed to overcome the initial overhead of parallelStream() is much more significant.

Downloads

The sample code used in this article is available as a NetBeans project.  As the project includes a CSV file with over 300,000 entries, it is larger than one might expect.  The blogs.oracle.com  site prohibits storing files larger than 2MB in size so this project source has been compressed and split into three parts.  Here are the links:

Just concatenate the three downloaded files together to recreate the original LambdaMicrobench.zip file.  In Linux, the command would look something like this:

$ cat LambdaMicrobench.zip.part? > LambdaMicrobench.zip

Conclusion

A great deal of effort has been put into making Java 8 a much more universal platform.  Our simple example here demonstrates that even an embedded Java runtime environment as small as 10½ MB can take advantage of the latest advances to the platform.  This is just the beginning.  There is lots more work to be done to further enhance the performance characteristics of parallel stream Lambda Expressions.  We look forward to future enhancements.

Monday Mar 10, 2014

Introducing the EJDK

In lock step with the introduction of Compact Profiles, Java 8 includes a new distribution mechanism for Java SE Embedded called the EJDK.  As the potential exists to confuse the EJDK with the standard JDK (Java Development Kit), it makes sense to dedicate a few words towards highlighting how these two packages differ in form and function.

The JDK

The venerable Java Development Kit is the mainstay of Java developers.  It incorporates not only a standard Java Runtime Environment (JRE), but also includes critical tools required by those same developers.  For example, among many others, the JDK comes with a Java compiler (javac), a Java console application (jconsole), the Java debugger (jdb) and the Java archive utility (jar).  It also serves as the underpinnings for very popular Java Integrated Development Environments (IDEs) such as NetBeans, Eclipse, JDeveloper and IntelliJ to name a few.

Like Java, the Java Development Kit is constantly evolving, and Java 8 brings about its fair share of enhancements to the JDK.  For Java 8, javac can now be instructed (via the -profile command-line option) to insure that your source code is compatible with a specific compact profile.  Furthermore, the Java 8 JDK comes with a new useful tool called jdeps, providing a means to analyze your compiled class and jar files for dependencies.

The EJDK

The EJDK is new to Java 8, and although similar in namesake to the JDK, it serves quite a different purpose.  Prior to Java 8, supported Java SE-Embedded runtime platforms were provided as binaries by Oracle.  With the advent of Compact Profiles, the number of possible binary options per supported platform would simply be too unweildy.  Rather than furnishing binaries for each of the possible combinations, an EJDK will be supplied for each supported Java SE-Embedded platform.  It contains the tools needed to create the profile you wish to use.

The EJDK is designed to be run with either Windows or Linux/Unix platforms alongside a Java runtime environment.  It contains a wrapper called jrecreate (jrecreate.sh for Unix/Linux and jrecreate.bat for Windows) whose function it is to create deployable compact profile instances. In the examples that follow, we'll show two sample invocations.

First off, let's briefly take a look at the contents of a typical EJDK.   For our first example, we've installed the EJDK on a linux/x86 system.   Listing the contents of the ejdk1.8.0/ directory, we see a subdirectory named linux_arm_vfp_hflt/.  This tells us what platform this instance of the EJDK supports.  For all our examples we'll use an EJDK that creates compact profiles suitable for Linux/Arm Hard Float platform, often times referred to as armhf.

$ ls ejdk1.8.0
bin  doc  lib  linux_arm_vfp_hflt

Looking one level deeper into the bin/ directory, we see the jrecreate.bat and jrecreate.sh files:

$ ls ejdk1.8.0/bin
jrecreate.bat  jrecreate.config.properties  jrecreate.sh

As we're on a Linux system, let's use the jrecreate.sh script to create a compact profile:

$ ./ejdk1.8.0/bin/jrecreate.sh --profile compact1 --dest compact1-minimal --vm minimal

Briefly reviewing this invocation, the --profile compact1 option instructs jrecreate to use the Compact1 profile.  The --profile option accepts [compact1 | compact2 | compact3]  as an argument. The --dest compact1-minimal option specifies the name of the destination directory containing the newly generated profile.  Note that the directory argument to --dest must not exist prior to invocation.  Finally, the --vm minimal option tells jrecreate to use the minimal (i.e. the smallest) virtual machine for this instance.  The --vm option accepts  [minimal | client | server | all] as an argument.  Running the complete jrecreate.sh command, we get the following output:

$ ./ejdk1.8.0/bin/jrecreate.sh --profile compact1 --dest compact1-minimal --vm minimal
Building JRE using Options {
   ejdk-home: /home/java8/ejdk1.8.0
    dest: /home/java8/compact1-minimal
    target: linux_arm_vfp_hflt
    vm: minimal
    runtime: compact1 profile
    debug: false
    keep-debug-info: false
    no-compression: false
    dry-run: false
    verbose: false
    extension: []
}

Target JRE Size is 10,595 KB (on disk usage may be greater).
Embedded JRE created successfully

This creates a Compac1 profile distribution of about 10 ½ MB in the compact-1-minimal/ directory.  For our second example, we'll create a profile based on Compact2 and the client VM, this time from a Windows 7/64-bit system:

c:\demo>ejdk1.8.0\bin\jrecreate.bat --profile compact2 --dest compact2-client --vm client
Building JRE using Options {
    ejdk-home: c:\demo\ejdk1.8.0\bin\..
    dest: c:\demo\compact2-client
    target: linux_arm_vfp_hflt
    vm: client
    runtime: compact2 profile
    debug: false
    keep-debug-info: false
    no-compression: false
    dry-run: false
    verbose: false
    extension: []
}

Target JRE Size is 17,552 KB (on disk usage may be greater).
Embedded JRE created successfully

This Compact2 instance is created in the compact2-client/ directory and has an approximate footprint of 17 ½ MB.  Additional options to jrecreate are available for further customization.

Finally, lets migrate the generated profiles over to a real device.  As a host platform we'll use none other than the ubiquitous Raspberry Pi.  Here's a listing of the two profiles and their size (in 1K blocks) on the filesystem:

pi@pi0 ~/java8 $ ls
compact1-minimal  compact2-client

pi@pi0 ~/java8 $ du -sk compact*
10616   compact1-minimal
17660   compact2-client

And here's what each version outputs when java -version is run:

pi@pi0 ~/java8 $ ./compact1-minimal/bin/java -version
java version "1.8.0"
Java(TM) SE Embedded Runtime Environment (build 1.8.0-b127, profile compact1, headless)
Java HotSpot(TM) Embedded Minimal VM (build 25.0-b69, mixed mode)

pi@pi0 ~/java8 $ ./compact2-client/bin/java -version
java version "1.8.0"
Java(TM) SE Embedded Runtime Environment (build 1.8.0-b127, profile compact2, headless)
Java HotSpot(TM) Embedded Client VM (build 25.0-b69, mixed mode)

In conclusion, you are encouraged to experiment with the EJDK.  It will very quickly give you a feel for the compact profile configuration options available for your device.

Friday Dec 06, 2013

Java SE Embedded Pricing Explained

You're probably asking yourself, "Pricing?  Really?  In a techie blog?", and I would normally agree wholeheartedly with your assessment.  But in this one instance the topic might be worthy of a few words.  There is, as the expression goes, no such thing as a free lunch.  Whether you pay for software outright, or roll your own with open source projects, a cost must be paid.

Like clockwork, we regularly receive inquiries for Java embedded information that go something like this:

Dear Oracle,  We've downloaded and evaluated Java SE-Embedded and have found it to be a very appealing platform to run our embedded application.  We understand this is commercial software; before we decide to deploy our solution with your runtime, can you give us a feel for the royalties associated with shipping x number of units?

Seems pretty straightforward, right?  Well, yes, except that in the past Oracle required the potential customer to sign a non-disclosure agreement prior to receiving any embedded pricing information.  It didn't matter if the customer was interested in deploying ten units or ten thousand, they all had to go through this process.  Now certain aspects of pricing may still require confidential agreements, but why not make quantity 1 list prices available?   With the release of this document, that pricing information is now public.

The evidence is out there, both anecdotal and real, demonstrating that Oracle's Java SE-Embedded platform is unquestionably superior in quality and performance to the OpenJDK variants.  For the latest example, take a look at this blog entry.  So the question becomes, is it actually more affordable to pay for a commercial platform that is fully supported, faster and more reliable or to opt for a "free" platform and support it yourself.

So What Does Java SE-Embedded Cost?

The universal answer to such a question is: it depends.  That is to say it depends upon the capability of the embedded processor.  Before we lose you, let's show the list price for Java embedded licensing associated with three platforms and then explain how we arrived at the numbers.  As of the posting of this entry, 06 December, 2013, here they are:

  1. Per-unit cost for a Raspberry Pi: US $0.71
  2. Per-unit cost for system based on Intel Atom Z510P: US $2.68
  3. Per-unit cost for a Compulab Trim-Slice: US $5.36

How Does It Work?

These bullet points help describe the process, then we'll show how we arrived at our three sample platform prices.

  • Pricing is done on a per-core basis.
  • Processors are classified based on their capability and assigned a core factor.  The more capable the processor, the higher the core factor.
  • Per-core pricing is determined by multiplying the standard per-core Java embedded price by the core factor.
  • A 19% Software Update License & Support Fee is automatically added onto each system.

The core factor table that follows, found in the Oracle Java Embedded Global Price List, dated September 20, 2013, groups processors of similar capabilities into buckets called chip classes.  Each chip class is assigned a core factor.


Example 1

To compute the per-unit cost, use this formula:

Oracle Java Embedded per-core license fee  *  core factor  *  number of cores  *  support uplift

The standard per-core license fee is always $300.  The Raspberry Pi is a Class I device and therefore has a core factor of .002.  There is only one core in the Raspberry Pi, and the Software Update License & Support fee is always 19%.  So plugging in the numbers, we get:

$300  *  .002  *  1  *  1.19  =  $0.714

Example 2

The processor in this example, the Intel Atom Z510P, is a Class II device and has a core factor of .0075.  Using the same formula from Example 1, here's what we get:

$300  *  .0075  *  1  *  1.19  =  $2.6775

Example 3

The processor for the Trim-Slice is based on the ARM Cortex-A9, a Class II device.  Furthermore it is a dual-core system.  Using the same formula as the previous examples, we arrive at the following per-unit pricing:

$300  *  .0075  *  2  *  1.19  = $5.355

Conclusion

With your hardware specs handy, you should now have enough information to make a reasonable estimate of Oracle Java embedded licensing costs.  At minimum, it could be a help in your "buy vs. roll your own" decision making process.  And of course, if you have any questions, don't be afraid to ask.


Monday Oct 14, 2013

Oracle Java Now Part of Raspberry Pi Raspian Distribution

Having sold more than 1.75 million units in its brief lifespan, there is no denying the profound impact the Raspberry Pi has had on the embedded development community.  Amid all the hoopla surrounding the recently completed Oracle OpenWorld and Java One events, one announcement that flew under the radar dealt with the fact that the Oracle JDK is now part of the Raspberry Pi Raspian distribution.

This means that by default, when you download and install the latest Raspian distribution on your Raspberry Pi, the Oracle Java runtime environment and development tools are automatically part of the list of packages installed.  Here's a screenshot showing a login session to a Raspberry Pi running the 2013-09-25-wheezy-raspian distribution.  The JDK is installed as the oracle-java7-jdk package and is utilizing the Java 7u40 release.

For those who either cannot or do not wish to perform an entire Raspian upgrade, the Oracle JDK is available via the following command:

$ sudo apt-get update && sudo apt-get install oracle-java7-jdk

Great news.

Tuesday Sep 17, 2013

Comparing Linux/Arm JVMs Revisited

It's been about 18 months since we last compared Linux/Arm JVMs, and with the formal release of the much anticipated Java SE Embedded for Arm hard float binary, it marks a good time to revisit JVM performance.  The information and results that follow will highlight the following comparisons:

  1. Java SE-E Arm VFP (armel) vs. Arm Hard Float (armhf)
  2. Java SE-E armhf Client Compiler (c1) vs. armhf Server Compiler (c2)
  3. And last but certainly not least ... Java SE-E 7u40 armhf vs. Open JDK armhf

The Benchmark

For the sake of simplicity and consistency, we'll use a subset of the DaCapo benchmark suite.  It's an open source group of real world applications that put a good strain on a system both from a processor and memory workload perspective. We are aware of customers who use DaCapo to gauge performance, and due to its availability and ease of use, enables anyone interested to run their own set of tests in fairly short order.

The Hardware

It would have been grand to run all these benchmarks on one platform, most notably the beloved Raspberry Pi, but unfortunately it has its limitations:

  • There is no Java SE-E server compiler (c2) for the Raspberry Pi.  Why?  Because the Pi is based on an ARMv6 instruction set whereas the Java SE-E c2 compiler requires a minimum ARMv7 instruction set.
  • Demonstrating how rapidly advances are being made in the hardware arena, the Raspberry Pi, within the context of these tests, is quite a humble platform.  With 512MB RAM, it runs out of memory when running some of the large DaCapo component applications.
For these tests we'll primarily use a quad-core Cortex-A9 based system, and for one test we'll utilize a single core Marvell Armada system just to compare what effect the number of cores has on server compiler performance.  The devices in question are:
  1. Boundary Devices BD-SL-i.MX6, quad core 1GHz Cortex-A9 (Freescale i.MX6), 1GB RAM, Debian Wheezy distribution, 3.0.35 kernel (for both armel and armhf configurations)
  2. GlobalScale D2Plug, single core 800MHz ARMv6/v7 processor (Marvell PXA510), 1GB RAM, Debian Wheezy distribution, 3.5.3-cubox-di+ kernel for armhf

Java SE-E armel vs. armhf

The chart that follows compares the relative performance of the armel JavaSE-E 7u40 JRE with the armhf JavaSE-E 7u40 JRE for 8 of the DaCapo component applications.  These tests were conducted on the Boundary Devices BD-SL-i.MX6.  Both armel and armhf environments were based on the Debian Wheezy distribution running a 3.0.35 kernel.  For all charts, the smaller the result, the faster the run.

In all 8 tests, the armhf binary is faster, some only slightly, and in one case (eclipse) a few percentage points faster.  The big performance gain associated with the armhf standard deals with floating point operations, and in particular, the passing of arguments directly into floating point registers.  The performance gains realized by the newer armhf standard will be seen more in the native application realm than for Java SE-Embedded primarily because  the Java SE-E armel VM already uses FP registers for Java floating point methods.  There are still however certain floating point workloads that may show a modest performance increase (in the single digit percent range) with JavaSE-E armhf over Java SE-E armel.

Java SE-E Client Compiler (c1) vs. Server Compiler (c2)

In this section, we'll show tests results for two different platforms, the first a single core system, followed by the same tests on a quad-core system.  To further demonstrate how workload changes performance, we'll take advantage of the ability to run the DaCapo component applications in three different modes: small, default (medium) and large.  The first chart displays the aggregate time required to run the tests for the three modes, utilizing both the 7u40 client (c1) compiler and the server (c2) compiler.  As expected, c1 outperforms c2 by a wide margin for the tests that run only briefly.  As the total time to run the tests increases from small to large, the c2 compiler gets a chance to "warm up" and close the gap in performance.  But it never does catch up.  

Contrast the first chart with the one that follows where small, medium and large versions of the tests were run on a quad core system.  The c2 compiler is better able to utilize the additional compute resources supplied by this platform, the result being that initial gap in performance between c1 and c2 for the small version of the test is only 19%.  By the time we reach the large version, c2 outperforms c1 by 7%.  The moral of the story here is, given enough resources, the server compiler might be the better of the VMs for your workload if it is a long-lived process.

Java SE-E 7u40 armhf vs. Open JDK armhf

For this final section, we'll break out performance on an application-by-application basis for the following JRE/VMs:

  • Java SE Embedded 7u40 armhf Client Compiler (c1)
  • Java SE Embedded 7u40 armhf Server Compiler (c2)
  • OpenJDK 7 IcedTea 2.3.10 7u25-2.3.10-1~deb7u1 OpenJDK Zero VM (build 22.0-b10, mixed mode)
  • OpenJDK 7 IcedTea 2.3.10 7u25-2.3.10-1~deb7u1 JamVM (build 1.6.0-devel, inline-threaded interpreter with stack-caching)
  • OpenJDK 6 IcedTea6 1.12.6 6b27-1.12.6-1~deb7u1 OpenJDK Zero VM (build 20.0-b12, mixed mode)
  • OpenJDK 6 IcedTea6 1.12.6 6b27-1.12.6-1~deb7u1 JamVM (build 1.6.0-devel, inline-threaded interpreter with stack-caching)
  • OpenJDK IcedTea6 1.12.6 6b27-1.12.6-1~deb7u1 CACAO (build 1.6.0+r68fe50ac34ec, compiled mode)

The OpenJDK packages were pulled from the Debian Wheezy distribution.

It appears the bulk of performance work to OpenJDK/Arm still revolves around the OpenJDK 6 platform even though Java 7 was released over two years ago (and Java 8 is coming soon).  Regardless, Java SE still outperforms most OpenJDK tests by a wide margin, and perhaps more importantly appears to be the much more reliable platform considering the number of tests that failed with the OpenJDK variants.  As demonstrated in previous benchmark results, the older armel OpenJDK VMs appear to be more stable than the armhf versions tested here.  Considering the stated direction by the major linux distributions is to migrate towards the armhf binary standard, this is a bit eye opening.

As always, comments are welcome.



Monday Aug 12, 2013

Compact Profiles Demonstrated

Following up on an article introducing compact profiles, the video that follows demonstrates how this new feature in the upcoming Java 8 release can be utilized.  The video:

  • Describes the compact profile feature and the rationale for its creation.
  • Shows how to use the new jrecreate utility to generate compact profiles that can be readily deployed.
  • Demonstrates that even the smallest of profiles (less than 11MB) is robust enough to support very popular and important software frameworks like OSGi.

The software demonstrated is in early access.  For those interested in trying it out before the formal release of Java 8, there are two options:

  1. Members of the Oracle Partner Network (OPN) with a gold membership or higher can download the early access Java 8 binaries of Java SE-Embedded shown here.  For those not at this level, it may still be possible to get early access software, but it will require a qualification process beforehand.
  2. It's not as intimidating as it sounds, you can pull down the source code for OpenJDK 8, and build it yourself.  By default, compact profiles are not built, but this forum post shows you how.  The reference platform for this software is linux/x86.  Functionally, the generated compact profiles will contain the pared down modules for each compact profile, but you'll find the footprint for each to be much larger than the ones demonstrated in this video, as none of the Java SE-Embedded space optimizations are performed by default.

Not having any premium privileges on YouTube, the maximum allowed length of a video is 15 minutes.  There's actually lots more to talk about with compact profiles, including enhancements to java tools and utilities (javac, jar, jdeps, and the java command itself) that have incorporated intelligence for dealing with profiles.

Hmm.  Maybe there's an opportunity for a Compact Profiles Demonstrated Part II?


Wednesday Jul 31, 2013

An Introduction to Java 8 Compact Profiles

Java SE is a very impressive platform indeed, but with all that functionality comes a large and ever increasing footprint.  It stands to reason then that one of the more frequent requests from the community has been the desire to deploy only those components required for a particular application instead of the entire Java SE runtime environment.  Referred to as subsetting, the benefits of such a concept would seem to be many:

  • A smaller Java environment would require less compute resources, thus opening up a new domain of devices previously thought to be too humble for Java.
  • A smaller runtime environment could be better optimized for performance and start up time.
  • Elimination of unused code is always a good idea from a security perspective.
  • If the environment could be pared down significantly, there may be tremendous benefit to bundling runtimes with each individual Java application.
  • These bundled applications could be downloaded more quickly.

Despite these perceived advantages, the platform stewards (Sun, then Oracle) have been steadfast in their resistance to subsetting.  The rationale for such a stance is quite simple: there was sincere concern that the Java SE platform would fragment.  Agree or disagree, the Java SE standard has remained remarkably in tact over time.  If you need any further evidence of this assertion, compare the state of Java SE to that of Java ME, particularly in the mobile telephony arena.  Better still, look how quickly Android has spawned countless variants in its brief lifespan.

Nonetheless, a formal effort has been underway having the stated goal of providing a much more modular Java platform.  Called Project Jigsaw, when complete, Java SE will be composed of a set of finer-grained modules and will include tools to enable developers to identify and isolate only those modules needed for their application.  However, implementing this massive internal change and yet maintaining compatibility has proven to be a considerable challenge.  Consequently full implementation of the modular Java platform has been delayed until Java 9.

Understanding that Java 9 is quite a ways off, an interim solution will be available for Java 8, called Compact Profiles.  Rather than specifying a complete module system, Java 8 will define subset profiles of the Java SE platform specification that developers can use to deploy.  At the current time three compact profiles have been defined, and have been assigned the creative names compact1, compact2, and compact3. The table that follows lists the packages that comprise each of the profiles.  Each successive profile is a superset of its predecessor.  That is to say, the compact2 profile contains all of the packages in compact1 plus those listed under the compact2 column below.  Likewise, compact3 contains all of compact2 packages plus the ones listed in the compact3 column.

compact1                     compact2                    compact3
--------------------------   -----------------------     --------------------------
java.io                      java.rmi                    java.lang.instrument
java.lang                    java.rmi.activation         java.lang.management
java.lang.annotation         java.rmi.registry           java.security.acl
java.lang.invoke             java.rmi.server             java.util.prefs
java.lang.ref                java.sql                    javax.annotation.processing
java.lang.reflect            javax.rmi.ssl               javax.lang.model
java.math                    javax.sql                   javax.lang.model.element
java.net                     javax.transaction           javax.lang.model.type
java.nio                     javax.transaction.xa        javax.lang.model.util
java.nio.channels            javax.xml                   javax.management
java.nio.channels.spi        javax.xml.datatype          javax.management.loading
java.nio.charset             javax.xml.namespace         javax.management.modelbean
java.nio.charset.spi         javax.xml.parsers           javax.management.monitor
java.nio.file                javax.xml.stream            javax.management.openmbean
java.nio.file.attribute      javax.xml.stream.events     javax.management.relation
java.nio.file.spi            javax.xml.stream.util       javax.management.remote
java.security                javax.xml.transform         javax.management.remote.rmi
java.security.cert           javax.xml.transform.dom     javax.management.timer
java.security.interfaces     javax.xml.transform.sax     javax.naming
java.security.spec           javax.xml.transform.stax    javax.naming.directory
java.text                    javax.xml.transform.stream  javax.naming.event
java.text.spi                javax.xml.validation        javax.naming.ldap
java.util                    javax.xml.xpath             javax.naming.spi
java.util.concurrent         org.w3c.dom                 javax.script
java.util.concurrent.atomic  org.w3c.dom.bootstrap       javax.security.auth.kerberos
java.util.concurrent.locks   org.w3c.dom.events          javax.security.sasl
java.util.jar                org.w3c.dom.ls              javax.sql.rowset
java.util.logging            org.xml.sax                 javax.sql.rowset.serial
java.util.regex              org.xml.sax.ext             javax.sql.rowset.spi
java.util.spi                org.xml.sax.helpers         javax.tools
java.util.zip                                            javax.xml.crypto
javax.crypto                                             javax.xml.crypto.dom
javax.crypto.interfaces                                  javax.xml.crypto.dsig
javax.crypto.spec                                        javax.xml.crypto.dsig.dom
javax.net                                                javax.xml.crypto.dsig.keyinfo
javax.net.ssl                                            javax.xml.crypto.dsig.spec
javax.security.auth                                      org.ieft.jgss
javax.security.auth.callback
javax.security.auth.login
javax.security.auth.spi
javax.security.auth.x500
javax.security.cert

You may ask what savings can be realized by using compact profiles?  As Java 8 is in pre-release stage, numbers will change over time, but let's take a look at a snapshot early access build of Java SE-Embedded 8 for ARMv5/Linux.  A reasonably configured compact1 profile comes in at less than 14MB.  Compact2 is about 18MB and compact3 is in the neighborhood of 21MB.  For reference, the latest Java 7u21 SE Embedded ARMv5/Linux environment requires 45MB.

So at less than one-third the original size of the already space-optimized Java SE-Embedded release, you have a very capable runtime environment.  If you need the additional functionality provided by the compact2 and compact3 profiles or even the full VM, you have the option of deploying your application with them instead.

In the next installment, we'll look at Compact Profiles in a bit more detail.


Saturday Mar 16, 2013

Is it armhf or armel?

Arm processors come in all makes and sizes, a certain percentage of which address a market where cost, footprint and power requirements are at a premium.  In this space, the inclusion of even a floating point unit would be considered an unnecessary luxury.  To perform floating point operations with these processors, software emulation is required.

Higher-end Arm processors come bundled with additional capability that enables hardware execution of floating point operations.  The difference between these two architectures gave rise to two separate Embedded Application Binary Interfaces or EABIs for ARM: soft float and VFP (Vector Floating Point).  Although there is forward compatibility between soft and hard float, there is no backward compatibility.  And in fact, when it comes to providing binaries for Java SE Embedded for Arm, Oracle provides two separate options: a soft float binary and a VFP binary.  In the Linux community, releases built upon both these EABIs are refereed to as armel based distributions.

Enter armhf.  Although a big step up in performance, the VFP EABI utilizes less-than-optimal argument passing when a floating point operations take place.  In this scenario, floating point arguments must first be passed through integer registers prior to executing in the floating point unit.  A new EABI, referred to as armhf optimizes the calling convention for floating point operations by passing arguments directly into floating point registers.  It furthermore includes a more efficient system call convention.  The end result is applications compiled with the armhf standard should demonstrate modest performance improvement in some cases, and significant improvement for floating point intensive applications.

Alas, armhf represents yet another binary incompatible standard, but one that has already gained considerable traction in the community. Although still relatively early, the transition from armel to armhf is underway.  In fact, Ubuntu has already announced that future releases will only be built to the armhf standard, effectively obsoleting armel. As mentioned in Henrik's Stahl's Blog, an armhf version of Java SE Embedded is in the works, and we have already made available a armhf-based developer Preview of JDK 8 with JavaFX.

In the interim, we will have to deal with the incompatibilities between armel and armhf.  Most recently we've seen a rash of failed attempts to run the ArmV7 VFP Java SE Embedded binary on top of an armhf-based Linux distro.  During diagnosis, the question becomes, how can I determine whether my Linux distribution is based on armel or armhf?  Turns out this is not as straightforward as one might think.  Aside from experience and anecdotal evidence, one possible way to ascertain whether you're running on armel or armhf is to run the following obscure command:

$ readelf -A /proc/self/exe | grep Tag_ABI_VFP_args

If the Tag_ABI_VFP_args tag is found, then you're running on an armhf system.  If nothing is returned, then it's armel.  To show you an example, here's what happens on a Raspberry Pi running the Raspbian distribution:

pi@raspberrypi:~$ readelf -A /proc/self/exe | grep Tag_ABI_VFP_args
  Tag_ABI_VFP_args: VFP registers

This indicates an armhf distro, which in fact is what Raspbian is.  On the original, soft-float Debian Wheezy distribution, here's what happens:

pi@raspberrypi:~$ readelf -A /proc/self/exe | grep Tag_ABI_VFP_args

Nothing returned indicates that this is indeed armel.

Many thanks to the folks participating in this Raspberry Pi forum topic for providing this suggestion.



Saturday Dec 22, 2012

A Raspberry Pi / JavaFX Electronic Scoreboard Application

As evidenced at the recently completed JavaOne 2012 conference, community excitement towards the Raspberry Pi and its potential as a Java development and deployment platform was readily palpable.  Fast forward three months, Oracle has announced the availability of a JDK 8 (with JavaFX) for Arm Early Access Developer Preview where the reference platform for this release is none other than the Raspberry Pi.

What makes this especially interesting to me is the addition of JavaFX to the Java SE-Embedded 8 platform.  It turns out that at $35US, the (not so) humble Raspberry Pi has a very capable graphics processor, opening up a Pandora's box of graphics applications that could be applied to this beloved device.  As a first step in becoming familiar with just how this works, I decided to dust off a two year old JavaFX scoreboard application, originally written for a Windows laptop, and see how it would run on the Pi.  Low and behold, the application runs unmodified (without even a recompile).

The video that follows shows how an ordinary flat screen TV can be converted into a full screen electronic scoreboard driven by a Raspberry Pi.  The requirements for such a solution are incredibly straightforward: (1) the TV needs access to a power receptacle and (2) it must be within range of a WiFi network in order to receive scoreboard update packets.  The device is so compact and miserly from a power perspective, that we velcro the Pi to the back of the TV and get our power from the TV's USB port. If you can spare a few moments, it just might be worth your while to take a look.



Tuesday Oct 09, 2012

Raspberry Pi and Java SE: A Platform for the Masses

One of the more exciting developments in the embedded systems world has been the announcement and availability of the Raspberry Pi, a very capable computer that is no bigger than a credit card.  At $35 US, initial demand for the device was so significant, that very long back orders quickly ensued. After months of patiently waiting, mine finally arrived. 

Those initial growing pains appear to have been fixed, so availability now should be much more reasonable. At a very high level, here are some of the important specs:

  • Broadcom BCM2835 System on a chip (SoC)
  • ARM1176JZFS, with floating point, running at 700MHz
  • Videocore 4 GPU capable of BluRay quality playback
  • 256Mb RAM
  • 2 USB ports and Ethernet
  • Boots from SD card
  • Linux distributions (e.g. Debian) available

So what's taking place taking place with respect to the Java platform and Raspberry Pi?

  • A Java SE Embedded binary suitable for the Raspberry Pi is available for download (Arm v6/7) here.  Note, this is based on the armel architecture, a variety of Arm designed to support floating point through a compatibility library that operates on more platforms, but can hamper performance.  In order to use this Java SE binary, select the available Debian distribution for your Raspberry Pi.
  • The more recent Raspbian distribution is based on the armhf (hard float) architecture, which provides for more efficient hardware-based floating point operations.  However armhf is not binary compatible with armel.  As of the writing of this blog, Java SE Embedded binaries are not yet publicly available for the armhf-based Raspbian distro, but as mentioned in Henrik Stahl's blog, an armhf release is in the works.
  • As demonstrated at the just-completed JavaOne 2012 San Francisco event, the graphics processing unit inside the Raspberry Pi is very capable indeed, and makes for an excellent candidate for JavaFX.  As such, plans also call for a Pi-optimized version of JavaFX in a future release too.
A thriving community around the Raspberry Pi has developed at light speed, and as evidenced by the packed attendance at Pi-specific sessions at Java One 2012, the interest in Java for this platform is following suit. So stay tuned for more developments...


About

Jim Connors-Oracle

Search

Categories
Archives
« July 2015
SunMonTueWedThuFriSat
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
       
Today