Skip to content

Commit

Permalink
Merge pull request #1293 from lf-lang/ts-tan
Browse files Browse the repository at this point in the history
Added advance-message-interval option and more federated tests for TypeScript
  • Loading branch information
hokeun authored Jul 25, 2022
2 parents 1c7924c + 1c6a598 commit a08584b
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 17 deletions.
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public enum TargetProperty {
* Key-value pairs giving options for clock synchronization.
*/
COORDINATION_OPTIONS("coordination-options",
DictionaryType.COORDINATION_OPTION_DICT, Arrays.asList(Target.C, Target.CCPP, Target.Python),
DictionaryType.COORDINATION_OPTION_DICT, Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS),
(config, value, err) -> {
for (KeyValuePair entry : value.getKeyvalue().getPairs()) {
CoordinationOption option = (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT
Expand Down
16 changes: 15 additions & 1 deletion org.lflang/src/org/lflang/generator/ts/TSConstructorGenerator.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.lflang.generator.ts

import org.lflang.ErrorReporter
import org.lflang.TargetConfig
import org.lflang.federated.FederateInstance
import org.lflang.generator.PrependOperator
import org.lflang.lf.Action
Expand All @@ -20,7 +21,8 @@ class TSConstructorGenerator (
private val tsGenerator: TSGenerator,
private val errorReporter: ErrorReporter,
private val reactor : Reactor,
private val federate: FederateInstance
private val federate: FederateInstance,
private val targetConfig: TargetConfig
) {
private fun getInitializerList(param: Parameter): List<String> =
tsGenerator.getInitializerListW(param)
Expand Down Expand Up @@ -105,6 +107,17 @@ class TSConstructorGenerator (
return connectionInstantiations.joinToString("\n")
}

// Generate code for setting target configurations.
private fun generateTargetConfigurations(): String {
val targetConfigurations = LinkedList<String>()
if ((reactor.isMain || reactor.isFederated) &&
targetConfig.coordinationOptions.advance_message_interval != null) {
targetConfigurations.add(
"this.setAdvanceMessageInterval(${timeInTargetLanguage(targetConfig.coordinationOptions.advance_message_interval)})")
}
return targetConfigurations.joinToString("\n")
}

// Generate code for registering Fed IDs that are connected to
// this federate via ports in the TypeScript's FederatedApp.
// These Fed IDs are used to let the RTI know about the connections
Expand Down Expand Up @@ -140,6 +153,7 @@ class TSConstructorGenerator (
${" | "..generateConstructorArguments(reactor)}
|) {
${" | "..generateSuperConstructorCall(reactor, federate)}
${" | "..generateTargetConfigurations()}
${" | "..generateFederateConfigurations()}
${" | "..instances.generateInstantiations()}
${" | "..timers.generateInstantiations()}
Expand Down
10 changes: 10 additions & 0 deletions org.lflang/src/org/lflang/generator/ts/TSExtensions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.lflang.generator.ts

import org.lflang.TimeValue
import org.lflang.isBank
import org.lflang.isMultiport
import org.lflang.lf.Action
Expand Down Expand Up @@ -64,3 +65,12 @@ fun getActionType(action: Action): String {
return "Present"
}
}

fun timeInTargetLanguage(value: TimeValue): String {
return if (value.unit != null) {
"TimeValue.${value.unit.canonicalName}(${value.time})"
} else {
// The value must be zero.
"TimeValue.zero()"
}
}
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/generator/ts/TSGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ class TSGenerator(
val (mainParameters, parameterCode) = parameterGenerator.generateParameters()
tsCode.append(parameterCode)

val reactorGenerator = TSReactorGenerator(this, errorReporter)
val reactorGenerator = TSReactorGenerator(this, errorReporter, targetConfig)
for (reactor in reactors) {
tsCode.append(reactorGenerator.generateReactor(reactor, federate))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import org.lflang.TimeValue
import org.lflang.generator.PrependOperator
import org.lflang.lf.Parameter
import org.lflang.lf.Reactor
import org.lflang.TimeUnit
import java.util.StringJoiner

/**
Expand Down Expand Up @@ -60,15 +59,6 @@ class TSParameterPreambleGenerator(
}
}

private fun timeInTargetLanguage(value: TimeValue): String {
return if (value.unit != null) {
"TimeValue.${value.unit.canonicalName}(${value.time})"
} else {
// The value must be zero.
"TimeValue.zero()"
}
}

private fun getParameters(): List<Parameter> {
var mainReactor: Reactor? = null
for (reactor in reactors) {
Expand Down
21 changes: 19 additions & 2 deletions org.lflang/src/org/lflang/generator/ts/TSReactorGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import java.util.*
*/
class TSReactorGenerator(
private val tsGenerator: TSGenerator,
private val errorReporter: ErrorReporter
private val errorReporter: ErrorReporter,
private val targetConfig: TargetConfig
) {
// Initializer functions
fun getTargetInitializerHelper(param: Parameter,
Expand Down Expand Up @@ -93,6 +94,22 @@ class TSReactorGenerator(
}
}

if (minOutputDelay != TimeValue.MAX_VALUE && targetConfig.coordinationOptions.advance_message_interval == null) {
// There is a path from a physical action to output for reactor but advance message interval is not set.
// Report a warning.
errorReporter.reportWarning(
"""
Found a path from a physical action to output for reactor ${defn.name}.
The amount of delay is $minOutputDelay.
With centralized coordination, this can result in a large number of messages to the RTI.
Consider refactoring the code so that the output does not depend on the physical action,
or consider using decentralized coordination. To silence this warning, set the target
parameter coordination-options with a value like {advance-message-interval: 10 msec}
""".trimIndent()
)

}

return with(PrependOperator) {
"""
|// ************* Starting Runtime for ${defn.name} + of class ${defn.reactorClass.name}.
Expand Down Expand Up @@ -143,7 +160,7 @@ class TSReactorGenerator(
val actionGenerator = TSActionGenerator(tsGenerator, reactor.actions, federate)
val portGenerator = TSPortGenerator(reactor.inputs, reactor.outputs)

val constructorGenerator = TSConstructorGenerator(tsGenerator, errorReporter, reactor, federate)
val constructorGenerator = TSConstructorGenerator(tsGenerator, errorReporter, reactor, federate, targetConfig)
return with(PrependOperator) {
"""
|// =============== START reactor class ${reactor.name}
Expand Down
56 changes: 56 additions & 0 deletions test/TypeScript/src/federated/DistributedDoublePort.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Test the case for when two upstream federates
* send messages to a downstream federte on two
* different ports. One message should carry a
* microstep delay relative to the other
* message.
*
* @author Soroush Bateni
* @author Hokeun Kim
*/
target TypeScript {
timeout: 900 msec,
coordination-options: {advance-message-interval: 100 msec},
logging: DEBUG
};

import Count from "../lib/Count.lf";

reactor CountMicrostep {
state count:number(1);
output out:number;
logical action act:number;
timer t(0, 1 sec);
reaction(t) -> act {=
actions.act.schedule(0, count++);
=}

reaction(act) -> out {=
out = act;
=}
}

reactor Print {
input inp:number;
input inp2:number;
reaction(inp, inp2) {=
const elapsedTime = util.getElapsedLogicalTime();
console.log("At tag " + elapsedTime + ", microstep:" + util.getCurrentTag().microstep +
", received inp = " + inp + " and inp2 = " + inp2 + ".");
if (inp !== undefined && inp2 !== undefined) {
util.requestErrorStop("ERROR: invalid logical simultaneity.");
}
=}

reaction(shutdown) {=
console.log("SUCCESS: messages were at least one microstep apart.");
=}
}

federated reactor DistributedDoublePort {
c = new Count();
cm = new CountMicrostep();
p = new Print();
c.out -> p.inp; // Indicating a 'logical' connection.
cm.out -> p.inp2;
}
3 changes: 2 additions & 1 deletion test/TypeScript/src/federated/LoopDistributedDouble.lf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
* @author Hokeun Kim
*/
target TypeScript {
timeout: 5 sec
timeout: 5 sec,
coordination-options: {advance-message-interval: 100 msec}
}

reactor Looper(incr:number(1), delay:time(0 msec)) {
Expand Down
14 changes: 14 additions & 0 deletions test/TypeScript/src/federated/SimpleFederated.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
target TypeScript {
timeout: 2 secs
};
reactor Fed {
input inp:number;
output out:number;
}
federated reactor {
fed1 = new Fed();
fed2 = new Fed();

fed1.out -> fed2.inp;
fed2.out -> fed1.inp;
}

0 comments on commit a08584b

Please sign in to comment.