From 5f5653e4b571649f433969f80b233a050fee27cc Mon Sep 17 00:00:00 2001 From: EYRAUD-DUBOIS Lionel Date: Mon, 25 Mar 2019 15:16:51 +0100 Subject: [PATCH] New Indep algorithm: MinMin, based on doi:10.1006/jpdc.2000.1714 --- README.md | 3 ++ include/IndepMinMin.h | 30 +++++++++++++ schedulers/CMakeLists.txt | 2 +- schedulers/IndepBased.cpp | 3 ++ schedulers/IndepMinMin.cpp | 87 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 include/IndepMinMin.h create mode 100644 schedulers/IndepMinMin.cpp diff --git a/README.md b/README.md index 0c65379..ff30c9a 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,9 @@ resources. All of these only work with two types of resources. Implements the CLB2C strategy (see [Considerations on distributed load balancing for fully heterogeneous machines: Two particular cases.](https://doi.org/10.1109/IPDPSW.2015.36)). Not exactly equivalent to this strategy, since `indep` performs list scheduling based only on the assignment to different types of resources. + + `minmin` + Implements the MinMin strategy (see [A Comparison of Eleven Static Heuristics for Mapping a Class of Independent Tasks onto Heterogeneous Distributed Computing Systems](https://doi.org/10.1006/jpdc.2000.1714).) + + `rank` (except for style `strict`) as for the previous algorithms + `dosort` (except for `strict`, default `yes`) diff --git a/include/IndepMinMin.h b/include/IndepMinMin.h new file mode 100644 index 0000000..41febe4 --- /dev/null +++ b/include/IndepMinMin.h @@ -0,0 +1,30 @@ +// +// Created by eyraud on 25/03/19. +// Based on A Comparison of Eleven Static Heuristics for +// Mapping a Class of Independent Tasks onto +// Heterogeneous Distributed Computing Systems +// doi:10.1006/jpdc.2000.1714 + + +#ifndef PMTOOL_MINMIN_H +#define PMTOOL_MINMIN_H + + +#include "IndepAllocator.h" + +class IndepMinMin : public IndepAllocator { +private: + + Instance* ins; + std::vector workerIndices; + std::vector bestWorkers; /* length = nb worker types */ + + int getEarliestWorker(std::vector &loads, int type); + inline double endTime(std::vector &loads, int workerType, int task); +public: + IndepResult compute(Instance &ins, std::vector &taskSet, std::vector &loads) override; + IndepMinMin(const AlgOptions &options); +}; + + +#endif //PMTOOL_MINMIN_H diff --git a/schedulers/CMakeLists.txt b/schedulers/CMakeLists.txt index aa549bf..7495c69 100644 --- a/schedulers/CMakeLists.txt +++ b/schedulers/CMakeLists.txt @@ -27,7 +27,7 @@ set(SCHED_SRC OnlineLG.cpp ../include/OnlineLG.h OnlineMG.cpp ../include/OnlineMG.h IndepCLB2C.cpp ../include/IndepCLB2C.h - + IndepMinMin.cpp ../include/IndepMinMin.h ) if(CPLEX_FOUND) diff --git a/schedulers/IndepBased.cpp b/schedulers/IndepBased.cpp index a51da88..85215ef 100644 --- a/schedulers/IndepBased.cpp +++ b/schedulers/IndepBased.cpp @@ -9,6 +9,7 @@ #include "IndepBalanced.h" #include "IndepZhang.h" #include +#include #include #include @@ -49,6 +50,8 @@ IndepBased::IndepBased(const AlgOptions& options) : GreedyAlgorithm(options) { indep = new IndepZhang(options); if(indepName == "clb2c") indep = new IndepCLB2C(options); + if(indepName == "minmin") + indep = new IndepMinMin(options); #ifdef WITH_CPLEX if(indepName == "round") indep = new AreaRound(options); diff --git a/schedulers/IndepMinMin.cpp b/schedulers/IndepMinMin.cpp new file mode 100644 index 0000000..baf665a --- /dev/null +++ b/schedulers/IndepMinMin.cpp @@ -0,0 +1,87 @@ + +// Created by eyraud on 25/03/19 + +#include "IndepMinMin.h" +#include +#include +#include "util.h" + +using namespace std; + +IndepMinMin::IndepMinMin(const AlgOptions& options) : IndepAllocator(options) { + needsPreciseLoads = true; +} + +int IndepMinMin::getEarliestWorker(vector &loads, int type) { + int best = workerIndices[type]; + int to = workerIndices[type+1]; + for(int i = workerIndices[type]; i < to; ++i){ + if(loads[i] < loads[best]) + best = i; + } + return best; +} + +double IndepMinMin::endTime(vector &loads, int workerType, int task) { + return loads[bestWorkers[workerType]] + ins->execType(workerType, task); +} + +IndepResult IndepMinMin::compute(Instance & ins, vector &taskSet, vector &loads) { + + this->ins = & ins; + + workerIndices.resize(ins.nbWorkerTypes + 1); + bestWorkers.resize(ins.nbWorkerTypes); + workerIndices[0] = 0; + for(int i = 0; i < ins.nbWorkerTypes; ++i) { + workerIndices[i+1] = workerIndices[i] + ins.nbWorkers[i]; + bestWorkers[i] = getEarliestWorker(loads, i); + } + + IndepResult result(ins.nbWorkerTypes); + + set tasks(taskSet.begin(), taskSet.end()); + int nbTasks = taskSet.size(); + + while(nbTasks > 0) { + int bestWorkerType = -1; + int bestTask = -1; + for(int t: tasks) { + int bestWorkerTypeForThisTask = 0; + for(int j = 1; j < ins.nbWorkerTypes; ++j) { + if(endTime(loads, j, t) < endTime(loads, bestWorkerTypeForThisTask, t)) + bestWorkerTypeForThisTask = j; + } + if(bestTask < 0 || + endTime(loads, bestWorkerTypeForThisTask, t) < endTime(loads, bestWorkerType, bestTask)) { + bestTask = t; + bestWorkerType = bestWorkerTypeForThisTask; + } + } + + result[bestWorkerType].push_back(bestTask); + loads[bestWorkers[bestWorkerType]] += ins.execType(bestWorkerType, bestTask); + bestWorkers[bestWorkerType] = getEarliestWorker(loads, bestWorkerType); + + nbTasks -= 1; + tasks.erase(bestTask); + + } + + return(result); +} + + +// Possibilities +// As an IndepAllocator, close to CLB2C +// +// O(n^2m') m' = # worker types +// Until done: O(n) +// find best worker for each type of worker O(m) +// Find smallest ready task for each type of worker O(nm') =>O(m'(1+update)) +// Assign. +// Keep ordered sets of tasks, one for each worker type ? Updates seem costly, but worst case is still better +// Keep best worker for each type ? Avoids recomputation. + + +// What about MaxMin ? -- GitLab