Skip to content
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

[Experimental] Quasi-static scheduler #1190

Draft
wants to merge 1 commit into
base: master
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
4 changes: 3 additions & 1 deletion org.lflang/src/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,7 @@ public String getcMakeName() {
/**
* Supported schedulers.
* @author{Soroush Bateni <[email protected]>}
* @author{Shaokai Lin <[email protected]>}
*/
public enum SchedulerOption {
NP(false), // Non-preemptive
Expand All @@ -1373,8 +1374,9 @@ public enum SchedulerOption {
Path.of("data_collection.h")
)),
GEDF_NP(true), // Global EDF non-preemptive
GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID
GEDF_NP_CI(true), // Global EDF non-preemptive with chain ID
// PEDF_NP(true); // Partitioned EDF non-preemptive (FIXME: To be re-added in a future PR)
QS(false); // Quasi-static

/**
* Indicate whether or not the scheduler prioritizes reactions by deadline.
Expand Down
12 changes: 12 additions & 0 deletions org.lflang/src/org/lflang/generator/ReactionInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ public ReactionInstance(
* If left at the default, parallel execution will be based purely
* on levels.
*/
//TODO:
public long reactionid ;
public long chainID = 1L;

/**
Expand Down Expand Up @@ -535,10 +537,20 @@ public class Runtime {
/** ID ranging from 0 to parent.getTotalWidth() - 1. */
public int id = 0;
public int level = 0;
public int reactionID = 0; // Reaction Runtime ID

public ReactionInstance getReaction() {
return ReactionInstance.this;
}

public long getReactionID() {
return this.reactionID;
}

public String getFullName() {
return ReactionInstance.this.toString();
}

@Override
public String toString() {
String result = ReactionInstance.this + "(level: " + level;
Expand Down
49 changes: 35 additions & 14 deletions org.lflang/src/org/lflang/generator/ReactionInstanceGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import java.util.List;
import java.util.Set;

import org.eclipse.xtext.xbase.lib.Exceptions;

import org.lflang.generator.ReactionInstance.Runtime;
import org.lflang.graph.PrecedenceGraph;
import org.lflang.lf.Variable;

/**
* This class analyzes the dependencies between reaction runtime instances.
* For each ReactionInstance, there may be more than one runtime instance because
Expand All @@ -60,18 +61,23 @@ public class ReactionInstanceGraph extends PrecedenceGraph<ReactionInstance.Runt
* Create a new graph by traversing the maps in the named instances
* embedded in the hierarchy of the program.
*/
public ReactionInstanceGraph(ReactorInstance main) {
public ReactionInstanceGraph(ReactorInstance main, boolean detectCycles) {
this.main = main;
this.detectCycles = detectCycles;
rebuild();
}

///////////////////////////////////////////////////////////
//// Public fields

/**
* The main reactor instance that this graph is associated with.
*/
/** The main reactor instance that this graph is associated with. */
public final ReactorInstance main;

/**
* Whether this ReactionInstanceGraph is built for detecting cycles,
* which involves removing nodes from the graph.
*/
public final boolean detectCycles;

///////////////////////////////////////////////////////////
//// Public methods
Expand All @@ -83,14 +89,16 @@ public ReactionInstanceGraph(ReactorInstance main) {
public void rebuild() {
this.clear();
addNodesAndEdges(main);
// Assign a level to each reaction.
// If there are cycles present in the graph, it will be detected here.
assignLevels();
if (nodeCount() != 0) {
// The graph has cycles.
// main.reporter.reportError("Reactions form a cycle! " + toString());
// Do not throw an exception so that cycle visualization can proceed.
// throw new InvalidSourceException("Reactions form a cycle!");
if (this.detectCycles) {
// Assign a level to each reaction.
// If there are cycles present in the graph, it will be detected here.
assignLevels();
if (nodeCount() != 0) {
// The graph has cycles.
// main.reporter.reportError("Reactions form a cycle! " + toString());
// Do not throw an exception so that cycle visualization can proceed.
// throw new InvalidSourceException("Reactions form a cycle!");
}
}
}

Expand All @@ -115,6 +123,19 @@ public int getBreadth() {
return maxBreadth;
}

/*
* Get a reaction in the dependency graph based on a reaction ID.
*/
public Runtime getReactionByID(long reactionID) {
for (var node : this.nodes()) {
if (node.getReactionID() == reactionID)
return node;
}
Exceptions.sneakyThrow(
new Exception("Reaction with ID " + reactionID + " not found."));
return null;
}

///////////////////////////////////////////////////////////
//// Protected methods

Expand Down Expand Up @@ -291,7 +312,7 @@ private void assignLevels() {
}
}

// Remove visited origin.
// (IMPORTANT) Remove visited origin.
removeNode(origin);

// Update numReactionsPerLevel info
Expand Down
3 changes: 2 additions & 1 deletion org.lflang/src/org/lflang/generator/ReactorInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ public ReactorInstance(Reactor reactor, ReactorInstance parent, ErrorReporter re
public ReactionInstanceGraph assignLevels() {
if (depth != 0) return root().assignLevels();
if (cachedReactionLoopGraph == null) {
cachedReactionLoopGraph = new ReactionInstanceGraph(this);
// The 2nd param, `true`, enables cycle detection.
cachedReactionLoopGraph = new ReactionInstanceGraph(this, true);
}
return cachedReactionLoopGraph;
}
Expand Down
4 changes: 2 additions & 2 deletions org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.lflang.FileConfig;
import org.lflang.TargetConfig;
import org.lflang.TargetProperty.Platform;
import org.lflang.TargetProperty.SchedulerOption;
import org.lflang.generator.CodeBuilder;
import org.lflang.util.FileUtil;

Expand Down Expand Up @@ -231,8 +232,7 @@ CodeBuilder generateCMakeCode(
cMakeCode.pr("add_link_options( "+compilerFlag+")");
}
}
cMakeCode.newLine();


// Add the install option
cMakeCode.pr("install(");
cMakeCode.indent();
Expand Down
1 change: 1 addition & 0 deletions org.lflang/src/org/lflang/generator/c/CCoreFilesUtils.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.lflang.generator.c;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down
42 changes: 42 additions & 0 deletions org.lflang/src/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import org.lflang.TargetProperty.ClockSyncMode;
import org.lflang.TargetProperty.CoordinationType;
import org.lflang.TargetProperty.Platform;
import org.lflang.TargetProperty.SchedulerOption;
import org.lflang.TimeValue;
import org.lflang.federated.FedFileConfig;
import org.lflang.federated.FederateInstance;
Expand All @@ -87,6 +88,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import org.lflang.generator.TargetTypes;
import org.lflang.generator.TimerInstance;
import org.lflang.generator.TriggerInstance;
import org.lflang.generator.uclid.UclidScheduleGenerator;
import org.lflang.lf.Action;
import org.lflang.lf.ActionOrigin;
import org.lflang.lf.Expression;
Expand Down Expand Up @@ -579,6 +581,11 @@ public void doGenerate(Resource resource, LFGeneratorContext context) {
Exceptions.sneakyThrow(e);
}

// Generate scheduler-specific code. In the case of the QS scheduler,
// a schedule.h is generated. This is separated from the logic in
// pickScheduler(), since pickScheduler() does not generate new code.
generateCodeForScheduler();

// Create docker file.
if (targetConfig.dockerOptions != null && mainDef != null) {
dockerGenerator.addFile(
Expand Down Expand Up @@ -882,6 +889,25 @@ private void generateCodeForCurrentFederate(
}
}

/**
* Generate scheduler-specific code. In the case of the QS scheduler,
* a schedule.h is generated. This is separated from the logic in
* pickScheduler(), since pickScheduler() does not generate new code.
*/
private void generateCodeForScheduler() {
// Generate schedule.h if QS scheduler is used.
if (targetConfig.schedulerType == SchedulerOption.QS) {
var scheduleGenerator = new UclidScheduleGenerator(fileConfig, errorReporter, main, targetConfig);
var scheduleFile = fileConfig.getSrcGenPath() + File.separator + "schedule.h";
var scheduleCode = scheduleGenerator.generateScheduleCode();
try {
scheduleCode.writeToFile(scheduleFile);
} catch (IOException e) {
Exceptions.sneakyThrow(e);
}
}
}

protected CDockerGenerator getDockerGenerator() {
return new CDockerGenerator(isFederated, CCppMode, targetConfig);
}
Expand Down Expand Up @@ -924,6 +950,22 @@ private void pickScheduler() {
targetConfig.compileAdditionalSources.add(
"core" + File.separator + "utils" + File.separator + "semaphore.c"
);

// Perform a set of QS scheduler-specific operations.
if (targetConfig.schedulerType == SchedulerOption.QS) {
// Define a macro in CMake.
targetConfig.compileDefinitions.put("SCHEDULER_QS", "");
// Copy an additional header file for QS.
try {
FileUtil.copyFilesFromClassPath(
"/lib/c/reactor-c/core",
fileConfig.getSrcGenPath().resolve("core"),
List.of("threaded/scheduler_QS.h")
);
} catch (IOException e) {
Exceptions.sneakyThrow(e);
}
}
}

private boolean hasDeadlines(List<Reactor> reactors) {
Expand Down
Loading