picoPERC: A Small-Footprint Dialect of Java

picoPERC is a Java subset in which the core Virtual Machine implementation fits in less than 64 KB of memory. This 64-KB footprint is nearly 1/16th the size of JavaSoft's yet-to-be-defined Embedded Java and over 50 times smaller than typical Enterprise Java implementations.


March 01, 1998
URL:http://www.drdobbs.com/jvm/picoperc-a-small-footprint-dialect-of-ja/184410510

Dr. Dobb's Journal March 1998: picoPERC: A Small-Footprint Dialect of Java

Kelvin is president of NewMonics and can be contacted at http://www.newmonics .com/ or [email protected].


Embedded computers are everywhere. In grocery stores, for example, they tally up your bill, gather consumer-profile information about your buying habits, provide online access to your bank and credit-card accounts, and open the doors for you when you are ready to leave. In cars, embedded computers unlock doors, roll down windows, adjust mirrors, control fuel injection, report speed, and monitor for situations that require antilock braking or air-bag deployment. At home, they control the circulation and temperature of air, microwave and convection ovens, dish and clothes washers, television sets, stereo systems, cable or satellite TV converters, and remote-control devices. Projections by companies such as Motorola, in fact, suggest that by the year 2000, the average number of microcontrollers in a typical home will exceed 200. Furthermore, the report "Software 2000: A View of the Future" (ICL, 1994) projects that by the year 2010, there will be ten times as many software developers working on embedded-system software as will be developing commercial software for use with desktop computers and servers.

Java is attractive to embedded-systems developers for many of the same reasons it appeals to desktop/Internet programmers. Unlike C++, Java has a clean and simple design. Java is easy to learn and easy to use. It is object oriented and strongly typed. Java compilers prohibit many error-prone practices that are permitted in C and C++. Beyond the standard math, file handling, and text-formatting libraries, Java also provides standard libraries for Internet, multimedia, and multithreaded programming. Finally, Java provides garbage collection, a high-level service that automatically reclaims memory for objects that are no longer in use. Even though Java development tools and compilers are still relatively immature, embedded-systems companies are already experimenting with this new technology. Engineers at a large telecommunications company recently reported they were twice as productive writing code in Java than in C++. Engineers from the same company reported that they had been disappointed with C++, in part because they had found it necessary to spend millions of dollars finding and fixing memory leaks in their C++-based telecommunications software. Another issue raised by these engineers was Java's impact on human resources. They had found it difficult to recruit competent C++ programmers and subcontractors. Even more difficult was finding people skilled in this company's in-house proprietary languages and tools. These engineers felt that it would be easier to find skilled Java programmers, or, if necessary, to train existing technical staff in effective use of Java.

The Portable Executive for Reliable Control (PERC) is a clean-room implementation of the Java Virtual Machine developed by NewMonics (my company). PERC is designed specifically for embedded and real-time programming applications. Some of the qualities of PERC that make it especially well suited for these applications are its incremental defragmenting real-time garbage collector; a special ROMizer tool that allows Java bytecodes to be executed out of ROM memory and supports ahead-of-time compilation of Java bytecodes to native-machine language; a Minimal Windows Toolkit that is approximately one third the size of Java's Abstract Windows Toolkit; and optional real-time extensions that allow real-time tasks to reserve resources for periodic execution, a particular amount of live memory, and a particular rate for dynamic memory turnover. In supporting the real-time extensions, PERC converts the various memory requests into a CPU-time requirement for garbage collection. Then it uses rate-monotonic analysis to determine whether the workload representing all application-level tasks combined with the garbage-collection task can meet the desired real-time constraints. Once CPU time and memory budgets have been granted, PERC enforces the budgets. Tasks are not allowed to run longer or allocate more memory than was budgeted.

