Caracas 2009

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

2009 Third International Conference on Sensor Technologies and Applications

Mote Runner: A Multi-Language Virtual Machine for Small Embedded Devices

A. Caracaş T. Kramp M. Baentsch M. Oestreicher T. Eirich I. Romanov


IBM Zurich Research Laboratory
{xan,thk,mib,oes,eir,iro}@zurich.ibm.com

Abstract embedded Java variants. As we discuss in Section 2, existing


embedded virtual machines are generally designed starting
This paper introduces a new virtual machine for sensor from the high-level language and removing features hard
networks and small embedded devices which has been to implement efficiently on resource-constrained embedded
designed with efficient resource usage and an event-driven systems. For an efficient resource usage a VM and corre-
programming model in mind. The virtual machine runs on sponding byte codes should be designed along the reactive
8, 16, and 32-bit micro-controllers with as little as 4 KB programming model for wireless sensors and embedded sys-
of volatile and 32 KB of non-volatile memory. Our virtual tems in general. Furthermore, efficiently loading and linking
machine is not bound to a single high-level programming applications in a low power and scarce resource environment
language, but targets all strictly-typed programming lan- is not solved by existing embedded Java VM variants. Hence
guages. In conjunction with the virtual machine, we also the need for a new VM designed to meet the requirements
present our development tool chain for Java and C#, and of our target environment: low-power, resource-constrained,
discuss the effects of our virtual machine design on these and wirelessly-connected embedded systems running on 8 bit
high-level languages. We also present a compact load-file micro-controllers with as little as 4 KB of volatile (RAM) and
format which allows applications to be stream-linked in 32 KB of non-volatile (flash, EEPROM) memory.
a way that minimizes memory usage and bandwidth. All From an application development perspective, the VM
presented components are part of the IBM Mote Runner, should be able to support multiple high-level languages
a run-time environment for wireless sensor networks. such as Java and C# and leverage integrated development
environments (IDEs) such as Eclipse, Visual Studio, and
Keywords: embedded systems, sensor networks, virtual
MonoDevelop. We deem this approach essential to enable
machines, multi-language, C#, Java, byte code, Mote Runner
domain specialists to focus on solving their problems rather
than tools — specific hardware, operating system, or pro-
1. Introduction gramming language.
This paper shows how our VM provides the necessary
Embedded devices do not stand isolated, but work co- concepts to meet these design goals. Section 2 gives an
operatively in networks interacting with their environment. overview of related embedded virtual machines while Sec-
The most prominent example are sensor networks, connected tion 3 describes our generic VM for wireless sensors and
wirelessly in an ad-hoc fashion. These potentially heteroge- embedded devices. Subsequently, in Section 4 we discuss
neous networks are composed of so-called motes which are the effects of our VM design on high-level languages. Next,
limited by scarce resources [1]. Per se, developing applica- in Section 5, we present our corresponding tool chain that
tions for such an environment is challenging. Furthermore, currently supports Java and C#. Finally, in Section 6 we
dynamically distributing, loading, and deleting applications present a compact load-file format which allows applications
is virtually impossible without introducing a higher level to be stream-linked on motes.
of abstraction that shields the application from hardware Our virtual machine is part of IBM Mote Runner, a run-
details. time environment for wireless sensor networks [2].
Such an abstraction layer is provided by a virtual machine
(VM), which levels the underlying hardware from an appli- 2. Related Work
cation point of view. Introducing a VM on small hardware
platforms is a difficult technical task. This effort is beneficial The platforms enabling wireless sensor networks can be
for all future application development, particularly if one is split in two major classes based on available hardware
concerned about device and development cost and hence, resources. The mobile connected class of devices includes
resources and application development support. foremost mobile phones and PDAs with minimal require-
From a design perspective, an important question is ments of a 16 or 32-bit processor, 16-32 KB volatile and
whether the VM should mimic or be derived from an 160 KB non-volatile memory [3]. The mote class of devices
already existing virtual machine such as one of the many have moderate to scarce resources running on 8 or 16-bit

978-0-7695-3669-9/09 $25.00 © 2009 IEEE 117


