Commit 1f4101ca authored by EYRAUD-DUBOIS Lionel's avatar EYRAUD-DUBOIS Lionel

Factorization: Convert Dmdas to GreedyAlgorithm

parent a7b14c77
......@@ -4,16 +4,29 @@
#include "instance.h"
#include "algorithm.h"
#include "algoptions.h"
#include "GreedyAlgorithm.h"
class Dmdas : public Algorithm {
class Dmdas : public GreedyAlgorithm {
protected:
RankComputer ranker;
int verbosity;
std::vector<TaskSet*> localQueues;
std::vector<double> assignedLoad;
TaskSet* readyTasks;
Instance* ins;
double getFinishedTime(double now, int task, int w, int wType);
int getBestWorker(double now, int task);
void assignFront(double now);
public:
Dmdas(const AlgOptions& options);
double compute(Instance &ins, SchedAction* action);
double compute(Instance &ins, SchedAction* action) override;
int chooseTask(int worker, double now) override;
void onTaskPush(int task, double now) override;
};
......
......@@ -10,227 +10,82 @@
using namespace std;
Dmdas::Dmdas(const AlgOptions& options):
Dmdas::Dmdas(const AlgOptions& options) : GreedyAlgorithm(options),
ranker(options), verbosity(options.asInt("verbosity", 0)) {
}
double Dmdas::compute(Instance &ins, SchedAction* action) {
double Dmdas::compute(Instance &instance, SchedAction* action) {
// Compute ranks
TaskSet* readyTasks = ranker.makeSet(ins);
int nbWorkers = ins.totalWorkers;
int n = ins.nbTasks;
ins = &instance;
readyTasks = ranker.makeSet(instance);
vector< vector<int> > revDependencies = ins.getRevDependencies();
vector<TaskSet*> localQueues(nbWorkers);
localQueues.resize(instance.totalWorkers);
for(auto && tq: localQueues) {
tq = ranker.makeSet(ins);
tq = ranker.makeSet(instance);
}
vector<double> endtimesWorkers(nbWorkers, 0);
vector<double> endtimesTasks(n, -1);
vector<double> assignedLoad(nbWorkers, 0);
vector<int> currentRunningTask(nbWorkers, -1);
// vector<bool> leaveIdle(ins.nbWorkerTypes, false);
vector<bool> finishedTasks(n, false);
vector<int> nbDep(n, 0);
/*
vector<int> wTypeOrdering(ins.nbWorkerTypes);
vector<int> wStartIndex(ins.nbWorkerTypes);
assignedLoad.resize(instance.totalWorkers, 0);
GreedyAlgorithm::compute(instance, action);
}
// For now keep the "old" version of dmdas where the assigned load also
// counts lower priority tasks
double Dmdas::getFinishedTime(double now, int task, int w, int wType) {
double execTime = ins->execType(wType, task);
if(ins->isValidValue(execTime)) {
double s = max(endTimesWorkers[w], now);
return (s + assignedLoad[w]
+ execTime);
} else
return std::numeric_limits<double>::infinity();
}
vector<double> aggregateTimings(ins.nbWorkerTypes, 1);
int index = 0;
for(int i = 0; i < ins.nbWorkerTypes; i++) {
wStartIndex[i] = index;
index += ins.nbWorkers[i];
for(int j = 0; j < ins.nbTaskTypes; j++) {
aggregateTimings[i] *= ins.execTimes[i][j];
int Dmdas::getBestWorker(double now, int task) {
double bestSoFar = std::numeric_limits<double>::infinity();
int bestWorker = -1;
int i = 0;
for(int wType = 0; wType < ins->nbWorkerTypes; ++wType) {
for(int j = 0; j < ins->nbWorkers[wType]; ++j, ++i) {
double t = getFinishedTime(now, task, i, wType);
if(t < bestSoFar) {
bestSoFar = t; bestWorker = i;
}
aggregateTimings[i] = pow(aggregateTimings[i], 1.0 / ins.nbTaskTypes);
}
for(int i = 0; i < ins.nbWorkerTypes; i++)
wTypeOrdering[i] = i;
sort(wTypeOrdering.begin(), wTypeOrdering.end(),
[&] (int a, int b) { return aggregateTimings[a] < aggregateTimings[b]; });
if(verbosity >= 6)
cout << "List: wTypeOrdering= " << wTypeOrdering << endl;
*/
for(int i = 0; i < n; i++) {
nbDep[i] = ins.dependencies[i].size();
if(nbDep[i] == 0){
readyTasks->insert(i);
if(action != NULL) action->onTaskPush(i);
}
}
double currentTime = 0;
int tasksToSchedule = n;
// For now keep the "old" version of dmdas where the assigned load also
// counts lower priority tasks
auto getFinishedTime = [&] (int task, int w, int wType) {
double execTime = ins.execType(wType, task);
if(ins.isValidValue(execTime)) {
double s = max(endtimesWorkers[w], currentTime);
return (s + assignedLoad[w]
+ execTime);
} else
return std::numeric_limits<double>::infinity();
};
auto getBestWorker = [&] (int task) {
double bestSoFar = std::numeric_limits<double>::infinity();
int bestWorker = -1;
int i = 0;
for(int wType = 0; wType < ins.nbWorkerTypes; ++wType) {
for(int j = 0; j < ins.nbWorkers[wType]; ++j, ++i) {
double t = getFinishedTime(task, i, wType);
if(t < bestSoFar) {
bestSoFar = t; bestWorker = i;
}
}
}
if(bestWorker < 0) {
cerr << "Dmdas: no valid worker for task " << task << endl;
throw(1);
}
return bestWorker;
};
auto assignFront = [&] () {
int task = readyTasks->front();
int w = getBestWorker(task);
if(verbosity >= 4) {
cout << "dmdas @ " << currentTime << " assigning task " << task << " to worker " << w << endl;
}
localQueues[w]->insert(task);
assignedLoad[w] += ins.execWorker(w, task);
readyTasks->eraseFront();
};
// int idle = wStartIndex[wTypeOrdering[0]];
while(tasksToSchedule > 0) {
while(!readyTasks->empty())
assignFront();
int w = 0;
for(int wType = 0; wType < ins.nbWorkerTypes; ++wType) {
for(int j = 0; j < ins.nbWorkers[wType]; ++j, ++w) {
if((endtimesWorkers[w] <= currentTime) && (!localQueues[w]->empty())) {
int task = localQueues[w]->front();
double finishTime = currentTime + ins.execType(wType, task);
if(verbosity >= 1)
cout << "dmdas: starting " << task << " of type " << ins.taskTypes[task] << " at " << currentTime << " to end at " << finishTime << " on worker " << w << " of type " << wType << endl;
tasksToSchedule --;
if(action != NULL)
action->onSchedule(task, w, currentTime, finishTime);
localQueues[w]->eraseFront();
assignedLoad[w] -= ins.execType(wType, task);
endtimesWorkers[w] = finishTime;
endtimesTasks[task] = finishTime;
currentRunningTask[w] = task;
}
}
}
double nextTime = -1;
for(int w = 0; w < nbWorkers; w++) {
if((endtimesWorkers[w] > currentTime) &&
((endtimesWorkers[w] < nextTime) || (nextTime == -1))) {
nextTime = endtimesWorkers[w];
}
}
if(nextTime == -1){
cerr << "dmdas: next Time == -1 !" << endl;
throw(-1);
}
currentTime = nextTime;
//Finish all tasks with finishTime <= currentTime
for(int j = 0; j < nbWorkers; j++) {
int i = currentRunningTask[j];
if((i != -1) && (!finishedTasks[i]) && (endtimesTasks[i] != -1) && (endtimesTasks[i] <= currentTime)) {
if(verbosity >= 1)
cout << "List: Finishing task " << i << " at time " << currentTime << endl;
finishedTasks[i] = true;
currentRunningTask[j] = -1;
for(int & k: revDependencies[i]) {
nbDep[k]--;
if(verbosity >= 7)
cout << " Dependent task: " << k << " remaining dependencies: " << nbDep[k] << endl;
if(nbDep[k] == 0){
readyTasks->insert(k);
if(action != NULL) {
action->onTaskPush(k);
}
}
}
}
}
if(bestWorker < 0) {
cerr << "Dmdas: no valid worker for task " << task << endl;
throw(1);
}
return getMax(endtimesTasks);
return bestWorker;
}
// class Dmdas_Action : public SchedAction {
// protected:
// vector<TaskSet> allocated;
// vector<double> allocatedLoad;
// Instance& instance;
// vector<double> endtimesWorkers;
// int verbosity;
// public:
// Dmdas_Action(Instance& ins, int verb) :
// allocated(ins.totalWorkers), allocatedLoad(ins.totalWorkers),
// instance(ins),
// endtimesWorkers(ins.totalWorkers, 0), verbosity(verb) {
// }
// void onSchedule(int task, int worker, double start, double end) {
// int t = getType(worker, instance.nbWorkers, NULL);
// allocated[t].erase(find(allocated[t].begin(), allocated[t].end(), task));
// allocatedLoad[t] -= ins.execTimes[ins.taskTypes[task]][t];
// endtimesWorkers[worker] = end;
// }
void Dmdas::assignFront(double now) {
int task = readyTasks->front();
int w = getBestWorker(now, task);
localQueues[w]->insert(task);
assignedLoad[w] += ins->execWorker(w, task);
readyTasks->eraseFront();
}
// void onTaskPush(int task) {
// // choose worker w with min finish time
// // add task to allocated[w]
// }
// int chooseTask(int wType, double now) {
// // Hmm. How do I manage this ? There is no notion of *this* worker
// // in ListAlgorithm ... It's bad, cause I have to do "average
// // load" in that case.
// // Probably easier to recode as an "event-based" algorithm
// // Or just find any idle worker of type wType and give the task
// // in its queue.
// // So:
// // take first worker of type wType with finish time <= now
// // and whose queue is non empty. But that's like so wasteful: listAlgorithm knows ;'(
/* On Task Push does not schedule directly, to make sure
that the decision about tasks are performed in prioriy order
as much as possible */
void Dmdas::onTaskPush(int task, double now) {
readyTasks->insert(task);
}
// }
int Dmdas::chooseTask(int worker, double now) {
/* Now we assign tasks to workers */
while(!readyTasks->empty())
assignFront(now);
// }
if (!localQueues[worker]->empty()) {
int result = localQueues[worker]->front();
localQueues[worker]->eraseFront();
assignedLoad[worker] -= ins->execWorker(worker, result);
return result;
}
return -1;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment