## CS 662: Theory of Parallel Algorithms SR Parallel

San Diego State University -- This page last updated February 1, 1996

## Concurrent Execution

```

resource foo()
write("Start A")

process A
fa k := 1 to 5 -> write("In A");
af
end A

write("Start B")

process B
fa k := 1 to 5 -> write("In B");
af
end B

write("All done")
end foo
```
Output

Start A
Start B
All done
In B
In B
In B
In B
In B
In A
In A
In A
In A
In A

Process Example 2
```
resource foo()
var X: int := 0
write("Before A")

process A
write("Start A")
fa k := 1 to 5 -> X := X - 1  af
write("End A")
end A

write("Between A and B")

process B
write("Start B")
fa k := 1 to 5 -> X := X + 2  af
write("End B")
end B

write("After B")
final
write("X is: ", X)
end
write("After final")
end foo
```
Output
Before A
Between A and B
After B
After final
Start A
Start B
End B
End A
X is: 5
Using Common Procedures
```
resource foo()
var X: int := 0

procedure CallMe(What: string[20])
write(What)
end

write("Before A")

process A
CallMe("Start A")
fa k := 1 to 5 -> X := X - 1 af
CallMe("End A")
end A

write("Between A and B")

process B
CallMe("Start B")
fa k := 1 to 5 -> X := X + 2 af
CallMe("End B")
end B

end foo
```

Unabbreviated Form of Process
```resource foo()
op TestProc(How: string[20]) {send}

write("Before A")

send TestProc("A")

write("Between A and B")

send TestProc("B")

write("After B")

proc TestProc(How)
fa k := 1 to 5 -> write(How) af
end TestProc

end foo

```
Output

Before A
Between A and B
After B
B
B
B
B
B
A
A
A
A
A

Procedure vs Process
```

resource foo()

op TestProc(How: string[20]) {send, call}

write("Before A")

TestProc("A")		#procedure

write("Between A and B")

send TestProc("B") #process

write("After B")

proc TestProc(How)
fa k := 1 to 5 -> write(How) af
end TestProc
end foo
```

Output
Before A
A
A
A
A
A
Between A and B
After B
B
B
B
B
B
Just to Show the Processes
```
resource foo()

process TestProc(K := 1 to 3, J := 2 to 4)
var Crap: real

fa x := 1 to 90,
y := 1 to 90 -> Crap := sin(x+y)
af

write("K: ", K, "J: ",J)

end TestProc

end foo
```
Output

K: 1 J: 2
K: 1 J: 4
K: 2 J: 3
K: 3 J: 2
K: 3 J: 4
K: 2 J: 2
K: 3 J: 3
K: 2 J: 4
K: 1 J: 3

### Concurrent Invocation

```co command
// command
// command -> block
oc
```

command is a call invocation, send invocation, or a simple assignment that calls a user-defined function

```resource Cotest()
procedure me(X: string[10])
write(X)
end
co me("A")  // me("B")  oc

write("At the end")
end

```
Output

A
B
At the end

```
resource Cotest()
var X: int := 0
procedure Y(me: int) returns r: int
r := me
end

co X := Y(4)  //  X := Y(5)  oc

write(X)  #prints 4
end

```

Concurrent Invocation
```
resource Cotest()
procedure me(X: int) returns r: int
r := X
end

var X: int := 0
co (K :=  1 to 5) X := me(K) oc

write(X)		#prints 1
end

resource Cotest()
procedure me(X: int) returns r: int
r := X
end

var X: int := 0, count: int := 0

co (K :=  1 to 5) X := me(K) ->
count++
write("Count: ", count, "K: ", K)
oc

write(X)
end

```
Output
Count: 1 K: 5
Count: 2 K: 4
Count: 3 K: 3
Count: 4 K: 2
Count: 5 K: 1
1
Concurrent Invocation Example
```
resource partial_sums()
var distance: int := 1
var N: int; getarg(1,N)

var sum[N], old[N]: int

procedure save(K: int)
old[K] := sum[K]
end

procedure update(K: int)
if K > distance ->
sum[K] +:= old[K - distance]
fi
end

fa K := 1 to N -> sum[K] := i af

do distance < N ->
co (K := 1 to N) save(K) oc
co (K := 1 to N) update(K) oc
distance +:= distance #double distance
od

fa K := 1 to N -> write(K, sum[K]) af
end

```
Execution
saturn 36-> sr sums.sr
saturn 37-> a.out 5
1 1
2 3
3 6
4 10
5 15