DOI 10.1109/SENSORCOMM.2009.27
micro-controllers with 1-2 KB volatile memory, 16-48 KB library classes are available at compile time hinders de-
non-volatile memory [1]. This last class represents the lower veloping applications when these resources are unavailable.
bound for our target platform. The Scylla VM mimics the register architecture of modern
From a resource perspective the mote class of devices processors where byte codes are compiled on the fly to native
are comparable with so called smartcards [4] with financial, instructions taking into account energy consumption. The
identification and security applications. The main difference Maté VM provides only a limited byte code highly specific
is that smartcards are usually wired and not self-powered.1 to sensor networks, relies heavily on TinyOS, and does not
Nevertheless, this category of embedded systems represents provide a general virtual machine platform. Both the Scylla
an interesting class because of scarce hardware resource and and Maté VM offer no support for high-level languages such
existing standards — JavaCard for the Java language and as Java and C#.
respective VM [5].
In the mobile phones space there are standards for virtual 3. The Virtual Machine
machines with the most prominent high-level language being
Java. VMs for mobile connected devices follow the Java ME This section discusses our VM design decisions, which
CLDC (J2ME) specification [3]. More recent efforts in the address the goals for the targeted environment.
Java space include the register-based Dalvik VM for the In our system, we define an assembly as the unit of
Android [6] platform. management to be loaded onto or deleted from an embedded
Java ME CLDC, for instance, is a subset of “big” Java device. Each assembly is a versioned container for libraries
with some heavy-weight features such as threads, strings, and applications. All user assemblies are implicitly depen-
and floating-point arithmetic being turned into optional dent on the system assembly which contains basic services.
features of the underlying virtual machine (also known as
kilobyte virtual machine or KVM). Java ME applications 3.1. Stack-Based and Typed
can therefore be executed by Java SE, while many of the
tools developed for Java (e.g., compilers) can be used for For an efficient and compact implementation able to
Java ME as well. The same is basically true for JavaCard. execute on a very small hardware platform, the byte code
A subset approach for the high-level language and cor- is statically typed, which saves an additional lookup to
responding run-time environment also has downsides. For determine the type of the objects on the stack. Having a
example, JavaCard rightfully emphasizes the use of Java’s typed byte code makes it possible to map various statically
16-bit short data type over 32-bit int, but internally the Java typed high-level programming languages onto the byte code,
compiler promotes data types to int. As a consequence, Java most prominently Java and C#. We focus on statically
source code written for JavaCard is either polluted with casts typed high-level languages as they allow code analysis and
to short or, if the virtual machine implements the optional verification, and static type flow analysis.
support for 32-bit int, prone to be slow on small micro- An initial implementation of our VM uses roughly 2 KB
controllers that require significantly more cycles for 32-bit of RAM memory and 23 KB of flash on the AVR 8-bit
computations. platform which is within range for our targeted hardware
More importantly, programming wireless sensors and platform (mote class). We opted for a stack-based VM
embedded devices is fundamentally different from desktop architecture, which offers a more compact application code
programming, which should be also reflected in the byte representation as opposed to register-based VMs [11]. To
codes of the VM. This type of programming is not part of support low-power operation, we allow the embedded device
the main design criteria for both the KVM and the JavaCard to go into deep sleep for as long as possible, only being
byte codes which are a good match for the Java language. active or communicating when necessary (e.g., in reaction
For the mote class of wireless devices there are no to certain events). Therefore, we advocate an event-driven
standards for virtual machines. Possible VM candidates are programming model using delegates as primitive run-time
the Squawk VM [7] running on the SunSPOT hardware, the types.
register-based Scylla VM [8], and the Maté VM [9] running
on top of the TinyOS [10] operating system. The Squawk 3.2. Reactive Programming and Delegates
VM follows the J2ME specification and due to its hardware
requirements (32-bit ARM9 processor, 53 KB RAM, 80 KB Wireless sensors and embedded programming are inher-
flash) fits more into the mobile devices category. Moreover, ently about reacting to external events in the most resource-
by design, the Squawk VM does not allow for application efficient way. That is, embedded applications do not work
development using stubs. Requiring that all system and self-directed but rather are notified whenever an event oc-
curs that the application is interested in. The application
1. Smartcards receive power and perform communication through metal
contact. More recent advances allow smartcards to be powered through then performs some typically short burst of processing in
electrical induction and communicate wirelessly in a near field. response, possibly changes its state, and possibly triggers

