/*
*
* Copyright 2007-2008 University Of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package edu.isi.pegasus.planner.provisioner;
import java.util.*;
/**
* This class keeps structure of an Occupation Diagram and conduct BTS algorithm
*
* @author Eunkyu Byun
*/
public class OccupationDiagram {
TreeSet nodes;
long RFT;
LinkedList[] timeMap;
int max;
int maxIndex;
/**
* Constructor
* @param rft Requested finish time(deadline) of algorithm.
*/
public OccupationDiagram(long rft) {
nodes = new TreeSet(new NodeComp());
this.RFT = rft;
max = 0;
maxIndex = 0;
timeMap = new LinkedList[(int)rft];
for(int i = 0 ; i < rft ; i++) {
timeMap[i] = new LinkedList();
}
}
/**
* Comparator which compare the schedulable duration of two nodes
*/
private class NodeComp implements Comparator<Node> {
// compare schedulable duration of two nodes
public int compare(Node a, Node b) {
if( (a.rb - a.lb) > (b.rb - b.lb) ) return 1;
if( (a.rb - a.lb) < (b.rb - b.lb) ) return -1;
// tie is broken by the number of dependent nodes
if( a.getDepET() > b.getDepET() ) return 1;
if( a.getID() == b.getID() ) return 0;
return -1;
}
}
/**
* Add tasks into the occupation diagram. But task placement is not conducted yet
* @param node Node to be added
*/
public void add( Node node ) {
// node with narrower has priority
if( node.evalWeight() > 0 ) {
nodes.add( node );
}
}
private void printNodes() {
System.out.println("******************");
Iterator iter = nodes.iterator();
while( iter.hasNext() ) {
Node n = (Node)iter.next();
System.out.println(n.getID()+" lb:"+n.lb+" lb:"+n.rb+" diff:"+(n.rb-n.lb)+" dep:"+n.getDepET() );
}
}
/**
* Run Task placement phase of BTS algorithm
* @param print if true print debug message to stdout
* @return maxinum height of Occupation diagram when Task placement is done
*/
public int stack(boolean print) {
while( nodes.size() > 0 ) {
double t00 = Calendar.getInstance().getTimeInMillis();
// printNodes();
Node cn = (Node)nodes.first();
nodes.remove(cn);
cn.stacked = true;
int leftB = (int)cn.lb;
int rightB = (int)cn.rb;
int et = (int)cn.evalWeight();
if( et <= 0 ) continue;
boolean rightBias = (cn.getDesSize()<cn.getAncSize());
int min = 100000;
int cursor = leftB;
for(int i = leftB ; i <= (rightB-et) ; i++) {
int localMax = 0;
for(int j = i ; j < (i+et); j++) {
localMax = Math.max(localMax, timeMap[j].size());
}
if( min > localMax ) {
min = localMax;
cursor = i;
}
if( min == localMax && rightBias) {
cursor = i;
}
}
for(int i = cursor ; i < (cursor+et) ; i++) {
timeMap[i].add(cn);
max = Math.max(max, timeMap[i].size());
}
cn.tempST = (long)cursor;
cn.tempFT = (long)(cursor + et);
// System.out.println(cn.getID()+"(lb:"+leftB+",rb:"+rightB+",et:"+et+") -> <"+cn.tempST+","+cn.tempFT+"> height:"+(min+1));
LinkedList parents = cn.getIn();
for(int i = 0; i < parents.size() ;i++) {
Edge ce = (Edge)parents.get(i);
Node n = ce.getFrom();
n.updateRightBound(cn.tempST - ce.getCost(), nodes);
}
LinkedList childs = cn.getOut();
for(int i = 0; i < childs.size() ;i++) {
Edge ce = (Edge)childs.get(i);
Node n = ce.getTo();
n.updateLeftBound(cn.tempFT + ce.getCost(), nodes);
}
double t01 = Calendar.getInstance().getTimeInMillis();
// System.out.println("stack :"+cn.getID()+" takes " + (t01-t00) );
}
return max;
}
/**
* Run Task redistribution phase of BTS algorithm
* @param goal Redistribution loop is stop if maximum height of OD reach this goal value.
* @param print if true print debug message to stdout
* @return maxinum height of Occupation diagram when Task redistribution is done
*/
public int balance(int goal, boolean print) {
int max = 0;
int maxIndexL = 0;
int maxIndexR = 0;
int cntWhile = 0;
int cntNPt = 0;
int cntNP = 0;
int cntPt = 0;
int cntP = 0;
LinkedList sortTemp = null;
while(true) {
cntWhile++;
max = 0;
// find maximum time slot
for(int i = 0 ; i < RFT ; i++) {
// System.out.println("ts: "+i+ " h: "+ timeMap[i].size() );
if( timeMap[i].size() == max ) maxIndexR = i;
if( timeMap[i].size() > max ) {
max = timeMap[i].size();
maxIndexL = i;
maxIndexR = i;
}
}
if( max <= goal ) break;
// System.out.println("RFT: "+ RFT+" max: "+max+" maxIndexL: "+maxIndexL+" maxIndexR: "+maxIndexR);
boolean reduced = false;
// non propagated balancing
for(int k = 0 ; k < max ; k++ ) {
cntNPt++;
Node cn = (Node)timeMap[maxIndexL].get(k);
if( cn.NPbalance(timeMap, max, false) ) {
reduced = true;
cntNP++;
break;
}
cn = (Node)timeMap[maxIndexR].get(k);
if( cn.NPbalance(timeMap, max, false) ) {
reduced = true;
cntNP++;
break;
}
}
if( reduced ) continue;
// propagated balancing
// redistribute to left direction
sortTemp = new LinkedList();
for(int k = 0 ; k < max ;k++) { // among tasks in the highest time slot
Node cn = (Node)timeMap[maxIndexL].get(k);
if( (cn.tempST-cn.olb) >= cn.evalWeight() ) { //check whether the tasks can be moved or not
boolean mid = false;
for(int ii = 0 ; ii < sortTemp.size(); ii++ ) { //sorting movable tasks with the number ancestor tasks and ET
Node tn = (Node)sortTemp.get(ii);
if( tn.getAncET() > cn.getAncET() ) {
sortTemp.add(ii, cn);
mid = true;
break;
} else if ( tn.getAncET() < cn.getAncET() ) {
continue;
} else if( tn.evalWeight() > cn.evalWeight() ) { //tie break
sortTemp.add(ii, cn);
mid = true;
}
}
if( !mid ) sortTemp.add(cn);
}
}
boolean succ = false;
for(int k = 0 ; k < sortTemp.size() ; k++ ) {
Node cn = (Node)sortTemp.get(k);
succ = cn.moveLeft(timeMap, max, maxIndexL);
if( succ ) break;
}
if( succ ) continue;
// redistribute to right direction
sortTemp = new LinkedList();
for(int k = 0 ; k < max ;k++) { // among tasks in the highest time slot
Node cn = (Node)timeMap[maxIndexR].get(k);
if( (cn.orb - cn.tempFT) >= cn.evalWeight() ) { //check whether the tasks can be moved or not
boolean mid = false;
for(int ii = 0 ; ii < sortTemp.size(); ii++ ) { //sorting movable tasks with the number descendant tasks and ET
Node tn = (Node)sortTemp.get(ii);
if( tn.getDesET() > cn.getDesET() ) {
sortTemp.add(ii, cn);
mid = true;
break;
} else if ( tn.getDesET() < cn.getDesET() ) {
continue;
} else if( tn.evalWeight() > cn.evalWeight() ) { //tie break
sortTemp.add(ii, cn);
mid = true;
}
}
if( !mid ) sortTemp.add(cn);
}
}
for(int k = 0 ; k < sortTemp.size() ; k++ ) {
Node cn = (Node)sortTemp.get(k);
succ = cn.moveRight(timeMap, max, maxIndexR+1);
if( succ ) break;
}
if( !succ ) break;
}
// System.out.println("cntWhile: "+cntWhile+" cntNP: "+cntNP+" cntNPt:"+cntNPt+" cntP: "+cntP+" cntPt:"+cntPt+" max:"+max);
return max;
}
}