### Semaphores

sem S
V(S) increases S by one
P(S) waits until S is positive, decreases S by 1

```resource Sem()
const N := 4
var X := 0

sem SafeX := 1

process p(K := 1 to N)
fa L := 1 to 2 ->
P(SafeX)
write("Safe Area", K)
X := X + 1
V(SafeX)
af
end
end
```
Output

Safe Area 1
Safe Area 1
Safe Area 2
Safe Area 2
Safe Area 3
Safe Area 3
Safe Area 4
Safe Area 4

Arrays of Semaphores
```resource Sem()
const N := 4

sem Safe[N] := (1, [N-1] 0)

process p(K := 1 to N)

fa L := 1 to 2 ->

P(Safe[K])

write("Safe Area", K)

var NextSafe: int := (K mod N) + 1

V(Safe[NextSafe])
af
end
end
```
Output

Safe Area 1
Safe Area 2
Safe Area 3
Safe Area 4
Safe Area 1
Safe Area 2
Safe Area 3
Safe Area 4

Problems In Semaphore Land
```resource SemaLand()
var X := 0

sem SafeX := 1

process A
do true ->
P(SafeX)
X := X + 1
V(SafeX)
od
end

process B
do true ->
P(SafeX)
X := X - 1
V(SafeX)
od
end

process C
do true ->
P(SafeX)
write(X)
V(SafeX)
od
end

end
```

Monitors
```global MonitorX
op increase(amount: int)
op decrease(amount: int)
op print()

body MonitorX
sem SafeX := 1
var X: int := 0

proc increase(amount)
P(SafeX)
X +:= amount
V(SafeX)
end

proc decrease(amount)
P(SafeX)
X -:= amount
V(SafeX)
end
end

resource SemFree()
import MonitorX

process A
fa K := 1 to 3 -> increase(2)  af
end

process B
fa K := 1 to 3 -> decrease(1) af
end

end
```

### Asychronous Message Passing

```resource Message()
op MyMessage(X: int)
send MyMessage(0)

process one
fa K := 1 to 3 -> send MyMessage(K)
write("Sent: ",K)
af
end

process two

nap(0)
af
end

process three

af
end
end

```
Sent: 1
Sent: 2
Sent: 3

#### Semphores and Message Passing

```resource Sem()
const N := 4
var X := 0
var Size := 1

sem SafeX := Size

process p(K:=1 to N)

fa L := 1 to 2 ->
P(SafeX)
write("Safe", K)
X := X + 1
V(SafeX)
af
end
end

resource Sem()
const N := 4
var X := 0
var Size := 1

op SafeX() {send}
fa K:= 1 to Size
send SafeX()
af

process p(K:=1 to N)

fa L := 1 to 2 ->
write("Safe", K)
X := X + 1
send SafeX()
af
end
end

```
```
```

Too Many Messages
```resource Message()
op MyMessage(X: int)

process one
fa K := 1 to 5 -> send MyMessage(K)
write("Sent: ",K)
af
end

process two

af
end
end
```

Sent: 1
Sent: 2
Sent: 3
Sent: 4
Sent: 5

Too Few Ears
```resource Message()
op MyMessage(X: int)

process one

fa K := 1 to 2 ->
send MyMessage(K)
write("Sent: ",K)
af

end

process two

fa J := 1 to 5 ->
af

end
end
```

Output
Sent: 1
Sent: 2
RTS warning: blocked process:Message.two : file message.sr, line 16
What is Wrong With This?
```

resource foo
op bar(X: int)

body foo(Me: char)

end foo
```

```resource main()
import foo

var X: cap foo

X := create foo('A')

send X.bar(1)
end
```

Messages to Resources
```
resource foo
op bar(X: int)

body foo(Me: char)

process one

end one

end foo
```
```resource main()
import foo

var X: cap foo

X := create foo('A')

send X.bar(1)
end
```

```resource Message()
op MyMessage(X: int)

write("Start")

send MyMessage(3)

write("Send")

final
write("The End")
end

end
```
Output

Start
The End
RTS warning: blocked process:Message.body : file message.sr, line 6

```
resource Message()
op MyMessage(X: int)

process one
var J: int

write("Start one")
write("End one")
end

process two

write("Start Two")
write("End two")
end

final
write("The End")
end

end

```
Output
Start one
Start Two
The End
RTS warning: blocked process:Message.two : file message.sr, line 15
RTS warning: blocked process: Message.one : file message.sr, line 8