118
operations that eventually may result in further events. So, the application state. We choose delegates for our VM as
conceptually there is a finite state machine underlying the they require only a small overhead in terms of memory and
code whose transitions are triggered by events. run-time execution when compared to the previous approach.
There are several approaches in existing systems to imple-
instruction parameters stack before→after
ment such applications. In a purely thread-based model each
call.asm [asmid][methidx] [arg1,...,argn]→[ret]
thread checks on some event and blocks until that event is call.loc [rel] [arg1,...,argn]→[ret]
fired [3]. Supporting threads on small embedded systems has call.virt [virtidx] [obj][arg1,...,argn]→[ret]
two drawbacks. The stack supplied with each thread needs call.ifc [ifcref][ifcidx] [obj][arg1,...,argn]→[ret]
to be large enough to run arbitrary user applications, or the Table 1. Method invocation byte code.
virtual machine must provide a mechanism to dynamically
resize a stack. So, either precious RAM space is wasted
and badly utilized because threads are waiting for events More precisely, the Mote Runner VM introduces specific
most of the time, or the virtual machine gets bigger by byte codes (cf. Table 1)2 to call different types of methods:
implementing and managing a sophisticated stack growing Assembly level methods comprise all static methods from
and shrinking scheme. The virtual machine and operating all classes contained in an assembly. These methods do
system must provide an API and implementation for thread not require an object as context and may be public or
synchronization, thereby again increasing the footprint of private. Public assembly level methods can be called by
the virtual machine. In addition, the application program- other assemblies and their invocation (call.asm) requires
mer is faced with synchronizing concurrency introduced by the assembly and a unique index to select the method.
nondeterministic events. Private assembly level methods, in contrast, cannot be called
As a consequence, we decided against the support of by other assemblies. Their invocation within the assembly
threads altogether and instead favor a purely reactive pro- (call.loc) requires the address of the methods start.
gramming model. In such a model the application registers Virtual methods require an object as context and perform
a method to be called whenever an event fires. This scheme a dynamic lookup of the given virtual method (specified by
requires one and only one virtual machine stack and no an index). The virtual method is known at compile time and
synchronization since only one event handler or callback is is specified as an argument to the byte code (call.virt)
active at any point in time. This scheme is undemanding to while the object is computed at run time and is passed on
implement and results in simple application code as long as the stack.
the handling of events does not require lengthy processing. Interface methods are mapped to virtual methods and
Lengthy processing must be split up into smaller functions have two compile time parameters that uniquely identify
which are driven by a priority task list or by some timer the interface and the method within that interface. At run
event. In thread based systems, such tasks would be assigned time, the object reference is used to lookup a class specific
to a background thread. mapping of interface methods to virtual method indices.
To support a reactive programming scheme in an object- Then, the call (call.ifc) proceeds as a virtual method
oriented language there are basically two possibilities. call.
Firstly, the system API defines either an abstract class or Supporting a delegate mechanism for our virtual machine
interface which must be implemented by applications and now requires constructing a pointer to the various types of
can be registered with the operating system for callback methods described above. Thus, for each call instruction
whenever a specific event occurs. This scheme is resource in Table 1 there is a corresponding delegate instruction.
wasteful as it requires an application to implement many Table 2 shows these instructions which take exactly the
different abstract classes and have as many instances, while parameters and stack arguments as the call byte codes, but
these instances probably just forward the callback to an with two changes: the call arguments are not specified since
object that maintains the application state. When using in- invocation is performed later, and the return value has been
terfaces the disadvantage is that calls introduce an additional replaced by a del value which specifies the method address,
level of indirection which has to be resolved at run time by type, and optionally the object reference as method context
mapping interface methods to virtual methods. passed on the stack.
Secondly, the system allows a pointer to a method to be From an implementation point of view these delegate
registered — an older concept, more recently introduced byte codes are very similar to the actual calls and can be
in object oriented languages by C#, where it is called a
2. An asmid is an assembly identifier, methidx is an index of
delegate [12]. A delegate type describes the parameters and assembly level method, rel is a relative offset to method start, virtidx
return values of the method and at run time holds a pointer is an index of virtual method, ifcref is a reference to an interface
to an object and a pointer to a method implementation. A description, ifcidx is an index of interface method, obj is an ob-
ject reference required as execution context for virtual/interface methods,
delegate concept allows an application programmer to tie arg1,...,argn are the arguments passed to a method, and ret is the
event callbacks directly to those object instances that hold return value of a method.

