package xsched.analysis.core;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
//TV: task variable type
//SS: schedule site type
public class AnalysisTask<Instance, TV, SM extends TaskScheduleManager<TV>> {
public final Instance id;
private final TaskSchedule<TV, SM> taskSchedule;
private final AnalysisSession<Instance, TV, SM> analysis;
//map from task varible int to a collection of possible targets
private HashMap<Integer, Collection<AnalysisTask<Instance, TV, SM>>> possibleTargetTasksCache;
private HashMap<FormalParameterConstraints, AnalysisStepResult<Instance, TV, SM>> resultsCache = new HashMap<FormalParameterConstraints, AnalysisStepResult<Instance, TV, SM>>();
private HashSet<AnalysisTask<Instance, TV, SM>> childrenCache;
AnalysisTask(AnalysisSession<Instance, TV, SM> analysis, Instance id, TaskSchedule<TV, SM> taskSchedule) {
this.analysis = analysis;
this.id = id;
this.taskSchedule = taskSchedule;
}
public TaskSchedule<TV, SM> taskSchedule() {
return taskSchedule;
}
//call this method and it will compute the parallelTasks set for all tasks that are directly or indirectly scheduled when
//this is a root task
public AnalysisResult<Instance> solveAsRoot(AnalysisTaskResolver<Instance, TV, SM> resolver) {
AnalysisStepResult<Instance, TV, SM> result = analyze(resolver, new FormalParameterConstraints());
//a main task only has the now param
assert(result.formalParameterResult.numTaskParameters() == 1);
return new AnalysisResult<Instance>(result.parallelTasksResult);
}
private void populatePossibleTaskTargetsCache(AnalysisTaskResolver<Instance, TV, SM> resolver) {
//first, compute for all schedule sites the possible targets because we need that for all of them anyway
possibleTargetTasksCache = new HashMap<Integer, Collection<AnalysisTask<Instance, TV, SM>>>(taskSchedule.numberOfNonParameterTaskVariables());
Iterator<Integer> scheduleSites = taskSchedule.iterateNonParameterTaskVariables();
while(scheduleSites.hasNext()) {
int scheduleSite = scheduleSites.next();
Collection<Instance> taskInstanceIDs = resolver.possibleTargetTasksForSite(this, taskSchedule.nodeForTaskVariable(scheduleSite));
Collection<AnalysisTask<Instance, TV, SM>> possibleTargetTasks = analysis.tasksWithIDs(taskInstanceIDs);
this.possibleTargetTasksCache.put(scheduleSite, possibleTargetTasks);
}
}
private AnalysisStepResult<Instance, TV, SM> analyze(AnalysisTaskResolver<Instance, TV, SM> resolver, FormalParameterConstraints myParamConstraints) {
AnalysisStepResult<Instance, TV, SM> myResult = resultsCache.get(myParamConstraints);
if(myResult != null)
return myResult;
this.populatePossibleTaskTargetsCache(resolver);
//add the result to the cache immediately to avoid infinite recursion
myResult = new AnalysisStepResult<Instance, TV, SM>(new ParallelTasksResult<Instance, TV, SM>(), new FormalParameterResult<Instance, TV, SM>(taskSchedule.numberOfFormalParameterTaskVariables()));
resultsCache.put(myParamConstraints, myResult);
//analyze each schedule site and then compare it with each schedule site and each formal param O(n^2)
Iterator<Integer> scheduleSites = taskSchedule.iterateNonParameterTaskVariables();
while(scheduleSites.hasNext()) {
int scheduleSite = scheduleSites.next();
FormalParameterConstraints scheduleSiteConstraints = new FormalParameterConstraints(taskSchedule, scheduleSite);
Collection<AnalysisTask<Instance, TV, SM>> possibleTargetTasks = possibleTargetTasksCache.get(scheduleSite);
//for each possible target task of the schedule site, get the analysis result and aggregate all of them
FormalParameterResult<Instance, TV, SM> aggregate = new FormalParameterResult<Instance, TV, SM>(scheduleSiteConstraints.numActualParameters());
for(AnalysisTask<Instance, TV, SM> siteTask : possibleTargetTasks) {
AnalysisStepResult<Instance, TV, SM> siteResult = siteTask.analyze(resolver, scheduleSiteConstraints);
myResult.parallelTasksResult.mergeWith(siteResult.parallelTasksResult);
aggregate.mergeWith(siteResult.formalParameterResult);
}
//check relation of each schedule site with each incoming parameter
Iterator<Integer> formalParameters = taskSchedule.iterateFormalParameterTaskVariables();
while(formalParameters.hasNext()) {
int myFormalParam = formalParameters.next();
TaskSchedule.Relation relation = taskSchedule.relationForTaskVariables(scheduleSite, myFormalParam);
switch(relation) {
case singleton:
throw new RuntimeException("that can't be... a schedule site and a formal param can't be a singleton");
case happensBefore:
myResult.formalParameterResult.setTasksNotOrderedAfter(myFormalParam, possibleTargetTasks);
break;
case happensAfter:
myResult.formalParameterResult.setTasksNotOrderedBefore(myFormalParam, possibleTargetTasks);
break;
case ordered:
//?!? nothing to do here?
break;
case unordered:
myResult.formalParameterResult.setTasksNotOrderedBefore(myFormalParam, possibleTargetTasks);
myResult.formalParameterResult.setTasksNotOrderedAfter(myFormalParam, possibleTargetTasks);
break;
}
//"fold" the parameters and compute the effect for the formal parameter
//pessimistically assume that the parameter is parallel to all of the schedule site's children
UnorderedTasksSets<Instance, TV, SM> unorderedChildren = foldParameters(resolver, scheduleSite, aggregate, myFormalParam);
myResult.formalParameterResult.setTasksNotOrderedBefore(myFormalParam, unorderedChildren.tasksNotOrderedBefore);
myResult.formalParameterResult.setTasksNotOrderedAfter(myFormalParam, unorderedChildren.tasksNotOrderedAfter);
}
//check relation of the schedule site with each other schedule site
Iterator<Integer> otherScheduleSites = taskSchedule.iterateNonParameterTaskVariables();
while(otherScheduleSites.hasNext()) {
int otherScheduleSite = otherScheduleSites.next();
Collection<AnalysisTask<Instance, TV, SM>> otherPossibleTargetTasks = possibleTargetTasksCache.get(otherScheduleSite);
TaskSchedule.Relation relation = taskSchedule.relationForTaskVariables(scheduleSite, otherScheduleSite);
//if schedule sites are unordered, their immediate target tasks are unordered
switch(relation) {
case singleton:
//the targets are unordered
myResult.parallelTasksResult.setParallel(possibleTargetTasks, otherPossibleTargetTasks);
break;
default:
//that's ok
break;
}
//relate the children of this schedule site to the other's possible targets
UnorderedTasksSets<Instance, TV, SM> unorderedChildren = foldParameters(resolver, scheduleSite, aggregate, otherScheduleSite);
//intersect tasks that are not ordered before and not ordered after
HashSet<AnalysisTask<Instance, TV, SM>> unordered = new HashSet<AnalysisTask<Instance, TV, SM>>(unorderedChildren.tasksNotOrderedBefore);
unordered.retainAll(unorderedChildren.tasksNotOrderedAfter);
myResult.parallelTasksResult.setParallel(otherPossibleTargetTasks, unordered);
}
}
return myResult;
}
//returns the children that may be created as a result of a schedule site, but does NOT include the tasks that may be created at the schedule site itself!
public Set<AnalysisTask<Instance, TV, SM>> childrenForScheduleSite(int scheduleSite) {
HashSet<AnalysisTask<Instance, TV, SM>> result = new HashSet<AnalysisTask<Instance, TV, SM>>();
Collection<AnalysisTask<Instance, TV, SM>> possibleTargetTasks = this.possibleTargetTasksCache.get(scheduleSite);
for(AnalysisTask<Instance, TV, SM> child : possibleTargetTasks) {
result.addAll(child.children());
}
return result;
}
//given a schedule site, the result for the formal parameters and one schedule site (possibly an actual parameter),
//walk over the list of actuals of the schedule site and find its relation with the task variable
private UnorderedTasksSets<Instance, TV, SM> foldParameters(
AnalysisTaskResolver<Instance, TV, SM> resolver,
int scheduleSite,
FormalParameterResult<Instance, TV, SM> aggregate,
int taskVariable) {
//pessimistically assume that the parameter is parallel to all of the schedule site's children
Set<AnalysisTask<Instance, TV, SM>> children = this.childrenForScheduleSite(scheduleSite);
UnorderedTasksSets<Instance, TV, SM> unorderedChildren
= new UnorderedTasksSets<Instance, TV, SM>(new HashSet<AnalysisTask<Instance, TV, SM>>(children), new HashSet<AnalysisTask<Instance, TV, SM>>(children));
int[] actuals = taskSchedule.actualsForTaskVariable(scheduleSite);
for(int i = 0; i < actuals.length; i++) {
int actual = actuals[i];
TaskSchedule.Relation relation = taskSchedule.relationForTaskVariables(taskVariable, actual);
switch(relation) {
case singleton:
unorderedChildren.tasksNotOrderedBefore.retainAll(aggregate.tasksNotOrderedBefore(i));
unorderedChildren.tasksNotOrderedAfter.retainAll(aggregate.tasksNotOrderedAfter(i));
break;
case happensBefore:
unorderedChildren.tasksNotOrderedAfter.retainAll(aggregate.tasksNotOrderedAfter(i));
break;
case happensAfter:
unorderedChildren.tasksNotOrderedBefore.retainAll(aggregate.tasksNotOrderedBefore(i));
break;
case ordered:
//do nothing?!?
break;
default:
//do nothing
}
}
return unorderedChildren;
}
public Set<AnalysisTask<Instance, TV, SM>> children() {
if(childrenCache != null)
return childrenCache;
//init first, avoids infinite recursion
childrenCache = new HashSet<AnalysisTask<Instance, TV, SM>>();
//analyze each schedule site and then compare it with each schedule site and each formal param O(n^2)
Iterator<Integer> scheduleSites = taskSchedule.iterateNonParameterTaskVariables();
while(scheduleSites.hasNext()) {
int scheduleSite = scheduleSites.next();
Collection<AnalysisTask<Instance, TV, SM>> possibleTargetTasks = this.possibleTargetTasksCache.get(scheduleSite);
childrenCache.addAll(possibleTargetTasks);
for(AnalysisTask<Instance, TV, SM> possibleTask : possibleTargetTasks) {
childrenCache.addAll(possibleTask.children());
}
}
return childrenCache;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object otherObj) {
return otherObj == this;
}
}