From d604580e5a6ff7fd92010fd662834c7bfbfaad5c Mon Sep 17 00:00:00 2001 From: Antonin Portelli Date: Tue, 10 May 2016 19:07:41 +0100 Subject: [PATCH] Hadrons: all objects/modules mapped to an integer address system to remove string operations from scheduling --- programs/Hadrons/Application.cc | 166 +------- programs/Hadrons/Application.hpp | 14 +- programs/Hadrons/Environment.cc | 662 ++++++++++++++++++++++++++----- programs/Hadrons/Environment.hpp | 156 ++++++-- programs/Hadrons/Global.cc | 27 ++ programs/Hadrons/Global.hpp | 20 + 6 files changed, 734 insertions(+), 311 deletions(-) diff --git a/programs/Hadrons/Application.cc b/programs/Hadrons/Application.cc index 7bcc9959..6381a9e1 100644 --- a/programs/Hadrons/Application.cc +++ b/programs/Hadrons/Application.cc @@ -42,10 +42,9 @@ using namespace Hadrons; Application::Application(const std::string parameterFileName) : parameterFileName_(parameterFileName) , env_(Environment::getInstance()) -, modFactory_(ModuleFactory::getInstance()) { LOG(Message) << "Modules available:" << std::endl; - auto list = modFactory_.getBuilderList(); + auto list = ModuleFactory::getInstance().getBuilderList(); for (auto &m: list) { LOG(Message) << " " << m << std::endl; @@ -95,18 +94,12 @@ void Application::parseParameterFile(void) do { read(reader, "id", id); - module_[id.name] = modFactory_.create(id.type, id.name); - module_[id.name]->parseParameters(reader, "options"); - std::vector output = module_[id.name]->getOutput(); - for (auto &n: output) - { - associatedModule_[n] = id.name; - } - input_[id.name] = module_[id.name]->getInput(); + env_.createModule(id.name, id.type, reader); } while (reader.nextElement("module")); pop(reader); pop(reader); env_.setSeed(strToVec(par_.seed)); + env_.printContent(); } // schedule computation //////////////////////////////////////////////////////// @@ -116,7 +109,7 @@ sizeString((size)*locVol_) << " (" << sizeString(size) << "/site)" void Application::schedule(void) { // memory peak function - auto memPeak = [this](const std::vector &program) + auto memPeak = [this](const std::vector &program) { unsigned int memPeak; bool msg; @@ -124,7 +117,7 @@ void Application::schedule(void) msg = HadronsLogMessage.isActive(); HadronsLogMessage.Active(false); env_.dryRun(true); - memPeak = execute(program); + memPeak = env_.executeProgram(program); env_.dryRun(false); env_.freeAll(); HadronsLogMessage.Active(true); @@ -132,32 +125,14 @@ void Application::schedule(void) return memPeak; }; - // create dependency graph - Graph moduleGraph; - - LOG(Message) << "Scheduling computation..." << std::endl; - for (auto &m: module_) - { - std::vector input = m.second->getInput(); - for (auto &n: input) - { - try - { - moduleGraph.addEdge(associatedModule_.at(n), m.first); - } - catch (std::out_of_range &) - { - HADRON_ERROR("unknown object '" + n + "'"); - } - } - } - // constrained topological sort using a genetic algorithm + LOG(Message) << "Scheduling computation..." << std::endl; constexpr unsigned int maxGen = 200, maxCstGen = 50; unsigned int k = 0, gen, prevPeak, nCstPeak = 0; - std::vector> con = moduleGraph.getConnectedComponents(); - GeneticScheduler::Parameters par; - std::random_device rd; + auto graph = env_.makeModuleGraph(); + auto con = graph.getConnectedComponents(); + std::random_device rd; + GeneticScheduler::Parameters par; par.popSize = 20; par.mutationRate = .1; @@ -165,7 +140,7 @@ void Application::schedule(void) CartesianCommunicator::BroadcastWorld(0, &(par.seed), sizeof(par.seed)); for (unsigned int i = 0; i < con.size(); ++i) { - GeneticScheduler scheduler(con[i], memPeak, par); + GeneticScheduler scheduler(con[i], memPeak, par); gen = 0; do @@ -197,13 +172,13 @@ void Application::schedule(void) { program_.push_back(t[j]); LOG(Message) << std::setw(4) << std::right << k + 1 << ": " - << program_[k] << std::endl; + << env_.getModuleName(program_[k]) << std::endl; k++; } } } -// program execution /////////////////////////////////////////////////////////// +// loop on configurations ////////////////////////////////////////////////////// void Application::configLoop(void) { auto range = par_.configs.range; @@ -213,121 +188,8 @@ void Application::configLoop(void) LOG(Message) << BIG_SEP << " Starting measurement for trajectory " << t << " " << BIG_SEP << std::endl; env_.setTrajectory(t); - execute(program_); + env_.executeProgram(program_); env_.freeAll(); } LOG(Message) << BIG_SEP << " End of measurement " << BIG_SEP << std::endl; } - -unsigned int Application::execute(const std::vector &program) -{ - unsigned int memPeak = 0, sizeBefore, sizeAfter; - std::vector> freeProg; - bool continueCollect, nothingFreed; - - // build garbage collection schedule - freeProg.resize(program.size()); - for (auto &n: associatedModule_) - { - auto pred = [&n, this](const std::string &s) - { - auto &in = input_[s]; - auto it = std::find(in.begin(), in.end(), n.first); - - return (it != in.end()) or (s == n.second); - }; - auto it = std::find_if(program.rbegin(), program.rend(), pred); - if (it != program.rend()) - { - freeProg[program.rend() - it - 1].insert(n.first); - } - } - - // program execution - for (unsigned int i = 0; i < program.size(); ++i) - { - // execute module - LOG(Message) << SEP << " Measurement step " << i+1 << "/" - << program.size() << " (module '" << program[i] << "') " - << SEP << std::endl; - (*module_[program[i]])(); - sizeBefore = env_.getTotalSize(); - // print used memory after execution - LOG(Message) << "Allocated objects: " << MEM_MSG(sizeBefore) - << std::endl; - if (sizeBefore > memPeak) - { - memPeak = sizeBefore; - } - // garbage collection for step i - LOG(Message) << "Garbage collection..." << std::endl; - nothingFreed = true; - do - { - continueCollect = false; - auto toFree = freeProg[i]; - for (auto &n: toFree) - { - // continue garbage collection while there are still - // objects without owners - continueCollect = continueCollect or !env_.hasOwners(n); - if(env_.freeObject(n)) - { - // if an object has been freed, remove it from - // the garbage collection schedule - freeProg[i].erase(n); - nothingFreed = false; - } - } - } while (continueCollect); - // any remaining objects in step i garbage collection schedule - // is scheduled for step i + 1 - if (i + 1 < program.size()) - { - for (auto &n: freeProg[i]) - { - freeProg[i + 1].insert(n); - } - } - // print used memory after garbage collection if necessary - sizeAfter = env_.getTotalSize(); - if (sizeBefore != sizeAfter) - { - LOG(Message) << "Allocated objects: " << MEM_MSG(sizeAfter) - << std::endl; - } - else - { - LOG(Message) << "Nothing to free" << std::endl; - } - } - - return memPeak; -} - -// pretty size formatting ////////////////////////////////////////////////////// -std::string Application::sizeString(long unsigned int bytes) - -{ - constexpr unsigned int bufSize = 256; - const char *suffixes[7] = {"", "K", "M", "G", "T", "P", "E"}; - char buf[256]; - long unsigned int s = 0; - double count = bytes; - - while (count >= 1024 && s < 7) - { - s++; - count /= 1024; - } - if (count - floor(count) == 0.0) - { - snprintf(buf, bufSize, "%d %sB", (int)count, suffixes[s]); - } - else - { - snprintf(buf, bufSize, "%.1f %sB", count, suffixes[s]); - } - - return std::string(buf); -} diff --git a/programs/Hadrons/Application.hpp b/programs/Hadrons/Application.hpp index 6b7e54c5..67b8d7a0 100644 --- a/programs/Hadrons/Application.hpp +++ b/programs/Hadrons/Application.hpp @@ -82,22 +82,14 @@ private: void parseParameterFile(void); // schedule computation void schedule(void); - // program execution - void configLoop(void); - unsigned int execute(const std::vector &program); - // pretty size formatting - static std::string sizeString(long unsigned int bytes); + // loop on configurations + void configLoop(void); private: long unsigned int locVol_; std::string parameterFileName_; GlobalPar par_; Environment &env_; - ModuleFactory &modFactory_; - std::map> module_; - std::map associatedModule_; - std::map> input_; - std::vector program_; - std::vector> freeProg_; + std::vector program_; }; END_HADRONS_NAMESPACE diff --git a/programs/Hadrons/Environment.cc b/programs/Hadrons/Environment.cc index bdb8d0d2..4c7ce023 100644 --- a/programs/Hadrons/Environment.cc +++ b/programs/Hadrons/Environment.cc @@ -26,6 +26,8 @@ directory. *******************************************************************************/ #include +#include +#include using namespace Grid; using namespace QCD; @@ -41,6 +43,12 @@ Environment::Environment(void) GridDefaultLatt(), GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi())); gridRb4d_.reset(SpaceTimeGrid::makeFourDimRedBlackGrid(grid4d_.get())); + auto loc = getGrid()->LocalDimensions(); + locVol_ = 1; + for (unsigned int d = 0; d < loc.size(); ++d) + { + locVol_ *= loc[d]; + } rng4d_.reset(new GridParallelRNG(grid4d_.get())); } @@ -116,12 +124,312 @@ GridRedBlackCartesian * Environment::getRbGrid(const unsigned int Ls) const } } -// fermion actions ///////////////////////////////////////////////////////////// -void Environment::addFermionMatrix(const std::string name, FMat *fMat) +// random number generator ///////////////////////////////////////////////////// +void Environment::setSeed(const std::vector &seed) +{ + rng4d_->SeedFixedIntegers(seed); +} + +GridParallelRNG * Environment::get4dRng(void) const +{ + return rng4d_.get(); +} + +// module management /////////////////////////////////////////////////////////// +void Environment::createModule(const std::string name, const std::string type, + XmlReader &reader) +{ + auto addObject = [this](const std::string name, const int moduleAddress) + { + ObjInfo info; + + object_.push_back(info); + objectName_.push_back(name); + objectAddress_[name] = object_.size() - 1; + objectModule_.push_back(moduleAddress); + owners_.push_back(std::set()); + properties_.push_back(std::set()); + }; + + if (!hasModule(name)) + { + auto &factory = ModuleFactory::getInstance(); + std::vector inputAddress; + + module_.push_back(factory.create(type, name)); + moduleType_.push_back(type); + moduleName_.push_back(name); + moduleAddress_[name] = module_.size() - 1; + module_.back()->parseParameters(reader, "options"); + auto input = module_.back()->getInput(); + for (auto &in: input) + { + if (!hasObject(in)) + { + addObject(in , -1); + } + inputAddress.push_back(objectAddress_[in]); + } + moduleInput_.push_back(inputAddress); + auto output = module_.back()->getOutput(); + for (auto &out: output) + { + if (!hasObject(out)) + { + addObject(out , module_.size() - 1); + } + else + { + if (objectModule_[objectAddress_[out]] < 0) + { + objectModule_[objectAddress_[out]] = module_.size() - 1; + } + else + { + HADRON_ERROR("object '" + out + + "' is already produced by module '" + + moduleName_[objectModule_[getObjectAddress(out)]] + + "' (while creating module '" + name + "')"); + } + } + } + } + else + { + HADRON_ERROR("module '" + name + "' already exists"); + } +} + +Module * Environment::getModule(const unsigned int address) const +{ + if (hasModule(address)) + { + return module_[address].get(); + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +Module * Environment::getModule(const std::string name) const +{ + return getModule(getModuleAddress(name)); +} + +unsigned int Environment::getModuleAddress(const std::string name) const +{ + if (hasModule(name)) + { + return moduleAddress_.at(name); + } + else + { + HADRON_ERROR("no module with name '" + name + "'"); + } +} + +std::string Environment::getModuleName(const unsigned int address) const +{ + if (hasModule(address)) + { + return moduleName_[address]; + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +std::string Environment::getModuleType(const unsigned int address) const +{ + if (hasModule(address)) + { + return moduleType_[address]; + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +std::string Environment::getModuleType(const std::string name) const +{ + return getModuleType(getModuleAddress(name)); +} + +bool Environment::hasModule(const unsigned int address) const +{ + return (address < module_.size()); +} + +bool Environment::hasModule(const std::string name) const +{ + return (moduleAddress_.find(name) != moduleAddress_.end()); +} + +Graph Environment::makeModuleGraph(void) const +{ + Graph moduleGraph; + + for (unsigned int i = 0; i < module_.size(); ++i) + { + for (auto &j: moduleInput_[i]) + { + moduleGraph.addEdge(objectModule_[j], i); + } + } + + return moduleGraph; +} + +#define BIG_SEP "===============" +#define SEP "---------------" +#define MEM_MSG(size)\ +sizeString((size)*locVol_) << " (" << sizeString(size) << "/site)" + +unsigned int Environment::executeProgram(const std::vector &p) +{ + unsigned int memPeak = 0, sizeBefore, sizeAfter; + std::vector> freeProg; + bool continueCollect, nothingFreed; + + // build garbage collection schedule + freeProg.resize(p.size()); + for (unsigned int i = 0; i < object_.size(); ++i) + { + auto pred = [i, this](const unsigned int j) + { + auto &in = moduleInput_[j]; + auto it = std::find(in.begin(), in.end(), i); + + return (it != in.end()) or (j == objectModule_[i]); + }; + auto it = std::find_if(p.rbegin(), p.rend(), pred); + if (it != p.rend()) + { + freeProg[p.rend() - it - 1].insert(i); + } + } + + // program execution + for (unsigned int i = 0; i < p.size(); ++i) + { + // execute module + LOG(Message) << SEP << " Measurement step " << i+1 << "/" + << p.size() << " (module '" << moduleName_[p[i]] << "') " + << SEP << std::endl; + (*module_[p[i]])(); + sizeBefore = getTotalSize(); + // print used memory after execution + LOG(Message) << "Allocated objects: " << MEM_MSG(sizeBefore) + << std::endl; + if (sizeBefore > memPeak) + { + memPeak = sizeBefore; + } + // garbage collection for step i + LOG(Message) << "Garbage collection..." << std::endl; + nothingFreed = true; + do + { + continueCollect = false; + auto toFree = freeProg[i]; + for (auto &j: toFree) + { + // continue garbage collection while there are still + // objects without owners + continueCollect = continueCollect or !hasOwners(j); + if(freeObject(j)) + { + // if an object has been freed, remove it from + // the garbage collection schedule + freeProg[i].erase(j); + nothingFreed = false; + } + } + } while (continueCollect); + // any remaining objects in step i garbage collection schedule + // is scheduled for step i + 1 + if (i + 1 < p.size()) + { + for (auto &j: freeProg[i]) + { + freeProg[i + 1].insert(j); + } + } + // print used memory after garbage collection if necessary + sizeAfter = getTotalSize(); + if (sizeBefore != sizeAfter) + { + LOG(Message) << "Allocated objects: " << MEM_MSG(sizeAfter) + << std::endl; + } + else + { + LOG(Message) << "Nothing to free" << std::endl; + } + } + + return memPeak; +} + +unsigned int Environment::executeProgram(const std::vector &p) +{ + std::vector pAddress; + + for (auto &n: p) + { + pAddress.push_back(getModuleAddress(n)); + } + + return executeProgram(pAddress); +} + +// lattice store /////////////////////////////////////////////////////////////// +void Environment::freeLattice(const unsigned int address) +{ + if (hasLattice(address)) + { + if (!isDryRun()) + { + LOG(Message) << "Freeing lattice '" << moduleName_[address] + << "'" << std::endl; + } + lattice_.erase(address); + object_[address] = ObjInfo(); + } + else + { + HADRON_ERROR("trying to free unknown lattice (address " + + std::to_string(address) + ")"); + } +} + +bool Environment::hasLattice(const unsigned int address) const +{ + return (hasRegisteredObject(address) + and (lattice_.find(address) != lattice_.end())); +} + +bool Environment::hasLattice(const std::string name) const { if (hasObject(name)) { - fMat_[name].reset(fMat); + return hasLattice(getObjectAddress(name)); + } + else + { + return false; + } +} + +// fermion actions ///////////////////////////////////////////////////////////// +void Environment::addFermionMatrix(const std::string name, FMat *fMat) +{ + if (hasRegisteredObject(name)) + { + fMat_[getObjectAddress(name)].reset(fMat); } else { @@ -131,15 +439,21 @@ void Environment::addFermionMatrix(const std::string name, FMat *fMat) Environment::FMat * Environment::getFermionMatrix(const std::string name) const { + unsigned int i; + if (hasFermionMatrix(name)) { - return fMat_.at(name).get(); + i = getObjectAddress(name); + + return fMat_.at(i).get(); } else { if (hasSolver(name)) { - return fMat_.at(solverAction_.at(name)).get(); + i = getObjectAddress(solverAction_.at(name)); + + return fMat_.at(i).get(); } else { @@ -148,41 +462,80 @@ Environment::FMat * Environment::getFermionMatrix(const std::string name) const } } -void Environment::freeFermionMatrix(const std::string name) +bool Environment::hasFermionMatrix(const unsigned int address) const { - if (hasFermionMatrix(name)) - { - LOG(Message) << "Freeing fermion matrix '" << name << "'" << std::endl; - fMat_.erase(name); - object_.erase(name); - } - else - { - HADRON_ERROR("trying to free unknown fermion matrix '" + name + "'"); - } + return (hasRegisteredObject(address) + and (fMat_.find(address) != fMat_.end())); } bool Environment::hasFermionMatrix(const std::string name) const { - return (hasObject(name) and (fMat_.find(name) != fMat_.end())); + if (hasObject(name)) + { + return hasFermionMatrix(getObjectAddress(name)); + } + else + { + return false; + } +} + +void Environment::freeFermionMatrix(const unsigned int address) +{ + if (hasFermionMatrix(address)) + { + if (!isDryRun()) + { + LOG(Message) << "Freeing fermion matrix '" << objectName_[address] + << "'" << std::endl; + } + fMat_.erase(address); + object_[address] = ObjInfo(); + } + else + { + HADRON_ERROR("trying to free unknown fermion matrix (address " + + std::to_string(address) + ")"); + } +} + +void Environment::freeFermionMatrix(const std::string name) +{ + freeFermionMatrix(getObjectAddress(name)); } // solvers ///////////////////////////////////////////////////////////////////// void Environment::addSolver(const std::string name, Solver s) { - if (hasObject(name)) + auto address = getObjectAddress(name); + + if (hasRegisteredObject(address)) { - solver_[name] = s; + solver_[address] = s; } else { - HADRON_ERROR("no object named '" << name << "'"); + HADRON_ERROR("object with name '" + name + + "' exsists but is not registered"); } } +bool Environment::hasSolver(const unsigned int address) const +{ + return (hasRegisteredObject(address) + and (solver_.find(address) != solver_.end())); +} + bool Environment::hasSolver(const std::string name) const { - return (hasObject(name) and (solver_.find(name) != solver_.end())); + if (hasObject(name)) + { + return hasSolver(getObjectAddress(name)); + } + else + { + return false; + } } void Environment::setSolverAction(const std::string name, @@ -222,7 +575,7 @@ void Environment::callSolver(const std::string name, LatticeFermion &sol, { if (hasSolver(name)) { - solver_.at(name)(sol, source); + solver_.at(getObjectAddress(name))(sol, source); } else { @@ -230,114 +583,124 @@ void Environment::callSolver(const std::string name, LatticeFermion &sol, } } -// random number generator ///////////////////////////////////////////////////// -void Environment::setSeed(const std::vector &seed) +// general memory management /////////////////////////////////////////////////// +void Environment::registerObject(const unsigned int address, + const unsigned int size, const unsigned int Ls) { - rng4d_->SeedFixedIntegers(seed); -} - -GridParallelRNG * Environment::get4dRng(void) const -{ - return rng4d_.get(); -} - -// lattice store /////////////////////////////////////////////////////////////// -void Environment::freeLattice(const std::string name) -{ - if (hasLattice(name)) + if (!hasRegisteredObject(address)) { - LOG(Message) << "Freeing lattice '" << name << "'" << std::endl; - lattice_.erase(name); - object_.erase(name); + if (hasObject(address)) + { + ObjInfo info; + + info.size = size; + info.Ls = Ls; + info.isRegistered = true; + object_[address] = info; + } + else + { + HADRON_ERROR("no object with address " + std::to_string(address)); + } } else { - HADRON_ERROR("trying to free unknown lattice '" + name + "'"); + HADRON_ERROR("object with address " + std::to_string(address) + + " already registered"); } } -bool Environment::hasLattice(const std::string name) const -{ - return (hasObject(name) and (lattice_.find(name) != lattice_.end())); -} - -// general memory management /////////////////////////////////////////////////// -bool Environment::hasObject(const std::string name) const -{ - return (object_.find(name) != object_.end()); -} - void Environment::registerObject(const std::string name, const unsigned int size, const unsigned int Ls) { - if (!hasObject(name)) + registerObject(getObjectAddress(name), size, Ls); +} + +unsigned int Environment::getObjectAddress(const std::string name) const +{ + if (hasObject(name)) { - ObjInfo info{size, Ls}; - - object_[name] = info; + return objectAddress_.at(name); } else { - HADRON_ERROR("object '" + name + "' already exists"); + HADRON_ERROR("no object with name '" + name + "'"); + } +} + +std::string Environment::getObjectName(const unsigned int address) const +{ + if (hasObject(address)) + { + return objectName_[address]; + } + else + { + HADRON_ERROR("no object with address " + std::to_string(address)); + } +} + +unsigned int Environment::getObjectSize(const unsigned int address) const +{ + if (hasRegisteredObject(address)) + { + return object_[address].size; + } + else if (hasObject(address)) + { + HADRON_ERROR("object with address " + std::to_string(address) + + " exsists but is not registered"); + } + else + { + HADRON_ERROR("no object with address " + std::to_string(address)); } } unsigned int Environment::getObjectSize(const std::string name) const { - if (hasObject(name)) + return getObjectSize(getObjectAddress(name)); +} + +unsigned int Environment::getObjectLs(const unsigned int address) const +{ + if (hasRegisteredObject(address)) { - return object_.at(name).size; + return object_[address].Ls; + } + else if (hasObject(address)) + { + HADRON_ERROR("object with address " + std::to_string(address) + + " exsists but is not registered"); } else { - HADRON_ERROR("no object named '" + name + "'"); + HADRON_ERROR("no object with address " + std::to_string(address)); } } -long unsigned int Environment::getTotalSize(void) const -{ - long unsigned int size = 0; - - for (auto &s: object_) - { - size += s.second.size; - } - - return size; -} - unsigned int Environment::getObjectLs(const std::string name) const { - if (hasObject(name)) - { - return object_.at(name).Ls; - } - else - { - HADRON_ERROR("no object named '" + name + "'"); - } + return getObjectLs(getObjectAddress(name)); } -bool Environment::isObject5d(const std::string name) const +bool Environment::hasObject(const unsigned int address) const { - return (getObjectLs(name) > 1); + return (address < object_.size()); } -void Environment::addOwnership(const std::string owner, - const std::string property) -{ - owners_[property].insert(owner); - properties_[owner].insert(property); -} - -bool Environment::hasOwners(const std::string name) const +bool Environment::hasObject(const std::string name) const { + auto it = objectAddress_.find(name); - auto it = owners_.find(name); - - if (it != owners_.end()) + return ((it != objectAddress_.end()) and hasObject(it->second)); +} + +bool Environment::hasRegisteredObject(const unsigned int address) const +{ + if (hasObject(address)) { - return (!it->second.empty()); + return object_[address].isRegistered; } else { @@ -345,26 +708,94 @@ bool Environment::hasOwners(const std::string name) const } } -bool Environment::freeObject(const std::string name) +bool Environment::hasRegisteredObject(const std::string name) const { - if (!hasOwners(name)) + if (hasObject(name)) { - for (auto &p: properties_[name]) + return hasRegisteredObject(getObjectAddress(name)); + } + else + { + return false; + } +} + +bool Environment::isObject5d(const unsigned int address) const +{ + return (getObjectLs(address) > 1); +} + +bool Environment::isObject5d(const std::string name) const +{ + return (getObjectLs(name) > 1); +} + +long unsigned int Environment::getTotalSize(void) const +{ + long unsigned int size = 0; + + for (auto &o: object_) + { + if (o.isRegistered) { - owners_[p].erase(name); + size += o.size; } - properties_[name].clear(); - if (hasLattice(name)) + } + + return size; +} + +void Environment::addOwnership(const unsigned int owner, + const unsigned int property) +{ + owners_[property].insert(owner); + properties_[owner].insert(property); +} + +void Environment::addOwnership(const std::string owner, + const std::string property) +{ + addOwnership(getObjectAddress(owner), getObjectAddress(property)); +} + +bool Environment::hasOwners(const unsigned int address) const +{ + + if (hasObject(address)) + { + return (!owners_[address].empty()); + } + else + { + HADRON_ERROR("no object with address " + std::to_string(address)); + } +} + +bool Environment::hasOwners(const std::string name) const +{ + return hasOwners(getObjectAddress(name)); +} + +bool Environment::freeObject(const unsigned int address) +{ + if (!hasOwners(address)) + { + for (auto &p: properties_[address]) { - freeLattice(name); + owners_[p].erase(address); } - else if (hasFermionMatrix(name)) + properties_[address].clear(); + if (hasLattice(address)) { - freeFermionMatrix(name); + freeLattice(address); } - else if (hasObject(name)) + else if (hasFermionMatrix(address)) { - object_.erase(name); + freeFermionMatrix(address); + } + else if (hasObject(address)) + { + object_[address] = ObjInfo(); } return true; @@ -375,9 +806,13 @@ bool Environment::freeObject(const std::string name) } } +bool Environment::freeObject(const std::string name) +{ + return freeObject(getObjectAddress(name)); +} + void Environment::freeAll(void) { - object_.clear(); lattice_.clear(); fMat_.clear(); solver_.clear(); @@ -385,3 +820,20 @@ void Environment::freeAll(void) owners_.clear(); properties_.clear(); } + +void Environment::printContent(void) +{ + LOG(Message) << "Modules: " << std::endl; + for (unsigned int i = 0; i < module_.size(); ++i) + { + LOG(Message) << std::setw(4) << std::right << i << ": " + << moduleName_[i] << " (" + << moduleType_[i] << ")" << std::endl; + } + LOG(Message) << "Objects: " << std::endl; + for (unsigned int i = 0; i < object_.size(); ++i) + { + LOG(Message) << std::setw(4) << std::right << i << ": " + << objectName_[i] << std::endl; + } +} diff --git a/programs/Hadrons/Environment.hpp b/programs/Hadrons/Environment.hpp index 65f870ee..4cecf7da 100644 --- a/programs/Hadrons/Environment.hpp +++ b/programs/Hadrons/Environment.hpp @@ -29,28 +29,34 @@ directory. #define Hadrons_Environment_hpp_ #include +#include BEGIN_HADRONS_NAMESPACE /****************************************************************************** * Global environment * ******************************************************************************/ +// forward declaration of Module +class Module; + class Environment { SINGLETON(Environment); public: - typedef FermionOperator FMat; - typedef std::function Solver; + typedef std::unique_ptr ModPt; typedef std::unique_ptr GridPt; typedef std::unique_ptr GridRbPt; - typedef std::unique_ptr RngPt; + typedef FermionOperator FMat; typedef std::unique_ptr FMatPt; + typedef std::function Solver; + typedef std::unique_ptr RngPt; typedef std::unique_ptr LatticePt; private: struct ObjInfo { - unsigned int size, Ls; + unsigned int size{0}, Ls{0}; + bool isRegistered{false}; }; public: // dry run @@ -63,13 +69,45 @@ public: void createGrid(const unsigned int Ls); GridCartesian * getGrid(const unsigned int Ls = 1) const; GridRedBlackCartesian * getRbGrid(const unsigned int Ls = 1) const; + // random number generator + void setSeed(const std::vector &seed); + GridParallelRNG * get4dRng(void) const; + // module management + void createModule(const std::string name, + const std::string type, + XmlReader &reader); + Module * getModule(const unsigned int address) const; + Module * getModule(const std::string name) const; + unsigned int getModuleAddress(const std::string name) const; + std::string getModuleName(const unsigned int address) const; + std::string getModuleType(const unsigned int address) const; + std::string getModuleType(const std::string name) const; + bool hasModule(const unsigned int address) const; + bool hasModule(const std::string name) const; + Graph makeModuleGraph(void) const; + unsigned int executeProgram(const std::vector &p); + unsigned int executeProgram(const std::vector &p); + // lattice store + template + T * create(const std::string name); + template + T * get(const std::string name) const; + bool hasLattice(const unsigned int address) const; + bool hasLattice(const std::string name) const; + void freeLattice(const unsigned int address); + void freeLattice(const std::string name); + template + unsigned int lattice4dSize(void) const; // fermion actions void addFermionMatrix(const std::string name, FMat *mat); FMat * getFermionMatrix(const std::string name) const; - void freeFermionMatrix(const std::string name); + bool hasFermionMatrix(const unsigned int address) const; bool hasFermionMatrix(const std::string name) const; + void freeFermionMatrix(const unsigned int address); + void freeFermionMatrix(const std::string name); // solvers void addSolver(const std::string name, Solver s); + bool hasSolver(const unsigned int address) const; bool hasSolver(const std::string name) const; void setSolverAction(const std::string name, const std::string actionName); @@ -77,52 +115,73 @@ public: void callSolver(const std::string name, LatticeFermion &sol, const LatticeFermion &src) const; - // random number generator - void setSeed(const std::vector &seed); - GridParallelRNG * get4dRng(void) const; - // lattice store - template - T * create(const std::string name); - template - T * get(const std::string name) const; - bool hasLattice(const std::string name) const; - void freeLattice(const std::string name); - template - unsigned int lattice4dSize(void) const; // general memory management - bool hasObject(const std::string name) const; + void registerObject(const unsigned int address, + const unsigned int size, + const unsigned int Ls = 1); void registerObject(const std::string name, const unsigned int size, const unsigned int Ls = 1); template + void registerLattice(const unsigned int address, + const unsigned int Ls = 1); + template void registerLattice(const std::string name, const unsigned int Ls = 1); + unsigned int getObjectAddress(const std::string name) const; + std::string getObjectName(const unsigned int address) const; + unsigned int getObjectSize(const unsigned int address) const; unsigned int getObjectSize(const std::string name) const; - long unsigned int getTotalSize(void) const; + unsigned int getObjectLs(const unsigned int address) const; unsigned int getObjectLs(const std::string name) const; + bool hasObject(const unsigned int address) const; + bool hasObject(const std::string name) const; + bool hasRegisteredObject(const unsigned int address) const; + bool hasRegisteredObject(const std::string name) const; + bool isObject5d(const unsigned int address) const; bool isObject5d(const std::string name) const; + long unsigned int getTotalSize(void) const; + void addOwnership(const unsigned int owner, + const unsigned int property); void addOwnership(const std::string owner, const std::string property); + bool hasOwners(const unsigned int address) const; bool hasOwners(const std::string name) const; + bool freeObject(const unsigned int address); bool freeObject(const std::string name); void freeAll(void); + void printContent(void); private: - -private: - bool dryRun_{false}; - unsigned int traj_; - GridPt grid4d_; - std::map grid5d_; - GridRbPt gridRb4d_; - std::map gridRb5d_; - RngPt rng4d_; - std::map object_; - std::map lattice_; - std::map fMat_; - std::map solver_; - std::map solverAction_; - std::map> owners_; - std::map> properties_; + // general + bool dryRun_{false}; + unsigned int traj_, locVol_; + // grids + GridPt grid4d_; + std::map grid5d_; + GridRbPt gridRb4d_; + std::map gridRb5d_; + // random number generator + RngPt rng4d_; + // module and related maps + std::vector module_; + std::vector moduleType_; + std::vector moduleName_; + std::map moduleAddress_; + std::vector> moduleInput_; + // lattice store + std::map lattice_; + // fermion matrix store + std::map fMat_; + // solver store & solver/action map + std::map solver_; + std::map solverAction_; + // object register + std::vector object_; + std::vector objectName_; + std::map objectAddress_; + std::vector objectModule_; + std::vector> owners_; + std::vector> properties_; }; /****************************************************************************** @@ -137,11 +196,12 @@ unsigned int Environment::lattice4dSize(void) const template T * Environment::create(const std::string name) { - GridCartesian *g = getGrid(getObjectLs(name)); + auto i = getObjectAddress(name); + GridCartesian *g = getGrid(getObjectLs(i)); - lattice_[name].reset(new T(g)); + lattice_[i].reset(new T(g)); - return dynamic_cast(lattice_[name].get()); + return dynamic_cast(lattice_[i].get()); } template @@ -149,25 +209,35 @@ T * Environment::get(const std::string name) const { if (hasLattice(name)) { - if (auto pt = dynamic_cast(lattice_.at(name).get())) + auto i = getObjectAddress(name); + + if (auto pt = dynamic_cast(lattice_.at(i).get())) { return pt; } else { HADRON_ERROR("object '" + name + "' does not have type " - + typeid(T *).name() + "(object type: " - + typeid(lattice_.at(name).get()).name() + ")"); + + typeName() + "(object type: " + + typeName(*lattice_.at(i).get()) + ")"); } } else { - HADRON_ERROR("no lattice name '" + name + "'"); + HADRON_ERROR("no lattice with name '" + name + "'"); return nullptr; } } +template +void Environment::registerLattice(const unsigned int address, + const unsigned int Ls) +{ + createGrid(Ls); + registerObject(address, Ls*lattice4dSize()); +} + template void Environment::registerLattice(const std::string name, const unsigned int Ls) { diff --git a/programs/Hadrons/Global.cc b/programs/Hadrons/Global.cc index ec5e8f51..a13efec1 100644 --- a/programs/Hadrons/Global.cc +++ b/programs/Hadrons/Global.cc @@ -36,3 +36,30 @@ HadronsLogger Hadrons::HadronsLogWarning(1,"Warning"); HadronsLogger Hadrons::HadronsLogMessage(1,"Message"); HadronsLogger Hadrons::HadronsLogIterative(1,"Iterative"); HadronsLogger Hadrons::HadronsLogDebug(1,"Debug"); + +// pretty size formatting ////////////////////////////////////////////////////// +std::string Hadrons::sizeString(long unsigned int bytes) + +{ + constexpr unsigned int bufSize = 256; + const char *suffixes[7] = {"", "K", "M", "G", "T", "P", "E"}; + char buf[256]; + long unsigned int s = 0; + double count = bytes; + + while (count >= 1024 && s < 7) + { + s++; + count /= 1024; + } + if (count - floor(count) == 0.0) + { + snprintf(buf, bufSize, "%d %sB", (int)count, suffixes[s]); + } + else + { + snprintf(buf, bufSize, "%.1f %sB", count, suffixes[s]); + } + + return std::string(buf); +} diff --git a/programs/Hadrons/Global.hpp b/programs/Hadrons/Global.hpp index 38bdcc0f..c42753c1 100644 --- a/programs/Hadrons/Global.hpp +++ b/programs/Hadrons/Global.hpp @@ -30,6 +30,7 @@ directory. #include #include +#include #include #define BEGIN_HADRONS_NAMESPACE \ @@ -91,6 +92,25 @@ public:\ private:\ name(void) = default; +// pretty size formating +std::string sizeString(long unsigned int bytes); + +template +std::string typeName(const T &x) +{ + std::string name(typeid(x).name()); + + return name; +} + +template +std::string typeName(void) +{ + std::string name(typeid(T).name()); + + return name; +} + END_HADRONS_NAMESPACE #endif // Hadrons_Global_hpp_