Pistache: A π-Calculus Internal Domain Specific Language for Scala

Post on 18-May-2015

349 views 0 download

description

Presented at: XIV Simpósio Brasileiro de Métodos Formais (SBMF 2011), September/2011.

Transcript of Pistache: A π-Calculus Internal Domain Specific Language for Scala

PISTACHEA π-Calculus Internal Domain Specific Language for Scala

•Pedro Matiellopmatiello@gmail.com

•Ana Cristina de Meloacvm@ime.usp.br

•http://code.google.com/p/pistache/

• Pistache is an implementation of the π-Calculus as a domain specific language hosted in Scala

INTRODUCTION

• It provides π-Calculus’ abstractions for concurrent computation within the Scala programming language

INTRODUCTION

π-CALCULUS

•π-Calculus is a formal language for describing concurrent computation with dynamic reconfiguration

•Agents communicate by exchanging names through channels (which are also names)

•Connections between agents may change in the course of the computation

AGENTS

0 Nil

α.P Prefix

P + Q Sum

P|Q Parallel

(νx)P Restriction

[x=y].P Match

[x≠y].P Mismatch

PREFIXES

yx Output

y(x) Input

τ Silent

_

• The Agents:C = (νz) y(p).pzS = yx.SP = x(w).α.P

• The composition:C | S | P

&

6

3

\ [

__

EXAMPLE

Example adapted from: An Introduction to the pi-Calculus, by Joachim Parrow

SCALA

•Scala is a general-purpose programming language providing features both of object-oriented and functional programming

•Flexible syntax

•Statically-typed

•Runs on the Java Virtual Machine

•Actively-developed

•Growing community

PISTACHE

•Pistache is an implementation of π-Calculus as an internal Domain Specific Language for Scala

val P = Agent(...)

lazy val recP:Agent = Agent(...)

val restrP = Agent { val restrictedName = Name(...) ...}

AGENT DEFINITION

val name = Name(some_object)

val name = Name[Type]

name := other_object

value = name.value

NAMES

val y = Link[Type]

y~x yx

y(x) y(x)

CHANNELS

_

val silent = Action{ doSomething() } τ

SILENT TRANSITIONS

val P = Agent { p1 * p2 * Q } P = α.β.Q

CONCATENATION

val P = Agent { Q | R | S } P = Q | R | S

COMPOSITION

val P = Agent { (p1 :: Q) + (p2 :: R) + (p3 :: S) P = αQ + βR + γS

}

SUMMATION

val P = Agent(If (x==y) {Q}) P = [x=y] Q

MATCHING

• The Agents:C = (νz) y(p).pzS = yx.SP = x(w).α.P

• The composition:C | S | P

&

6

3

\ [

__

EXAMPLE

val y = Link[Link[String]]val x = Link[String]

EXAMPLE

val y = Link[Link[String]]val x = Link[String]

val C = Agent { val p = Name[Link[String]] val z = "message" y(p) * p~z}

EXAMPLE

C = (νz) y(p).pz_

val y = Link[Link[String]]val x = Link[String]

val C = Agent { val p = Name[Link[String]] y(p) * p~"message"}

lazy val S:Agent = Agent { y~x*S }

EXAMPLE

S = yx.S_

val y = Link[Link[String]]val x = Link[String]

val C = Agent { val p = Name[Link[String]] y(p) * p~"message"}

lazy val S:Agent = Agent { y~x*S }

lazy val P:Agent = Agent { val w = Name[String] val act = Action { println(msg.value) } x(w) * act * P}

EXAMPLE

P = x(w).α.P

val y = Link[Link[String]]val x = Link[String]

val C = Agent { val p = Name[Link[String]] y(p) * p~"message"}

lazy val S:Agent = Agent { y~x*S }

lazy val P:Agent = Agent { val msg = Name[String] val act = Action { println(msg.value) } x(msg) * act * P}

new ThreadedRunner(C | S | P) start

EXAMPLE

C | S | P

MESSAGE PASSING

• Channels are implemented as shared buffers

• Communication between agents is synchronous

MESSAGE PASSING

Output yx Input y(x)

Wait until y is empty Wait until y is not empty

Put x on y Put the contents of y in x

Signal y not empty Signal y empty

Wait until y is empty

_

val P = Agent ( p1 * p2 * p3 * Q )

DATA STRUCTURE

val P = Agent ( p1 * p2 * p3 * Q )

DATA STRUCTURE

3

S�

&RQFDWHQDWLRQ$JHQW

&RQFDWHQDWLRQ3UHIL[

&RQFDWHQDWLRQ3UHIL[

4

S�S�

def execute(agent:PiObject) { agent match { case ConcatenationAgent(left, right) => ... case CompositionAgent(left, right) => ... ... }}

EXECUTION

case ConcatenationAgent(left, right) => execute(left apply) execute(right apply)

EXECUTION

case CompositionAgent(left, right) => executeInNewThread(left apply) executeInNewThread(right apply)

EXECUTION

def executeInNewThread(agent:PiObject) {

val runnable = new Runnable() { override def run() { execute(agent) } }

executor.execute(runnable)}

THREAD SPAWNING

THREAD SPAWNING

• CachedThreadPool

• Caches finished threads

• Reuses cached threads

• Creates new threads if none are available

•Deletes from the pool threads that have not been used reused for 60 seconds

THREAD SPAWNING

Strategy Time consumed for 100k agents

new Thread 23 743 ms

CachedThreadPool 2 089 ms

•We knew that:

• Concurrent programming is hard

CONCLUSION

•We learned that:

• Proper abstractions can improve our understanding of concurrency and concurrent programs

CONCLUSION

•We also learned that:

• The abstractions present in π-Calculus provide a feasible model for concurrency in actual software programming

CONCLUSION

PISTACHEPedro Matiello

Ana Cristina de Melo