diff --git a/extras/Hadrons/Application.cc b/extras/Hadrons/Application.cc index 0860437b..af67dff3 100644 --- a/extras/Hadrons/Application.cc +++ b/extras/Hadrons/Application.cc @@ -73,12 +73,6 @@ Application::Application(const std::string parameterFileName) parameterFileName_ = parameterFileName; } -// environment shortcut //////////////////////////////////////////////////////// -Environment & Application::env(void) const -{ - return Environment::getInstance(); -} - // access ////////////////////////////////////////////////////////////////////// void Application::setPar(const Application::GlobalPar &par) { @@ -94,12 +88,13 @@ const Application::GlobalPar & Application::getPar(void) // execute ///////////////////////////////////////////////////////////////////// void Application::run(void) { - if (!parameterFileName_.empty() and (env().getNModule() == 0)) + if (!parameterFileName_.empty() and (vm().getNModule() == 0)) { parseParameterFile(parameterFileName_); } - env().checkGraph(); + //vm().checkGraph(); env().printContent(); + vm().printContent(); if (!scheduled_) { schedule(); @@ -137,7 +132,7 @@ void Application::parseParameterFile(const std::string parameterFileName) do { read(reader, "id", id); - env().createModule(id.name, id.type, reader); + vm().createModule(id.name, id.type, reader); } while (reader.nextElement("module")); pop(reader); pop(reader); @@ -147,7 +142,7 @@ void Application::saveParameterFile(const std::string parameterFileName) { XmlWriter writer(parameterFileName); ObjectId id; - const unsigned int nMod = env().getNModule(); + const unsigned int nMod = vm().getNModule(); LOG(Message) << "Saving application to '" << parameterFileName << "'..." << std::endl; write(writer, "parameters", getPar()); @@ -155,10 +150,10 @@ void Application::saveParameterFile(const std::string parameterFileName) for (unsigned int i = 0; i < nMod; ++i) { push(writer, "module"); - id.name = env().getModuleName(i); - id.type = env().getModule(i)->getRegisteredName(); + id.name = vm().getModuleName(i); + id.type = vm().getModule(i)->getRegisteredName(); write(writer, "id", id); - env().getModule(i)->saveParameters(writer, "options"); + vm().getModule(i)->saveParameters(writer, "options"); pop(writer); } pop(writer); @@ -178,9 +173,9 @@ GeneticScheduler::ObjFunc memPeak = \ \ msg = HadronsLogMessage.isActive();\ HadronsLogMessage.Active(false);\ - env().dryRun(true);\ - memPeak = env().executeProgram(program);\ - env().dryRun(false);\ + vm().dryRun(true);\ + memPeak = vm().executeProgram(program);\ + vm().dryRun(false);\ env().freeAll();\ HadronsLogMessage.Active(msg);\ \ @@ -193,7 +188,7 @@ void Application::schedule(void) // build module dependency graph LOG(Message) << "Building module graph..." << std::endl; - auto graph = env().makeModuleGraph(); + auto graph = vm().makeModuleGraph(); LOG(Debug) << "Module graph:" << std::endl; LOG(Debug) << graph << std::endl; auto con = graph.getConnectedComponents(); @@ -273,7 +268,7 @@ void Application::saveSchedule(const std::string filename) << std::endl; for (auto address: program_) { - program.push_back(env().getModuleName(address)); + program.push_back(vm().getModuleName(address)); } write(writer, "schedule", program); } @@ -291,7 +286,7 @@ void Application::loadSchedule(const std::string filename) program_.clear(); for (auto &name: program) { - program_.push_back(env().getModuleAddress(name)); + program_.push_back(vm().getModuleAddress(name)); } scheduled_ = true; memPeak_ = memPeak(program_); @@ -308,7 +303,7 @@ void Application::printSchedule(void) for (unsigned int i = 0; i < program_.size(); ++i) { LOG(Message) << std::setw(4) << i + 1 << ": " - << env().getModuleName(program_[i]) << std::endl; + << vm().getModuleName(program_[i]) << std::endl; } } @@ -321,8 +316,8 @@ void Application::configLoop(void) { LOG(Message) << BIG_SEP << " Starting measurement for trajectory " << t << " " << BIG_SEP << std::endl; - env().setTrajectory(t); - env().executeProgram(program_); + vm().setTrajectory(t); + vm().executeProgram(program_); } LOG(Message) << BIG_SEP << " End of measurement " << BIG_SEP << std::endl; env().freeAll(); @@ -331,7 +326,7 @@ void Application::configLoop(void) // memory profile ////////////////////////////////////////////////////////////// void Application::memoryProfile(void) { - auto graph = env().makeModuleGraph(); + auto graph = vm().makeModuleGraph(); auto program = graph.topoSort(); bool msg; diff --git a/extras/Hadrons/Application.hpp b/extras/Hadrons/Application.hpp index 8b11b0c7..66488206 100644 --- a/extras/Hadrons/Application.hpp +++ b/extras/Hadrons/Application.hpp @@ -31,8 +31,7 @@ See the full license in the file "LICENSE" in the top level distribution directo #define Hadrons_Application_hpp_ #include -#include -#include +#include #include BEGIN_HADRONS_NAMESPACE @@ -100,7 +99,9 @@ public: void configLoop(void); private: // environment shortcut - Environment & env(void) const; + DEFINE_ENV_ALIAS; + // virtual machine shortcut + DEFINE_VM_ALIAS; // memory profile void memoryProfile(void); private: @@ -119,14 +120,14 @@ private: template void Application::createModule(const std::string name) { - env().createModule(name); + vm().createModule(name); } template void Application::createModule(const std::string name, const typename M::Par &par) { - env().createModule(name, par); + vm().createModule(name, par); } END_HADRONS_NAMESPACE diff --git a/extras/Hadrons/Environment.cc b/extras/Hadrons/Environment.cc index 27849bd7..ea41f343 100644 --- a/extras/Hadrons/Environment.cc +++ b/extras/Hadrons/Environment.cc @@ -56,38 +56,6 @@ Environment::Environment(void) rng4d_.reset(new GridParallelRNG(grid4d_.get())); } -// dry run ///////////////////////////////////////////////////////////////////// -void Environment::dryRun(const bool isDry) -{ - dryRun_ = isDry; -} - -bool Environment::isDryRun(void) const -{ - return dryRun_; -} - -void Environment::memoryProfile(const bool doMemoryProfile) -{ - memoryProfile_ = doMemoryProfile; -} - -bool Environment::doMemoryProfile(void) const -{ - return memoryProfile_; -} - -// trajectory number /////////////////////////////////////////////////////////// -void Environment::setTrajectory(const unsigned int traj) -{ - traj_ = traj; -} - -unsigned int Environment::getTrajectory(void) const -{ - return traj_; -} - // grids /////////////////////////////////////////////////////////////////////// void Environment::createGrid(const unsigned int Ls) { @@ -153,6 +121,11 @@ int Environment::getDim(const unsigned int mu) const return dim_[mu]; } +unsigned long int Environment::getLocalVolume(void) const +{ + return locVol_; +} + // random number generator ///////////////////////////////////////////////////// void Environment::setSeed(const std::vector &seed) { @@ -164,313 +137,6 @@ GridParallelRNG * Environment::get4dRng(void) const return rng4d_.get(); } -// module management /////////////////////////////////////////////////////////// -void Environment::pushModule(Environment::ModPt &pt) -{ - std::string name = pt->getName(); - - if (!hasModule(name)) - { - std::vector inputAddress; - unsigned int address; - ModuleInfo m; - - m.data = std::move(pt); - m.type = typeIdPt(*m.data.get()); - m.name = name; - auto input = m.data->getInput(); - for (auto &in: input) - { - if (!hasObject(in)) - { - addObject(in , -1); - } - m.input.push_back(objectAddress_[in]); - } - auto output = m.data->getOutput(); - module_.push_back(std::move(m)); - address = static_cast(module_.size() - 1); - moduleAddress_[name] = address; - for (auto &out: output) - { - if (!hasObject(out)) - { - addObject(out, address); - } - else - { - if (object_[objectAddress_[out]].module < 0) - { - object_[objectAddress_[out]].module = address; - } - else - { - HADRON_ERROR("object '" + out - + "' is already produced by module '" - + module_[object_[getObjectAddress(out)].module].name - + "' (while pushing module '" + name + "')"); - } - } - } - } - else - { - HADRON_ERROR("module '" + name + "' already exists"); - } -} - -unsigned int Environment::getNModule(void) const -{ - return module_.size(); -} - -void Environment::createModule(const std::string name, const std::string type, - XmlReader &reader) -{ - auto &factory = ModuleFactory::getInstance(); - auto pt = factory.create(type, name); - - pt->parseParameters(reader, "options"); - pushModule(pt); -} - -ModuleBase * Environment::getModule(const unsigned int address) const -{ - if (hasModule(address)) - { - return module_[address].data.get(); - } - else - { - HADRON_ERROR("no module with address " + std::to_string(address)); - } -} - -ModuleBase * 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 module_[address].name; - } - else - { - HADRON_ERROR("no module with address " + std::to_string(address)); - } -} - -std::string Environment::getModuleType(const unsigned int address) const -{ - if (hasModule(address)) - { - return typeName(module_[address].type); - } - else - { - HADRON_ERROR("no module with address " + std::to_string(address)); - } -} - -std::string Environment::getModuleType(const std::string name) const -{ - return getModuleType(getModuleAddress(name)); -} - -std::string Environment::getModuleNamespace(const unsigned int address) const -{ - std::string type = getModuleType(address), ns; - - auto pos2 = type.rfind("::"); - auto pos1 = type.rfind("::", pos2 - 2); - - return type.substr(pos1 + 2, pos2 - pos1 - 2); -} - -std::string Environment::getModuleNamespace(const std::string name) const -{ - return getModuleNamespace(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) - { - moduleGraph.addVertex(i); - for (auto &j: module_[i].input) - { - moduleGraph.addEdge(object_[j].module, i); - } - } - - return moduleGraph; -} - -void Environment::checkGraph(void) const -{ - for (auto &o: object_) - { - if (o.module < 0) - { - HADRON_ERROR("object '" + o.name + "' does not have a creator"); - } - } -} - -#define BIG_SEP "===============" -#define SEP "---------------" -#define MEM_MSG(size)\ -sizeString((size)*locVol_) << " (" << sizeString(size) << "/site)" - -Environment::Size -Environment::executeProgram(const std::vector &p) -{ - Size memPeak = 0, sizeBefore, sizeAfter; - std::vector> freeProg; - bool continueCollect, nothingFreed; - - // build garbage collection schedule - LOG(Debug) << "Building garbage collection schedule..." << std::endl; - freeProg.resize(p.size()); - for (unsigned int i = 0; i < object_.size(); ++i) - { - auto pred = [i, this](const unsigned int j) - { - auto &in = module_[j].input; - auto it = std::find(in.begin(), in.end(), i); - - return (it != in.end()) or (j == object_[i].module); - }; - auto it = std::find_if(p.rbegin(), p.rend(), pred); - if (it != p.rend()) - { - freeProg[std::distance(it, p.rend()) - 1].insert(i); - } - } - - // program execution - LOG(Debug) << "Executing program..." << std::endl; - for (unsigned int i = 0; i < p.size(); ++i) - { - // execute module - if (!isDryRun()) - { - LOG(Message) << SEP << " Measurement step " << i+1 << "/" - << p.size() << " (module '" << module_[p[i]].name - << "') " << SEP << std::endl; - } - (*module_[p[i]].data)(); - sizeBefore = getTotalSize(); - // print used memory after execution - if (!isDryRun()) - { - LOG(Message) << "Allocated objects: " << MEM_MSG(sizeBefore) - << std::endl; - } - if (sizeBefore > memPeak) - { - memPeak = sizeBefore; - } - // garbage collection for step i - if (!isDryRun()) - { - 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); - // free temporaries - for (unsigned int i = 0; i < object_.size(); ++i) - { - if ((object_[i].storage == Storage::temporary) - and hasCreatedObject(i)) - { - freeObject(i); - } - } - // 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 - if (!isDryRun()) - { - sizeAfter = getTotalSize(); - if (sizeBefore != sizeAfter) - { - LOG(Message) << "Allocated objects: " << MEM_MSG(sizeAfter) - << std::endl; - } - else - { - LOG(Message) << "Nothing to free" << std::endl; - } - } - } - - return memPeak; -} - -Environment::Size Environment::executeProgram(const std::vector &p) -{ - std::vector pAddress; - - for (auto &n: p) - { - pAddress.push_back(getModuleAddress(n)); - } - - return executeProgram(pAddress); -} - // general memory management /////////////////////////////////////////////////// void Environment::addObject(const std::string name, const int moduleAddress) { @@ -490,6 +156,17 @@ void Environment::addObject(const std::string name, const int moduleAddress) } } +void Environment::setObjectModule(const unsigned int objAddress, + const int modAddress) +{ + object_[objAddress].module = modAddress; +} + +unsigned int Environment::getMaxAddress(void) const +{ + return object_.size(); +} + unsigned int Environment::getObjectAddress(const std::string name) const { if (hasObject(name)) @@ -555,7 +232,24 @@ Environment::Size Environment::getObjectSize(const std::string name) const return getObjectSize(getObjectAddress(name)); } -unsigned int Environment::getObjectModule(const unsigned int address) const +Environment::Storage Environment::getObjectStorage(const unsigned int address) const +{ + if (hasObject(address)) + { + return object_[address].storage; + } + else + { + HADRON_ERROR("no object with address " + std::to_string(address)); + } +} + +Environment::Storage Environment::getObjectStorage(const std::string name) const +{ + return getObjectStorage(getObjectAddress(name)); +} + +int Environment::getObjectModule(const unsigned int address) const { if (hasObject(address)) { @@ -567,7 +261,7 @@ unsigned int Environment::getObjectModule(const unsigned int address) const } } -unsigned int Environment::getObjectModule(const std::string name) const +int Environment::getObjectModule(const std::string name) const { return getObjectModule(getObjectAddress(name)); } @@ -696,7 +390,7 @@ bool Environment::freeObject(const unsigned int address) { if (!hasOwners(address)) { - if (!isDryRun() and hasCreatedObject(address)) + if (hasCreatedObject(address)) { LOG(Message) << "Destroying object '" << object_[address].name << "'" << std::endl; @@ -732,14 +426,9 @@ void Environment::freeAll(void) } } -void Environment::printContent(void) +// print environment content /////////////////////////////////////////////////// +void Environment::printContent(void) const { - LOG(Debug) << "Modules: " << std::endl; - for (unsigned int i = 0; i < module_.size(); ++i) - { - LOG(Debug) << std::setw(4) << i << ": " - << getModuleName(i) << std::endl; - } LOG(Debug) << "Objects: " << std::endl; for (unsigned int i = 0; i < object_.size(); ++i) { diff --git a/extras/Hadrons/Environment.hpp b/extras/Hadrons/Environment.hpp index 58e035ac..9d482923 100644 --- a/extras/Hadrons/Environment.hpp +++ b/extras/Hadrons/Environment.hpp @@ -31,20 +31,12 @@ See the full license in the file "LICENSE" in the top level distribution directo #define Hadrons_Environment_hpp_ #include -#include - -#ifndef SITE_SIZE_TYPE -#define SITE_SIZE_TYPE unsigned int -#endif BEGIN_HADRONS_NAMESPACE /****************************************************************************** * Global environment * ******************************************************************************/ -// forward declaration of Module -class ModuleBase; - class Object { public: @@ -66,26 +58,22 @@ private: std::unique_ptr objPt_{nullptr}; }; +#define DEFINE_ENV_ALIAS \ +inline Environment & env(void) const\ +{\ + return Environment::getInstance();\ +} + class Environment { SINGLETON(Environment); public: typedef SITE_SIZE_TYPE Size; - typedef std::unique_ptr ModPt; typedef std::unique_ptr GridPt; typedef std::unique_ptr GridRbPt; typedef std::unique_ptr RngPt; - typedef std::unique_ptr LatticePt; enum class Storage {object, cache, temporary}; private: - struct ModuleInfo - { - const std::type_info *type{nullptr}; - std::string name; - ModPt data{nullptr}; - std::vector input; - size_t maxAllocated; - }; struct ObjInfo { Size size{0}; @@ -98,53 +86,17 @@ private: std::unique_ptr data{nullptr}; }; public: - // dry run - void dryRun(const bool isDry); - bool isDryRun(void) const; - void memoryProfile(const bool doMemoryProfile); - bool doMemoryProfile(void) const; - // trajectory number - void setTrajectory(const unsigned int traj); - unsigned int getTrajectory(void) const; // grids void createGrid(const unsigned int Ls); GridCartesian * getGrid(const unsigned int Ls = 1) const; GridRedBlackCartesian * getRbGrid(const unsigned int Ls = 1) const; std::vector getDim(void) const; int getDim(const unsigned int mu) const; + unsigned long int getLocalVolume(void) const; unsigned int getNd(void) const; // random number generator void setSeed(const std::vector &seed); GridParallelRNG * get4dRng(void) const; - // module management - void pushModule(ModPt &pt); - template - void createModule(const std::string name); - template - void createModule(const std::string name, - const typename M::Par &par); - void createModule(const std::string name, - const std::string type, - XmlReader &reader); - unsigned int getNModule(void) const; - ModuleBase * getModule(const unsigned int address) const; - ModuleBase * getModule(const std::string name) const; - template - M * getModule(const unsigned int address) const; - template - M * 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; - std::string getModuleNamespace(const unsigned int address) const; - std::string getModuleNamespace(const std::string name) const; - bool hasModule(const unsigned int address) const; - bool hasModule(const std::string name) const; - Graph makeModuleGraph(void) const; - void checkGraph(void) const; - Size executeProgram(const std::vector &p); - Size executeProgram(const std::vector &p); // general memory management void addObject(const std::string name, const int moduleAddress = -1); @@ -153,18 +105,23 @@ public: const Storage storage, const unsigned int Ls, P &&pt); + void setObjectModule(const unsigned int objAddress, + const int modAddress); template T * getObject(const unsigned int address) const; template T * getObject(const std::string name) const; + unsigned int getMaxAddress(void) const; unsigned int getObjectAddress(const std::string name) const; std::string getObjectName(const unsigned int address) const; std::string getObjectType(const unsigned int address) const; std::string getObjectType(const std::string name) const; Size getObjectSize(const unsigned int address) const; Size getObjectSize(const std::string name) const; - unsigned int getObjectModule(const unsigned int address) const; - unsigned int getObjectModule(const std::string name) const; + Storage getObjectStorage(const unsigned int address) const; + Storage getObjectStorage(const std::string name) const; + int getObjectModule(const unsigned int address) const; + int getObjectModule(const std::string name) const; unsigned int getObjectLs(const unsigned int address) const; unsigned int getObjectLs(const std::string name) const; bool hasObject(const unsigned int address) const; @@ -187,11 +144,11 @@ public: bool freeObject(const unsigned int address); bool freeObject(const std::string name); void freeAll(void); - void printContent(void); + // print environment content + void printContent(void) const; private: // general - bool dryRun_{false}, memoryProfile_{false}; - unsigned int traj_, locVol_; + unsigned long int locVol_; // grids std::vector dim_; GridPt grid4d_; @@ -201,12 +158,6 @@ private: unsigned int nd_; // random number generator RngPt rng4d_; - // module and related maps - std::vector module_; - std::map moduleAddress_; - std::string currentModule_{""}; - // lattice store - std::map lattice_; // object store std::vector object_; std::map objectAddress_; @@ -243,46 +194,7 @@ void Holder::reset(T *pt) /****************************************************************************** * Environment template implementation * ******************************************************************************/ -// module management /////////////////////////////////////////////////////////// -template -void Environment::createModule(const std::string name) -{ - ModPt pt(new M(name)); - - pushModule(pt); -} - -template -void Environment::createModule(const std::string name, - const typename M::Par &par) -{ - ModPt pt(new M(name)); - - static_cast(pt.get())->setPar(par); - pushModule(pt); -} - -template -M * Environment::getModule(const unsigned int address) const -{ - if (auto *pt = dynamic_cast(getModule(address))) - { - return pt; - } - else - { - HADRON_ERROR("module '" + module_[address].name - + "' does not have type " + typeid(M).name() - + "(object type: " + getModuleType(address) + ")"); - } -} - -template -M * Environment::getModule(const std::string name) const -{ - return getModule(getModuleAddress(name)); -} - +// general memory management /////////////////////////////////////////////////// template void Environment::createObject(const std::string name, const Environment::Storage storage, diff --git a/extras/Hadrons/Global.hpp b/extras/Hadrons/Global.hpp index 371256e8..1f0ce201 100644 --- a/extras/Hadrons/Global.hpp +++ b/extras/Hadrons/Global.hpp @@ -35,6 +35,10 @@ See the full license in the file "LICENSE" in the top level distribution directo #include #include +#ifndef SITE_SIZE_TYPE +#define SITE_SIZE_TYPE unsigned int +#endif + #define BEGIN_HADRONS_NAMESPACE \ namespace Grid {\ using namespace QCD;\ diff --git a/extras/Hadrons/Makefile.am b/extras/Hadrons/Makefile.am index 9cb23600..826cb158 100644 --- a/extras/Hadrons/Makefile.am +++ b/extras/Hadrons/Makefile.am @@ -8,7 +8,8 @@ libHadrons_a_SOURCES = \ Application.cc \ Environment.cc \ Global.cc \ - Module.cc + Module.cc \ + VirtualMachine.cc libHadrons_adir = $(pkgincludedir)/Hadrons nobase_libHadrons_a_HEADERS = \ $(modules_hpp) \ @@ -20,7 +21,8 @@ nobase_libHadrons_a_HEADERS = \ Graph.hpp \ Module.hpp \ Modules.hpp \ - ModuleFactory.hpp + ModuleFactory.hpp \ + VirtualMachine.hpp HadronsXmlRun_SOURCES = HadronsXmlRun.cc HadronsXmlRun_LDADD = libHadrons.a -lGrid diff --git a/extras/Hadrons/Module.cc b/extras/Hadrons/Module.cc index 2549a931..bf596bfc 100644 --- a/extras/Hadrons/Module.cc +++ b/extras/Hadrons/Module.cc @@ -39,7 +39,6 @@ using namespace Hadrons; // constructor ///////////////////////////////////////////////////////////////// ModuleBase::ModuleBase(const std::string name) : name_(name) -, env_(Environment::getInstance()) {} // access ////////////////////////////////////////////////////////////////////// @@ -48,11 +47,6 @@ std::string ModuleBase::getName(void) const return name_; } -Environment & ModuleBase::env(void) const -{ - return env_; -} - // get factory registration name if available std::string ModuleBase::getRegisteredName(void) { @@ -64,7 +58,7 @@ std::string ModuleBase::getRegisteredName(void) void ModuleBase::operator()(void) { setup(); - if (!env().isDryRun()) + if (!vm().isDryRun()) { execute(); } diff --git a/extras/Hadrons/Module.hpp b/extras/Hadrons/Module.hpp index 017a9172..d1910c9b 100644 --- a/extras/Hadrons/Module.hpp +++ b/extras/Hadrons/Module.hpp @@ -31,7 +31,7 @@ See the full license in the file "LICENSE" in the top level distribution directo #define Hadrons_Module_hpp_ #include -#include +#include BEGIN_HADRONS_NAMESPACE @@ -148,7 +148,6 @@ public: virtual ~ModuleBase(void) = default; // access std::string getName(void) const; - Environment &env(void) const; // get factory registration name if available virtual std::string getRegisteredName(void); // dependencies/products @@ -163,9 +162,12 @@ protected: // setup virtual void setup(void) {}; virtual void execute(void) = 0; + // environment shortcut + DEFINE_ENV_ALIAS; + // virtual machine shortcut + DEFINE_VM_ALIAS; private: std::string name_; - Environment &env_; }; // derived class, templating the parameter class diff --git a/extras/Hadrons/Modules/MContraction/Meson.hpp b/extras/Hadrons/Modules/MContraction/Meson.hpp index 31640b7c..7c0012d2 100644 --- a/extras/Hadrons/Modules/MContraction/Meson.hpp +++ b/extras/Hadrons/Modules/MContraction/Meson.hpp @@ -211,7 +211,7 @@ void TMeson::execute(void) Gamma gSrc(gammaList[i].second); std::string ns; - ns = env().getModuleNamespace(env().getObjectModule(par().sink)); + ns = vm().getModuleNamespace(env().getObjectModule(par().sink)); if (ns == "MSource") { PropagatorField1 &sink = envGet(PropagatorField1, par().sink); diff --git a/extras/Hadrons/VirtualMachine.cc b/extras/Hadrons/VirtualMachine.cc new file mode 100644 index 00000000..f09e2710 --- /dev/null +++ b/extras/Hadrons/VirtualMachine.cc @@ -0,0 +1,388 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/VirtualMachine.cc + +Copyright (C) 2017 + +Author: Antonin Portelli + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +See the full license in the file "LICENSE" in the top level distribution directory +*************************************************************************************/ +/* END LEGAL */ + +#include +#include + +using namespace Grid; +using namespace QCD; +using namespace Hadrons; + +/****************************************************************************** + * VirtualMachine implementation * + ******************************************************************************/ +// dry run ///////////////////////////////////////////////////////////////////// +void VirtualMachine::dryRun(const bool isDry) +{ + dryRun_ = isDry; +} + +bool VirtualMachine::isDryRun(void) const +{ + return dryRun_; +} + +void VirtualMachine::memoryProfile(const bool doMemoryProfile) +{ + memoryProfile_ = doMemoryProfile; +} + +bool VirtualMachine::doMemoryProfile(void) const +{ + return memoryProfile_; +} + +// trajectory counter ////////////////////////////////////////////////////////// +void VirtualMachine::setTrajectory(const unsigned int traj) +{ + traj_ = traj; +} + +unsigned int VirtualMachine::getTrajectory(void) const +{ + return traj_; +} + +// module management /////////////////////////////////////////////////////////// +void VirtualMachine::pushModule(VirtualMachine::ModPt &pt) +{ + std::string name = pt->getName(); + + if (!hasModule(name)) + { + std::vector inputAddress; + unsigned int address; + ModuleInfo m; + + m.data = std::move(pt); + m.type = typeIdPt(*m.data.get()); + m.name = name; + auto input = m.data->getInput(); + for (auto &in: input) + { + if (!env().hasObject(in)) + { + env().addObject(in , -1); + } + m.input.push_back(env().getObjectAddress(in)); + } + auto output = m.data->getOutput(); + module_.push_back(std::move(m)); + address = static_cast(module_.size() - 1); + moduleAddress_[name] = address; + for (auto &out: output) + { + if (!env().hasObject(out)) + { + env().addObject(out, address); + } + else + { + if (env().getObjectModule(env().getObjectAddress(out)) < 0) + { + env().setObjectModule(env().getObjectAddress(out), address); + } + else + { + HADRON_ERROR("object '" + out + + "' is already produced by module '" + + module_[env().getObjectModule(out)].name + + "' (while pushing module '" + name + "')"); + } + } + } + } + else + { + HADRON_ERROR("module '" + name + "' already exists"); + } +} + +unsigned int VirtualMachine::getNModule(void) const +{ + return module_.size(); +} + +void VirtualMachine::createModule(const std::string name, const std::string type, + XmlReader &reader) +{ + auto &factory = ModuleFactory::getInstance(); + auto pt = factory.create(type, name); + + pt->parseParameters(reader, "options"); + pushModule(pt); +} + +ModuleBase * VirtualMachine::getModule(const unsigned int address) const +{ + if (hasModule(address)) + { + return module_[address].data.get(); + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +ModuleBase * VirtualMachine::getModule(const std::string name) const +{ + return getModule(getModuleAddress(name)); +} + +unsigned int VirtualMachine::getModuleAddress(const std::string name) const +{ + if (hasModule(name)) + { + return moduleAddress_.at(name); + } + else + { + HADRON_ERROR("no module with name '" + name + "'"); + } +} + +std::string VirtualMachine::getModuleName(const unsigned int address) const +{ + if (hasModule(address)) + { + return module_[address].name; + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +std::string VirtualMachine::getModuleType(const unsigned int address) const +{ + if (hasModule(address)) + { + return typeName(module_[address].type); + } + else + { + HADRON_ERROR("no module with address " + std::to_string(address)); + } +} + +std::string VirtualMachine::getModuleType(const std::string name) const +{ + return getModuleType(getModuleAddress(name)); +} + +std::string VirtualMachine::getModuleNamespace(const unsigned int address) const +{ + std::string type = getModuleType(address), ns; + + auto pos2 = type.rfind("::"); + auto pos1 = type.rfind("::", pos2 - 2); + + return type.substr(pos1 + 2, pos2 - pos1 - 2); +} + +std::string VirtualMachine::getModuleNamespace(const std::string name) const +{ + return getModuleNamespace(getModuleAddress(name)); +} + +bool VirtualMachine::hasModule(const unsigned int address) const +{ + return (address < module_.size()); +} + +bool VirtualMachine::hasModule(const std::string name) const +{ + return (moduleAddress_.find(name) != moduleAddress_.end()); +} + +Graph VirtualMachine::makeModuleGraph(void) const +{ + Graph moduleGraph; + + for (unsigned int i = 0; i < module_.size(); ++i) + { + moduleGraph.addVertex(i); + for (auto &j: module_[i].input) + { + moduleGraph.addEdge(env().getObjectModule(j), i); + } + } + + return moduleGraph; +} + +// void VirtualMachine::checkGraph(void) const +// { +// for (auto &o: object_) +// { +// if (o.module < 0) +// { +// HADRON_ERROR("object '" + o.name + "' does not have a creator"); +// } +// } +// } + +// general execution /////////////////////////////////////////////////////////// +#define BIG_SEP "===============" +#define SEP "---------------" +#define MEM_MSG(size)\ +sizeString((size)*env().getLocalVolume()) << " (" << sizeString(size) << "/site)" + +VirtualMachine::Size +VirtualMachine::executeProgram(const std::vector &p) +{ + Size memPeak = 0, sizeBefore, sizeAfter; + std::vector> freeProg; + bool continueCollect, nothingFreed; + + // build garbage collection schedule + LOG(Debug) << "Building garbage collection schedule..." << std::endl; + freeProg.resize(p.size()); + for (unsigned int i = 0; i < env().getMaxAddress(); ++i) + { + auto pred = [i, this](const unsigned int j) + { + auto &in = module_[j].input; + auto it = std::find(in.begin(), in.end(), i); + + return (it != in.end()) or (j == env().getObjectModule(i)); + }; + auto it = std::find_if(p.rbegin(), p.rend(), pred); + if (it != p.rend()) + { + freeProg[std::distance(it, p.rend()) - 1].insert(i); + } + } + + // program execution + LOG(Debug) << "Executing program..." << std::endl; + for (unsigned int i = 0; i < p.size(); ++i) + { + // execute module + if (!isDryRun()) + { + LOG(Message) << SEP << " Measurement step " << i+1 << "/" + << p.size() << " (module '" << module_[p[i]].name + << "') " << SEP << std::endl; + } + (*module_[p[i]].data)(); + sizeBefore = env().getTotalSize(); + // print used memory after execution + if (!isDryRun()) + { + LOG(Message) << "Allocated objects: " << MEM_MSG(sizeBefore) + << std::endl; + } + if (sizeBefore > memPeak) + { + memPeak = sizeBefore; + } + // garbage collection for step i + if (!isDryRun()) + { + 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 !env().hasOwners(j); + if(env().freeObject(j)) + { + // if an object has been freed, remove it from + // the garbage collection schedule + freeProg[i].erase(j); + nothingFreed = false; + } + } + } while (continueCollect); + // free temporaries + for (unsigned int i = 0; i < env().getMaxAddress(); ++i) + { + if ((env().getObjectStorage(i) == Environment::Storage::temporary) + and env().hasCreatedObject(i)) + { + env().freeObject(i); + } + } + // 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 + if (!isDryRun()) + { + 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; +} + +VirtualMachine::Size VirtualMachine::executeProgram(const std::vector &p) +{ + std::vector pAddress; + + for (auto &n: p) + { + pAddress.push_back(getModuleAddress(n)); + } + + return executeProgram(pAddress); +} + +// print VM content //////////////////////////////////////////////////////////// +void VirtualMachine::printContent(void) const +{ + LOG(Debug) << "Modules: " << std::endl; + for (unsigned int i = 0; i < module_.size(); ++i) + { + LOG(Debug) << std::setw(4) << i << ": " + << getModuleName(i) << std::endl; + } +} diff --git a/extras/Hadrons/VirtualMachine.hpp b/extras/Hadrons/VirtualMachine.hpp new file mode 100644 index 00000000..357fdb5b --- /dev/null +++ b/extras/Hadrons/VirtualMachine.hpp @@ -0,0 +1,164 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/VirtualMachine.hpp + +Copyright (C) 2017 + +Author: Antonin Portelli + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +See the full license in the file "LICENSE" in the top level distribution directory +*************************************************************************************/ +/* END LEGAL */ + +#ifndef Hadrons_VirtualMachine_hpp_ +#define Hadrons_VirtualMachine_hpp_ + +#include +#include +#include + +BEGIN_HADRONS_NAMESPACE + +#define DEFINE_VM_ALIAS \ +inline VirtualMachine & vm(void) const\ +{\ + return VirtualMachine::getInstance();\ +} + +/****************************************************************************** + * Virtual machine for module execution * + ******************************************************************************/ +// forward declaration of Module +class ModuleBase; + +class VirtualMachine +{ + SINGLETON_DEFCTOR(VirtualMachine); +public: + typedef SITE_SIZE_TYPE Size; + typedef std::unique_ptr ModPt; +private: + struct ModuleInfo + { + const std::type_info *type{nullptr}; + std::string name; + ModPt data{nullptr}; + std::vector input; + size_t maxAllocated; + }; +public: + // dry run + void dryRun(const bool isDry); + bool isDryRun(void) const; + void memoryProfile(const bool doMemoryProfile); + bool doMemoryProfile(void) const; + // trajectory counter + void setTrajectory(const unsigned int traj); + unsigned int getTrajectory(void) const; + // module management + void pushModule(ModPt &pt); + template + void createModule(const std::string name); + template + void createModule(const std::string name, + const typename M::Par &par); + void createModule(const std::string name, + const std::string type, + XmlReader &reader); + unsigned int getNModule(void) const; + ModuleBase * getModule(const unsigned int address) const; + ModuleBase * getModule(const std::string name) const; + template + M * getModule(const unsigned int address) const; + template + M * 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; + std::string getModuleNamespace(const unsigned int address) const; + std::string getModuleNamespace(const std::string name) const; + bool hasModule(const unsigned int address) const; + bool hasModule(const std::string name) const; + Graph makeModuleGraph(void) const; + void checkGraph(void) const; + // print VM content + void printContent(void) const; + // general execution + Size executeProgram(const std::vector &p); + Size executeProgram(const std::vector &p); +private: + // environment shortcut + DEFINE_ENV_ALIAS; +private: + // general + bool dryRun_{false}, memoryProfile_{false}; + unsigned int traj_; + // module and related maps + std::vector module_; + std::map moduleAddress_; + std::string currentModule_{""}; +}; + +/****************************************************************************** + * VirtualMachine template implementation * + ******************************************************************************/ +// module management /////////////////////////////////////////////////////////// +template +void VirtualMachine::createModule(const std::string name) +{ + ModPt pt(new M(name)); + + pushModule(pt); +} + +template +void VirtualMachine::createModule(const std::string name, + const typename M::Par &par) +{ + ModPt pt(new M(name)); + + static_cast(pt.get())->setPar(par); + pushModule(pt); +} + +template +M * VirtualMachine::getModule(const unsigned int address) const +{ + if (auto *pt = dynamic_cast(getModule(address))) + { + return pt; + } + else + { + HADRON_ERROR("module '" + module_[address].name + + "' does not have type " + typeid(M).name() + + "(has type: " + getModuleType(address) + ")"); + } +} + +template +M * VirtualMachine::getModule(const std::string name) const +{ + return getModule(getModuleAddress(name)); +} + +END_HADRONS_NAMESPACE + +#endif // Hadrons_VirtualMachine_hpp_