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.

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


Monday Aug 13, 2012

Java One 2012 Java SE Embedded Hands On Lab Returns!

After successful runs at Java One 2011 San Francisco and Tokyo, The Java SE Embedded Hands On Lab returns for Java One 2012.  If you're attending the Java One event in San Francisco (Sept 30 - Oct 4), please consider signing up for this session.  As an added incentive, we will be raffling off a couple of the Plug Computer devices that you'll gain experience with during this lab.  Seating is limited to 100 students, so register early.

Here's an overview:

This hands-on lab aims to show that developers already familiar with the Java develop/debug/deploy lifecycle can apply those same skills to develop Java applications, using Java SE Embedded, on embedded devices. The participants in the lab will:

    • Have their own individual embedded device so they can gain valuable hands-on experience
    • Turn their embedded device into a web container, using off-the-shelf software
    • Learn how to deploy embedded Java applications, developed with an IDE, onto their device
    • Learn how embedded Java applications can be remotely debugged from their desktop IDE
    • Learn how to remotely monitor and manage embedded Java applications from their desktop

The course description can be found here:
HOL 7889: Java SE Embedded Development Made Easy

In addition, 2012 marks the first year that we will have a venue specifically tailored for the Java embedded community.  Entitled Java Embedded @ Java One,  this event takes place during the JavaOne/OpenWorld week in San Francisco on October 3-4.  To Quote from the Java Embedded @ Java One URL:

The conference will feature dedicated business-focused content from Oracle discussing how Java Embedded delivers a secure, optimized environment ideal for multiple network-based devices, as well as meaningful industry-focused sessions from peers who are already successfully utilizing Java Embedded.

So if you want to participate in what many consider to be the next big trend in computing -- the internet of things -- come join us 10/3-4 in San Francisco.

Thursday May 26, 2011

The Shackles are Off

Today marks an important milestone for JavaFX 2.0.  Prior to this date, only a select few partners had early access privilege to the technology, and for good reason.  During that early access period, the API was in a very fluid state, and from personal experience I can tell you that changes to the JavaFX 2.0 API were done almost on a build-by-build basis.  The announcement of a public beta not only makes the software available worldwide, but also signals that the JavaFX 2.0 API is on much more solid footing.

So check out the javafx.com website for the latest JavaFX 2.0 information.   Three software downloads are now available:

  1. JavaFX 2.0 Beta SDK - the JavaFX functionality needed to develop directly via the command line or with other tools
  2. JavaFX 2.0 Beta Runtime - the runtime environment required for running JavaFX 2.0 applications 
  3. JavaFX 2.0 Beta Plugin for NetBeans IDE 7.0 -  for building, previewing, and debugging JavaFX applications in NetBeans 7.

Wednesday Nov 04, 2009

Consumer Electronics: Your Utility Company's Best Friend

If you're reading this article, the chances are real good that your home is full of electronic gadgets.  Moreover many are permanently plugged into wall sockets.   Having recently purchased a P3 International P4460 Kill A Watt EZ power meter, I've been running around getting a feel for how much energy some of these common components use.

For this first table, I wanted to see how much energy was being consumed by audio/visual components that were plugged into the wall, but not powered on.  Indeed some of these numbers are eye-opening:

 Device  Watts consumed (powered off)
Visio 22" LCD HDTV (circa 2007)  1.58
Visio 32" LCD HDTV (circa 2009)  1.18
25" RCA Tube TV (circa 1990)  4.17
Marantz AV Surround Reveiver SR7200  2.79
Marantz CD Changer CC9100  1.43
Marantz DVD Player DV6200  3.60
Boston Micro90pv II Subwoofer 14.53
Microsoft Xbox 360  3.64
Nintendo Wii  2.70
Sony PlayStation 2  0.67
Scientific Atlanta Explorer 4250HD set top 17.27
Scientific Atlanta Explorer 8300HD DVR set top 20.00

The granularity of the P4460 is hundredths of kilowatt-hours, which means that in order to get a decent reading on a low-power device, you've got to leave it attached for a while.  No doubt some of these measurements could be more accurate, but I think you get the point.  Of note:

  1. The 4 components that comprise the audio system consume over 22 watts all day, every day 24x7.
  2. As set top boxes gain more functionality (e.g. DVR), they suck up even more power.   At this rate, you'd think the power utility would subsidize the cable companies to get as many of these things installed as possible.
  3. All told, the devices in the preceding table consume an amount of energy similar to a 75 watt incandescent light bulb being left on all the time.

For the most part, these components are non-critical, and one could argue that some (e.g  the stereo) should be connected to a power strip with an on/off button. This should not pose much of an inconvenience.  However, it's a completely different story when it comes to the video components.  When powered cycled, set top boxes take forever to reach full functionality as they reboot over the cable network.  And televisions, if left untethered to electric power for too long, go through this whole channel search sequence when they're powered up.  In short, when it comes to video, you're currently stuck with paying the hidden price of "convenience".