119
instruction parameters stack before→after
del.asm [asmid][methidx] []→[del]
mind, and as such provide language features which would
del.loc [rel] []→[del] put an unreasonable strain on an embedded device. We
del.virt [virtidx] [obj]→[del] therefore bar the usage of certain Java and C# language
del.ifc [ifcref][ifcidx] [obj]→[del] features. Similar constraints will apply to other languages
Table 2. Delegate definition byte code. and violations are detected and rejected by our converter
(see Section 5) tool.
In accordance with the requirements imposed by embed-
ded devices, language features can be classified as follows.
implemented with a small amount of additional code. They Firstly, features that are not supported at all. In our
perform the same method lookup, but instead of invoking design, these are threads (as discussed before), floating point
the method, they write the delegate value onto the stack. arithmetic, integer data types larger than 32 bits, character
Note that delegates are values and not objects as opposed and string data types, boolean arrays, multi-dimensional
to C#. Choosing delegates to be values means that the array, generics (a.k.a. templates), and run-time features such
implementation is very efficient. Creating a delegate does as inspection and reflection.
not require allocation of an object from the heap, nor does Secondly, supported features with slightly modified se-
overwriting a delegate with a new value create garbage that mantics while keeping the same syntax. 32-bit data types,
has to be reclaimed later by an expensive garbage collection. for example, are mapped by our converter onto 16-bit
instruction parameters stack before→after signed/unsigned integer arithmetic whereas 64-bit data types
del.this either [del]→[obj] are mapped to 32-bit signed integer arithmetic. No explicit
or [del]→[] casts in the source code are needed. In addition, delegates
call.del [localvar] either [obj][arg1,...,[argn]→[ret]
or [arg1,...,argn]→[ret]
are limited to only hold one method pointer. Also, the
exception handling mechanism is slightly modified to match
Table 3. Delegate invocation byte code. the constraints of the platform.
Thirdly, fully supported features; all those not mentioned
so far, including inheritance, interfaces, encapsulation, a
The final element needed is to perform an invocation of large set of signed and unsigned types, array types etc.
a delegate. To achieve this we need two byte codes (cf. Fourthly, extensions of high-level languages via attributes
Table 3). One instruction call.del that actually performs or annotations. Modern languages such as Java and C# can
the invocation. The stack layout must be exactly the same as be extended to a certain degree by custom-defined attributes.
if the method had been called by a regular call instruction We use this mechanism to introduce additional features such
and depends on the type of method: a) assembly level as immutable data and signature mapping.
methods (call.asm/call.loc) no object reference, b) For instance, the immutable attribute allows storage of
virtual/interface method (call.virt/call.ifc) object pre-initialized read-only arrays in persistent memory. Spec-
reference required. ified at the level of the programming language, the attribute
Before the arguments are pushed onto the stack, the is mapped to an attribute in the Mote Runner intermediate
second byte code del.this decides if the call requires language and is also present in the binary file. The signature
an object reference. The instruction examines the delegate attribute for Java, in contrast, maps a Java method signature
value on the stack and either clears the stack or extracts to its counterpart on the platform to mitigate the lack of
the object reference from the delegate value and puts it on unsigned data types in Java. Unsigned data types are valu-
the stack. The call.del instruction locates the method able for a system implementation close to the hardware. The
address using the delegate value stored in localvar and system and other libraries naturally export many methods
invokes it. expecting unsigned types as parameters.
4. Language Representation Listing 1. Java unsigned signature mapping.
@com.ibm.saguaro.system.attr.
This section complements the previous design decisions Signature("(u[],u,u,u)u")
public static int fillData
by considering high-level programming languages such as (int[] ary, int off, int len, int filler){}
Java and C# and defining a subset applicable to embedded
systems, adds extensions to efficiently support delegates and The sample code in Listing 1 defines a method
shows how these are used in practice. fillData with parameters of signed primitive and signed
primitive array types and includes a Signature attribute
4.1. Language Subset indicating the concrete receiver method on the platform.
Such a method typically is just an empty stub exporting
High-level object-oriented languages such as Java and C# an API to Java. Note that the converter does not have a
have been developed with desktop or server computing in predefined scheme of signature mappings due to possible

