Commit 35c8f92b by EYRAUD-DUBOIS Lionel

Merge branch 'parallel' into 'master'

Parallel

See merge request !3
parents e69b8fd0 a991512d
......@@ -9,6 +9,9 @@ include_directories("include")
find_package(LibRec REQUIRED)
include_directories(${LIBREC_INCLUDE_DIRS})
set(THREADS_PREFER_PTHREAD_FLAG)
find_package(Threads REQUIRED)
add_subdirectory("core")
add_subdirectory("schedulers")
......@@ -28,14 +31,16 @@ set(PROG_SRC
)
add_executable(pmtool ${PROG_SRC})
target_link_libraries(pmtool core)
target_link_libraries(pmtool schedulers)
target_link_libraries(pmtool ${LIBREC_LIBRARIES})
if(CPLEX_FOUND)
target_link_libraries(pmtool bounds)
target_link_libraries(pmtool ${CPLEX_LIBRARIES})
endif()
target_link_libraries(pmtool core)
target_link_libraries(pmtool ${LIBREC_LIBRARIES})
if(THREADS_FOUND)
target_link_libraries(pmtool Threads::Threads)
endif()
......@@ -92,7 +92,9 @@ else()
set(CPLEX_ROOT_DIR "" CACHE PATH "CPLEX root directory.")
set(CPLEX_WIN_PLATFORM "")
string(TOLOWER ${CMAKE_SYSTEM_NAME} CPLEX_SYSTEM_NAME_LOWER)
set(CPLEX_PLATFORM "${CMAKE_SYSTEM_PROCESSOR}_${CPLEX_SYSTEM_NAME_LOWER}")
endif()
message(STATUS "cplex root dir: ${CPLEX_ROOT_DIR}")
......@@ -118,6 +120,7 @@ FIND_PATH(CPLEX_CONCERT_INCLUDE_DIR
FIND_LIBRARY(CPLEX_LIBRARY
NAMES cplex${CPLEX_WIN_VERSION} cplex
HINTS ${CPLEX_ROOT_DIR}/cplex/lib/${CPLEX_WIN_PLATFORM} #windows
${CPLEX_ROOT_DIR}/cplex/lib/${CPLEX_PLATFORM}/static_pic #generic
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_debian4.0_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_linux/static_pic #linux (ubuntu)
......@@ -131,6 +134,7 @@ message(STATUS "CPLEX Library: ${CPLEX_LIBRARY}")
FIND_LIBRARY(CPLEX_ILOCPLEX_LIBRARY
ilocplex
HINTS ${CPLEX_ROOT_DIR}/cplex/lib/${CPLEX_WIN_PLATFORM} #windows
${CPLEX_ROOT_DIR}/cplex/lib/${CPLEX_PLATFORM}/static_pic #generic
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_debian4.0_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/cplex/lib/x86-64_osx/static_pic #osx
......@@ -144,6 +148,7 @@ message(STATUS "ILOCPLEX Library: ${CPLEX_ILOCPLEX_LIBRARY}")
FIND_LIBRARY(CPLEX_CONCERT_LIBRARY
concert
HINTS ${CPLEX_ROOT_DIR}/concert/lib/${CPLEX_WIN_PLATFORM} #windows
${CPLEX_ROOT_DIR}/concert/lib/${CPLEX_PLATFORM}/static_pic #generic
${CPLEX_ROOT_DIR}/concert/lib/x86-64_debian4.0_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/concert/lib/x86-64_sles10_4.1/static_pic #unix
${CPLEX_ROOT_DIR}/concert/lib/x86-64_osx/static_pic #osx
......@@ -162,10 +167,13 @@ if(WIN32)
else()
FIND_PATH(CPLEX_BIN_DIR
cplex
HINTS ${CPLEX_ROOT_DIR}/cplex/bin/x86-64_sles10_4.1 #unix
HINTS ${CPLEX_ROOT_DIR}/cplex/bin/x86-64_sles10_4.1 #unix
${CPLEX_ROOT_DIR}/cplex/bin/${CPLEX_PLATFORM}/static_pic #generic
${CPLEX_ROOT_DIR}/cplex/bin/x86-64_debian4.0_4.1 #unix
${CPLEX_ROOT_DIR}/cplex/bin/x86-64_osx #osx
${CPLEX_ROOT_DIR}/cplex/bin/x86-64_darwin #osx
${CPLEX_ROOT_DIR}/cplex/bin/x86-64_linux #linux (ubuntu)
ENV LIBRARY_PATH
ENV LD_LIBRARY_PATH
)
......
......@@ -29,6 +29,7 @@ static const int opt_no_dependencies = 11;
static const int opt_no_header = 12;
static const int opt_rev_dep = 13;
static const int opt_best = 14;
static const int opt_thread = 15;
static struct option long_options[] = {
......@@ -48,6 +49,7 @@ static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"default", optional_argument, 0, 'd'},
{"best", optional_argument, 0, opt_best},
{"threads", optional_argument, 0, opt_thread},
{0, 0, 0, 0 }
};
......@@ -63,6 +65,7 @@ ProgramOptions::ProgramOptions() {
noHeader = false;
optRevDep = false;
outputBest = false;
nbThreads = 1;
}
void ProgramOptions::parse(int argc, char** argv) {
......@@ -143,6 +146,12 @@ void ProgramOptions::parse(int argc, char** argv) {
if(optarg)
outputBestFile = s_optarg;
break ;
case opt_thread:
if(optarg)
nbThreads = stoi(s_optarg);
else
nbThreads = -1;
break;
case '?':
case 'h':
usage();
......
......@@ -89,7 +89,7 @@ double AreaBound::compute() {
(*shared)[i][j] = values[i][j] / countTasks[i];
}
ins->extraData[share + "[repart]"] = (void*) shared;
ins->extraData.insert(share + "[repart]", (void*) shared);
}
double result = indepCplex.getObjValue();
......
......@@ -152,11 +152,9 @@ double DepBound::compute () {
// TODO: include the threshold in the share name
vector<int> DepBound::getAllocTasks(double threshold) {
vector<int>* values = (vector<int>*) instance->extraData["dep[alloc]"];
if(values != NULL)
return (*values);
if(instance->extraData.hasValue("dep[alloc]")) {
return * ((vector<int>*) instance->extraData.get("dep[alloc]"));
}
vector<int> result(nbTasks, -1);
if(threshold == -1)
......@@ -169,9 +167,9 @@ vector<int> DepBound::getAllocTasks(double threshold) {
continue;
}
}
instance->extraData["dep[alloc]"] = new vector<int>(result);
instance->extraData.insert("dep[alloc]", new vector<int>(result));
return result;
}
......
......@@ -331,9 +331,9 @@ double IntervalBound::compute(Instance & ins) {
}
if(shareName != "") {
instance->extraData[shareName + "[alloc]"] = new vector<int>(alloc);
instance->extraData[shareName + "[med]"] = new vector<double>(medianInterval);
instance->extraData[shareName + "[avg]"] = new vector<double>(averageInterval);
instance->extraData.insert(shareName + "[alloc]", new vector<int>(alloc));
instance->extraData.insert(shareName + "[med]", new vector<double>(medianInterval));
instance->extraData.insert(shareName + "[avg]", new vector<double>(averageInterval));
}
if(saveName != "") {
......
......@@ -3,6 +3,7 @@ set(CORE_SRC
instance.cpp
RecFileReader.cpp
schedAction.cpp
util.cpp)
util.cpp
SynchroMap.cpp)
add_library(core ${CORE_SRC})
......@@ -129,6 +129,9 @@ int recTask::outputCount = 0;
void RecFileInstance::readFromFile(const string inputFile, unordered_map<string, vector<double> > timings) {
this->inputFile = inputFile;
if(recTask::recName == NULL) recTask::recReaderInit();
char* inputFileC = new char[inputFile.length() + 1];
......@@ -218,6 +221,8 @@ RecFileInstance::RecFileInstance(const string inputFile) {
}
RecFileInstance::RecFileInstance(const string inputFile, const string platformFile) {
this->platformFile = platformFile;
char* platformFileC = new char[platformFile.length() + 1];
strcpy(platformFileC, platformFile.c_str());
FILE* platformFILE = fopen(platformFileC, "r");
......
#include "SynchroMap.h"
using namespace std;
SynchroMap::SynchroMap() {
}
// If you want more performance when using many keys, have this function
// return an iterator to the newly inserted pair
// Need to ensure safety though.
// Assumes mutex is already taken, anyway.
void SynchroMap::link(const string & key) {
std::promise<void*>* prom = new std::promise<void*>();
std::shared_future<void*> fut = prom->get_future().share();
dict[key] = make_pair(prom, fut);
}
void SynchroMap::insert(const string &key, void* value) {
{
lock_guard<mutex> lock(mtx);
if(dict.find(key) == dict.end())
link(key);
auto pair = dict[key];
if(pair.first) {
pair.first->set_value(value);
free(pair.first);
pair.first = NULL;
}
}
}
void* SynchroMap::get(const string & key) {
std::pair< std::promise<void*>*, std::shared_future<void*> > pair;
{
lock_guard<mutex> lock(mtx);
if(dict.find(key) == dict.end())
link(key);
pair = dict[key];
}
return pair.second.get();
}
bool SynchroMap::isPresent(const string & key) {
{
lock_guard<mutex> lock(mtx);
if(dict.find(key) == dict.end())
return false;
return true;
}
}
bool SynchroMap::hasValue(const string & key) {
if(!isPresent(key)) return false;
auto pair = dict[key];
return (pair.second.wait_for(std::chrono::seconds(0)) == std::future_status::ready);
}
......@@ -5,6 +5,8 @@
#include <cmath>
using namespace std;
#include <mutex>
#include "instance.h"
#include "util.h"
......@@ -21,6 +23,7 @@ Instance::Instance() {
Instance::Instance(const string input_file, int convertIndices) {
// cout << "Opening " << input_file << "..." << endl;
this->inputFile = input_file;
ifstream input(input_file);
int i;
......@@ -230,23 +233,29 @@ void Instance::mergeWorkerTypes(const vector<int> indicesToMerge) {
/* Accessors for static analysis */
vector<int> Instance::getTopOrder() {
lock_guard<mutex> lock(mtx);
computeTopOrder();
return topOrder;
}
vector< vector<int> > Instance::getAncestors() {
lock_guard<mutex> lock(mtx);
computeAncestors();
return ancestors;
}
vector< vector<int> > Instance::getRevDependencies() {
lock_guard<mutex> lock(mtx);
computeRevDependencies();
return revDep;
}
vector<double> Instance::computeRanks(vector<double> wbar, int to, int from) {
computeRevDependencies();
computeTopOrder();
{
lock_guard<mutex> lock(mtx);
computeRevDependencies();
computeTopOrder();
}
vector<double> rank(nbTasks, -std::numeric_limits<double>::infinity());
if(to == -1) to = topOrder[nbTasks -1];
if(from == -1) from = topOrder[0];
......@@ -397,7 +406,6 @@ void Instance::computeTopOrder() {
if(topOrder.size() != 0)
return;
vector<int> computed(nbTasks, 0);
topOrder.resize(nbTasks);
int i, l = 0;
......@@ -412,44 +420,43 @@ void Instance::computeTopOrder() {
// ancestors[i][j] == 1 iff there exists a path from j to i
void Instance::computeAncestors() {
if(ancestors.size() != 0)
return;
computeTopOrder();
int i, j, k, l = 0;
ancestors.resize(nbTasks);
for(i = 0; i < nbTasks; i++) {
ancestors[i].resize(nbTasks);
for(j = 0; j < nbTasks; j++)
ancestors[i][j] = (i==j) ? 1 : 0;
}
for(i = 0; i < nbTasks; i++) {
j = topOrder[i];
for(l = 0; l < (int) dependencies[j].size(); l++) {
// Add all ancestors of precedence l
for(k = 0; k < nbTasks; k++) {
if(ancestors[dependencies[j][l]][k] == 1)
ancestors[j][k] = 1;
}
if(ancestors.size() != 0)
return;
computeTopOrder();
ancestors.resize(nbTasks);
for(int i = 0; i < nbTasks; i++) {
ancestors[i].resize(nbTasks);
for(int j = 0; j < nbTasks; j++)
ancestors[i][j] = (i==j) ? 1 : 0;
}
for(int i = 0; i < nbTasks; i++) {
int j = topOrder[i];
for(int l = 0; l < (int) dependencies[j].size(); l++) {
// Add all ancestors of precedence l
for(int k = 0; k < nbTasks; k++) {
if(ancestors[dependencies[j][l]][k] == 1)
ancestors[j][k] = 1;
}
}
}
}
void Instance::computeRevDependencies() {
if(revDep.size() != 0)
return;
revDep.resize(nbTasks);
int i, j;
for(i = 0; i < nbTasks; i++)
for(j = 0; j < (int) dependencies[i].size(); j++)
revDep[dependencies[i][j]].push_back(i);
}
if(revDep.size() != 0)
return;
revDep.resize(nbTasks);
int i, j;
for(i = 0; i < nbTasks; i++)
for(j = 0; j < (int) dependencies[i].size(); j++)
revDep[dependencies[i][j]].push_back(i);
}
#define TOTALOP(n, i) ((3*n*n + 6*n -3*n*(i) -3*(i) + (i)*(i) +2)*(i)/6)
......
......@@ -46,7 +46,7 @@ ExportSchedule::ExportSchedule(Instance* ins, string name)
}
ExportToFile::ExportToFile(string filename, Instance* ins, bool header, string name): ExportSchedule(ins, name), f(new ofstream(filename)) {
ExportToFile::ExportToFile(string filename, Instance* ins, bool header, string name): ExportSchedule(ins, name), f(new ofstream(filename, ios::app)) {
output = f;
if(header) outputHeader();
}
......@@ -123,7 +123,7 @@ ExportAlloc::~ExportAlloc() {
UtilAnalysis::UtilAnalysis(Instance* _ins, string saveFile) :
ins(_ins), repartition(_ins->nbWorkerTypes,
std::vector<int>(ins->nbTaskTypes, 0)),
output(saveFile) {
output(saveFile, ios::app) {
}
UtilAnalysis::~UtilAnalysis(){
......@@ -171,10 +171,10 @@ void InternalShare::onSchedule(int i, int w, double s, double f) {
}
void InternalShare::finish() {
instance->extraData[shareName + "[worker]"] = new vector<int>(worker);
instance->extraData[shareName + "[alloc]"] = new vector<int>(allocation);
instance->extraData[shareName + "[start]"] = new vector<double>(startTimes);
instance->extraData[shareName + "[end]"] = new vector<double>(endTimes);
instance->extraData.insert(shareName + "[worker]", new vector<int>(worker));
instance->extraData.insert(shareName + "[alloc]", new vector<int>(allocation));
instance->extraData.insert(shareName + "[start]", new vector<double>(startTimes));
instance->extraData.insert(shareName + "[end]", new vector<double>(endTimes));
}
ExportBubble::ExportBubble(string filename, Instance* ins, int btt) :
......
......@@ -48,7 +48,7 @@ class ProgramOptions {
bool optRevDep = false;
bool outputBest;
std::string outputBestFile;
int nbThreads;
std::set<std::string> optionKeys;
std::vector<fullAlg> algs;
......
#ifndef SYNCHROMAP_H
#define SYNCHROMAP_H
#include <map>
#include <string>
#include <future>
#include <mutex>
class SynchroMap {
std::map<std::string, std::pair< std::promise<void*>*, std::shared_future<void*> > > dict;
std::mutex mtx; // Need to protect my map.
void link(const std::string & key);
public:
SynchroMap();
// Inserts a value in the map
void insert(const std::string & key, void* value);
// gets a value. If not already present, blocks until the value has been pushed.
// This gets dangerous if user misbehaves: leads to deadlock since no one will ever wake me up.
// Solving it would require bounds & algs to declare what keys they will write to.
void* get(const std::string & key);
bool isPresent(const std::string & key);
bool hasValue(const std::string & key);
};
#endif
......@@ -4,8 +4,9 @@
#include <vector>
#include <string>
#include <limits>
#include <map>
#include "SynchroMap.h"
#include <unordered_map>
#include <mutex>
class Instance {
public:
......@@ -18,12 +19,17 @@ public:
int nbTaskTypes;
int nbWorkerTypes;
std::map<std::string, void*> extraData;
SynchroMap extraData;
std::mutex mtx;
// Those are optional, only printed if available.
std::vector<std::string> workerNames;
std::vector<std::string> taskTypeNames;
std::vector<std::string> taskIDs;
std::string inputFile;
std::string platformFile;
// Computed afterwards
public:
std::vector< std::vector<int> > revDep;
......
......@@ -44,7 +44,7 @@ double GreedyFile::compute(Instance & instance, SchedAction* action) {
ins = &instance;
if(file.substr(0, 4) == "int@") {
vector<int>* values = (vector<int>*) ins->extraData[file.substr(4)];
vector<int>* values = (vector<int>*) ins->extraData.get(file.substr(4));
if(!values) {
cerr << "GreedyFile: could not find shared allocation " << file << ". Did you really use the share=<...> option in a previous algorithm?" << endl;
throw(1);
......
......@@ -186,7 +186,7 @@ IndepResult IndepAccel::compute(Instance& instance, vector<int> taskSet, vector<
}
if(verbosity >= 4)
cout << "Result of IndepDP2: " << result << endl;
cout << "Result of IndepAccel: " << result << endl;
if(result[0].size() + result[1].size() != taskSet.size()) {
cerr << "IndepAccel: not the correct number of tasks in result !" << endl;
throw(1);
......
......@@ -74,10 +74,9 @@ double computeLambda(vector<double> & w, vector<double> &m) {
vector<vector<int> >* getSortedByLength(Instance & ins) {
string key = "IB-length";
auto found = ins.extraData.find(key);
if(found != ins.extraData.end()) {
return (vector<vector<int> >*) found->second;
}
if(ins.extraData.hasValue(key))
return (vector<vector<int> >*) ins.extraData.get(key);
auto result = new vector<vector<int> >(2);
for(unsigned int i = 0; i < 2; i++) {
......@@ -88,7 +87,7 @@ vector<vector<int> >* getSortedByLength(Instance & ins) {
return ins.execTimes[i][a] > ins.execTimes[i][b];
});
}
ins.extraData[key] = (void*) result;
ins.extraData.insert(key, (void*) result);
return result;
}
......
......@@ -5,9 +5,9 @@
using namespace std;
double ReproduceAlgorithm::compute(Instance& ins, SchedAction * action) {
vector<int>* allocP = (vector<int>*) ins.extraData[shareKey + "[worker]"];
vector<double>* startP = (vector<double>*) ins.extraData[shareKey + "[start]"];
vector<double>* endP = (vector<double>*) ins.extraData[shareKey + "[end]"];
vector<int>* allocP = (vector<int>*) ins.extraData.get(shareKey + "[worker]");
vector<double>* startP = (vector<double>*) ins.extraData.get(shareKey + "[start]");
vector<double>* endP = (vector<double>*) ins.extraData.get(shareKey + "[end]");
if(!allocP || !startP || !endP) {
cerr << "ReproduceAlgorithm: data associated with key " << shareKey
<< " is not complete" << endl;
......
......@@ -30,13 +30,13 @@ intCompare* RankComputer::oneCmp(Instance& ins, string subRankOpt) {
#ifdef WITH_CPLEX
else if(subRankOpt == "area") {
vector<vector<double> >* repartition;
if(ins.extraData.find("area") == ins.extraData.end()) {
if(! ins.extraData.hasValue("area")) {
AlgOptions o;
o.insert("share", "area");
AreaBound bound(o);
((ModifiableBound*)(& bound))->compute(ins);
}
repartition = ( vector<vector<double>>*) ins.extraData["area[repart]"];
repartition = ( vector<vector<double>>*) ins.extraData.get("area[repart]");
vector<double> wbarType(ins.nbTaskTypes, 0);
vector<double> wbar(ins.nbTasks, 0);
for(int i = 0; i < ins.nbTaskTypes; i++)
......@@ -66,7 +66,7 @@ intCompare* RankComputer::oneCmp(Instance& ins, string subRankOpt) {
// Those files give lower values to higher priority tasks
} else if(subRankOpt.substr(0, 4) == "int@") {
string key = subRankOpt.substr(4);
w = * ((vector<double>*) ins.extraData.at(key));
w = * ((vector<double>*) ins.extraData.get(key));
// reverse = true;
}
else {
......
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