For the computer nerd in us, here's a table comprising some of the computer/network-related components that are left on 24x7.

Device
 Watts Consumed
Belkin Wireless G Router
 5.09
Motorola SBV5120 SURFboard Cable Modem
 5.40
Netgear ProSafe 16 port 10/100 Switch (FS116)
 8.33
HP Photosmart c6280 printer (circa 2008) (networked)
 4.78
HP Laserjet 4P (circa 1994)
 5.32
Canon ImageCLASS MF4270 all-in-one laser printer (networked) (circa 2009)
 3.60
Fit-PC Slim with external USB hard disk (network file server)
 7.50

A decade ago, devices like those listed above were virtually non-existent in the home.  So what's the cost of being Internet ready anytime, anywhere?  About 40 watts all day and all night. Some final points:

  1. In general, carefully consider keeping around older gadgets.  The circa 1990s devices definitely use more energy than their newer, more functional counterparts.
  2. Notice no computers are included.  You know you have more than one, some (present company included) have way more than one.  Let's hope you're turning these off or at least putting them to sleep at night!

Monday May 11, 2009

You Are What You Eat?

So you may ask, what effect does the food we eat have on our blood pressure?  My experience, documented below, won't likely hold up to whole lot of scientific scrutiny, but it's good enough lesson for me.

A combination of poor eating habits and genetics lands me in that ever-increasing group of individuals who have high blood pressure.  At first I was what you might consider borderline hypertensive.  Being thin and active, in conjunction with my doctor, we only monitored my levels to make sure they didn't get worse.  Unfortunately they did.

In an attempt at avoiding medication, I started seriously watching my sodium intake.  The resulting change in blood pressure was noticeable in pretty short order.   See the table below for daily readings for the last two weeks.  In general, I try to take my reading at or around 8:00AM if possible.

Having spent my whole life eating pretty much what I please, it's not easy to make this lifestyle change.   But with the help of loved ones, things have been going quite well.  But then came Mother's day (5/10).   A combination of brunch with my parents and dinner with my in-laws put the kabash on any diet plans.  I knew this would happen, and was frankly looking forward to the feast.  It only took one day for my pressure to skyrocket.  Amazing.  But man did I enjoy eating the waffles, bacon, crumbcake, bagels, Mimosas (Orange Juice and Champagne) cookies, macaroni, meatballs, turkey, chocoloate cake, Coke, Espresso, wine, Sambuca and Cognac to name a few.


 Date  Time  Blood Pressure
 4/29 8:01 AM
 124/73
 4/30 8:19 AM
 124/73
 5/1 8:18 AM
 123/71
 5/2 7:48 AM
 119/75
 5/3 9:22 AM
 126/74
 5/4 7:53 AM
 129/79
 5/5 8:20 AM
 119/69
 5/6 7:16 AM
 126/75
 5/7 6:19 AM
 126/72
 5/8 6:56 AM
 125/75
 5/9 7:48 AM
 133/71
 5/10 9:14 AM
 129/73
 5/11 7:56 AM
 159/81

Back to the bland diet, that is, until the next feast.

Friday Feb 16, 2007

The Verbal Regret Coefficient

I am convinced that scientists will some day find an explanation for my continual verbal ineptitude.  It will probably be identified as a sequence in our genome and they'll call it something like The Verbal Regret Coefficient.  We are all born with it, and we can't escape how it influences us everyday.  In advance of its discovery, I propose this definition: The Verbal Regret Coefficient is that innate ensemble of dispositions which guarantees that after uttering a number of words, you will regret having said a certain percentage of them. 

My first choice for a name was Regret Coefficient, but incredibly a quick search seems to indicate that the insurance industry already uses that term.   If my theory catches on -- and you'll know that when someone dedicates a wikipedia entry -- I don't want to have to deal with copyright and trademark infringement.  So Verbal Regret Coefficient it is.

The Verbal Regret Coefficient or VRC will ultimately be quantified, and like a cholesterol count, we'll all be assigned a VRC value.  Most will fall into an average range, but there will be outliers.  A high VRC manifests itself behaviorally in many ways: some high VRC'ers are purposely controversial, outspoken, brash or arrogant.  While others simply fail to think before they speak.  In case you're wondering, I am one of those outliers with a dangerously high VRC.  Furthermore, I'm quite sure I don't fit into the arrogant and controversial group.  But it's not all good news for those with a low VRC.   Although low VRC'ers tend not to say anything regrettable, they tend also not to say anything of substance either.  We call these people politicians.

If the current social trend continues, we'll get away with blaming any verbal faux pas to our VRC.  They'll be VRC support groups and celebrity VRC rehabilitation clinics.   Or maybe we could avoid all this silliness and just heed the advice of Mark Twain who once said:

It is better to keep your mouth closed and let people think you are a fool than to open it and remove all doubt.

But that is sooooo hard. 


About

Jim Connors

Search

Categories
Archives
« April 2014
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
   
       
Today