Shrinking the memory footprint is of prime importance in tailoring Java implementations for embedded systems. For consumer electronics products shipped in the millions, every penny shaved from unit manufacturing costs adds up to a significant savings. Handheld devices must be small and lightweight. Battery-powered devices must operate on very low current. picoPERC is a Java subset in which the core Virtual Machine implementation fits in less than 64 KB of memory. This 64-KB footprint is nearly 1/16th the size of JavaSoft's yet-to-be-defined EmbeddedJava and over 50 times smaller than typical Enterprise Java implementations.

picoPERC consists of a core virtual machine upon which optional extensions can be layered. Unlike standard Java, the picoPERC core lacks support for floating-point numbers, 64-bit integers, automatic garbage collection, the standard lang, util, io, and net class libraries, and dynamic bytecode loading and verification. All of these capabilities can be added to the picoPERC core under programmer control.

With so much of standard Java missing from the picoPERC core, you might wonder which, if any, of the traditional Java benefits are supported by picoPERC. The main benefit is that the source language is the same as standard Java. This means that if you are developing very small, deeply embedded systems, you can use the same language and development tools you use for larger embedded systems. Also, this means that picoPERC programmers benefit from the simplicity and consistency of the Java language design, and from the strong type checking performed by Java compilers. Another benefit of picoPERC is that it uses Java's portable bytecode representation. This means that portable software components can be developed or delivered by multiple independent suppliers and integrated in binary form, without requiring source code access for system integration. Finally, because picoPERC uses the same byte code representation as traditional Java, it is possible to run, evaluate, and debug picoPERC programs using traditional Java Virtual Machines and integrated development environments. Once the software development effort is done, the ROMizer tool can be used to target the bytecode representation to ROM memory for execution by the picoPERC Virtual Machine.

Black Jack Application

Several months ago, a customer asked us to assist with the development of an application that could demonstrate Java's benefits to management in order to obtain funding approval for development of a larger application. The sample application would have to run on existing hardware, which limited the RAM memory to one MB, restrict output to a two-line by 32-character display, and take all input from a numeric keypad. We wrote the Black Jack program, which I'll present in this article. The source code for the program is available electronically (see "Resource Center," page 3).

The program acts as a Black Jack dealer for a single human player. Before the game begins, the dealer asks how much the user would like to bet on the game. The following interaction indicates that the user's account has $95, of which the user bets $5.

[95]Bet:
5

The computer starts the game by dealing two cards for itself and two for the player. One of the dealer's cards is face down. All other cards are face up. The following display indicates that the dealer has one face down card and one Ten of Hearts. The player has a Nine of Diamonds and Ace of Clubs.

D> * TH
P> 9D AC

The dealer waits for the user to request an action. The user types "s" to stay with the current hand, or "h" (for hit) to request an additional card. Once the user types "s," the dealer begins dealing additional cards to itself. In this case, the dealer also stays, resulting in a tie game. This is represented as:

D Ties> QH TH
P Ties> 9D AC

Figure 1 shows a graphical version of the Black Jack program.

Implementing Black Jack

The main functionality of Black Jack is implemented by the following object (class) definitions:

Unlike PERC and Java, the picoPERC core does not support automatic garbage collection. Thus, it is necessary to explicitly delete each object after its useful lifetime has expired. This Black Jack program is written as a persistent embedded program. Black Jack starts when the embedded computer is powered up. It continues to run until the computer is powered down. There is no need to ever reclaim the main data structures of the program. Black Jack allocates 52 Card objects to represent the cards of a standard deck. These cards are never recycled. They are simply moved back and forth between the deck, the dealer's hand, and the player's hand. The only dynamically allocated object that must be explicitly reclaimed is the string created by Hand.toString(). Note the invocations of MM.delete() in the showPlayer() and showDealer() methods of the BlackJack class.

To reduce memory footprint, picoPERC does not include all of the standard library services that are built into standard Java. Since these services are redundant with the services provided by many embedded and real-time operating systems, the services can be easily implemented using native methods. A PERC native method is a method implemented by a C program. In the Black Jack program, native methods implement keypad input, LED output, graphics output, and random number generation. The interfaces following represent these services:

