Here is the presentation I did at Trifork GeekNights, January 12+13.
The talk is about my journey into Erlang land, how we need to start thinking about threads and processes in a new way, and some aspects of the work I have done towards implementing Erlang on the JVM platform.
Follow-up discussion either at my blog: http://javalimit.com/ or at http://groups.google.com/group/erjang
3. My Goal Today
• Erjang is an exploration project.
• Today I will show that it is viable.
• I cannot complete it myself.
• I need to find people who want to help
make it complete, and build a
community.
4. I’m an Explorer
I’m an explorer
Illustration for french edition : Comment j'ai retrouvé Livingstone. Paris : Hachette, 1876.
Title : Rencontre de Livingstone
5. Why?
• Trends
• Multi core / network-on-chip CPUs
• Distributed / Cloud services composition
• Thus, we need to make it easy to...
• Do distributed/concurrency
programming
• Make such systems reliable
6. What factors increase our
Capacity for Complexity?
A. Our system’s ability to perform and
scale as problem size grows.
B. Our ability to understand and
reason about systems
as they grow big.
7. What factors increase our
Capacity for Complexity?
A. Our system’s ability to perform and
scale as problem size grows.
B. Our ability to understand and
reason about systems
as they grow big. I’m an
intuitive
person...
17. Concurrency Landscape
Explicit / Implicit /
Reactive Functional
Here we need to
understand and
reason about
parallelism
18. Concurrency Landscape
Explicit / Implicit /
Reactive Functional
Here we need to Here, we
understand and abstract the
reason about parallelism
parallelism away
19. Concurrency Landscape
Explicit / Implicit /
Reactive Functional
Distributed Telephone Systems Search Engine
Trading Systems Indexing
Erlang / CORBA Model Simulations,
Message Middleware Weather Forecasts
Local GUI-applications Google/Hadoop
Control Systems Map-Reduce
Data-Parallelism
Threads
20. Trend in “New”
Concurrency Languages
• Clojure • Comprehending
concurrent systems is
• F# difficult
• Scala + Actors • Mutable state is bad
• Erlang • Make things simpler
21. Understanding Learning by
Doing: Don't Dissect
Actors the Frog, Build It.
• To really understand actors,
I wrote a simple actor framework for
Java.
• Each “actor” has an interface, and a
behavior that implements that interface.
• The framework creates a proxy that
implement the interface and dispatches via
a thread pool...
22. Java Actor Framework
client
«interface» «abstract class»
Logger ActorBehavior
«class»
Proxy LoggerBehavior
Thread Pool
23. Java Actor Framework
// the actor’s interface
interface Logger {
void log(String val);
}
// ... and it’s behavior
class LoggerBehavior extends ActorBehavior<Logger> {
void log(String val) { System.out.println(value); }
}
// ... then use it like this...
Logger logger = new LoggerBehavior().actor();
logger.log(“Something happened”);
24. Issues with this approach
Sharing. If an actor receives a reference to
a shared object then multiple actors/threads
may mutate that object concurrently.
Threads. If an actor blocks during it’s
operation, it is holding a precious resource,
namely a thread.
Concurrency. If the actor’s methods returns
a value, then the client will block, or what?
25. Why is Erlang interesting?
• Design context is suddenly relevant
• 20 years of experience in the community
• Real production use
• Ericsson, CouchDB, Riak, ...
• Amazon, Linked-in, ...
• Getting Popular ➟ Developer Availability
27. Reliable Systems
link
Computer A Computer B
• You need at least two pieces of hardware
to make a reliable system; one monitors
the other.
• Abstract this notion to software, and you
have the Erlang error handling
mechanism.
28. Reliable Systems
link
Process A Process B
• One process “supervises” the other
• Make code in “Process B” simpler
• Allow upgrade/modification of code in
“Process A” when a new kind of failure
appears.
29. Process ≡ Actor ≡ Object
• Erlang processes have many characteristics
of objects
• Identity
• Polymorphism
• Encapsulation
“The way objects should have been”...
32. BEAM files
• Erlang modules compile to byte code
• .BEAM file
• Module ring in ring.beam
• Similar to “Java .class file”
• .beam files are read by an “error handler”
when missing modules/functions are seen.
35. Erjang BEAM Loading *
currently external
erlang:load_module error_handler:undefined_function
erlang service
“beam_loader”
BEAM Reader ring.beam
Type Analysis ClassLoader.loadClass(“erjang.m.ring”)
JVM Codegen ring-2a149ada.jar
36. Erjang BEAM Loading *
currently external
erlang:load_module error_handler:undefined_function
erlang service
“beam_loader”
BEAM Reader ring.beam
Type Analysis ClassLoader.loadClass(“erjang.m.ring”)
JVM Codegen ring-2a149ada.jar
package
erjang.beam
37. Light-Weight Processes
• Threads don’t cut it;
• Typical JVMs are limited to ~1000
threads
• Context switch for threads is very
expensive
• Erjang uses Kilim, a separate project
• Run ~2-4 threads to utilize processors
38. Kilim
Kilim: Isolation-Typed Actors for Java 105
;":")
",,-&"&%. &'!%( /'&%(
!"#$%
$#) )*%)+ )-.%
*%"! 2$-1"&2-, 345 /'&%(
%<&%#,"1 0-.%1 )*%)+ &#",$6-#0 )-.%
",,-&"&2-,$
7212089%":%#
Fig. 1. javac output post-processed by Kilim weaver
network and disk) [4] and service-oriented workflows. With a view to immedi-
ate industrial adoption, we impose the following additional requirements: (a) no
changes to Java syntax or to the JVM, (b) lightweight actors1 (c) fast messaging
(d ) no assumptions made about a message receiver’s location and implementa-
39. Kilim
• Rewrites code in methods declared
‘throws kilim.Pausable‘
so that they can
• save call stack to “fiber data structure”
• and restore it later, continue execution...
40. Kilim Rewriting, in brief ...
class Actor extends kilim.Task {
void execute() { .. throw error ...}
void execute(Fiber f) throws Pausable {
switch (f.pc) {
case 0:
class Actor extends kilim.Task { f.down();
void execute() throws Pausable { mbox.get(f);
switch(f.up()) {
// also declared Pausable case SAVE_STATE:
mbox.get(); case SAVE_NO_STATE:
} .. f.stack.push(new State(...));
} case NORMAL_NO_STATE:
case NORMAL_STATE:
}
}
}
41. $"!! &#!!!
%&'()* ()*+,-
+,',- ./*/0
&"!!!
$!!!
&!!!!
#"!!
%!!!
$!!!
#!!!
#!!!
"!!
"!!!
! !
! "!!!! #!!!!! #"!!!! $!!!!! ! &!!! "!!! '!!!
(a) Creation and Destruction (b) Messaging
Fig. 11. Erlang vs. Kilim times. X-axis: n actors (n2 messages), Y-axis: Time in ms
(lower is better).
Kilim
Kilim’s creation penalty is negligible (200,000 actors in 578ms, a rate of 350KHz),
and scaling is linear. We were unable to determine the reason for the knee in the
Erlang curve.
Messaging Performance. The second test (Fig. 11(b)) has n actors exchanging n2
messages with one another. This tests messaging performance and the ability to
make use of multiple processing elements (cores or processors). Kilim’s messaging
48. ETuple
Subclasses ETupleN (for an n-tuple) are
generated on-demand, and distinct.
elemN fields are public, but can only be
accessed from generated code...
ETuple0, ETuple1 and ETuple2 hand coded;
otherwise use ETuple.make(EObject...)
Tuples in erlang are 1-indexed; coding
convention is to use idx1 for 1-indexed, and
idx0 for 0-indexed index variables.
49. ECons
ECons & ESeq ESeq EPair EBinList
ENil EList EString
• ESeq is a well-formed list - similar to
Clojure ISeq; .tail() is also an ESeq.
• EString is list of small integers [0..255]
• EPair is a non-well-formed list
• EBinList is [byte,byte,byte | Tail]
50. EFun / Functions
abstract class EFun extends EObject {
/** generic invoke, used only for apply */
public abstract EObject apply(EProc proc, ESeq args)
throws Pausable;
/** used for of tail recursive calls */
public abstract EObject go(EProc eproc)
throws Pausable;
}
51. EFun / Functions
/** generated base class for functions with 2 arguments... */
abstract class EFun2 extends EFun {
/** generic invoke, used only for apply */
public abstract EObject apply(EProc proc, ESeq args) throws Pausable {
EObject arg1 = args.head();
EObject arg2 = args.tail().head();
/* add error checking ... */
return invoke(proc, arg1, arg2);
}
public EObject invoke(EProc proc, EObject arg1, EObject arg2)
throws Pausable {
EObject res = this.body(proc,arg1,arg2);
while(res == TAIL_MARKER) { res = proc.tail.go(); }
return res;
}
...
52. EFun / Functions
/** generated base class for functions with 2 arguments... */
abstract class EFun2 extends EFun {
...
public abstract EObject body(EProc proc, EObject arg1, EObject arg2)
throws Pausable;
public abstract EObject go(EProc proc)
throws Pausable {
EObject arg1 = proc.arg1;
EObject arg2 = proc.arg2;
proc.arg1 = null;
proc.arg2 = null;
proc.tail = null;
return this.body(proc, arg1, arg2);
}
}
53. Tail Recursion
fibo_tr( 0, Result, _Next)
-> Result; %% last recursion output
fibo_tr( Iter, Result, Next) when Iter>0
-> fibo_tr( Iter -1, Next, Result + Next).
fibo(N) -> fibo_tr( N, 0, 1) .
56. Interfacing to Java
• Erlang’s primitive operations “BIFs” are
implemented in java - obviously
• @BIF annotation makes a static-public
method available from Erlang.
• Erlang port concept for “drivers”
• Future of integration?
57. Status today?
• I’m working on OTP
boot; i.e., getting to
the prompt of “erl”
command line.
• 83% there, measured
by modules loaded/
compiled.