Paul's Raspberry Pi Journal
From Resin 4.0 Wiki
Contents |
Intro
Hi! I'm Paul Cowan, a software engineer at Caucho Technology. Caucho is primarily a Java EE application server vendor. Our application server is called Resin. I mostly write Java code, but I'm also a computer hobbyist and like to tinker with anything techie.
During Caucho's last engineer meeting in San Francisco (October 2012), I brought up Raspberry Pi as an avenue we could explore for Resin. It probably wouldn't directly sell Resin licenses, but it would be a great marketing vehicle. Everybody like it, Caucho is cool like that, and so I'm off.
About Resin
Resin is a fairly light-weight for an app server and embeds well. It's really a nice platform on which to build just about anything in Java, since it can make just about any app HTTP enabled and handles all the mundane services like logging and you don't really want to have to deal with. It also provides a dependency injection container... Now you may be asking "why do I can about dependency injection when I'm just playing around with hobby projects." Well personally I pump out Java code much faster using dependency injection and just find it easier to write in that style.
Resin also includes Quercus, a Java based PHP interpreter. I'm not really planning to make PHP a focus of this project, but it's handy to have available just in case.
About This Journal
The Raspberry Pi platform and community certainly seems to be evolving rapidly, but it still seems like there's not enough documentation out there. In particular Java support is kinda spotty, and I haven't found anything on JEE on a Raspberry Pi. So I'm going to document my experience in hope it is useful to other Java developers getting started with Raspberry Pi.
Hardware
- Raspberry Pi Model B board from Newark Element 14 (Upgraded from 256 Mb model for free)
- Little transparent plastic enclosure also from Newark
I ordered the Pi early in October, but it was backordered by about 4 weeks. 10/15 they sent me an email my order was upgraded for free from 256 Mb to the 512 Mb model. It was delivered 10/18, so about 2 weeks early.
I use an IOGear DVI KVM so monitor and keyboard aren't a problem. In fact the KVM combines the mouse and keyboard into a single USB cable, so that leaves me a free USB port on the RasPi. However I needed an adapter and HDMI cable. Monoprice is great for this kind of stuff.
- PNY 8 Gb SD card from BJ's... I think, I stolen from the family camera :)
- MicroUSB cable and AC adapter from my Kindle
Getting Started
I started with this write up from Oracle and the Raspberry Pi downloads page. It becomes apparent pretty quickly that there's a float-point compatibility issue with Java on Raspberry Pi. Here's a summary of what I understand regarding the state of Raspberry Pi operating systems and Java support as of 11/2012:
OS
- The "official" distro is Raspbian Wheezy, which is offered for download on on raspberrypi.org/downloads
- This distro is variant of Raspbian Wheezy from raspbian.org but with a light-weight desktop, Midori web browser, and a few other development extra specifically for Raspberry Pi
- Raspbian Wheezy is a variant of Debian Wheezy but compiled for ARM processor with optimization specifically for Raspberry Pi (hardware floating-point)
- Debian Wheezy is the "testing" distro of Debian, while Debian Squeeze is the current stable release
- There are various other linux distros supporting ARM processor
I should mention that my understand is you can't just use any ARM linux distro straight up. The boot sequence for a Raspberry Pi dependent on the SD card. It actually boots from a small RISC core on the GPU, but the GPU firmware is loaded from the SD card. More here.
This article helps if you're a little lost like I was: Understanding ARM Architectures.
Java Compatability
- Currently NO Java distro that I'm aware of has support for Raspberry Pi's hardware floating point unit (hard-float)
- Therefore we need OS distro that support soft-float, ARMv6, little-endian
- The Oracle article is discussing using Debian Squeeze, which I suspect is because it was the best distro available at the time with soft floating-point support.
- However there is now a Soft-float Debian wheezy Rasbian image available at raspberrypi.org/downloads, so I'm going to try that to start out
Honestly I don't want a desktop at all and would like fast boot, so the Arch Linux distro appeals to me. (Note to try it later.)
Imaging
There's a Fedora installer that sounds interesting, but I'm running on OSX. The instructions on the Oracle article are based on Linux, but there's also decent instructions here. Basically the distro is a raw SD card image, containing partitions, so you have to write it directly to the SD card in raw form.
- Inserted the SD card into my MacBook's SD Slot
- Ran Search->Disk Utility
- SD card is listed as 8.01 GB APPLE SD Card...
- Erase->MS-DOS(FAT), Name: RASPI
- Erase
Next, I tried RasPiWrite and failed. The script doesn't even run due to syntax errors. I'm not going to debug a Python script, so that fails the 10-minute test.
Now following "Easy Way" instructions from the Raspberry Pi wiki...
- df -h reveals my SD card mount simply enough:
/dev/disk1s1 7.4Gi 624Ki 7.4Gi 1% /Volumes/RASPI
$ sudo diskutil unmount /dev/disk1s1 Password: Volume RASPI on disk1s1 unmounted
$ sudo dd bs=1m if=~/Downloads/2012-08-08-wheezy-armel.img of=/dev/rdisk1 1850+0 records in 1850+0 records out 1939865600 bytes transferred in 136.071302 secs (14256243 bytes/sec)
Well that looks like it worked!
First Boot
The Raspberry Pi booted right into a blue menu screen called raspi-config that lets you configure basic OS settings.
- The first thing I did was hit EXPAND-ROOTFS to use of the rest of the free space on the SD card
- After a "sudo reboot" it printed logs about resizing the root file system. That took a few minutes but seems work fine.
- I configured, locale, timezone, enabled SSHD, and set the the desktop to NOT start on boot
- Finished, reboot
- The pi is showing up on my network, SSH works, looks good to go!
pi@raspberrypi ~ $ df -h Filesystem Size Used Avail Use% Mounted on rootfs 7.3G 1.3G 5.7G 19% / /dev/root 7.3G 1.3G 5.7G 19% / tmpfs 22M 228K 22M 2% /run tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 44M 0 44M 0% /tmp tmpfs 10M 0 10M 0% /dev tmpfs 44M 0 44M 0% /run/shm /dev/mmcblk0p1 56M 35M 22M 61% /boot
The Oracle article goes into a lot of detail about setting up DHCP, local. time-zone, etc e which doesn't seem necessary since Raspbian provides raspi-config.
Hmm, I'm noticing the OS is only seeing 256 Mb instead of 512.... They told me I was sent an upgraded model to the 512 Mb.
pi@raspberrypi ~ $ free -h total used free shared buffers cached Mem: 216M 48M 168M 0B 9.0M 23M -/+ buffers/cache: 15M 200M Swap: 99M 0B 99M
pi@raspberrypi ~ $ cat /proc/cpuinfo Processor : ARMv6-compatible processor rev 7 (v6l) BogoMIPS : 697.95 Features : swp half thumb fastmult vfp edsp java tls CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xb76 CPU revision : 7 Hardware : BCM2708 Revision : 0005 Serial : 00000000edc79c8a
(Emailed Newark customer service about it, have not heard back yet).
Getting Oracle JRE 7 Running
As I mentioned above, there's no Raspi hardware floating-point support in Java (yet?). I'm planning to install Oracle/OpenJDK/JRE to do some testing and see what runs best. Resin is not fully functional with a JRE, it can't compile JSPs...
Downloading ARMv6/7 Linux - Headless EABI, VFP, SoftFP ABI, Little Endian1 (ejre-7u6-fcs-b24-linux-arm-vfp-client_headless-10_aug_2012.tar.gz) from [Oracle http://www.oracle.com/technetwork/java/embedded/downloads/javase/index.html]
(Hmm, it takes like 2 minutes to scp 32Mb to the Pi from OSX... That troubling. Not sure if it's the write to SD card speed or network.)
Unziped, untar, there's no installer. There's only 2 files in bin, java and keytool. I'm going to setup Java like a typical linux install by moving the extracted dir to /usr/ejre1.7.0_06 and symlink to /usr/java and link the executables into /usr/bin.
pi@raspberrypi ~ $ which java /usr/bin/java pi@raspberrypi ~ $ java -version java version "1.7.0_06" Java(TM) SE Embedded Runtime Environment (build 1.7.0_06-b24, headless) Java HotSpot(TM) Embedded Client VM (build 23.2-b09, mixed mode)
Getting Resin Running
I'm going to focus on the open-source Resin Servlet Container for this project.
wget http://www.caucho.com/download/resin-4.0.32.zip
Extracting the zip was fast, but the whole system then stopped responding for a few seconds afterwards... I guessing it's write buffering to the SD card and has to wait for the hardware to catchup. (?)
Trying a configure/make/make install of Resin:
./configure
configure: error: *** Can't find JNI directory in JAVA_HOME=/usr/java *** JNI is expected in /usr/java/include/linux
Crap... this Java distro does not include the Java headers. We won't be able to compile Resin native libraries with this Java, maybe one of the others will have headers. Resin will still work in pure Java mode.
Let's try with:
./configure --disable-jni
Configure succeeds that time. "make" succeeds. "sudo make install" succeeds.
Resin is installed to /etc/init.d, /etc/resin, /usr/local/share/resin, /var/resin, etc.
pi@raspberrypi /var/resin $ resinctl start Resin/4.0.32 launching watchdog at 127.0.0.1:6600 java.io.FileNotFjava.io.FiloundExceNotFoeption:undExce /var/ption: /log/resivar/logn/watch/resin/dog-manwatchdoager.log g-manage(Permissr.log (Pion deermissionied) n denied) at java.io.FileOutputStream.open(Native Method) at java.io.FileOutputStream.<init>(FileOutputStream.java:212) at java.io.FileOutputStream.<init>(FileOutputStream.java:104) at com.caucho.vfs.FilePath.openAppendImpl(FilePath.java:586) at com.caucho.vfs.Path.openAppend(Path.java:1229) at com.caucho.boot.WatchdogManager.<init>(WatchdogManager.java:143) at com.caucho.boot.WatchdogManager.main(WatchdogManager.java:1009) Resin/4.0.32 started -server 'app-0' with watchdog at 127.0.0.1:6600
Well that's a weird error... I forgot to start with sudo, retry.
pi@raspberrypi /var/log/resin $ sudo resinctl start Resin/4.0.32 launching watchdog at 127.0.0.1:6600 Resin/4.0.32 started -server 'app-0' with watchdog at 127.0.0.1:6600
That's better. It only took about 15 seconds to startup, not too bad. Checking the logs...
[2012/12/04 14:14:31.094] {main} Unable to find native library 'resin_os' for com.caucho.bootjni.JniProcess. Resin expects to find this library in: (Unix) /usr/local/share/resin-4.0.32/libexec/libresin_os.so On Unix, run ./configure --prefix=`pwd`; make; make install. The JVM exception was: java.lang.UnsatisfiedLinkError: no resin_os in java.library.path
watchdog-manager.log is complaining about missing native libraries, but that's expected.
[12-12-04 14:15:12.478] {main} Resin-4.0.32 (built Mon, 01 Oct 2012 03:05:04 PDT) [12-12-04 14:15:12.482] {main} [12-12-04 14:15:12.485] {main} Linux 3.2.27+ arm [12-12-04 14:15:12.489] {main} Java(TM) SE Embedded Runtime Environment 1.7.0_06-b24, UTF-8, en [12-12-04 14:15:12.493] {main} Java HotSpot(TM) Embedded Client VM 23.2-b09, 32, mixed mode, Oracle Corporation
Cool!
Trying http://raspberrypi:8080/
500 Servlet Exception javac compiler is not available in Java(TM) SE Embedded Runtime Environment 1.7.0_06-b24. Check that you are using the JDK, not the JRE.
Well that's expect also, we're using a JRE so no JSP compiler...
Trying http://raspberrypi:8080/resin-doc/ That works! Why?... XTP is not compiled!
Trying http://raspberrypi:8080/resin-admin That works too! PHP is not compiled either!
Admin account generation worked. Resin restart took 45 seconds, Ugh.
Getting OpenJDK 7 Running
Attempting to install OpenJDK from the package:
apt-get install openjdk-7-jdk
Nice! That works!
root@raspberrypi:~# which java /usr/bin/java root@raspberrypi:~# cd /usr/bin/ root@raspberrypi:/usr/bin# ls -l java
l rwxrwxrwx 1 root root 22 Dec 4 16:21 java -> /etc/alternatives/java
root@raspberrypi:/usr/bin# cd /etc/alternatives/ root@raspberrypi:/etc/alternatives# ls -l java lrwxrwxrwx 1 root root 46 Dec 4 16:21 java -> /usr/lib/jvm/java-7-openjdk-armel/jre/bin/java root@raspberrypi:/etc/alternatives# cd /usr/lib/jvm/ root@raspberrypi:/usr/lib/jvm# ls -l total 8 lrwxrwxrwx 1 root root 20 Oct 18 03:13 java-1.7.0-openjdk-armel -> java-7-openjdk-armel drwxr-xr-x 7 root root 4096 Dec 4 16:19 java-7-openjdk-armel drwxr-xr-x 3 root root 4096 Dec 4 16:16 java-7-openjdk-common
So OpenJDK uses the Linux Alternatives project... (Not a big fan of alternatives but I'll deal.) It install armel and common, not sure what that's about.
Starting Resin with OpenJDK...
[12-12-05 20:05:52.793] {main} [12-12-05 20:05:52.817] {main} Resin-4.0.32 (built Mon, 01 Oct 2012 03:05:04 PDT) [12-12-05 20:05:52.826] {main} [12-12-05 20:05:52.838] {main} Linux 3.2.27+ arm [12-12-05 20:05:52.872] {main} OpenJDK Runtime Environment 1.7.0_03-b21, UTF-8, en [12-12-05 20:05:52.887] {main} OpenJDK Zero VM 22.0-b10, 32, mixed mode, Oracle Corporation
Ok it start, but wow it's really slow. ResinBoot itself took like 20 seconds, and it must have been 3 minutes before port 8080 was bound. http://raspberrypi:8080/ loads to, but it took like 40 seconds.
Doing some research, I see there's 3 different VM's built into OpenJDK, that's interesting. Here's the 3:
The /usr/lib/jvm/java-7-openjdk-armel/docs/README.Debian explains this in detail:
The OpenJDK build is configured --with-additional-vms to build with different virtual machines. The original implementation of the hotspot VM is only available on the amd64, i386, lpia and sparc architectures. Other VM's are CACAO, providing a just in time compiler on several architectures (although the VM implementation is incomplete), and Zero, providing a byte code interpreter for every architecture. On some architectures Zero is built with JIT support using shark (still considered experimental). To use a different VM other than the default, use java -cacao|-zero|-shark or for the java tools, use <tool name> -J-cacao|-J-zero|-J-shark. The zero build on the ix86 architectures is built with shark (just in time compiler); to use the zero build without shark support, use the `-Xint' option to operate in interpreted-only mode. On some architectures (currently armel and powerpc, when built against llvm-2.6) which use ther zero vm as the default, the openjdk-7-jre-zero package contains the shark vm. To change the default permanently, edit /etc/java-7-openjdk/jvm.cfg. The CACAO VM can be found in the icedtea-7-jre-cacao package, the Zero/Shark VM can be found in the openjdk-7-jre-zero package (on the architectures where the Hotspot VM is available).
So Zero is the default, which is interpreted mode, so that could account for the slow performance I was seeing. Sounds like I need to do some performance testing.
I see OpenJDK includes headers!
root@raspberrypi:/usr/lib/jvm/java-7-openjdk-armel/include# ls -l total 212 -rw-r--r-- 1 root root 21079 Oct 18 03:05 classfile_constants.h -rw-r--r-- 1 root root 9544 Oct 18 03:05 jawt.h lrwxrwxrwx 1 root root 15 Oct 18 03:13 jawt_md.h -> linux/jawt_md.h -rw-r--r-- 1 root root 7206 Oct 18 03:05 jdwpTransport.h -rw-r--r-- 1 root root 74663 Oct 18 03:05 jni.h lrwxrwxrwx 1 root root 14 Oct 18 03:13 jni_md.h -> linux/jni_md.h -rw-r--r-- 1 root root 4771 Oct 18 03:05 jvmticmlr.h -rw-r--r-- 1 root root 78425 Oct 18 03:05 jvmti.h drwxr-xr-x 2 root root 4096 Dec 4 16:19 linux
So I wonder if Resin will compile on Raspberry Pi now... Trying...
./configure works!
Resin Configuration Summary: RESIN : 4.0.32 home : /usr/local/share/resin-4.0.32 root : /var/resin conf : /etc/resin log : /var/log/resin plugins : common resin_os init : /etc/init.d/resin JAVA_HOME : /usr/lib/jvm/java-7-openjdk-armel/jre/bin/../.. JNI : 32-bit include : -I/usr/lib/jvm/java-7-openjdk-armel/jre/bin/../../include CFLAGS : cflags_shlib : -fpic ld_shlib : gcc ldflags_shlib : -shared -fPIC -m32 libs_shlib : epoll() for keepalives
But make fails:
gcc -g -O2 -DEPOLL -D_POSIX_PTHREAD_SEMANTICS -pthread -fPIC -fno-omit-frame-pointer -O2 -DHAS_SOCK_TIMEOUT -DHAS_SENDFILE -DHAS_SPLICE -DPOLL -DHAS_JVMTI -fPIC -m32 -DRESIN_HOME=\"/usr/local/share/resin-4.0.32\" -I/usr/include -I/usr/lib/jvm/java-7-openjdk-armel/jre/bin/../../include -I../common -DCPU=\"armv6l\" -DOS= -c -o boot.o boot.c cc1: error: unrecognized command line option �-m32�
So gcc on Raspberry Pi doesn't like -m32... It's a 32-bit architecture. I can probably work out the proper compilation flags but will put that off until later. For now we'll continue to run Resin in java-only mode.
JVM Performance Testing
Resin on OpenJDK
Resin is automatically adding -server to the Resin command line during startup. -server implies -zero, so I can't get it to use -cacao or -jamvm at all without changes.
I'm staring a [Resin Changes To Support Raspberry Pi] list.