Skip to content

[WIP] Savina Successive Over Relaxation #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: mutation/full
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/benchmark/sucoverrelax/actor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* eslint-disable @typescript-eslint/prefer-readonly */
// The SOR (Re)actor
import { InPort, Reactor, State } from "../../core/internal";
import { Message } from "./sorutils";

export class SORActor extends Reactor {
constructor(
parent: Reactor,
pos: number,
_value: number,
colour: number,
nx: number,
ny: number,
omega: number,
sorSource: Reactor,
peer: boolean
) {
super(parent, "SORActor");

const x = Math.floor(pos / ny);
const y = pos % ny;

const omegaOverFour = 0.25 * omega;
const oneMinusOmega = 1.0 - omega;

this.portFromRunner = new InPort<Message>(this);

const neighbours = (() => {
const calPos = (x: number, y: number): number => (x * ny + y);

if (x > 0 && x < nx - 1 && y > 0 && y < ny - 1) {
return [calPos(x, y + 1),
calPos(x + 1, y),
calPos(x, y - 1),
calPos(x - 1, y)];
}
if ((x === 0 || x === (nx - 1)) && (y === 0 || y === (ny - 1))) {
return [
(x === 0) ? calPos(x + 1, y) : calPos(x - 1, y),
(y === 0) ? calPos(x, y + 1) : calPos(x, y - 1)
];
}
if ((x === 0 || x === (nx - 1)) || (y === 0 || y === (ny - 1))) {
if (x === 0 || x === nx - 1) {
return [
(x === 0) ? calPos(x + 1, y) : calPos(x - 1, y),
calPos(x, y + 1),
calPos(x, y - 1)
];
}
return [
(y === 0) ? calPos(x, y + 1) : calPos(x, y - 1),
calPos(x+1, y),
calPos(x-1, y)
];
}
return [];
})();
}

private iter = new State(0);
private maxIter = new State(0);
private msgRcv = new State(0);
private sorActors = new State<Reactor[]>([]);

public portFromRunner: InPort<Message>;
}
71 changes: 71 additions & 0 deletions src/benchmark/sucoverrelax/peer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { InPort, MutationSandbox, OutPort, Reactor, State } from "../../core/internal";
import { SORActor } from "./actor";
import { SORRunner } from "./runner";
import { Message, MessageTypes, SorBorder as SORBorder, SorBorder } from "./sorutils";

export class SORPeer extends Reactor {

s: State<number>;
partStart: State<number>;
matrixPart: State<number[][]>;
border: State<SORBorder>;
sorSource: State<SORRunner>


sorActors: State<Reactor[]>;
public portFromSORRunner: InPort<Message>;

constructor(
parent: Reactor,
s: number,
partStart: number,
matrixPart: number[][],
border: SORBorder,
sorSource: SORRunner
) {
super(parent, "SORPeer");
this.sorActors = new State([]);
this.s = new State(s);
this.partStart = new State(partStart);
this.matrixPart = new State(matrixPart);
this.border = new State(border);
this.sorSource = new State(sorSource);

this.portFromSORRunner = new InPort(this);
}

static boot(this: MutationSandbox, args: BootProcessingArgs) {
const myBorder: SORActor[] = [];
const {_s, border, sorActors, partStart} = args;
const s = _s.get();
const partStartVal = partStart.get();

const sorActorsValue = sorActors.get();
const borderValue = border.get();
for (let i = 0; i < s; ++i) {
sorActorsValue[i * (s - partStartVal + 1)] = borderValue.borderActors[i];
}
sorActors.set(sorActorsValue);

for ()
}
}

interface BootProcessingArgs {
type: MessageTypes.sorBootMessage,
_s: State<number>,
border: State<SORBorder>,
sorActors: State<SORActor[]>,
partStart: State<number>,
}
interface ResultProcessingArgs {
type: MessageTypes.sorResultMessage,
expectingBoot: State<boolean>,
totalMsgRcv: State<number>,
returned: State<number>,
gTotal: State<number>,
s: State<number>,
part: State<number>
}

type ProcessingArgs = BootProcessingArgs | ResultProcessingArgs;
126 changes: 126 additions & 0 deletions src/benchmark/sucoverrelax/runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { InMultiPort, InPort, MutationSandbox, OutMultiPort, OutPort, Parameter, Reactor, State, Variable, } from "../../core/internal";
import { SORActor } from "./actor";
import { SORPeer, SORPeer } from "./peer";
import { Message, MessageTypes, SORBootMessage, SORBorderMessage, SORResultMessage, SORStartMessage, SorBorder, arrayOfDim, jacobi, omega, randomMatrix } from "./sorutils";