These are represented as interfaces because we want to provide different implementations of these services, depending on execution environment. All of the code can be run either on a traditional Java Virtual Machine or on a picoPERC Virtual Machine.

For development, testing, and debugging, we used KeyboardViaJava to implement Input, ASCIIViaJava to implement Output, and RandGenViaJava to implement RandGen. These classes implement the required services using standard Java libraries. This is portable and convenient, but it adds considerably to the size of the application because it requires inclusion of the standard Java libraries. Once the basic functionality of the application had been tested and debugged, we ported the code to the small LED embedded device by replacing these classes with KeyboardViaNative, ASCIIViaNative, and RandGenViaNative, respectively.

These three classes use native methods, which are not shown, to implement the various services. The ASCIIViaNative methods assume the output device supports only text output. The corresponding clearCardArea() and drawCard() implementations are empty, meaning that there is no attempt to display any graphics on this device.

Later, we ported the code to the VGA flatpanel device by modifying the implementations of KeyboardViaNative and RandGenViaNative, and by replacing ASCIIViaNative with class GUI. The appropriate implementation of native methods depends on the underlying hardware and the services that are provided by the host operating system.

Preparing the picoPERC ROM Image

After the Black Jack program was tested, we prepared a version to be placed into the embedded device. First, we compiled the various Java source files (also available electronically) using the javac program supplied in JavaSoft's JDK 1.0.2:

javac BlackJack.java Deck.java
   Hand.java Card.java
javac Input.java Output.java
   RandGen.java 
javac KeyboardViaJava.java
   ASCIIViaJava.java
   RandGenViaJava.java

We used our ROMizer tool to preload the various class files. The ROMizer resolves symbolic references and replaces certain byte code instructions with more efficient representations. The command-line invocation:

romize -f %perc%\images\picoperc
classes	-f BlackJack.classes

invokes the ROMizer, telling it to preload all of the classes identified in the %perc%\images\picoperc.classes and BlackJack.classes files. %perc%\images\ picoperc.classes names the files that represent the core picoPERC classes. Included among these are simplified definitions of java.lang.Class and java.lang.String and certain exceptions that may be thrown by the Java interpreter. BlackJack.classes names the classes that represent the Black Jack demo. For each loaded class, the ROMizer automatically loads all classes that are directly referenced by the class if those classes have not already been loaded.

We compiled and linked an earlier version of the Black Jack program for the ARM processor running on a Pixel Press board supplied by Applied Data Systems (http://www.flatpanel.com/) and analyzed the resulting memory image. Table 1 describes the memory layout. The subtotal is 4344 bytes larger than the actual size of the load image. This is because the subtotal was calculated by summing individual object file sizes, whereas the total load image size is the size of the linked program. Certain information is discarded from the object files in the process of linking the various files together. We are currently working on a number of optimizations designed to shrink the in-memory sizes of the Java classes by approximately 50 percent.

Acknowledgment

Simanta Mitra and Paul Thompson first ported Black Jack to an embedded computer with only an LED device. Steve Lee ported Black Jack to the picoPERC core. Jim Lathrop and Jason Britton ported the resulting Black Jack program to a Pixel Press ARM computer by Applied Data Systems. Finally, Steve Lee assisted in polishing the Black Jack code for public distribution.

DDJ


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal March 1998: picoPERC: A Small-Footprint Dialect of Java

picoPERC: A Small-Footprint Dialect of Java

By Kelvin Nilsen

Dr. Dobb's Journal March 1998

Figure 1: The visual Black Jack program.


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal March 1998: picoPERC: A Small-Footprint Dialect of Java

picoPERC: A Small-Footprint Dialect of Java

By Kelvin Nilsen

Dr. Dobb's Journal March 1998

Table 1: Memory layout. (*The in-memory sizes of Java classes are approximated by scaling individual class file sizes proportional to the ratio between the sum of class file sizes and the size of the ROM memory image.)


Copyright © 1998, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.