From 7317bfba0fe6278df6fc05f8dbb74d18d2bbd18d Mon Sep 17 00:00:00 2001 From: Nadeshiko Kagamihara Date: Tue, 5 Sep 2023 21:07:50 -0700 Subject: [PATCH 1/3] Add necessary capabilities for reactors to create other reactors and make connections 0. Added _addChild and _addSibling necessary for mutation APIs 1. Solved issues related to hierarchy and ownership. --- src/core/reactor.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/core/reactor.ts b/src/core/reactor.ts index 806bf2af..0f200f21 100644 --- a/src/core/reactor.ts +++ b/src/core/reactor.ts @@ -153,6 +153,11 @@ export abstract class Reactor extends Component { */ private readonly _keyChain = new Map(); + // This is the keychain for creation, i.e. if Reactor R's mutation created reactor B, + // then R is B's creator, even if they are siblings. R should have access to B, + // at least semantically......? + private readonly _creatorKeyChain = new Map(); + /** * This graph has in it all the dependencies implied by this container's * ports, reactions, and connections. @@ -387,6 +392,9 @@ export abstract class Reactor extends Component { return owner._getKey(component, this._keyChain.get(owner)); } } + return component + .getContainer() + ._getKey(component, this._creatorKeyChain.get(component.getContainer())); } /** @@ -1555,6 +1563,36 @@ export abstract class Reactor extends Component { toString(): string { return this._getFullyQualifiedName(); } + + protected _addChild( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ): R { + const newReactor = new constructor(this, ...args); + return newReactor; + } + + protected _addSibling( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ): R { + if (this._getContainer() == null) { + throw new Error( + `Reactor ${this} does not have a parent. Sibling is not well-defined.` + ); + } + if (this._getContainer() === this) { + throw new Error( + `Reactor ${this} is self-contained. Adding sibling creates logical issue.` + ); + } + const newReactor = this._getContainer()._addChild( + constructor, + ...args + ); + this._creatorKeyChain.set(newReactor, newReactor._key); + return newReactor; + } } /* From 5b53bf78ad5529413cceacca941fe9be33196432 Mon Sep 17 00:00:00 2001 From: Nadeshiko Kagamihara Date: Tue, 5 Sep 2023 21:26:24 -0700 Subject: [PATCH 2/3] Mutation Sandbox API --- src/core/reactor.ts | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/core/reactor.ts b/src/core/reactor.ts index 0f200f21..8fa8844b 100644 --- a/src/core/reactor.ts +++ b/src/core/reactor.ts @@ -475,6 +475,20 @@ export abstract class Reactor extends Component { public delete(reactor: Reactor): void { reactor._delete(); } + + public addChild( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ): R { + return this.reactor._addChild(constructor, ...args); + } + + public addSibling( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ): R { + return this.reactor._addSibling(constructor, ...args); + } }; /** @@ -1586,10 +1600,7 @@ export abstract class Reactor extends Component { `Reactor ${this} is self-contained. Adding sibling creates logical issue.` ); } - const newReactor = this._getContainer()._addChild( - constructor, - ...args - ); + const newReactor = this._getContainer()._addChild(constructor, ...args); this._creatorKeyChain.set(newReactor, newReactor._key); return newReactor; } @@ -1833,6 +1844,16 @@ export interface MutationSandbox extends ReactionSandbox { getReactor: () => Reactor; // Container + addChild: ( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ) => R; + + addSibling: ( + constructor: new (container: Reactor, ...args: G) => R, + ...args: G + ) => R; + // FIXME: // forkJoin(constructor: new () => Reactor, ): void; } From 67b1b7928ff1b42d2657e8866a6c096055a997a6 Mon Sep 17 00:00:00 2001 From: Nadeshiko Kagamihara Date: Wed, 6 Sep 2023 18:04:22 -0700 Subject: [PATCH 3/3] Implemented Savina FJCreate --- src/benchmark/FJCreate.ts | 87 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/benchmark/FJCreate.ts diff --git a/src/benchmark/FJCreate.ts b/src/benchmark/FJCreate.ts new file mode 100644 index 00000000..9729fc63 --- /dev/null +++ b/src/benchmark/FJCreate.ts @@ -0,0 +1,87 @@ +/** + * Typescript runtime implementation of Fork Join - Create benchmark programme + * of Savina benchmark suite. + * @author axmmisaka (github.com/axmmisaka) + */ + +import { + Log, + Reactor, + App, + type TimeValue, + InPort, + OutPort +} from "../core/internal"; + +Log.global.level = Log.levels.ERROR; + +const N = 4000; + +export class ForkJoinReactor extends Reactor { + // private valueToCalculate; + triggerPort: InPort; + constructor(parent: Reactor, name = "Innocent Reactor") { + super(parent); + this.triggerPort = new InPort(this); + this.addReaction( + [this.triggerPort], + [this.triggerPort], + (inp) => { + const val = inp.get(); + if (val == null) { + throw new Error(`inp is absent for ${this._getFullyQualifiedName()}`) + } + const sint = Math.sin(val); + const res = sint * sint; + if (res <= 0) { + throw new Error(`this is kinda insane, ${res}`); + } else { + console.log(`I am ${this._getFullyQualifiedName()}. I finished calculating after ${this.util.getElapsedLogicalTime()}; ${this.util.getElapsedPhysicalTime()}. Result is ${res}`) + } + } + ); + } +} + +export class FJCreator extends Reactor { + forks: ForkJoinReactor[]; + outp: OutPort; + + constructor(parent: Reactor) { + super(parent); + this.forks = []; + this.outp = new OutPort(this); + this.addMutation( + [this.startup], + [this.writable(this.outp)], + function (this, outp) { + console.log("startup triggered!") + for (let i = 0; i < N; ++i) { + const fork = this.addSibling(ForkJoinReactor, `FJReactor ${i}`); + // this.getReactor().forks.push(fork); + this.connect(outp.getPort(), fork.triggerPort); + console.log(`Fork ${i} created at physical time ${this.util.getElapsedPhysicalTime()}`) + } + outp.set(114.514); + } + ) + } +} + +export class FJHost extends App { + creator: FJCreator; + constructor( + name: string, + timeout: TimeValue | undefined = undefined, + keepAlive = false, + fast = false, + success?: () => void, + fail?: () => void + ) { + super(timeout, keepAlive, fast, success, fail); + this.creator = new FJCreator(this); + } +} + +const fj = new FJHost("FJ"); +fj._start();