export class SORRunner extends Reactor {
protected s: State<number>;
protected part: State<number>;

protected sorActors: State<SORActor[]>;
protected sorPeer: State<SORPeer | undefined>;

// Definition of Ports. Initialisation will take place in the constructor, because some of them needs to access
// some parametres.
/// Runner will interact with App. It will receive BootMsg, and send ResultMsg.
/// In the original Savina benchmark suite there is no ResultMsg.
/// Instead, Runner handles validation and simply quits the programme.
/// We are taking a more based approach but there is no difference.
/// See https://github.com/shamsimam/savina/blob/52e546959a57670cdba7a88f0a030b53cfdb16d6/src/main/scala/edu/rice/habanero/benchmarks/sor/SucOverRelaxAkkaActorBenchmark.scala#L112-L115
protected portFromApp: InPort<SORBootMessage>;
protected portToApp: OutPort<unknown[]>;

/// Runner will send StartMsg to all actors, and receive ResultMsg from all actors.
/// Runner will also supply them with a the list of actors. We will do the same, connection will be handled by individual Actors.
protected portsFromActors: InMultiPort<SORResultMessage>;
protected portsToActors: OutMultiPort<SORStartMessage>;

/// Runner will send BootMsg to Peer, and receive BorderMsg OR ResultMsg from Peer.
/// I am using a 3-port approach here, this way I can handle SORResultMessage in a single mutation.
protected portFromPeerBorder: InPort<SORBorderMessage>;
protected portFromPeerResult: InPort<SORResultMessage>;
protected portToPeer: OutPort<SORBootMessage>;

protected gTotal = new State(0.0);
protected returned = new State(0);
protected totalMsgRcv = new State(0);
protected expectingBoot = new State(true);

// In Savina, randoms is accessed directly from SucOverRelaxConfig.
// Here we pass it in to the closure.
constructor(parent: Reactor, s: number, _randoms: number[][]) {
super(parent);
this.s = new State(s);
// In the scala implementation a simple /2 was used.
// In JS we might need to enforce some sort of guarantee as it was used to calculate position
const part = Math.floor(s / 2);
this.part = new State(part);

// The following lines are from Savina. They should be rather irrelevant, actually, because message passing are handled by ports
this.sorActors = new State([]);
this.sorPeer = new State(undefined);

// Initialisation of ports
this.portFromApp = new InPort(this);
this.portToApp = new OutPort(this);
// size * (part + 1) is the size of sorActors in the Savina benchmark
this.portsFromActors = new InMultiPort(this, s * (part + 1));
this.portsToActors = new OutMultiPort(this, s * (part + 1));

this.portFromPeerBorder = new InPort(this);
this.portFromPeerResult = new InPort(this);
this.portToPeer = new OutPort(this);

this.addMutation(
[this.startup],
[],
function (this) {
console.log("I am SORRunner [M1]. I am trolling.")
}
);

// SORRunner::process(msg: SorBootMessage) and SORRunner::boot
this.addMutation(
[this.portFromApp],
[this.portFromApp, this.expectingBoot, this.sorActors, this.sorPeer, this.writable (this.portToPeer)],
function(this, portFromApp, expectingBoot, sorActorsState, sorPeerState, portToPeer) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const randoms = portFromApp.get()!.A!;

const sorActors = sorActorsState.get();
expectingBoot.set(false);
// SORRunner::boot
const myBorder: SORActor[] = [];
// In Scala/Akka, 0 until s is [0, s)
for (let i = 0; i < s; ++i) {
let c = i % 2;
for (let j = 0; j < part; ++j) {
const pos = i * (part + i) + j;
c = 1 - c;
sorActors[pos] = this.addSibling(SORActor, pos, randoms[i][j], c, s, part + 1, omega, this.getReactor(), false);
if (j === (part - 1)) {
myBorder[i] = sorActors[pos];
}
}
}
const partialMatrix = arrayOfDim([s, s - part], 0 as number);
for (let i = 0; i < s; ++i) {
for (let j = 0; j < s - part; ++j) {
partialMatrix[i][j] = randoms[i][j + part];
}
}
const sorPeer = this.addSibling(SORPeer, s, part, partialMatrix, new SorBorder(myBorder), this.getReactor() as SORRunner);
this.connect(portToPeer.getPort(), sorPeer.portFromSORRunner);
sorPeerState.set(sorPeer);
portToPeer.set({
messageType: MessageTypes.sorBootMessage,
A: undefined
});
}
);

this.addMutation(
[this.portsFromActors, this.portFromPeerResult],
[this.portsFromActors, this.portFromPeerResult, this.totalMsgRcv],
function (this, portsFromActors, portFromPeerResult, totalMsgRcvState) {
const message =

const totalMsgRcv = totalMsgRcvState.get();

}
);

}


}
Loading