compiling java for low-end embedded systems ulrik p. schultz isis/daimi university of aarhus kim...
Post on 19-Dec-2015
214 views
TRANSCRIPT
Compiling Java for Low-End Embedded Systems
Ulrik P. SchultzISIS/DAIMI
University of Aarhus
Kim BurgaardSystematic Software
Engineering A/S
Flemming G. Christensen
Jørgen L. KnudsenMjølner Informatics
A/S
Based on joint work with:
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
2
Motivation Scenario: baggage control system
Family of tiny embedded systems (e.g., ½K RAM, 4K ROM)
Opportunities for software reuse… across hardware platforms across device types
Immediate solution: use C++ Large minimal memory footprint when using
virtuals Unneeded library/framework code included
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
3
Motivation Scenario: baggage control system
Family of tiny embedded systems (e.g., ½K RAM, 4K ROM)
Opportunities for software reuse… across hardware platforms across device types
Immediate solution: use C++ Large minimal memory footprint when using
virtuals Unneeded library/framework code included
This talk: use compiled “Java” instead!
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
4
Motivation Scenario: baggage control system
Family of tiny embedded systems (e.g., ½K RAM, 4K ROM)
Opportunities for software reuse… across hardware platforms across device types
Immediate solution: use C++ Large minimal memory footprint when using
virtuals Unneeded library/framework code included
Relevance to JavaCard?
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
5
Relevance of a Java compiler
JavaCardsoftware
(1) downloadbytecode
Runtime system
(also in Java!)(1) compilestatically
Binaryexecutable
image
Standard approach Alternative approach (this talk)
(2) run on JVM
+JAVA
(2) producecheap cards
(3) executedirectly on card
(c.f. Jean-Jacques Vandewalle, #3)
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
6
Outline
1. Low-end embedded systems vs. Java
2. Our solution: JEPES3. Non-intrusive configuration (IDC)4. Stack size analysis5. Experiments6. Conclusion & future work
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
7
Low-end embedded systems vs. Java Pervasive computing 8/16 bit devices vs. 32-bit devices:
cheaper, more robust, lower power consumption, more predictable
resource constrained (RAM, ROM, CPU) This talk: 8-bit devices with very little
memory Java pros and cons:
object-oriented, simple, platform independent automatic memory management inefficient execution
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
8
Our solution: JEPES Scalable Java execution platform for low-end
embedded systems Language: larger than JavaCard, smaller than
J2ME (different API, no dynamic class loading, static/stack allocation [more], …)
Compiler: ahead-of-time compiler outputs Atmel AVR, Hitachi H8, x86, or Java bytecode; bare-bones execution; space-saving optimizations driven by global analyses [more]; stack size analysis [more]
Hardware-close programming: interface-directed configuration [more]; API with hardware access (streams, interrupts, ...)
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
9
Compiler optimizations No pointers => easy to optimize Interprocedural CHA, inlining, stack
allocation, tree shaking, etc. Ghost allocation:
…Stream getStream() { Serial port=new Serial(); port.setBaudRate(9600); port.setHandShake(Serial.HS_HW); return port;}
…Stream s=io.getStream();s.writeByte(b);
• Constant propagation and method inlining allows serial port object to be completely eliminated
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
10
Interface-directed configuration: basic idea
Problem: need for extra configuration information (e.g., interrupt handlers need alternate call semantics)
Solution: use Java interfaces to attach semantic properties to classes (Java example: java.io.Serializable)
JEPES example: interrupt handler for vector 0x0E
interface InterruptEHandler {}
InterruptEHandler.java
InterruptEHandler { methods { static void handlerE() { vector = 0x0E; } }}
InterruptEHandler.jid
class Handler implements InterruptEHandler { … static void handlerE() { … }}
Handler.java
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
11
Interface-directed configuration Non-intrusive
no special syntax needed specific information declared elsewhere
No “magic” names Used in JEPES for
interrupt handlers and interrupt control [more] assembly macros for direct hardware access forcing ghost allocation and stack allocation
[more] external access …
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
12
Memory management1. Heap allocation (not relevant here: ½K RAM)2. Static allocation
3. Stack allocation can be forced using IDC, forced when no GC intuition: type checking
interface StackedIterator extends Iterator, StackAlloc {}
StackAlloc { class { stack-allocate; }}
jepes/lang/StackAlloc.jid
Iterator i = new SetIterator(…);printAll(i);
class SetIterator implementsStackedIterator { … }
static final queue = new Queue(…);
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
13
Stack size analysis: what Each stack frame has fixed size (including
stack-allocated objects) Memory consumed at run-time bounded by:
statically allocated objects, plus highest sum of stack frame sizes in
approximated call graph (assuming fixed-size arrays)
But: interrupts are part of the call graph!void process() { Iterator i = …; while(i.hasNext()) { Record c = (Record)i.next(); c.update(…);}
static void handle_INT0() { Context c = …; …}
INT0
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
14
Stack size analysis: how
Solution: interrupt-aware analysis [Brylow, Damgaard, Palsberg: ICSE’01]
Caveats: interrupt control is low-level
analysis is complex (although efficient)
void criticalOperation(byte[] data) { int old_mask = System.getInterruptMask(); System.setInterruptMaskXOR(Atmel.INT0); … System.setInterruptMask(old_mask);}
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
15
Simple stack size analysis (1)
1. Use IDC to declaratively control interrupts
2. Simple static analysis propagates interrupt enable/disable at method granularity
public class InputProcessor implements DisableINT0 { void criticalOperation(byte[] data) { … }}
process(){ }
criticalOperation(){INT0 disable}
handle_INT0(){global disable}
handle_INT7(){global disable}
INT0
INT7
storeData(){INT7 disable}
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
16
Simple stack size analysis (1)
1. Use IDC to declaratively control interrupts
2. Simple static analysis propagates interrupt enable/disable at method granularity
public class InputProcessor implements DisableINT0 { void criticalOperation(byte[] data) { … }}
process(){ }
criticalOperation(){INT0 disable}
handle_INT0(){global disable}
handle_INT7(){global disable}
INT0
INT7
storeData(){INT7 disable}
none disabled
all disabled
INT0 disabled
INT0,INT7 disabled
all disabled
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
17
Simple stack size analysis (2)
3. Construct interrupt-aware call graph which includes potential interrupt handler calls
4. Compute stack depth on interrupt-aware call graph (cycle means unbounded)
process(){ }
criticalOperation(){INT0 disable}
handle_INT0(){global disable}
handle_INT7(){global disable}
INT0
INT7
storeData(){INT7 disable}
none disabled
all disabled
INT0 disabled
INT0,INT7 disabled
all disabled
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
18
Simple stack size analysis (2)
3. Construct interrupt-aware call graph which includes potential interrupt handler calls
4. Compute stack depth on interrupt-aware call graph (cycle means unbounded)
process(){ }
criticalOperation(){INT0 disable}
handle_INT0(){global disable}
handle_INT7(){global disable}
INT0
INT7
storeData(){INT7 disable}
none disabled
all disabled
INT0 disabled
INT0,INT7 disabled
all disabled
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
19
Simple stack size analysis (2)
3. Construct interrupt-aware call graph which includes potential interrupt handler calls
4. Compute stack depth on interrupt-aware call graph (cycle means unbounded)
process(){ }
criticalOperation(){INT0 disable}
handle_INT0(){global disable}
handle_INT7(){global disable}
INT0
INT7
storeData(){INT7 disable}
none disabled
all disabled
INT0 disabled
INT0,INT7 disabled
all disabled
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
20
Experiments
0 0,2 0,4 0,6 0,8 1
Lego lift
Valve controller
Bridge (object)
Bridge (static)
EightQueens
Dragon
KvmHttpTest
Native size
Java size
KVM demo(avg. size: 68K)
average: 32.6%
JEPES demo(avg. size: 8K)
native average: 18.9%
footprint: 1511B
ROM, 50B RAM
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
21
Future work
Compilation of JavaCard programs Real experiments:
large, realistic programs instantiated from frameworks (Bang & Olufsen A/V infrastructure?)
smart dust More aggressive program
configuration using partial evaluation techniques
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
22
Summary JEPES allows ”Java” to be used on a ½K RAM
4K ROM embedded system Interface-directed configuration:
non-intrusive, Java-style assembly macro, interrupt handler, force stack
allocation, … Static memory (stack) size analysis Initial experiments:
CHA essential stack allocation discipline acceptable stack size analysis would benefit from context
sensitivity[Availability: commercial product from Mjølner, GPL version pending]
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
23
JEPES concurrency model
Interrupts: event-driven concurrency
Threads: interface to underlying OS (example: LegOS)
Standard thread API for embedded devices? Interaction between threads and interrupts?
System.disableInterrupts();… // critical codeSystem.enableInterrupts();
Statement level Method granularity (declarative)public class IP implements DisableINT7 { void process(byte[] data) { … }}
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
24
JDK 1.5 Annotation Types JDK 1.5 supports source-level program
annotations (compiled into class file attributes)
Usable in JEPES for interrupt handlers, interrupts masking
assembly macros, external access, …
public class InputHandler { @DisableInterrupt({Atmel.INT0,Atmel.INT7}) void handle(byte b) { … }}
Schultz, ISIS/DAIMI, University of Aarhus CASSIS'04
25
Interface-directed configuration: assembly macros
Assembly macros
High-performance, complement native methods, simulation code easy to implement
class SerialImp implements jepes.io.ISerialImp { byte readByte() { return 0; } void writeByte(byte b) { ; }}
jepes/io/bus/SerialImp.java
Receive: SBI UCR,RXENSBIS USR,RXCRJMP Receive ; Wait until readyIN <@R>,UDR ; Write data to return registerCBI UCR,RXEN ; Clear receive flag on UART
jepes/io/bus/ISerialImp/AVR/readByte__B.asm