Skip to content

Commit

Permalink
Track instructions (transition guards) that contribute to hyperperiod…
Browse files Browse the repository at this point in the history
… startup overhead
  • Loading branch information
lsk567 committed Nov 13, 2024
1 parent 22d523e commit 19410c7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 28 deletions.
25 changes: 18 additions & 7 deletions core/src/main/java/org/lflang/analyses/dag/Dag.java
Original file line number Diff line number Diff line change
Expand Up @@ -392,13 +392,24 @@ public CodeBuilder generateDot(List<List<Instruction>> instructions) {
}

// Add PretVM instructions.
if (instructions != null && node.nodeType == DagNode.dagNodeType.REACTION) {
int worker = node.getWorker();
List<Instruction> workerInstructions = instructions.get(worker);
if (node.filterInstructions(workerInstructions).size() > 0)
label += "\\n" + "Instructions:";
for (Instruction inst : node.filterInstructions(workerInstructions)) {
label += "\\n" + inst.getOpcode() + " (worker " + inst.getWorker() + ")";
if (instructions != null) {
if (node.nodeType == DagNode.dagNodeType.REACTION) {
int worker = node.getWorker();
List<Instruction> workerInstructions = instructions.get(worker);
if (node.filterInstructions(workerInstructions).size() > 0)
label += "\\n" + "Instructions:";
for (Instruction inst : node.filterInstructions(workerInstructions)) {
label += "\\n" + inst.getOpcode();
}
}
else if (node.nodeType == DagNode.dagNodeType.SYNC) {
int workers = instructions.size();
for (int worker = 0; worker < workers; worker++) {
List<Instruction> workerInstructions = instructions.get(worker);
for (Instruction inst : node.filterInstructions(workerInstructions)) {
label += "\\n" + inst.getOpcode() + " (worker " + inst.getWorker() + ")";
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/lflang/analyses/dag/DagNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void setReleaseValue(Long value) {
* collect instructions which belong to that node.
*/
public List<Instruction> filterInstructions(List<Instruction> workerInstructions) {
return workerInstructions.stream().filter(it -> it.getDagNode() == this).toList();
return workerInstructions.stream().filter(it -> it.getDagNodes().contains(this)).toList();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1770,9 +1770,15 @@ private String getWorkerLabelString(Object label, int worker) {
}

/**
* Link multiple object files into a single executable (represented also in an object file class).
* Link multiple object files into a single executable (represented also in an object file class).
* Instructions are also inserted based on transition guards between fragments. In addition,
* PREAMBLE and EPILOGUE instructions are inserted here.
*
* Very importantly, transition guards are added to the DAG start
* nodes of the downstream fragments, because they are placed after
* the sync block and DU, so they should factor into the startup
* overhead of the next hyperperiod. Locations marked by "STARTUP
* OVERHEAD REASONING" is related to this.
*/
public PretVmExecutable link(List<PretVmObjectFile> pretvmObjectFiles, Path graphDir) {

Expand Down Expand Up @@ -1814,31 +1820,55 @@ public PretVmExecutable link(List<PretVmObjectFile> pretvmObjectFiles, Path grap
// Obtain partial schedules from the current object file.
List<List<Instruction>> partialSchedules = current.getContent();

// Append guards for downstream transitions to the partial schedules.
// Declare placeholders for default transition and default
// fragment. They need to be added last, after the other
// transitions.
List<Instruction> defaultTransition = null;
for (var dsFragment : downstreamFragments) {
List<Instruction> transition = current.getFragment().getDownstreams().get(dsFragment);
StateSpaceFragment defaultDownstreamFragment = null;
// Append guards for downstream transitions to the partial schedules.
for (StateSpaceFragment dsFragment : downstreamFragments) {
List<Instruction> abstractTransition = current.getFragment().getDownstreams().get(dsFragment);
// Check if a transition is a default transition.
if (StateSpaceUtils.isDefaultTransition(transition)) {
defaultTransition = transition;
// If so, save them for later.
if (StateSpaceUtils.isDefaultTransition(abstractTransition)) {
defaultTransition = abstractTransition;
defaultDownstreamFragment = dsFragment;
continue;
}
// Add COPIES of guarded transitions to the partial schedules.
// They have to be copies since otherwise labels created for different
// workers will be added to the same instruction object, creating conflicts.
for (int i = 0; i < workers; i++) {
partialSchedules
.get(i)
.addAll(replaceAbstractRegistersToConcreteRegisters(transition, i));
// workers will be added to the same instruction object,
// creating conflicts.
for (int w = 0; w < workers; w++) {
// Replace the abstract registers with concrete registers.
List<Instruction> concreteTransition = replaceAbstractRegistersToConcreteRegisters(abstractTransition, w);
//// STARTUP OVERHEAD REASONING
// Since the transition logic is executed after the sync
// block and the DU, we need to attribute them to the head
// node of the next phase.
DagNode dagStartNodeOfNextPhase = dsFragment.getObjectFile().getDag().start;
// Add instructions for worker.
addInstructionSequenceForWorker(partialSchedules, w, dagStartNodeOfNextPhase, null, concreteTransition);
}
}
// Handling the default transition
// Make sure to have the default transition copies to be appended LAST,
// since default transitions are taken when no other transitions are taken.
if (defaultTransition != null) {
for (int i = 0; i < workers; i++) {
partialSchedules
.get(i)
.addAll(replaceAbstractRegistersToConcreteRegisters(defaultTransition, i));
for (int w = 0; w < workers; w++) {
List<Instruction> concreteTransition = replaceAbstractRegistersToConcreteRegisters(defaultTransition, w);
//// STARTUP OVERHEAD REASONING
// If the downstream fragment is EPILOGUE, which does not have
// object files. Set the associated DAG node to null.
DagNode dagStartNodeOfNextPhase;
if (defaultDownstreamFragment.getObjectFile() == null && defaultDownstreamFragment.getPhase() == Phase.EPILOGUE) {
dagStartNodeOfNextPhase = null;
} else if (defaultDownstreamFragment.getObjectFile() != null) {
dagStartNodeOfNextPhase = defaultDownstreamFragment.getObjectFile().getDag().start;
} else {
throw new RuntimeException("Unhandled phase without object files: " + defaultDownstreamFragment.getPhase());
}
addInstructionSequenceForWorker(partialSchedules, w, dagStartNodeOfNextPhase, null, concreteTransition);
}
}

Expand Down Expand Up @@ -1996,7 +2026,7 @@ private List<List<Instruction>> generateEpilogue(List<DagNode> nodes) {

/** Generate the synchronization code block. */
private List<List<Instruction>> generateSyncBlock(List<DagNode> nodes) {

System.out.println("*** Nodes: " + nodes);
List<List<Instruction>> syncBlock = new ArrayList<>();

for (int w = 0; w < workers; w++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ public enum Opcode {
/** Worker who owns this instruction */
private int worker;

/** DAG node for which this instruction is generated */
private DagNode node;
/** A list of DAG nodes for which this instruction is generated. This
* is a list because an instruction can be generated for nodes in
* different phases. For example, a WU instruction in the sync block. */
private List<DagNode> nodes = new ArrayList<>();

/** Getter of the opcode */
public Opcode getOpcode() {
Expand Down Expand Up @@ -139,11 +141,17 @@ public void setWorker(int worker) {
}

public DagNode getDagNode() {
return this.node;
if (this.nodes.size() > 1)
throw new RuntimeException("This instruction is generated for more than one node!");
return this.nodes.get(0);
}

public List<DagNode> getDagNodes() {
return this.nodes;
}

public void setDagNode(DagNode node) {
this.node = node;
this.nodes.add(node);
}

@Override
Expand Down

0 comments on commit 19410c7

Please sign in to comment.