• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Erjang - A journey into Erlang-land
 

Erjang - A journey into Erlang-land

on

  • 4,150 views

Here is the presentation I did at Trifork GeekNights, January 12+13....

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

Statistics

Views

Total Views
4,150
Views on SlideShare
3,352
Embed Views
798

Actions

Likes
2
Downloads
55
Comments
0

6 Embeds 798

http://www.gungus.se 760
http://www.slideshare.net 29
http://gunguslse.wordpress.com 6
http://www.mefeedia.com 1
http://guzand.wordpress.com 1
http://www.docshut.com 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Erjang - A journey into Erlang-land Erjang - A journey into Erlang-land Presentation Transcript

    • Erjang— a JVM-based Erlang VM Kresten Krab Thorup, Trifork
    • 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.
    • I’m an Explorer I’m an explorer Illustration for french edition : Comment j'ai retrouvé Livingstone. Paris : Hachette, 1876. Title : Rencontre de Livingstone
    • 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
    • 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.
    • 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...
    • complexity ability time
    • complexity ability time
    • complexity ability performance / scaleability time
    • complexity ability performance / scaleability dynamic virtual machines time
    • complexity ability performance / scaleability multi-core hardware dynamic virtual machines time
    • complexity ability performance / scaleability understandability multi-core hardware dynamic virtual machines time
    • complexity ability performance / scaleability understandability multi-core hardware object-oriented modeling time
    • complexity ability performance / scaleability understandability concurrency modeling? object-oriented modeling time
    • Concurrency Landscape Explicit / Implicit / Reactive Functional
    • Concurrency Landscape Explicit / Implicit / Reactive Functional Here we need to understand and reason about parallelism
    • Concurrency Landscape Explicit / Implicit / Reactive Functional Here we need to Here, we understand and abstract the reason about parallelism parallelism away
    • 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
    • Trend in “New” Concurrency Languages • Clojure • Comprehending concurrent systems is • F# difficult • Scala + Actors • Mutable state is bad • Erlang • Make things simpler
    • 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...
    • Java Actor Framework client «interface» «abstract class» Logger ActorBehavior «class» Proxy LoggerBehavior Thread Pool
    • 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”);
    • 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?
    • 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
    • Erlang Principles • Strategy for error handling • Actors = Processes + Messaging • Immutable Values
    • 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.
    • 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.
    • Process ≡ Actor ≡ Object • Erlang processes have many characteristics of objects • Identity • Polymorphism • Encapsulation “The way objects should have been”...
    • Erjang - Challenges • Ultra Light-Weight Processes • Real-time Behavior • Tail-recursion • Arbitrary Precision Numbers • Pattern Matching • Erlang Drivers • JVM is type safe, urgh!
    • Erjang - Challenges • Ultra Light-Weight Processes • Real-time Behavior • Tail-recursion • Arbitrary Precision Numbers • Pattern Matching • Erlang Drivers • JVM is type safe, urgh!
    • 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.
    • Erjang Compiler BEAM Reader ring.beam Type Analysis JVM Codegen ring-2a149ada.jar
    • Erjang BEAM Loading * erlang:load_module error_handler:undefined_function BEAM Reader ring.beam Type Analysis ClassLoader.loadClass(“erjang.m.ring”) JVM Codegen ring-2a149ada.jar
    • 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
    • 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
    • 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
    • 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-
    • 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...
    • 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: } } }
    • $"!! &#!!! %&'()* ()*+,- +,',- ./*/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
    • Pattern Matching ins_opts([H | T], T2) -> ins_opts(T, ins_opt(H, T2)); ins_opts([], T2) -> T2.
    • The BEAM Code function, ins_opts, {nargs,2}}. {label,264}. {test,is_nonempty_list,{else,265},[{x,0}]}. {get_list,{x,0},{x,0},{y,0}}. {call,2,ins_opt}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {call_last,2,ins_opts,1}. {label,265}. {test,is_nil,{else,263},[{x,0}]}. {move,{x,1},{x,0}}. return. {label,263}. {func_info,{atom,appmon_info},{atom,ins_opts},2}.
    • The BEAM Code function, ins_opts, {nargs,2}}. {label,264}. {test,is_nonempty_list,{else,265},[{x,0}]}. {get_list,{x,0},{x,0},{y,0}}. {call,2,ins_opt}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {call_last,2,ins_opts,1}. {label,265}. {test,is_nil,{else,263},[{x,0}]}. {move,{x,1},{x,0}}. return. {label,263}. {func_info,{atom,appmon_info},{atom,ins_opts},2}.
    • public static EObject ins_opts___2(EProc eproc, EObject arg1, EObject arg2) { tail: while(true) { ECons cons; if((cons = arg1.test_nonempty_list()) != null) { // extract list EObject hd = cons.head(); EObject tl = cons.tail(); // call ins_opt/2 EObject tmp = ins_opt___2(eproc, hd, arg2); // self-tail recursion arg1 = tl; arg2 = tmp; continue tail; } else if ((arg1.test_nil()) != null) { return arg2; } throw ERT.func_info(atom_appmon_info, atom_ins_opts, 2); } }
    • public static EObject ins_opts___2(EProc eproc, EObject arg1, EObject arg2) { tail: while(true) { ECons cons; if((cons = arg1.test_nonempty_list()) != null) { // extract list EObject hd = cons.head(); EObject tl = cons.tail(); // call ins_opt/2 EObject tmp = ins_opt___2(eproc, hd, arg2); // self-tail recursion arg1 = tl; arg2 = tmp; continue tail; } else if ((arg1.test_nil()) != null) { return arg2; } throw ERT.func_info(atom_appmon_info, atom_ins_opts, 2); } }
    • Core Erjang Types EObject ETuple EAtom EFun ECons ENumber ETuple1 Etuple3 ETuple0 EFun0 EFun1 EFun2 ESeq EPair EInteger EFloat Generated ENil EList ESmall EBig Function
    • 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.
    • 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]
    • 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; }
    • 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; } ...
    • 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); } }
    • 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) .
    • Tail Recursion class Fibo extends EFun3 { EObject body(EProc proc, EObject iter, EObject result, EObject next) { if (iter == Fibo.cst_zero) { return result; } if (ErlBif.op_gt_guard(iter, Fibo.cst_zero) != null) { proc.arg1 = iter.minus(Fibo.cts_one); proc.arg2 = next; proc.arg3 = result.plus(next); proc.tail = this; return TAIL_MARKER; } throw ERT.badmatch(iter,result,next); } EObject go(EProc proc) { return body(proc, proc.arg1, proc.arg2, proc.arg3); }
    • Demo! Tail-recursive Fibonacci, 10, 100, 1000, 10000, 100000 Ring example 10.000 processes x 10.000 cycles
    • 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?
    • 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.