### Real Parallelism

```resource hello
op WhoAreYou()

body hello()

external gethostname(res s: string[*];
nameLength: int)

proc WhoAreYou()
var HostName: string[32]

gethostname(HostName, maxlength(HostName))

write("Hello from ", HostName)
end
end

resource main()
import hello

var NewSpace: cap vm

NewSpace := create vm()

#NewSpace := create vm() on "saturn"

var X: cap hello

X := create hello() on NewSpace

X.WhoAreYou()
end
```

Using Multiple Workstations
```
resource hello
op WhoAreYou()

body hello()
external gethostname(res: s: string[*];
nameLength: int)

proc WhoAreYou()
var HostName: string[32]
gethostname(HostName, maxlength(HostName))
write("Hello from ", HostName)
end
end

resource main
import hello

var A, B, C: cap vm

locate(1,"ucssun1","~whitney/sr/a.out")
locate(2,"atlas","~whitney/sr/a.out")

A := create vm() on 1
B := create vm() on 2

var X, Y, Z: cap hello
X := create hello() on A
Y := create hello() on B
Z := create hello() on A

X.WhoAreYou()
Y.WhoAreYou()
Z.WhoAreYou()
end

```
Hello from ucssun1
Hello from atlas
Hello from ucssun1
Processes on Different Virtual Machines
```
resource foo
op TestProc(How: string[20]) {send}

body foo()
proc TestProc(How)
fa k := 1 to 5 -> write(How) af
end TestProc
final
write("You killed me!")
end
end foo
```
```resource main()
import foo
var A, B: cap vm
A := create vm()
B := create vm()

var X, Y: cap foo
X := create foo() on A
Y := create foo() on B

send X.TestProc("One")
write("Sent One")
send X.TestProc("Two")
write("Sent Two")
send Y.TestProc("Three")
write("Sent Three")

final
write("All done")
destroy A
end
end

Output
Sent One
Sent Two
Sent Three
One
Three
One
One
Three
Three
One
Three
One
Three
Two
Two
Two
Two
Two
All done
You killed me!
```

#### Asynchronous Messages and VM

```
resource foo
op bar(X: int)

body foo(Me: char)
process GetIt(P := 1 to 2)
fa k := 1 to 2 ->
af
end
```
end

```resource main()
import foo
var Name[2]: char := ('A', 'B')
var A[2]: cap vm
var X[2]: cap foo

fa K := 1 to 2 ->
A[K] := create vm()
X[K] := create foo(Name[K]) on A[K]
af

process fork(J := 1 to 2)
fa K := 1 to 4 -> send X[J].bar(K) af
end fork
end

```
Timing Saturn's Processors
Sequential Code

```resource main()

procedure worker(Amount: int)
var Crap: real

fa x := 1 to Amount,
y := 1 to Amount -> Crap := sin(x+y)
af

end worker

var Amount: int; getarg(1,Amount)
var Start: int := age()

fa K := 1 to 4 -> worker(Amount) af

final
var End: int := age()
write(End - Start)
end
end
```

Timing Saturn's Processors
Processes
```

resource main()

var Amount: int; getarg(1,Amount)
var Start: int := age()

process worker(K := 1 to 4)
var Crap: real

fa x := 1 to Amount,
y := 1 to Amount -> Crap := sin(x+y)
af

end worker

final
var End: int := age()
write(End - Start)
end
end
```

Timing Saturn's Processors
Virtual Machines
```resource foo
op worker(Amount: int) {send}

body foo()
proc worker(Amount)
var Crap: real

fa x := 1 to Amount,
y := 1 to Amount -> Crap := sin(x+y)
af
end worker
end foo
```
```resource main()
import foo
var A[4]: cap vm
var X[4]: cap foo

var Amount: int; getarg(1,Amount)
var Start: int := age()

fa K := 1 to 4 ->
A[K] := create vm()
X[K] := create foo() on A[K]
send X[K].worker(Amount)
af

final
var End: int := age()
write(End - Start)
end
end
```

Timing Saturn's Processors
Results

```Amount                    Sequential  Process                 VM
100                              316  335                     995
150                              701  719                     926
200                             1237  1255                    1018
250                             1958  1975                    1250
300                             2865  2787                    1372
350                             3848  3809                    1752
400                             5126  4976                    1959
800                                                           9779

```

### Remote Procedure Calls

A remote procedure requires creation of a new process, just to handle the procedure

