mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-31 12:04:33 +00:00 
			
		
		
		
	Hadrons: execution part moved in a new virtual machine class
This commit is contained in:
		| @@ -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<unsigned int>::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; | ||||
|      | ||||
|   | ||||
| @@ -31,8 +31,7 @@ See the full license in the file "LICENSE" in the top level distribution directo | ||||
| #define Hadrons_Application_hpp_ | ||||
|  | ||||
| #include <Grid/Hadrons/Global.hpp> | ||||
| #include <Grid/Hadrons/Environment.hpp> | ||||
| #include <Grid/Hadrons/ModuleFactory.hpp> | ||||
| #include <Grid/Hadrons/VirtualMachine.hpp> | ||||
| #include <Grid/Hadrons/Modules.hpp> | ||||
|  | ||||
| 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 <typename M> | ||||
| void Application::createModule(const std::string name) | ||||
| { | ||||
|     env().createModule<M>(name); | ||||
|     vm().createModule<M>(name); | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| void Application::createModule(const std::string name, | ||||
|                                const typename M::Par &par) | ||||
| { | ||||
|     env().createModule<M>(name, par); | ||||
|     vm().createModule<M>(name, par); | ||||
| } | ||||
|  | ||||
| END_HADRONS_NAMESPACE | ||||
|   | ||||
| @@ -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<int> &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<unsigned int> 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<unsigned int>(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<unsigned int> Environment::makeModuleGraph(void) const | ||||
| { | ||||
|     Graph<unsigned int> 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<unsigned int> &p) | ||||
| { | ||||
|     Size                                memPeak = 0, sizeBefore, sizeAfter; | ||||
|     std::vector<std::set<unsigned int>> 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<std::string> &p) | ||||
| { | ||||
|     std::vector<unsigned int> 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) | ||||
|     { | ||||
|   | ||||
| @@ -31,20 +31,12 @@ See the full license in the file "LICENSE" in the top level distribution directo | ||||
| #define Hadrons_Environment_hpp_ | ||||
|  | ||||
| #include <Grid/Hadrons/Global.hpp> | ||||
| #include <Grid/Hadrons/Graph.hpp> | ||||
|  | ||||
| #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<T> 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<ModuleBase>            ModPt; | ||||
|     typedef std::unique_ptr<GridCartesian>         GridPt; | ||||
|     typedef std::unique_ptr<GridRedBlackCartesian> GridRbPt; | ||||
|     typedef std::unique_ptr<GridParallelRNG>       RngPt; | ||||
|     typedef std::unique_ptr<LatticeBase>           LatticePt; | ||||
|     enum class Storage {object, cache, temporary}; | ||||
| private: | ||||
|     struct ModuleInfo | ||||
|     { | ||||
|         const std::type_info      *type{nullptr}; | ||||
|         std::string               name; | ||||
|         ModPt                     data{nullptr}; | ||||
|         std::vector<unsigned int> input; | ||||
|         size_t                    maxAllocated; | ||||
|     }; | ||||
|     struct ObjInfo | ||||
|     { | ||||
|         Size                    size{0}; | ||||
| @@ -98,53 +86,17 @@ private: | ||||
|         std::unique_ptr<Object> 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<int>        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<int> &seed); | ||||
|     GridParallelRNG *       get4dRng(void) const; | ||||
|     // module management | ||||
|     void                    pushModule(ModPt &pt); | ||||
|     template <typename M> | ||||
|     void                    createModule(const std::string name); | ||||
|     template <typename M> | ||||
|     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 <typename M> | ||||
|     M *                     getModule(const unsigned int address) const; | ||||
|     template <typename M> | ||||
|     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<unsigned int>     makeModuleGraph(void) const; | ||||
|     void                    checkGraph(void) const; | ||||
|     Size                    executeProgram(const std::vector<unsigned int> &p); | ||||
|     Size                    executeProgram(const std::vector<std::string> &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 <typename T> | ||||
|     T *                     getObject(const unsigned int address) const; | ||||
|     template <typename T> | ||||
|     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<int>                       dim_; | ||||
|     GridPt                                 grid4d_; | ||||
| @@ -201,12 +158,6 @@ private: | ||||
|     unsigned int                           nd_; | ||||
|     // random number generator | ||||
|     RngPt                                  rng4d_; | ||||
|     // module and related maps | ||||
|     std::vector<ModuleInfo>                module_; | ||||
|     std::map<std::string, unsigned int>    moduleAddress_; | ||||
|     std::string                            currentModule_{""}; | ||||
|     // lattice store | ||||
|     std::map<unsigned int, LatticePt>      lattice_; | ||||
|     // object store | ||||
|     std::vector<ObjInfo>                   object_; | ||||
|     std::map<std::string, unsigned int>    objectAddress_; | ||||
| @@ -243,46 +194,7 @@ void Holder<T>::reset(T *pt) | ||||
| /****************************************************************************** | ||||
|  *                     Environment template implementation                    * | ||||
|  ******************************************************************************/ | ||||
| // module management /////////////////////////////////////////////////////////// | ||||
| template <typename M> | ||||
| void Environment::createModule(const std::string name) | ||||
| { | ||||
|     ModPt pt(new M(name)); | ||||
|      | ||||
|     pushModule(pt); | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| void Environment::createModule(const std::string name, | ||||
|                                const typename M::Par &par) | ||||
| { | ||||
|     ModPt pt(new M(name)); | ||||
|      | ||||
|     static_cast<M *>(pt.get())->setPar(par); | ||||
|     pushModule(pt); | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| M * Environment::getModule(const unsigned int address) const | ||||
| { | ||||
|     if (auto *pt = dynamic_cast<M *>(getModule(address))) | ||||
|     { | ||||
|         return pt; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         HADRON_ERROR("module '" + module_[address].name | ||||
|                      + "' does not have type " + typeid(M).name() | ||||
|                      + "(object type: " + getModuleType(address) + ")"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| M * Environment::getModule(const std::string name) const | ||||
| { | ||||
|     return getModule<M>(getModuleAddress(name)); | ||||
| } | ||||
|  | ||||
| // general memory management /////////////////////////////////////////////////// | ||||
| template <typename T, typename P> | ||||
| void Environment::createObject(const std::string name,  | ||||
|                                const Environment::Storage storage, | ||||
|   | ||||
| @@ -35,6 +35,10 @@ See the full license in the file "LICENSE" in the top level distribution directo | ||||
| #include <Grid/Grid.h> | ||||
| #include <cxxabi.h> | ||||
|  | ||||
| #ifndef SITE_SIZE_TYPE | ||||
| #define SITE_SIZE_TYPE unsigned int | ||||
| #endif | ||||
|  | ||||
| #define BEGIN_HADRONS_NAMESPACE \ | ||||
| namespace Grid {\ | ||||
| using namespace QCD;\ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
|   | ||||
| @@ -31,7 +31,7 @@ See the full license in the file "LICENSE" in the top level distribution directo | ||||
| #define Hadrons_Module_hpp_ | ||||
|  | ||||
| #include <Grid/Hadrons/Global.hpp> | ||||
| #include <Grid/Hadrons/Environment.hpp> | ||||
| #include <Grid/Hadrons/VirtualMachine.hpp> | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -211,7 +211,7 @@ void TMeson<FImpl1, FImpl2>::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); | ||||
|   | ||||
							
								
								
									
										388
									
								
								extras/Hadrons/VirtualMachine.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								extras/Hadrons/VirtualMachine.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,388 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
| Source file: extras/Hadrons/VirtualMachine.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Antonin Portelli <antonin.portelli@me.com> | ||||
|  | ||||
| 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 <Grid/Hadrons/VirtualMachine.hpp> | ||||
| #include <Grid/Hadrons/ModuleFactory.hpp> | ||||
|  | ||||
| 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<unsigned int> 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<unsigned int>(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<unsigned int> VirtualMachine::makeModuleGraph(void) const | ||||
| { | ||||
|     Graph<unsigned int> 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<unsigned int> &p) | ||||
| { | ||||
|     Size                                memPeak = 0, sizeBefore, sizeAfter; | ||||
|     std::vector<std::set<unsigned int>> 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<std::string> &p) | ||||
| { | ||||
|     std::vector<unsigned int> 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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										164
									
								
								extras/Hadrons/VirtualMachine.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								extras/Hadrons/VirtualMachine.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
| Source file: extras/Hadrons/VirtualMachine.hpp | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Antonin Portelli <antonin.portelli@me.com> | ||||
|  | ||||
| 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 <Grid/Hadrons/Global.hpp> | ||||
| #include <Grid/Hadrons/Graph.hpp> | ||||
| #include <Grid/Hadrons/Environment.hpp> | ||||
|  | ||||
| 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<ModuleBase> ModPt; | ||||
| private: | ||||
|     struct ModuleInfo | ||||
|     { | ||||
|         const std::type_info      *type{nullptr}; | ||||
|         std::string               name; | ||||
|         ModPt                     data{nullptr}; | ||||
|         std::vector<unsigned int> 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 <typename M> | ||||
|     void                createModule(const std::string name); | ||||
|     template <typename M> | ||||
|     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 <typename M> | ||||
|     M *                 getModule(const unsigned int address) const; | ||||
|     template <typename M> | ||||
|     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<unsigned int> makeModuleGraph(void) const; | ||||
|     void                checkGraph(void) const; | ||||
|     // print VM content | ||||
|     void                printContent(void) const; | ||||
|     // general execution | ||||
|     Size                executeProgram(const std::vector<unsigned int> &p); | ||||
|     Size                executeProgram(const std::vector<std::string> &p); | ||||
| private: | ||||
|     // environment shortcut | ||||
|     DEFINE_ENV_ALIAS; | ||||
| private: | ||||
|     // general | ||||
|     bool                                dryRun_{false}, memoryProfile_{false}; | ||||
|     unsigned int                        traj_; | ||||
|     // module and related maps | ||||
|     std::vector<ModuleInfo>             module_; | ||||
|     std::map<std::string, unsigned int> moduleAddress_; | ||||
|     std::string                         currentModule_{""}; | ||||
| }; | ||||
|  | ||||
| /****************************************************************************** | ||||
|  *                   VirtualMachine template implementation                   * | ||||
|  ******************************************************************************/ | ||||
| // module management /////////////////////////////////////////////////////////// | ||||
| template <typename M> | ||||
| void VirtualMachine::createModule(const std::string name) | ||||
| { | ||||
|     ModPt pt(new M(name)); | ||||
|      | ||||
|     pushModule(pt); | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| void VirtualMachine::createModule(const std::string name, | ||||
|                                const typename M::Par &par) | ||||
| { | ||||
|     ModPt pt(new M(name)); | ||||
|      | ||||
|     static_cast<M *>(pt.get())->setPar(par); | ||||
|     pushModule(pt); | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| M * VirtualMachine::getModule(const unsigned int address) const | ||||
| { | ||||
|     if (auto *pt = dynamic_cast<M *>(getModule(address))) | ||||
|     { | ||||
|         return pt; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         HADRON_ERROR("module '" + module_[address].name | ||||
|                      + "' does not have type " + typeid(M).name() | ||||
|                      + "(has type: " + getModuleType(address) + ")"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename M> | ||||
| M * VirtualMachine::getModule(const std::string name) const | ||||
| { | ||||
|     return getModule<M>(getModuleAddress(name)); | ||||
| } | ||||
|  | ||||
| END_HADRONS_NAMESPACE | ||||
|  | ||||
| #endif // Hadrons_VirtualMachine_hpp_ | ||||
		Reference in New Issue
	
	Block a user