120
polymorphism-related caveats, and that the converter does Listing 4. Delegate-pattern code for Java.
not generate any code for these type conversions. It is up // The delegate class defined in the system package.
public abstract class Delegate {
to the Java programmer to handle the signed types in the public Object target;
context of unsigned operations correctly. public Delegate(Object o) { this.target = o; }
}
// The delegate subclass declaring the concrete
// delegate type, typically part of a library
4.2. Language Mapping public abstract class LibDelegateType
extends Delegate {
public LibDelegateType(Object o) { super(o); }
While the discussion so far is about if and how to support public abstract int call(int arg0, int arg1);
certain language features, we also have to look the other }
// The library which requires the above delegate type
way round. How are delegates as the key element of our public class Lib{
event-driven programming model represented in high-level void register(LibDelegateType d){
// library specific code for delegate registration
programming languages? }
}
// The application making use of the delegate
4.2.1. Delegates in C#. For C# the answer is rather straight- public class Appl {
forward. Delegates are a readily built-in language feature public void sender() {
LibDelegateType d = new LibDelegateType(this) {
that can be used as is. public int call(int arg0, int arg1){
return ((Appl) target).receive(arg0, arg1);
}
Listing 2. Example delegates in C#. };
namespace Lib { // The delegate can be passed around freely
public delegate int onSensorEvent(uint value); Lib.register(d);
} // or it is invoked...
namespace Samples{ d.call(10, 20);
public class Sample { }
Sample() { public int receive(int arg0, int arg1){ return 0; }
Lib.Sensor.watch(Sensor.TEMPERATURE_SENSOR, }
new Lib.onSensorEvent(this.onEvent));
}
public int onEvent(uint value) { } The sample code in Listing 4 shows the supported map-
}
} ping of delegates in Java. It uses an abstract system class
Delegate which stores the object reference and is the
Listing 2 demonstrates use of delegates in the Mote Runner anchor for the delegate recognition by the converter. System
environment. The method Sensor.watch is a library and libraries define abstract subclasses for each delegate they
method which checks periodically whether a sensor value require and accept for the notification of applications. The
resides in a certain range. If these boundaries are violated, converter can generate them automatically from exchange
the application class Sample is notified by a call to its files of libraries implemented in any other language. The
delegate, onSensorEvent. purpose of these subclasses is to specify the concrete signa-
In Mote Runner, delegates are built-in objects which do tures of any receiver method (analog to a declaration in C#).
not inherit from the base object class. This allows for a The application creates an instance of a subclass overriding
very resource efficient implementation despite the complex the call method. In the overridden method, the subclass
addressing scenarios introduced by delegates. As a conse- defines the run-time receiver method and passes the target
quence, however, the converter has to reject assignments reference in the constructor invocation. The created instance
to null of both an object and delegate reference (cf. of derived type of Delegate can be passed freely and its
Listing 3). This construct is deemed invalid because the delegate mechanism is triggered by the invocation of call.
Mote Runner system has to treat the built-in delegate type The language mapping also allows for the delegation to
differently from object references. static methods when the call method in the inner class of the
application references a static instead of an instance method.
Listing 3. Invalid use of delegates. Similar to C#, the converter checks for a correct use of
delegate void MyDelegate();
object o; MyDelegate d; the Delegate mechanism and rejects invalid operations
o = d = null; // invalid: a Delegate is not an Object such as implicit or explicit casts to/from Object. The
o = null; // ok
d = null; // ok converter also rejects more than one target method signature
in Delegate subclass declarations as it can only describe a
single method signature. Relying on generics could simplify
4.2.2. Delegates in Java. For Java, though, the situation is the code as no cast would be required. Reliance on such
slightly more complicated as delegates are not a language language features hinders an obvious specification of the
construct. Nevertheless, it is possible to emulate delegates by supported valid language subset. Instead, we plan to rely on
specific language patterns which then are recognized by our code wizards in IDEs, such as Eclipse, and the converter to
converter and mapped onto the aforementioned byte codes. help the programmer generate the necessary code pattern.

121
C# CLI assembler3 Mote-Runner assembler3
// step 1 // step 1 ;; step 1
public delegate .class MyDelegate extends ; Delegate is a built-in
int MyDelegate(int x); [mscorlib]System.MulticastDelegate { ; 32-bit data type. Thus,
.method void .ctor(object ’object’, ; nothing must be declared
native int ’method’)
.method int32 Invoke(int32 x) }

// step 2 // step 2 ;; step 2


public class Sample { .class Sample{ .class public Sample
public static void test() { .method static void test() { .method public static test()v
.maxstack 3 .limit stack,2
.locals init ([0] class A a, .limit local,3
[1] class MyDelegate d) .lvar 0,r:A,aobj
.lvar 1,d,d

// step 3 // step 3 ;; step 3


// create an instance newobj instance void A::.ctor() new r:A
A aobj = new A(); stloc.0 dup
call.asm A.A(r:A)
st.r.0

// step 4 // step 4 ;; step 4


// create a delegate ldloc.0 ld.r.0
MyDelegate d = dup del.virt A.m(i)
new MyDelegate(aobj.m); ldvirtftn instance int32 A::m(int32) st.d.1
newobj instance void
MyDelegate::.ctor(object, native int)
stloc.1

// step 5 // step 5 ;; step 5


// invoke the delegate ldloc.1 ld.d.1
if (d(8) == 0x2008) ldc.i4.8 del.this ; put aobj to stack
success = true; callvirt instance int32 ldc.b 8
MyDelegate::Invoke(int32) call.del
... ...
} } .end
} } .end
class A { .class A { .class A
public virtual int m(int x) { .method int32 m(int32 x) { .method m(i x)i
return x + 0x2000; ... ...
} } .end
} } .end
step 1 delegate object on the heap NO delegate object on the heap
step 5 delegate object indirection NO delegate object indirection
Figure 1. Comparison: creating and invoking a delegate byte codes.

4.2.3. Delegate Byte Code Comparison. We compare our and the necessary delegate information is transported in few,
delegate byte codes with the corresponding byte codes in the very resource efficient instructions. In step 4, the delegate is
CLI. We use the same example program, written in C# as instantiated. In the CLI byte code, ldvirtftn is used to
the high-level language, which is compiled to the respective lookup the method table index of the target method which
Mote Runner and CLI assembler code. Using the boilerplate is passed to the constructor invocation. In Mote Runner,
Java pattern for delegates (cf. Section 4.2.2) translates in the delegates are built-in types and the delegate information of
same Mote Runner assembler code. A direct comparison reference and index is thus stored directly in two cells on
with Java byte codes is not possible as the original Java the stack. Step 5 shows the invocation of the delegate. In
language provides no support for delegates. CLI, the delegate is called and the run-time environment and
Figure 1 takes a close look at the language and byte-code native code are responsible for forwarding the call. In Mote
level of C#, the CLI and Mote Runner and helps to explain Runner, object reference and method index are loaded in the
the correspondence. In step 1, a delegate is declared. This stack and the VM itself handles the delegate mechanism.
leads to the generation of a Delegate subclass in the CLI Figure 2 depicts the difference between objects and the
byte code, similar to what the Java mapping requires. In delegate built-in type in Mote Runner in contrast to CLI.
Mote Runner, no delegate class is stored in the binary as Storing null in a delegate reference requires an extra byte
type information is in general removed as much as possible code in Mote Runner as 2 16-bit cells on the stack must be
cleared whereas in CLI the delegate reference is as a regular
3. The listings are simplified to focus on the code relevant for compari- object reference.
son. Our delegate byte codes are more efficient than the

122
C# CLI assembler3 Mote Runner assembler3 In step 1, the source code is compiled with a standard
...
MyDelegate d;
...
ldc.null ; normal 16-bit null compiler for the respective language. For Java this might be
ldnull
d = null;
stloc.1
r2dd ; delegates are 32-bit the Sun Java SE compiler, for C# there are the Microsoft
st.d.1
and Mono compilers. Next, in step 2, the resulting byte
Figure 2. Comparison: Null-ing a delegate. code is converted by our own converter into an intermediate
language format, an object-oriented assembler which uses
our own byte code. These assembly files are processed by
our assembler in step 3 to generate compact load files that
can be loaded to and stream-linked on the embedded device
(see Section 6 for more details). When the output is a library
instead of an application, the assembler further generates
so-called exchange files describing the public API of the
generated library. From these exchange files a stub generator
creates in step 4 matching high-level language stub libraries
against which other applications written in these high-level
languages can link.

6. Load Files and Stream Linking


Dynamically loading and linking applications on power
constrained devices is a crucial aspect. Stream linking allows
for linking applications in a single pass and without costly
fix-ups (e.g. writing to flash memory) which consequently
saves computation cycles and valuable battery resources.
Moreover, communication itself, and especially radio com-
munication consumes power in the same order of magnitude
as running computations on the micro-controller [13]. To
meet our low-power design goal, it is crucial to be able
to stream link as well as transmit as little as possible
when loading new applications, particularly if multi-hops
are involved. Hence, we introduce a compact load-file for-
mat which allows applications to be stream linked on the
embedded device. In our system, a load-file is the binary
Figure 3. Mote Runner tool chain from source code to representation of an assembly (cf. Section 3.)
executables. Load files are transferred to the embedded device using a
protocol which divides the load-file into smaller units that
fill up a transmission unit including the protocol overhead.
corresponding CLI byte codes in terms of performance on an On the embedded device, a loader and linker processes the
embedded system, as we eliminate the indirection introduced load-file chunks sequentially, internally buffering in RAM
by object encapsulation. Moreover, to our knowledge there until enough data has been received to process some logical
is no other embedded VM with native support for delegates. structure. The load file is designed so that modifications of
the loaded data structures can take place in RAM before
5. Tool Chain they are eventually flushed out to persistent storage (flash,
EPPROM). This technique avoids processing stored data a
A virtual machine, especially one that introduces a new second time to perform fix-ups and reduces flash strain.
byte code, cannot stand isolated. We have therefore devel- To facilitate loading and linking using a small RAM
oped a complete tool chain that currently supports both Java buffer, the load file contains transient information which
and C#. This tool chain allows multi-language development only serves to help fix up certain values. These transient data
in the sense that a library written in one of the supported elements are removed during loading and linking and are not
languages can be used from any other of the supported written to persistent storage. Furthermore, to reduce the size
languages. For Java and C#, the process is shown in Figure 3, of load files, padding is omitted which can be reconstructed
where tools are represented on the left side and their on the fly by the loader on the embedded device.
resulting file artifacts on the right side — our contributions All integer values are encoded in big endian byte order;
are highlighted. the loader can adapt the byte order to the specific platform

123
Ratio
Application Classes Mote Squawk Dalvik JavaCard experience with load files which can be stream linked while
Name (bytes) Runner even compacter. The Squawk and Dalvik virtual machines
Empty 126 0.67 9.94 3.21 1.11 have a weighted average ratio of 59% and 84% respec-
Hanoi 418 0.46 3.30 1.80 0.62
Matrix 643 0.47 2.04 1.54 0.52
tively. Noticeable is also a relatively large overhead for the
Queens 753 0.60 1.94 1.47 0.67 Empty example for these two platforms. Such overhead is
Primes 2131 0.35 0.99 1.13 0.38 introduced by references to system classes and inclusion of
Richards 4688 0.24 0.52 0.82 0.24
Sort 6401 0.23 0.57 0.89 0.26
resources such as a manifest file. However, this information
DeltaBlue 15399 0.26 0.29 0.67 0.27 is required on the respective platforms. In the examples
Weighted containing a larger code base, the overhead levels out and
Average 0.27 0.59 0.84 0.30
all platforms exhibit a significant compaction with respect
Stream
Linking yes no no no
to the corresponding Java class files.
The class files are obtained by using a standard Java com-
Table 4. Image size compaction comparison. piler (Sun JDK 1.5.0 16) with flags to enable optimization
and exclude all debug information (--O --g:none) which
would unnecessarily increase the size of the Java class files.
To make the comparison fair on both sides, optimization
during upload to optimize run-time speed. Further, all ad- was enabled and debug information was disabled also for
dressing of classes, methods, and so on inside the assembly the tools generating the image or load-file for all platforms.
are either relative to the current position or are relative to All tests were performed without compression.
the base address of the assembly header component.
6.2. Different High-Level Languages and Compil-
6.1. Compact Load Format Evaluation ers
We evaluate the Mote Runner compaction ratio of load- Using our tool-chain, the same program written in C#
files when compared to the respective Java classes. Our and Java produces a load-file size within 3.2% standard
system is the only one supporting stream-linking, which deviation, normalized by the assembly size. Choosing dif-
translates into more efficient application management. ferent compilers for the same language has no significant
The Empty example is a class containing no methods impact on the load-file size. The Mote Runner assembly
and no members and is an indication of the overhead load-files obtained by compiling Java source code are on
incurred by the various platforms. Hanoi is a recursive average 27% of the size of the corresponding Java class
implementation to solve the towers of Hanoi problem. The files. The Mote Runner assembly load-files obtained by
Matrix test implements a matrix multiplication algorithm. compiling C# source code are on average 21% of the
Queens finds all solutions for the well-known problem of corresponding dynamic link library (dll) file compiled with
placing 8 queens on a chess-board without any of them being the --target:library --optimize flags. The ratio
attacked by the others. The Primes test computes the sum of is smaller for C# because the dll file generated by the C#
the first 32 prime numbers for 4 different data types: byte, compilers contains a significant amount of padding which
int, unsigned int, and long. These examples have a small makes its size larger when compared with the respective
to medium code size which exposes overhead required to Java class files.
encapsulate an executable image. The last three examples
have a larger code size which stresses both computation 7. Next Steps
and size of the executable image. Richards is a simulation
of a task dispatcher in an operating system based on the Performance for an embedded VM is a very difficult
original from Martin Richards. Sort is an implementation of topic which encompasses many aspects and deserves a full
a sorting algorithm for the same data types. DeltaBlue is paper treatment. One crucial issue is what are the rele-
an implementation of the incremental constraint hierarchy vant performance metrics? Various approaches use micro-
solver algorithm with the same name. benchmarking, macro-benchmarks, or application bench-
Table 4 compares the library load-file (or image) size in marks to determine characteristics for run-time, life-time,
bytes for the Mote Runner against the equivalent for other resource usage, etc. Such performance metrics could include:
embedded platforms: SunSPOT (Squawk VM), Android power consumption per VM instruction, number of cycles
(Dalvik VM) and JavaCard. Mote Runner outperforms all per VM instruction, application execution time, VM memory
tested platforms with a weighted-average load-file size 27% usage, application memory usage and life-time.
of the size of the corresponding Java class files. The second A comparison with other embedded environments and
smallest size is observed for the JavaCard with an average VMs requires a common hardware platform for running
of 30%. In Mote Runner, we improve on our JavaCard [4] benchmarks. Consequently, we are in the process of porting

124
our system to various 8, 16, and 32-bit embedded wireless [9] P. Levis and D. Culler, “Maté: A tiny virtual machine for sen-
sensor platforms. sor networks,” in International Conference on Architectural
Support for Programming Languages and Operating Systems,
San Jose, CA, USA, 2002.
8. Summary and Conclusions
[10] J. Hill, R. Szewczyk, A. Woo, S. Hollar, D. Culler, and K. Pis-
In this paper we presented a multi-language virtual ma- ter, “System architecture directions for networked sensors,”
chine especially designed for wireless sensors and small SIGPLAN Not., vol. 35, no. 11, pp. 93–104, 2000.
embedded hardware platforms in general. Our Mote Runner
virtual machine is capable of efficient loading and stream [11] Y. Shi, K. Casey, M. Ertl, and D. Gregg, “Virtual machine
linking of applications which is a prerequisite for power- showdown: Stack versus registers,” ACM Trans. Archit. Code
Optim., vol. 4, no. 4, pp. 1–36, 2008.
aware application management in a post-deployment phase.
For our targeted event-driven environments, we advocate [12] J. Miller and S. Ragsdale, The Common Language Infrastruc-
the use of delegates as a basic building block, which is ture Annotated Standard, ser. Microsoft .NET Development
reflected in the byte code of our virtual machine. To our Series. Boston, MA, USA: Addison-Wesley, 2003.
knowledge there is no embedded VM with native support
[13] J. Polastre, R. Szewczyk, and D. Culler, “Telos: enabling
for delegates. ultra-low power wireless research,” in IPSN ’05: Proceedings
To complement the VM, we also presented the necessary of the 4th international symposium on Information processing
tools to transform certain high-level programming languages in sensor networks. Piscataway, NJ, USA: IEEE Press, 2005,
such as C# and Java to our byte code and create dynamically p. 48.
loadable assemblies of applications and libraries.
Programming wireless sensors and embedded devices us- Note: All web references were last accessed in December 2008.
ing high-level languages greatly eases developing and main-
taining applications. The focus is shifted towards solving Some of the product, company or services names referred to in this paper
domain specific problems and developing the corresponding may be trademarks or registered trademarks of third parties in the USA,
other countries, or both.
application rather than hardware specific details and tools.
Moreover, a VM ensures code portability across compatible
sensing platforms.

References
[1] J. Hill, M. Horton, R. Kling, and L. Krishnamurthy, “The plat-
forms enabling wireless sensor networks,” Commun. ACM,
vol. 47, no. 6, pp. 41–46, 2004.
[2] IBM, “Mote Runner Project Website,” http://www.zurich.ibm.
com/moterunner, 2008.
[3] Sun Microsystems, “Connected Limited Device Configura-
tion: Specification Version 1.1 JavaTM 2 Platform, Micro Edi-
tion (J2METM ),” 2003.
[4] M. Baentsch, P. Buhler, T. Eirich, F. Horing, and M. Oestre-
icher, “Javacard-from hype to reality,” IEEE Concurrency,
vol. 7, no. 4, pp. 36–43, 1999.
[5] Sun Microsystems, “Virtual Machine Specification: Java
CardTM Platform, Version 3.0, Classic Edition,” 2008.
[6] Google, “Android,” http://code.google.com/android, 2008.
[7] D. Simon, C. Cifuentes, D. Cleal, J. Daniels, and D. White,
“JavaTM on the bare metal of wireless sensor devices: the
Squawk Java virtual machine,” in VEE ’06: Proceedings
of the 2nd international conference on Virtual execution
environments. New York, NY, USA: ACM, 2006, pp. 78–88.
[8] P. Stanley-Marbell and L. Iftode, “Scylla: a smart virtual
machine for mobile embedded systems,” in WMCSA ’00: Pro-
ceedings of the Third IEEE Workshop on Mobile Computing
Systems and Applications (WMCSA’00). Washington, DC,
USA: IEEE Computer Society, 2000, p. 41.

125

You might also like