If at all possible all procedure calls are treated as a normal procedure call, otherwise they are handled as a remote procedure call

```resource CallMe
op RealSoon(data: int)
body CallMe()
proc RealSoon(data)
write(data)
end
end

resource main()
import CallMe

var Here: cap CallMe
Here := create CallMe()
Here.RealSoon(5)		#procedure call

var RemoteIsland: cap vm
var There: cap CallMe

RemoteIsland:= create vm()
There := create() CallMe on RemoteIsland

There.RealSoon(5)		#remote procedure call

end
```

```resource main()
op WhatIsThis(var A: int)   {call, send}

proc WhatIsThis(A)
A := A + 1
return
end WhatIsThis

var X: int := 0
var Y: int := 0

call WhatIsThis(X)
send WhatIsThis(Y)

write("X ", X, "Y ", Y)
end
```

```resource main()
op TryMe(var A: int) returns B: int

proc TryMe(A) returns B
A := 1
B := 1

nap(50)
A := 20; B := 20
write("Still Here")
end

var X: int := 0
var Y: int := 0

Y := TryMe(X)
write(X, Y)				#prints 1 1
end
```

```resource converstion()
op server(N: int) returns
c: cap (s: string[5])

process client
var Size: int := 8
var t[Size]:string[5] := ([Size] "Hi")

var c: cap (s: string[5])
c := server(Size)
fa K := 1 to Size -> send c(t[K]) af
end

proc server(N) returns c
op line(s: string[5])
c := line
fa K := 1 to N ->
var s: string[5]
write(s)
af
end
end
```

### Rendezvous

Input Statement
```resource main()
op f(x: int), g(u: int) returns v: int

process p1
var y: int := 5
call f(y)
write("p1")
end

process p2
var w: int
w := g(10)
write("p2 ", w)
end

process Q
var z: int

in f(x) -> z := x; write("f")
[] g(u) returns v ->
z := u
v := 8
write("g")
ni
write("Q", z)
end
end

```
Output
f
Q 5
p1
```
```

In and Send
```
resource main()
op f(x: int), g(u: int)

process p1
send f(5)
write("p1")
end

process p2
send g(10)
write("p2 ")
end

process Q
var z: int

in f(x) -> z := x; write("f")
[] g(u) -> z := u; write("g")
ni

write("Q", z)
end
end
```

Output
p1
p2
f
Q 5
Peeking at the Message Queue
```resource main()
op foo(x: int), bar(y: int)

process one
nap(500)
send foo(5)
end

process two
var it: int
in foo(p) -> it := p
[] bar(p) -> it := p
[] else -> write("no message")
ni
end

end

```

Output

no message

```resource Message()
op it(X: int)

process one
send it(3)
end

process two
var X: int

write(X)
end

end

resource Message()
op it(X: int)

process one
send it(3)
end

process two
var X: int

in it(P) -> X :=P
ni

write(X)
end

end
```

### Message Passing Reviewed

Asychronous Message Passing
```op it(X: real)
op what(X: int)
```
```process one

send it(2.5)

end

process two
var Y: real
in it(w) -> Y := w
ni
end

process three

send what(2)

end

process four
var Y: int
end

```
Sychronous Message Passing
```op it(X: real)
op what(X: int)
```
```process one

call it(2.5)

end

process two
var Y: real
in it(w) -> Y := w
ni
end

process three

call what(2)

end

process four
var Y: int
end

```

#### Synchronization Expressions

```resource main()
op a(z: int)
op b(a: int, b: int)
var C: int

process one
var X: int
send a(X);  send b(3,X)
end one

process two
in a(x) st C > 0 -> write("2, C>0")
ni
end two

process three
in a(x) st x < 0 -> write("3, X<0")
ni
end

process four
in a(x) st x = 12 -> write("4, 12")
[] b(y,z) st y = sin(x) ->write("b")
ni
end

process five
var x: int
if ?a > 0 -> receive a(x)
fi
end
end
```

Scheduling Expressions
```resource main()
op a(x: int)

fa K := 4 downto 1 -> send a(K) af

do ?a > 0 ->
in a(x) by x -> write(x) ni
od
end

```
Output
1
2
3
4
```resource main()
op a(x: int)

fa K := 1 to 4 -> send a(K) af

fa K := 1 to 4 ->
in a(x) st  x mod 2 = 0 by -x ->
write(K, x)
[] else -> write(K, "No go")
ni
af
end
```

1 4
2 2
3 No go
4 No go