Skip to content

Commit 3549031

Browse files
committed
WIP - rebased to mutation/create-reactor-api
1 parent 5b53bf7 commit 3549031

File tree

6 files changed

+572
-0
lines changed

6 files changed

+572
-0
lines changed

src/benchmark/sucoverrelax/actor.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* eslint-disable @typescript-eslint/prefer-readonly */
2+
// The SOR (Re)actor
3+
import { InPort, Reactor, State } from "../../core/internal";
4+
import { Message } from "./sorutils";
5+
6+
export class SORActor extends Reactor {
7+
constructor(
8+
parent: Reactor,
9+
pos: number,
10+
_value: number,
11+
colour: number,
12+
nx: number,
13+
ny: number,
14+
omega: number,
15+
sorSource: Reactor,
16+
peer: boolean
17+
) {
18+
super(parent, "SORActor");
19+
20+
const x = Math.floor(pos / ny);
21+
const y = pos % ny;
22+
23+
const omegaOverFour = 0.25 * omega;
24+
const oneMinusOmega = 1.0 - omega;
25+
26+
this.portFromRunner = new InPort<Message>(this);
27+
28+
const neighbours = (() => {
29+
const calPos = (x: number, y: number): number => (x * ny + y);
30+
31+
if (x > 0 && x < nx - 1 && y > 0 && y < ny - 1) {
32+
return [calPos(x, y + 1),
33+
calPos(x + 1, y),
34+
calPos(x, y - 1),
35+
calPos(x - 1, y)];
36+
}
37+
if ((x === 0 || x === (nx - 1)) && (y === 0 || y === (ny - 1))) {
38+
return [
39+
(x === 0) ? calPos(x + 1, y) : calPos(x - 1, y),
40+
(y === 0) ? calPos(x, y + 1) : calPos(x, y - 1)
41+
];
42+
}
43+
if ((x === 0 || x === (nx - 1)) || (y === 0 || y === (ny - 1))) {
44+
if (x === 0 || x === nx - 1) {
45+
return [
46+
(x === 0) ? calPos(x + 1, y) : calPos(x - 1, y),
47+
calPos(x, y + 1),
48+
calPos(x, y - 1)
49+
];
50+
}
51+
return [
52+
(y === 0) ? calPos(x, y + 1) : calPos(x, y - 1),
53+
calPos(x+1, y),
54+
calPos(x-1, y)
55+
];
56+
}
57+
return [];
58+
})();
59+
}
60+
61+
private iter = new State(0);
62+
private maxIter = new State(0);
63+
private msgRcv = new State(0);
64+
private sorActors = new State<Reactor[]>([]);
65+
66+
public portFromRunner: InPort<Message>;
67+
}

src/benchmark/sucoverrelax/peer.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { InPort, MutationSandbox, OutPort, Reactor, State } from "../../core/internal";
2+
import { SORActor } from "./actor";
3+
import { SORRunner } from "./runner";
4+
import { Message, MessageTypes, SorBorder as SORBorder, SorBorder } from "./sorutils";
5+
6+
export class SORPeer extends Reactor {
7+
8+
s: State<number>;
9+
partStart: State<number>;
10+
matrixPart: State<number[][]>;
11+
border: State<SORBorder>;
12+
sorSource: State<SORRunner>
13+
14+
15+
sorActors: State<Reactor[]>;
16+
public portFromSORRunner: InPort<Message>;
17+
18+
constructor(
19+
parent: Reactor,
20+
s: number,
21+
partStart: number,
22+
matrixPart: number[][],
23+
border: SORBorder,
24+
sorSource: SORRunner
25+
) {
26+
super(parent, "SORPeer");
27+
this.sorActors = new State([]);
28+
this.s = new State(s);
29+
this.partStart = new State(partStart);
30+
this.matrixPart = new State(matrixPart);
31+
this.border = new State(border);
32+
this.sorSource = new State(sorSour ce);
33+
34+
this.portFromSORRunner = new InPort(this);
35+
}
36+
37+
static boot(this: MutationSandbox, args: BootProcessingArgs) {
38+
const myBorder: SORActor[] = [];
39+
const {_s, border, sorActors, partStart} = args;
40+
const s = _s.get();
41+
const partStartVal = partStart.get();
42+
43+
const sorActorsValue = sorActors.get();
44+
const borderValue = border.get();
45+
for (let i = 0; i < s; ++i) {
46+
sorActorsValue[i * (s - partStartVal + 1)] = borderValue.borderActors[i];
47+
}
48+
sorActors.set(sorActorsValue);
49+
50+
for ()
51+
}
52+
}
53+
54+
interface BootProcessingArgs {
55+
type: MessageTypes.sorBootMessage,
56+
_s: State<number>,
57+
border: State<SORBorder>,
58+
sorActors: State<SORActor[]>,
59+
partStart: State<number>,
60+
}
61+
interface ResultProcessingArgs {
62+
type: MessageTypes.sorResultMessage,
63+
expectingBoot: State<boolean>,
64+
totalMsgRcv: State<number>,
65+
returned: State<number>,
66+
gTotal: State<number>,
67+
s: State<number>,
68+
part: State<number>
69+
}
70+
71+
type ProcessingArgs = BootProcessingArgs | ResultProcessingArgs;

