From ba236984a049d4595302929367bdcffa978d00db Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:12:57 +0200 Subject: [PATCH 01/11] Added test for GEDF redesign --- core/src/main/resources/lib/c/reactor-c | 2 +- test/C/src/PeriodicTask.lf | 55 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/C/src/PeriodicTask.lf diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 0a4272234b..58a24ec53d 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 0a4272234b0e7109271e4797338f099facb8e48d +Subproject commit 58a24ec53df10c966701eff7699c4fd91683357e diff --git a/test/C/src/PeriodicTask.lf b/test/C/src/PeriodicTask.lf new file mode 100644 index 0000000000..f34ed98cbe --- /dev/null +++ b/test/C/src/PeriodicTask.lf @@ -0,0 +1,55 @@ +/** + * This test ensures that level 2 reaction with a tighter deadline runs + * before a level 1 reaction with a looser deadline when there is no + * dependency between these reactions. This is the correct behavior of + * the GEDF scheduler, so the scheduler is set to GEDF_NP. + */ +target C { + timeout: 200ms, + scheduler: GEDF_NP, + workers: 1 +}; + +reactor Periodic(period:time = 50ms, name:string = "Unnamed") { + timer trigger(0, period) + + output t: time + + reaction(trigger) -> t {= + instant_t start_time = lf_time_physical_elapsed(); + lf_set(t, start_time); + lf_print("%s started at physical time: " PRINTF_TIME, self->name, start_time); + =} +} + +reactor Probe(dl:time = 2ms, name:string = "Unnamed") { + input i: time + output t: time + + reaction (i) -> t {= + instant_t start_time = lf_time_physical_elapsed(); + lf_set(t, start_time); + lf_print("%s started at physical time: " PRINTF_TIME, self->name, start_time); + =} deadline (dl) {= + instant_t start_time = lf_time_physical_elapsed(); + lf_set(t, start_time); + lf_print("%s VIOLATED DEADLINE at physical time: " PRINTF_TIME, self->name, start_time); + =} +} + +main reactor { + task1 = new Periodic(period = 50ms, name = "task1") + detector1 = new Probe(dl = 50ms, name = "detector1") + + task1.t -> detector1.i + task2 = new Periodic(period = 50ms, name = "task2") + detector2 = new Probe(dl = 25ms, name = "detector2") + + task2.t -> detector2.i + + reaction(task1.t, detector2.t) {= + if (task1.t->is_present && detector2.t->is_present && task1.t->value < detector2.t->value) { + lf_print_error_and_exit("EDF policy violated. detector2 should execute before task1 when both are triggered."); + } + =} +} \ No newline at end of file From 4bd502b1426a3fbc1bdafa91034752c158b6ae8b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:15:48 +0200 Subject: [PATCH 02/11] Format --- test/C/src/PeriodicTask.lf | 45 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/test/C/src/PeriodicTask.lf b/test/C/src/PeriodicTask.lf index f34ed98cbe..83a83226c5 100644 --- a/test/C/src/PeriodicTask.lf +++ b/test/C/src/PeriodicTask.lf @@ -1,36 +1,35 @@ /** - * This test ensures that level 2 reaction with a tighter deadline runs - * before a level 1 reaction with a looser deadline when there is no - * dependency between these reactions. This is the correct behavior of - * the GEDF scheduler, so the scheduler is set to GEDF_NP. + * This test ensures that level 2 reaction with a tighter deadline runs before a level 1 reaction + * with a looser deadline when there is no dependency between these reactions. This is the correct + * behavior of the GEDF scheduler, so the scheduler is set to GEDF_NP. */ target C { - timeout: 200ms, + timeout: 200 ms, scheduler: GEDF_NP, workers: 1 -}; +} -reactor Periodic(period:time = 50ms, name:string = "Unnamed") { +reactor Periodic(period: time = 50 ms, name: string = "Unnamed") { timer trigger(0, period) - + output t: time - + reaction(trigger) -> t {= instant_t start_time = lf_time_physical_elapsed(); lf_set(t, start_time); lf_print("%s started at physical time: " PRINTF_TIME, self->name, start_time); - =} + =} } -reactor Probe(dl:time = 2ms, name:string = "Unnamed") { +reactor Probe(dl: time = 2 ms, name: string = "Unnamed") { input i: time output t: time - - reaction (i) -> t {= + + reaction(i) -> t {= instant_t start_time = lf_time_physical_elapsed(); lf_set(t, start_time); lf_print("%s started at physical time: " PRINTF_TIME, self->name, start_time); - =} deadline (dl) {= + =} deadline(dl) {= instant_t start_time = lf_time_physical_elapsed(); lf_set(t, start_time); lf_print("%s VIOLATED DEADLINE at physical time: " PRINTF_TIME, self->name, start_time); @@ -38,18 +37,18 @@ reactor Probe(dl:time = 2ms, name:string = "Unnamed") { } main reactor { - task1 = new Periodic(period = 50ms, name = "task1") - detector1 = new Probe(dl = 50ms, name = "detector1") - - task1.t -> detector1.i - task2 = new Periodic(period = 50ms, name = "task2") - detector2 = new Probe(dl = 25ms, name = "detector2") - + task1 = new Periodic(period = 50 ms, name="task1") + detector1 = new Probe(dl = 50 ms, name="detector1") + + task1.t -> detector1.i + task2 = new Periodic(period = 50 ms, name="task2") + detector2 = new Probe(dl = 25 ms, name="detector2") + task2.t -> detector2.i - + reaction(task1.t, detector2.t) {= if (task1.t->is_present && detector2.t->is_present && task1.t->value < detector2.t->value) { lf_print_error_and_exit("EDF policy violated. detector2 should execute before task1 when both are triggered."); } =} -} \ No newline at end of file +} From 021ebf2cf6af48254fc153e461762deaf054de76 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:29:38 +0200 Subject: [PATCH 03/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 58a24ec53d..9a34786cdd 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 58a24ec53df10c966701eff7699c4fd91683357e +Subproject commit 9a34786cdd06d25516877c6be1c009c1e44adb9e From 18f4210c1400f8582aa65b66f2883d8c41e37244 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:31:38 +0200 Subject: [PATCH 04/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 9a34786cdd..3784e6171c 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9a34786cdd06d25516877c6be1c009c1e44adb9e +Subproject commit 3784e6171c12d66e3c2392da496051cad3b6d833 From 6780f35e4aa68e908f8a12ee728deac20c04f0ae Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:46:08 +0200 Subject: [PATCH 05/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 3784e6171c..12aa9caa6f 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 3784e6171c12d66e3c2392da496051cad3b6d833 +Subproject commit 12aa9caa6f9ec6ea537e468426ccdbd1c09be5af From 4b14166b28fd6e6de1dc907f57a9bfea605d4d5b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 11:14:24 +0200 Subject: [PATCH 06/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 12aa9caa6f..60be3d1880 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 12aa9caa6f9ec6ea537e468426ccdbd1c09be5af +Subproject commit 60be3d188072986ee61de4650541a4e084d37a0d From 073a25b57206813aea91564cf14ce6715b34cf69 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 17:56:47 +0200 Subject: [PATCH 07/11] Remove unused (and incorrect) method --- .../org/lflang/generator/ReactorInstance.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/ReactorInstance.java b/core/src/main/java/org/lflang/generator/ReactorInstance.java index ad8f532a80..78f1312c97 100644 --- a/core/src/main/java/org/lflang/generator/ReactorInstance.java +++ b/core/src/main/java/org/lflang/generator/ReactorInstance.java @@ -207,22 +207,6 @@ public ReactionInstanceGraph assignLevels() { return cachedReactionLoopGraph; } - /** - * This function assigns/propagates deadlines through the Reaction Instance Graph. It performs - * Kahn's algorithm in reverse, starting from the leaf nodes and propagates deadlines upstream. To - * reduce cost, it should only be invoked when there are user-specified deadlines in the program. - * - * @return - */ - public ReactionInstanceGraph assignDeadlines() { - if (depth != 0) return root().assignDeadlines(); - if (cachedReactionLoopGraph == null) { - cachedReactionLoopGraph = new ReactionInstanceGraph(this); - } - cachedReactionLoopGraph.rebuildAndAssignDeadlines(); - return cachedReactionLoopGraph; - } - /** * Return the instance of a child rector created by the specified definition or null if there is * none. From c09ea42644e0a6d8623ab5b76c7bde52368c7d88 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 19:09:11 +0200 Subject: [PATCH 08/11] Fix inference of deadlines to not destroy the reaction graph and invoke it --- .../generator/ReactionInstanceGraph.java | 59 ++++++------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/ReactionInstanceGraph.java b/core/src/main/java/org/lflang/generator/ReactionInstanceGraph.java index 9dd7548d6c..5ce3ff38fb 100644 --- a/core/src/main/java/org/lflang/generator/ReactionInstanceGraph.java +++ b/core/src/main/java/org/lflang/generator/ReactionInstanceGraph.java @@ -24,12 +24,7 @@ package org.lflang.generator; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.NavigableMap; -import java.util.Set; -import java.util.TreeMap; +import java.util.*; import java.util.stream.Collectors; import org.lflang.generator.ReactionInstance.Runtime; import org.lflang.generator.c.CUtil; @@ -70,34 +65,24 @@ public ReactionInstanceGraph(ReactorInstance main) { /** The main reactor instance that this graph is associated with. */ public final ReactorInstance main; - /////////////////////////////////////////////////////////// - //// Public methods - /** * Rebuild this graph by clearing and repeating the traversal that adds all the nodes and edges. + * Note that after this executes, the graph is empty unless it has causality cycles, in which case + * it contains only those causality cycles. */ - public void rebuild() { + private void rebuild() { this.clear(); addNodesAndEdges(main); addEdgesForTpoLevels(main); - - // FIXME: Use {@link TargetProperty#EXPORT_DEPENDENCY_GRAPH}. + assignInferredDeadlines(); // Assign a level to each reaction. // If there are cycles present in the graph, it will be detected here. + // This will destroy the graph, leaving only nodes in cycles. assignLevels(); // Do not throw an exception when nodeCount != 0 so that cycle visualization can proceed. } - /** This function rebuilds the graph and propagates and assigns deadlines to all reactions. */ - public void rebuildAndAssignDeadlines() { - this.clear(); - addNodesAndEdges(main); - // addDependentNetworkEdges(main); - assignInferredDeadlines(); - this.clear(); - } - /* * Get an array of non-negative integers representing the number of reactions * per each level, where levels are indices of the array. @@ -399,40 +384,34 @@ private void assignPortLevel(Runtime current) { /** * This function assigns inferred deadlines to all the reactions in the graph. It is modeled after - * {@code assignLevels} but it starts at the leaf nodes and uses Kahns algorithm to build a - * reverse topologically sorted graph + * {@code assignLevels} but it starts at the leaf nodes, but it does not destroy the graph. */ private void assignInferredDeadlines() { - List start = new ArrayList<>(leafNodes()); + List start = new ArrayList<>(leafNodes()); + Set visited = new HashSet<>(); // All leaf nodes have deadline initialized to their declared deadline or MAX_VALUE while (!start.isEmpty()) { Runtime origin = start.remove(0); - Set toRemove = new LinkedHashSet<>(); + visited.add(origin); Set upstreamAdjacentNodes = getUpstreamAdjacentNodes(origin); - // Visit effect nodes. + // Visit upstream nodes. for (Runtime upstream : upstreamAdjacentNodes) { - // Stage edge between origin and upstream for removal. - toRemove.add(upstream); - + // If the upstream node has been visited, then we have a cycle, which will be + // an error condition. Skip it. + if (visited.contains(upstream)) continue; // Update deadline of upstream node if origins deadline is earlier. if (origin.deadline.isEarlierThan(upstream.deadline)) { upstream.deadline = origin.deadline; } - } - // Remove visited edges. - for (Runtime upstream : toRemove) { - removeEdge(origin, upstream); - // If the upstream node has no more outgoing edges, - // then move it in the start set. - if (getDownstreamAdjacentNodes(upstream).size() == 0) { - start.add(upstream); + // Determine whether the upstream node is now a leaf node. + var isLeaf = true; + for (Runtime downstream : getDownstreamAdjacentNodes(upstream)) { + if (!visited.contains(downstream)) isLeaf = false; } + if (isLeaf) start.add(upstream); } - - // Remove visited origin. - removeNode(origin); } } From 8147460f3a6ae646b73ac1c56a1ca3c02c26d9d2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 19:09:44 +0200 Subject: [PATCH 09/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 60be3d1880..90ea06c076 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 60be3d188072986ee61de4650541a4e084d37a0d +Subproject commit 90ea06c076b85aa99633a0af1221b22e3c4de5bd From b751f7e53840138f46f9fb0817d998cc808bceb1 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 19:22:10 +0200 Subject: [PATCH 10/11] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 90ea06c076..297c68b685 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 90ea06c076b85aa99633a0af1221b22e3c4de5bd +Subproject commit 297c68b6851a124d50a15c046bc55e5d365d9190 From 24a6b201ab132a51bb85d9c0e0cf99e8d1c3072f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:46:07 +0200 Subject: [PATCH 11/11] Removed chainID --- .../main/java/org/lflang/generator/ReactionInstance.java | 9 --------- .../java/org/lflang/generator/c/CReactionGenerator.java | 1 - .../org/lflang/generator/c/CTriggerObjectsGenerator.java | 4 ---- core/src/main/resources/lib/c/reactor-c | 2 +- 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/ReactionInstance.java b/core/src/main/java/org/lflang/generator/ReactionInstance.java index 385dbd6da8..339a68be83 100644 --- a/core/src/main/java/org/lflang/generator/ReactionInstance.java +++ b/core/src/main/java/org/lflang/generator/ReactionInstance.java @@ -173,15 +173,6 @@ public ReactionInstance(Reaction definition, ReactorInstance parent, int index) ////////////////////////////////////////////////////// //// Public fields. - /** - * Indicates the chain this reaction is a part of. It is constructed through a bit-wise or among - * all upstream chains. Each fork in the dependency graph setting a new, unused bit to true in - * order to disambiguate it from parallel chains. Note that zero results in no overlap with any - * other reaction, which means the reaction can execute in parallel with any other reaction. The - * default is 1L. If left at the default, parallel execution will be based purely on levels. - */ - public long chainID = 1L; - /** The ports or actions that this reaction may write to. */ public Set> effects = new LinkedHashSet<>(); diff --git a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java index 246e4e03eb..87b5c6fcb9 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java @@ -897,7 +897,6 @@ public static void generateReactionAndTriggerStructs( // Set the defaults of the reaction_t struct in the constructor. // Since the self struct is allocated using calloc, there is no need to set: // self->_lf__reaction_"+reactionCount+".index = 0; - // self->_lf__reaction_"+reactionCount+".chain_id = 0; // self->_lf__reaction_"+reactionCount+".pos = 0; // self->_lf__reaction_"+reactionCount+".status = inactive; // self->_lf__reaction_"+reactionCount+".deadline = 0LL; diff --git a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java index 133d06ff02..cf1587ae85 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -240,7 +240,6 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde temp.pr( String.join( "\n", - CUtil.reactionRef(r) + ".chain_id = " + r.chainID + ";", "// index is the OR of level " + level + " and ", "// deadline " + inferredDeadline.toNanoSeconds() + " shifted left 16 bits.", CUtil.reactionRef(r) + ".index = " + reactionIndex + ";")); @@ -249,7 +248,6 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde temp.pr( String.join( "\n", - CUtil.reactionRef(r) + ".chain_id = " + r.chainID + ";", "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) @@ -266,7 +264,6 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde temp.pr( String.join( "\n", - CUtil.reactionRef(r) + ".chain_id = " + r.chainID + ";", "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) @@ -283,7 +280,6 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde temp.pr( String.join( "\n", - CUtil.reactionRef(r) + ".chain_id = " + r.chainID + ";", "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 297c68b685..d54dbd6435 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 297c68b6851a124d50a15c046bc55e5d365d9190 +Subproject commit d54dbd64350dc2bb3e173e296580be1ae2401b2d