Attention une mise à jour du serveur va être effectuée le lundi 17 mai entre 13h et 13h30. Cette mise à jour va générer une interruption du service de quelques minutes.

Commit b900746f authored by EYRAUD-DUBOIS Lionel's avatar EYRAUD-DUBOIS Lionel

First working version, with list and Heft

parent 1bf781d3
#include "HeftAlgorithm.h"
#include "util.h"
#include <limits>
#include <queue>
#include <iostream>
using namespace std;
typedef priority_queue<int, vector<int>, rankCompare> rankSet;
HeftAlgorithm::HeftAlgorithm(const map<string, string> options) {
}
/* Copy-paste from List, but well, it just happens to be common,
there's no real reason to factorize ? */
vector<double> HeftAlgorithm::computeHEFTRank(Instance &ins) {
vector<double> wbar(ins.nbTasks, 0);
int i, j;
int z = getSum(ins.nbWorkers);
for(i = 0; i < ins.nbTasks; i++) {
for(j = 0; j < (int) ins.nbWorkers.size(); j++)
wbar[i] += ins.execTimes[j][ins.taskTypes[i]] * ins.nbWorkers[j];
wbar[i] /= z;
}
vector<double> rank = ins.computeRanks(wbar);
wbar.clear();
return rank;
}
static const string heftAlgName = "heft";
string HeftAlgorithm::name() {
return heftAlgName;
}
double HeftAlgorithm::compute(Instance& ins, SchedAction *action) {
int nbWorkers = getSum(ins.nbWorkers);
int n = ins.nbTasks;
vector<double> rank = computeHEFTRank(ins); // TODO: an option for this.
vector< vector<int> > revDependencies = ins.getRevDependencies();
rankCompare rc(rank);
rankSet queue(rc);
vector<AvailSequence> workerAvailability(nbWorkers);
vector<double> endtimesTasks(n, -1);
vector<int> nbDep(n, 0);
int i, j, k, t;
for(i = 0; i < n; i++) {
nbDep[i] = ins.dependencies[i].size();
if(nbDep[i] == 0){
queue.push(i);
if(action != NULL) action->onTaskPush(i);
}
}
while(! queue.empty()) {
i = queue.top();
queue.pop();
k = 0;
double depTime = 0;
for(j = 0; j < (int) ins.dependencies[i].size(); j++) {
depTime = std::max(depTime, endtimesTasks[ins.dependencies[i][j]]);
}
double bestTime = std::numeric_limits<double>::infinity();
double bestStart = -1;
int bestK = 0; int bestT = 0;
timeSeq::iterator bestPeriod; // Should belond to workerAvailability[bestK]
int targetType = -1;
if((action != NULL) && ((targetType = action->chooseType(i, queue.size())) >= 0)) {
k = 0;
for(t = 0; t < targetType; t++) k += ins.nbWorkers[t];
for(j = 0; j < ins.nbWorkers[targetType]; j++, k++) {
double e = -1; double l = ins.execTimes[targetType][ins.taskTypes[i]];
timeSeq::iterator p = workerAvailability[k].getAvail(depTime, l, e);
if(e +l < bestTime){
bestK = k;
bestTime = e + l;
bestStart = e;
bestPeriod = p;
bestT = targetType;
}
}
} else {
for(t = 0; t < (int) ins.nbWorkers.size(); t++) {
for(j = 0; j < ins.nbWorkers[t]; j++, k++) {
// TODO: remove copy-paste ?
double e = -1; double l = ins.execTimes[t][ins.taskTypes[i]];
timeSeq::iterator p = workerAvailability[k].getAvail(depTime, l, e);
if(e +l < bestTime){
bestK = k;
bestTime = e + l;
bestStart = e;
bestPeriod = p;
bestT = t;
}
}
}
}
double startTime = bestStart;
// cout << "HEFT " << i << " " << ins.taskTypes[i] << " " << startTime << " " << bestTime << " " << bestK << " " << bestT << endl;
if(action != NULL) {
action->onSchedule(i, bestK, startTime, bestTime);
}
workerAvailability[bestK].insertBusy(bestPeriod, startTime, ins.execTimes[bestT][ins.taskTypes[i]]);
endtimesTasks[i] = bestTime;
for(j = 0; j < (int) revDependencies[i].size(); j++) {
int k = revDependencies[i][j];
nbDep[k]--;
if(nbDep[k] == 0){
queue.push(k);
if(action != NULL) action->onTaskPush(i);
}
}
}
double res = getMax(endtimesTasks);
return(res);
}
#ifndef HEFTALGORITHM_H
#define HEFTALGORITHM_H
#include <map>
#include <string>
#include <vector>
#include "instance.h"
#include "algorithm.h"
#include "availSequence.h"
class HeftAlgorithm : public Algorithm {
protected:
std::vector<double> computeRanks(Instance& ins);
std::vector<double> computeHEFTRank(Instance& ins);
public:
// List of options:
// Rank
//
HeftAlgorithm(const std::map<std::string, std::string> options);
double compute(Instance& ins, SchedAction* action);
string name();
};
#endif
schedAction.h
remove dependency on Ilo stuff
add data to instances for algorithms to share results
finish list algorithms
do I still want to support merging ?
Should I provide an outside merging tool ?
What workflow am I coding for ?
I can start by *not* supporting merging. Maybe easier. KISS, agile, tout ça.
Standard schedule format ?
\ No newline at end of file
#ifndef ALGORITHM_H
#define ALGORITHM_H
#include "instance.h"
class SchedAction {
public:
virtual void onSchedule(int task, int worker, IloNum startTime, IloNum endTime) { }
virtual int chooseType(int task, int nbReady) {return -1; }
virtual void onTaskPush(int task) { }
};
#include "schedAction.h"
class Algorithm {
public:
virtual double compute(Instance* instance, SchedAction action) { return -1; }
virtual double compute(Instance& instance, SchedAction* action) = 0;
virtual string name() = 0 ;
};
class Bound {
public:
virtual double compute(Instance& instance)= 0;
virtual string name() = 0;
};
#endif
#include "availSequence.h"
#include <limits>
#include <ostream>
AvailSequence::AvailSequence(double start) {
// Period p();
seq.emplace_back(start, std::numeric_limits<double>::infinity()); /* ca marche ça ? */
}
timeSeq::iterator AvailSequence::getAvail(double from, double len, double& start) {
timeSeq::iterator i;
for(i = seq.begin(); i != seq.end(); i++) {
if(i->end >= from) break;
}
if(len <= i->end - std::max(from, i->start)) {
start = std::max(from, i->start);
} else {
for(i++; i != seq.end(); i++) {
if(len <= i->end - i->start) break;
}
start = i->start;
}
return i;
}
void AvailSequence::insertBusy(timeSeq::iterator i, double start, double len) {
/* Assumes i != seq.end(), i->start <= start, i->end >= start + len */
Period orig = *i;
auto j = seq.erase(i);
if(orig.start < start) {
Period before(orig.start, start);
seq.insert(j, before);
}
if(orig.end > start + len) {
Period after(start + len, orig.end);
seq.insert(j, after);
}
}
void AvailSequence::insertBusy(double start, double len) {
double actualStart;
timeSeq::iterator i = getAvail(start, len, actualStart);
insertBusy(i, actualStart, len);
}
void AvailSequence::display(std::ostream &out) {
for(auto it = seq.begin(); it != seq.end(); it++) {
out << "[" << it->start << " " << it->end << "] ";
}
out << std::endl;
}
#ifndef AVAILSEQUENCE_H
#define AVAILSEQUENCE_H
#include <list>
#include <ostream>
class Period {
public:
double start;
double end;
Period() {}
Period(double s, double e) : start(s), end(e) {}
};
typedef std::list<Period> timeSeq;
class AvailSequence {
/* Guarantee: seq always contains an infinitely long period (end = -1) at the end */
timeSeq seq;
public:
AvailSequence(double start = 0);
timeSeq::iterator getAvail(double from, double len, double& start);
void insertBusy(timeSeq::iterator, double start, double len);
void insertBusy(double start, double len);
void display(std::ostream&);
};
#endif
This diff is collapsed.
#ifndefined INSTANCE_H
#ifndef INSTANCE_H
#define INSTANCE_H
typedef IloArray<IloNumVarArray> NumVarMatrix;
typedef IloArray<IloNumArray> NumMatrix;
typedef IloArray<IloIntVarArray> IntVarMatrix;
typedef IloArray<IloIntArray> IntMatrix;
class Instance {
public:
IloIntArray nbWorkers;
NumMatrix execTimes;
IntMatrix dependencies;
IloIntArray taskTypes; // If empty it means it's an uncompressed instance ?
int nbTasks;
IloEnv env;
// Thos are optional, let's say.
IloArray<string> workerNames;
IloArray<string> taskTypeNames;
IloArray<string> taskIDs;
// Computed afterwards
protected:
IntMatrix revDep;
IloIntArray topOrder;
IntMatrix ancestors;
void doConvertIndices();
void populate(env);
public:
Instance(const char* input_file, int convertIndices, IloEnv env);
void display(int verbosity);
void mergeWorkerTypes(IloIntArray indicesToMerge);
/* Accessors for static analysis */
IloIntArray getTopOrder();
IntMatrix getAncestors();
IntMatrix getRevDependencies();
IloNumArray computeRanks(IloNumArray wbar);
protected:
void updateTopOrder(IloIntArray computed, int i, int* l);
void computeTopOrder();
void computeAncestors();
void computeRevDependencies();
};
class CholeskyInstance : public Instance {
CholeskyInstance(IloEnv env, int n, int nbCPU, int nbGPU, IloNum execTimesCPU[], IloNum execTimesGPU[]);
};
#include <vector>
using namespace std;
class Instance {
public:
......@@ -65,8 +23,9 @@ public:
// ancestors[i][j] == 1 iff there exists a path from j to i
void doConvertIndices();
Instance();
public:
Instance(const char* input_file, int convertIndices);
Instance(const string input_file, int convertIndices);
void display(int verbosity);
void mergeWorkerTypes(vector<int> indicesToMerge);
/* Accessors for static analysis */
......@@ -74,15 +33,18 @@ public:
vector< vector<int> > getAncestors();
vector< vector<int> > getRevDependencies();
vector<double> computeRanks(vector<double> wbar);
vector<double> computeLongestPath(const vector<double> &weights, bool display, vector<int>* storeCP);
vector<double> computeCriticalPath(bool display, vector<int>* storeCP);
protected:
void updateTopOrder(vector<int> computed, int i, int* l);
void updateTopOrder(vector<int>& computed, int i, int &l);
void computeTopOrder();
void computeAncestors();
void computeRevDependencies();
};
class CholeskyInstance : public Instance {
CholeskyInstance(int n, int nbCPU, int nbGPU, vector<double> execTimesCPU, vector<double> execTimesGPU);
CholeskyInstance(int n, int nbCPU, int nbGPU, double execTimesCPU[], double execTimesGPU[]);
};
......
#include "listAlgorithm.h"
#include "util.h"
#include <set>
#include <iostream>
#include "instance.h"
#include "algorithm.h"
using namespace std;
typedef set<int, rankCompare> rankSet;
typedef std::set<int, rankCompare> rankSet;
class ListAlgorithm : public Algorithm {
int getType(int m, vector<int> nbWorkersPerType, int* index) {
int i;
for(i = 0; i < (int) nbWorkersPerType.size(); i++) {
if(m < nbWorkersPerType[i]){
if (index != NULL)
*index = m;
return i;
} else
m -= nbWorkersPerType[i];
}
// That's an error if I get here: m was higher than total nb of workers.
throw(-1);
}
IloNumArray computeRanks(Instance* ins) {
//TODO : add an option, have several possible ranks
IloNumArray w = computeHEFTRank(*ins);
return w;
}
vector<double> ListAlgorithm::computeRanks(Instance& ins) {
//TODO : add an option, have several possible ranks
vector<double> w = computeHEFTRank(ins);
return w;
}
public:
// List of options:
// Rank
//
ListAlgorithm(options) {
vector<double> ListAlgorithm::computeHEFTRank(Instance &ins) {
vector<double> wbar(ins.nbTasks, 0);
int i, j;
int z = getSum(ins.nbWorkers);
for(i = 0; i < ins.nbTasks; i++) {
for(j = 0; j < (int) ins.nbWorkers.size(); j++)
wbar[i] += ins.execTimes[j][ins.taskTypes[i]] * ins.nbWorkers[j];
wbar[i] /= z;
}
double compute(Instance* ins, SchedAction *action) {
vector<double> rank = ins.computeRanks(wbar);
wbar.clear();
return rank;
}
// Compute ranks
IloNumArray rank = computeRanks(ins);
int nbWorkers = IloSum(ins->nbWorkersPerType);
rankCompare rc(rank);
rankSet readyTasks(rc);
int n = ins->nbTasks;
IloEnv env = ins.env;
IloNumArray endtimesWorkers(env);
IloNumArray endtimesTasks(env);
IloBoolArray leaveIdle(env);
IloBoolArray finishedTasks(env);
IloIntArray nbDep(env, n);
endtimesWorkers.add(nbWorkers, 0);
leaveIdle.add(nbWorkers, false);
endtimesTasks.add(n, -1);
finishedTasks.add(n, false);
// List of options:
// Rank
//
ListAlgorithm::ListAlgorithm(map<string, string> options) {
int nbTaskTypes = execTimes[0].getSize();
int i, j, k, t;
}
static const string listAlgName = "list";
string ListAlgorithm::name() {
return listAlgName;
}
double ListAlgorithm::compute(Instance& ins, SchedAction* action) {
// Compute ranks
vector<double> rank = computeRanks(ins);
int nbWorkers = getSum(ins.nbWorkers);
rankCompare rc(rank);
rankSet readyTasks(rc);
int n = ins.nbTasks;
vector< vector<int> > revDependencies = ins.getRevDependencies();
vector<double> endtimesWorkers(nbWorkers, 0);
vector<double> endtimesTasks(n, -1);
vector<bool> leaveIdle(nbWorkers, false);
vector<bool> finishedTasks(n, false);
vector<int> nbDep(n, 0);
int i, j;
for(i = 0; i < n; i++) {
nbDep[i] = dependencies[i].getSize();
nbDep[i] = ins.dependencies[i].size();
if(nbDep[i] == 0){
readyTasks.insert(i);
if(action != NULL) action->onTaskPush(i);
}
}
IloNum time = 0;
double currentTime = 0;
int idle = 0;
int tasksToSchedule = n;
while(tasksToSchedule > 0) {
int index = 0;
int t = getType(idle, nbWorkersPerType, &index);
auto it = readyTasks.begin();
int t = getType(idle, ins.nbWorkers, &index);
bool found = false;
auto it = readyTasks.begin();
for(; it != readyTasks.end(); it++) {
int choice = (action != NULL) ? action->chooseType(*it, readyTasks.size()) : -1;
if((choice == -1) || (choice == t)) {
......@@ -78,57 +113,59 @@ public:
int chosenTask = *it;
readyTasks.erase(it);
IloNum finishTime = time + execTimes[t][taskTypes[chosenTask]];
cout << "LIST " << chosenTask << " " << taskTypes[chosenTask] << " " << time << " " << finishTime << " " << idle << " " << t << endl;
double finishTime = currentTime + ins.execTimes[t][ins.taskTypes[chosenTask]];
// cout << "LIST " << chosenTask << " " << ins.taskTypes[chosenTask] << " " << currentTime << " " << finishTime << " " << idle << " " << t << endl;
tasksToSchedule --;
if(action != NULL)
action->onSchedule(chosenTask, t, index, time, finishTime);
action->onSchedule(chosenTask, idle, currentTime, finishTime);
endtimesWorkers[idle] = finishTime;
endtimesTasks[chosenTask] = finishTime;
}
IloNum nextTime = time;
double nextTime = currentTime;
idle = -1;
for(i = 0; i < nbWorkers; i++)
if(leaveIdle[i] == false)
if((idle == -1) || (endtimesWorkers[i] < nextTime)) { idle = i; nextTime = endtimesWorkers[i]; }
if((idle == -1) || (endtimesWorkers[i] < nextTime))
{ idle = i; nextTime = endtimesWorkers[i];
}
if(idle == -1) {
cout << "Found no eligible worker. Ready set size = " << readyTasks.size() << endl;
exit(-1);
cerr << "Found no eligible worker. Ready set size = " << readyTasks.size() << endl;
throw(-1);
}
time = max(time, nextTime);
currentTime = max(currentTime, nextTime);
//Finish all tasks with finishTime <= time
//Finish all tasks with finishTime <= currentTime
for(i = 0; i < n; i++)
if((!finishedTasks[i]) && (endtimesTasks[i] != -1) && (endtimesTasks[i] <= time)) {
// cout << "[" << time << "] Finishing task " << i << endl;
if((!finishedTasks[i]) && (endtimesTasks[i] != -1) && (endtimesTasks[i] <= currentTime)) {
// cout << "[" << currentTime << "] Finishing task " << i << endl;
finishedTasks[i] = true;
for(j = 0; j < revDependencies[i].getSize(); j++) {
for(j = 0; j < (int) revDependencies[i].size(); j++) {
int k = revDependencies[i][j];
nbDep[k]--;
// cout << " Dependent task: " << k << " remaining dependencies: " << nbDep[k] << endl;
if(nbDep[k] == 0){
auto r = readyTasks.insert(k);
if(!r.second) {
cout << "Task " << k <<" already present in set" << endl;
exit(-1);
cerr << "Task " << k <<" already present in set" << endl;
throw(-1);
}
int choice = -1;
if(action != NULL) {
action->onTaskPush(i);
choice = action->chooseType(k, readyTasks.size());
}
// cout << "[" << time << "] Pushing task " << k << endl;
// cout << "[" << currentTime << "] Pushing task " << k << endl;
if(choice == -1)
for(int l = 0; l < nbWorkers; l++)
leaveIdle[l] = false;
else {
int z = 0;
for(t = 0; t < choice; t++) z += nbWorkersPerType[t];
for(int l = 0; l < nbWorkersPerType[choice]; l++, z++)
for(t = 0; t < choice; t++) z += ins.nbWorkers[t];
for(int l = 0; l < ins.nbWorkers[choice]; l++, z++)
leaveIdle[z] = false;
}
}
......@@ -137,8 +174,7 @@ public:
}
return IloMax(endtimesTasks);
return getMax(endtimesTasks);
}
};