src/benchmark/sucoverrelax/runner.ts

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import { InMultiPort, InPort, MutationSandbox, OutMultiPort, OutPort, Parameter, Reactor, State, Variable, } from "../../core/internal";
2+
import { SORActor } from "./actor";
3+
import { SORPeer } from "./peer";
4+
import { Message, MessageTypes, SORBootMessage, SORResultMessage, SorBorder, jacobi, omega } from "./sorutils";
5+
6+
export class SORRunner extends Reactor {
7+
protected s: State<number>;
8+
protected part: State<number>;
9+
10+
protected sorActors: State<SORActor[]>;
11+
protected sorPeer: State<SORPeer | undefined>;
12+
13+
protected portToSORActors: OutPort<Message>;
14+
protected portToSORPeer: OutPort<Message>;
15+
// Unsure if this would work, let's just try......
16+
protected portFromSORActor: InPort<Message>;
17+
protected portFromSORPeer: InPort<Message>;
18+
19+
protected gTotal = new State(0.0);
20+
protected returned = new State(0);
21+
protected totalMsgRcv = new State(0);
22+
protected expectingBoot = new State(true);
23+
24+
// In Savina, randoms is accessed directly from SucOverRelaxConfig.
25+
// Here we pass it in to the closure.
26+
constructor(parent: Reactor, size: number, _randoms: number[][]) {
27+
super(parent, "SORRunner");
28+
// These are in SorRunner;
29+
this.s = new State(size);
30+
// In the scala implementation a simple /2 was used.
31+
// In JS we might need to enforce some sort of guarantee as it was used to calculate position
32+
this.part = new State(Math.floor(size / 2));
33+
/** These are from Savina. They should be rather irrelevant, actually. */
34+
this.sorActors = new State([]);
35+
this.sorPeer = new State(undefined);
36+
37+
/** These are the actual messaging passing mechanism that are synonomous to that of Savina. */
38+
// This creates a bunch of ports.
39+
this.portToSORActors = new OutPort(this);
40+
this.portToSORPeer = new OutPort(this);
41+
this.portFromSORActor = new InPort(this);
42+
this.portFromSORPeer = new InPort(this);
43+
44+
this.addMutation(
45+
[this.startup],
46+
[this.sorActors, this.sorPeer, this.portToSORActors, this.portToSORPeer],
47+
function (this, sorActors, sorPeer, portToSORActors, portToSORPeer) {
48+
// TODO: Add actual stuff
49+
;
50+
}
51+
);
52+
}
53+
54+
// This is to be used WITHIN mutation react functions.
55+
static process(this: MutationSandbox, message: Message, args: ProcessingArgs): void {
56+
switch (message.messageType) {
57+
case MessageTypes.sorBootMessage: {
58+
if (args.type !== MessageTypes.sorBootMessage) {
59+
throw new Error("Wrong type of arguments passed.");
60+
}
61+
// expectingBoot is args[0]
62+
args.expectingBoot.set(false);
63+
SORRunner.boot.apply(this, [args]);
64+
break;
65+
}
66+
case MessageTypes.sorResultMessage: {
67+
if (args.type !== MessageTypes.sorResultMessage) {
68+
throw new Error("Wrong type of arguments passed.");
69+
}
70+
71+
const {mv, msgRcv} = message;
72+
const {expectingBoot, totalMsgRcv, returned, gTotal, s, part} = args;
73+
74+
if (expectingBoot.get()) {
75+
throw new Error("SORRunner not booted yet!");
76+
}
77+
78+
totalMsgRcv.set(totalMsgRcv.get() + msgRcv);
79+
returned.set(returned.get() + 1);
80+
gTotal.set(gTotal.get() + mv);
81+
82+
if (returned.get() === (s.get() * part.get()) + 1) {
83+
// TODO: validate
84+
// TODO: exit
85+
;
86+
}
87+
break;
88+
}
89+
case MessageTypes.sorBorderMessage: {
90+
if (args.type !== MessageTypes.sorBorderMessage) {
91+
throw new Error("Wrong type of arguments passed.");
92+
}
93+
94+
const {mBorder} = message;
95+
const {expectingBoot, s, part, sorActors, portToSORActors} = args;
96+
97+
if (expectingBoot.get()) {
98+
throw new Error("SORRunner not booted yet!");
99+
}
100+
const sorActorsValue = sorActors.get();
101+
for (let i = 0; i <= s.get(); ++i) {
102+
sorActorsValue[(i + 1) * (part.get() + 1) - 1] = mBorder.borderActors[i];
103+
}
104+
sorActors.set(sorActorsValue);
105+
for (let i = 0; i <= s.get(); ++i) {
106+
for (let j = 0; j <= part.get(); ++j) {
107+
const pos = (i * (part.get() + 1)) + j;
108+
// Ibidem, connect then disconnect to simulate
109+
// "fire and forget" in scala.
110+
this.connect(portToSORActors, sorActorsValue[pos].portFromRunner);
111+
this.getReactor().writable(portToSORActors).set(
112+
{
113+
messageType: MessageTypes.sorStartMessage,
114+
mi: jacobi,
115+
mActors: sorActorsValue
116+
}
117+
);
118+
this.disconnect(portToSORActors, sorActorsValue[pos].portFromRunner);
119+
}
120+
}
121+
break;
122+
}
123+
default: {
124+
throw new Error("Received wrong message from port");
125+
}
126+
}
127+
}
128+
129+
// SorRunner::boot()
130+
static boot(this: MutationSandbox,
131+
args: BootProcessingArgs
132+
): void {
133+
const {_randoms, _s, _part, sorActors, sorPeer, portToSORPeer} = args;
134+
135+
const myBorder: SORActor[] = [];
136+
const randoms = _randoms;
137+
const s = _s.get();
138+
const part = _part.get();
139+
// In scala, (i <- 0 until s) is a loop excluding s.
140+
const sorActorsValue = sorActors.get();
141+
for (let i = 0; i < s; ++i) {
142+
let c = i % 2;
143+
for (let j = 0; j < part; ++j) {
144+
const pos = i * (part + 1) + j;
145+
c = 1 - c;
146+
// We modify them in bulk, then update the state.
147+
// Unlike in Scala we do not need to initialise the array here, JS supports sparse array.
148+
// I have absolutely no idea why these parametres are called as such......
149+
sorActorsValue[pos] = this.getReactor()._uncheckedAddSibling(
150+
SORActor,
151+
pos, randoms[i][j], c, s, part + 1, omega, this.getReactor(), false
152+
);
153+
154+
if (j === (part - 1)) {
155+
myBorder[i] = sorActorsValue[pos];
156+
}
157+
158+
}
159+
}
160+
sorActors.set(sorActorsValue);
161+
162+
const partialMatrix: number[][] = [];
163+
for (let i = 0; i < s; ++i) {
164+
for (let j = 0; j < s - part; ++j) {
165+
partialMatrix[i][j] = randoms[i][j + part];
166+
}
167+
}
168+
169+
const sorPeerValue = this.getReactor()._uncheckedAddSibling(
170+
SORPeer,
171+
s, part, partialMatrix, new SorBorder(myBorder),
172+
// A dirty hack. Maybe this will be removed as ports get added.
173+
this.getReactor() as SORRunner
174+
);
175+
sorPeer.set(sorPeerValue);
176+
// Pass message.
177+
// This is similar to Scala's !; but it looks pretty...... interesting in LF.
178+
// If node is concurrent or parallel, this might be a problem, so direct copy-pastaing to C++ runtime might not work.
179+
this.connect(portToSORPeer, sorPeerValue.portFromSORRunner);
180+
this.getReactor().writable(portToSORPeer).set({messageType: MessageTypes.sorBootMessage});
181+
// Disconnect immediately.
182+
this.disconnect(portToSORPeer, sorPeerValue.portFromSORRunner);
183+
}
184+
}
185+
186+
187+
interface BootProcessingArgs {
188+
type: MessageTypes.sorBootMessage,
189+
expectingBoot: State<boolean>,
190+
_randoms: number[][],
191+
_s: State<number>,
192+
_part: State<number>,
193+
sorActors: State<SORActor[]>,
194+
sorPeer: State<SORPeer>,
195+
portToSORPeer: OutPort<Message>
196+
}
197+
198+
interface ResultProcessingArgs {
199+
type: MessageTypes.sorResultMessage,
200+
expectingBoot: State<boolean>,
201+
totalMsgRcv: State<number>,
202+
returned: State<number>,
203+
gTotal: State<number>,
204+
s: State<number>,
205+
part: State<number>
206+
}
207+
208+
interface BorderProcessingArgs {
209+
type: MessageTypes.sorBorderMessage,
210+
expectingBoot: State<boolean>,
211+
s: State<number>,
212+
part: State<number>,
213+
sorActors: State<SORActor[]>,
214+
portToSORActors: OutPort<Message>
215+
}
216+
217+
type ProcessingArgs = BootProcessingArgs | ResultProcessingArgs | BorderProcessingArgs;

0 commit comments

Comments
 (0)