diff --git a/examples/deploy/cloudr.cpp b/examples/deploy/cloudr.cpp index 829bf19..56c1520 100644 --- a/examples/deploy/cloudr.cpp +++ b/examples/deploy/cloudr.cpp @@ -13,22 +13,23 @@ int main(int argc, char *argv[]) { // Instantiating base managers - auto instanceManager = HiCR::backend::mpi::InstanceManager::createDefault(&argc, &argv); - auto communicationManager = HiCR::backend::mpi::CommunicationManager(MPI_COMM_WORLD); - auto memoryManager = HiCR::backend::mpi::MemoryManager(); - auto computeManager = HiCR::backend::pthreads::ComputeManager(); + auto instanceManager = HiCR::backend::mpi::InstanceManager::createDefault(&argc, &argv); + auto communicationManager = HiCR::backend::mpi::CommunicationManager(MPI_COMM_WORLD); + auto memoryManager = HiCR::backend::mpi::MemoryManager(); + auto computeManager = HiCR::backend::pthreads::ComputeManager(); // Getting my base instance id and index - const auto baseInstanceId = instanceManager->getCurrentInstance()->getId(); - uint64_t baseInstanceIdx = 0; - for (size_t i = 0; i < instanceManager->getInstances().size(); i++) if (instanceManager->getInstances()[i]->getId() == baseInstanceId) baseInstanceIdx = i; + const auto baseInstanceId = instanceManager->getCurrentInstance()->getId(); + uint64_t baseInstanceIdx = 0; + for (size_t i = 0; i < instanceManager->getInstances().size(); i++) + if (instanceManager->getInstances()[i]->getId() == baseInstanceId) baseInstanceIdx = i; // Checking for parameters if (argc != 3) - { + { fprintf(stderr, "Error: You need to pass a deployment.json and a cloudr.json file as parameters.\n"); instanceManager->finalize(); - return 0; + return -1; } // Reading cloudr config file @@ -36,14 +37,17 @@ int main(int argc, char *argv[]) // Parsing deployment file contents to a JSON object std::ifstream ifs(cloudrConfigFilePath); - auto cloudrConfigJs = nlohmann::json::parse(ifs); + auto cloudrConfigJs = nlohmann::json::parse(ifs); // Make sure we're running the number of base instances as emulated cloudr instances if (instanceManager->getInstances().size() != cloudrConfigJs["Topologies"].size()) - { - fprintf(stderr, "Error: The number of requested cloudr instances (%lu) is different than the number of instances provided (%lu)\n", cloudrConfigJs["Topologies"].size(), instanceManager->getInstances().size()); + { + fprintf(stderr, + "Error: The number of requested cloudr instances (%lu) is different than the number of instances provided (%lu)\n", + cloudrConfigJs["Topologies"].size(), + instanceManager->getInstances().size()); instanceManager->finalize(); - return 0; + return -1; } // Getting my emulated topology from the cloudr configuration file @@ -57,11 +61,11 @@ int main(int argc, char *argv[]) auto hwlocTopologyManager = HiCR::backend::hwloc::TopologyManager(&hwlocTopology); // Finding the first memory space and compute resource to create our RPC engine - const auto& topology = hwlocTopologyManager.queryTopology(); - const auto& firstDevice = topology.getDevices().begin().operator*(); - const auto& RPCMemorySpace = firstDevice->getMemorySpaceList().begin().operator*(); - const auto& RPCComputeResource = firstDevice->getComputeResourceList().begin().operator*(); - + const auto &topology = hwlocTopologyManager.queryTopology(); + const auto &firstDevice = topology.getDevices().begin().operator*(); + const auto &RPCMemorySpace = firstDevice->getMemorySpaceList().begin().operator*(); + const auto &RPCComputeResource = firstDevice->getComputeResourceList().begin().operator*(); + // Instantiating RPC engine HiCR::frontend::RPCEngine rpcEngine(communicationManager, *instanceManager, memoryManager, computeManager, RPCMemorySpace, RPCComputeResource); @@ -72,14 +76,13 @@ int main(int argc, char *argv[]) deployr::Deployment deployment; // Instantiating CloudR - HiCR::backend::cloudr::InstanceManager cloudrInstanceManager(&rpcEngine, emulatedTopology, [&]() - { + HiCR::backend::cloudr::InstanceManager cloudrInstanceManager(&rpcEngine, emulatedTopology, [&]() { // Getting our current cloudr instance - const auto& currentInstance = cloudrInstanceManager.getCurrentInstance(); + const auto ¤tInstance = cloudrInstanceManager.getCurrentInstance(); // Getting our instance's emulated topology - const auto& emulatedTopology = dynamic_pointer_cast(currentInstance)->getTopology(); - + const auto &emulatedTopology = dynamic_pointer_cast(currentInstance)->getTopology(); + // Creating deployr object deployr::DeployR deployr(&cloudrInstanceManager, &rpcEngine, emulatedTopology); @@ -101,27 +104,27 @@ int main(int argc, char *argv[]) // Parsing deployment file contents to a JSON object std::ifstream ifs(deploymentFilePath); - auto deploymentJs = nlohmann::json::parse(ifs); + auto deploymentJs = nlohmann::json::parse(ifs); // Getting requested topologies from the json file - for (size_t i = 0; i < deploymentJs["Runners"].size(); i++) + for (size_t i = 0; i < deploymentJs["Runners"].size(); i++) { // Getting runner - const auto& runner = deploymentJs["Runners"][i]; + const auto &runner = deploymentJs["Runners"][i]; // Assigning runner topology const auto runnerTopology = HiCR::Topology(runner["Topology"]); // Asking cloudr to create new instances based on the topology requirement const auto instanceTemplate = cloudrInstanceManager.createInstanceTemplate(runnerTopology); - auto instance = cloudrInstanceManager.createInstance(*instanceTemplate); + auto instance = cloudrInstanceManager.createInstance(*instanceTemplate); // Adding new instances to list of newly created instances newInstances.push_back(instance); // Sanity check - if (instance == nullptr) - { + if (instance == nullptr) + { fprintf(stderr, "Error: Could not create instance with required topology: %s\n", runnerTopology.serialize().dump(2).c_str()); instanceManager->abort(-1); } @@ -132,13 +135,14 @@ int main(int argc, char *argv[]) // Creating deployr object deployr::DeployR deployr(&cloudrInstanceManager, &rpcEngine, topology); - + // Calling main algorithm driver deploy(deployr, deployment, cloudrInstanceManager.getCurrentInstance()->getId()); } // Reliqushing newly created instances from cloudr - if (cloudrInstanceManager.getCurrentInstance()->isRootInstance()) for (const auto& instance : newInstances) cloudrInstanceManager.terminateInstance(instance); + if (cloudrInstanceManager.getCurrentInstance()->isRootInstance()) + for (const auto &instance : newInstances) cloudrInstanceManager.terminateInstance(instance); // Finalizing cloudR cloudrInstanceManager.finalize(); diff --git a/examples/deploy/deploy.hpp b/examples/deploy/deploy.hpp index 2758ef1..25a0e29 100644 --- a/examples/deploy/deploy.hpp +++ b/examples/deploy/deploy.hpp @@ -4,16 +4,16 @@ void leaderFc(deployr::DeployR &deployr) { // Getting local instance - printf("[LeaderFc] Hi, I am instance id: %lu\n", deployr.getInstanceId()); + printf("[LeaderFc] Hi, I am instance id: %lu\n", deployr.getRunnerId()); } void workerFc(deployr::DeployR &deployr) { // Getting local instance - printf("[WorkerFc] Hi, I am instance id: %lu\n", deployr.getInstanceId()); + printf("[WorkerFc] Hi, I am instance id: %lu\n", deployr.getRunnerId()); } -void deploy(deployr::DeployR &deployr, const deployr::Deployment& deployment, const HiCR::Instance::instanceId_t coordinatorInstanceId) +void deploy(deployr::DeployR &deployr, const deployr::Deployment &deployment, const HiCR::Instance::instanceId_t coordinatorInstanceId) { // Initializing DeployR deployr.initialize(); diff --git a/examples/deploy/meson.build b/examples/deploy/meson.build index 2fb9ec7..e2e3cad 100644 --- a/examples/deploy/meson.build +++ b/examples/deploy/meson.build @@ -3,13 +3,13 @@ testSuite = [ 'examples', 'deploy' ] if 'mpi' in engines exec = executable('mpi', [ 'mpi.cpp'], dependencies: DeployRBuildDep) if get_option('buildTests') - test('mpi', mpirunExecutable, args : [ '-np', '3', '--oversubscribe', exec.full_path(), meson.current_source_dir() + '/request.json'], timeout: 60, suite: testSuite ) + test('mpi', mpirunExecutable, args : [ '-np', '3', '--oversubscribe', exec.full_path(), meson.current_source_dir() + '/deployment.json'], timeout: 60, suite: testSuite ) endif endif if 'cloudr' in engines exec = executable('cloudr', [ 'cloudr.cpp' ], dependencies: DeployRBuildDep) if get_option('buildTests') - test('cloudr', mpirunExecutable, args : [ '-np', '3', '--oversubscribe', exec.full_path(), meson.current_source_dir() + '/request.json'], timeout: 60, suite: testSuite ) + test('cloudr', mpirunExecutable, args : [ '-np', '5', '--oversubscribe', exec.full_path(), meson.current_source_dir() + '/deployment.json', meson.current_source_dir() + '/cloudr.json'], timeout: 60, suite: testSuite ) endif endif \ No newline at end of file diff --git a/examples/deploy/mpi.cpp b/examples/deploy/mpi.cpp index a54ceb6..854c7a1 100644 --- a/examples/deploy/mpi.cpp +++ b/examples/deploy/mpi.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) auto memoryManager = std::make_shared(); // Making sure we instantiated 3 instances, which is all we need for this example - if (instanceManager->getInstances().size() != 3) + if (instanceManager->getInstances().size() != 3) { fprintf(stderr, "Error: this example requires three instances to run.\n"); instanceManager->abort(-1); @@ -56,8 +56,8 @@ int main(int argc, char *argv[]) HiCR::frontend::RPCEngine rpcEngine(*communicationManager, *instanceManager, *memoryManager, computeManager, bufferMemorySpace, computeResource); // Gathering instances to run the example with - std::vector instances; - for (const auto& instance : instanceManager->getInstances()) instances.push_back(instance.get()); + std::vector instances; + for (const auto &instance : instanceManager->getInstances()) instances.push_back(instance.get()); // Initialize RPC engine rpcEngine.initialize(); @@ -70,9 +70,9 @@ int main(int argc, char *argv[]) // Getting the topology of the other MPI processes std::vector instanceIds; - for (const auto& instance : instanceManager->getInstances()) instanceIds.push_back(instance->getId()); + for (const auto &instance : instanceManager->getInstances()) instanceIds.push_back(instance->getId()); const auto globalTopology = deployr.gatherGlobalTopology(instanceManager->getRootInstanceId(), instanceIds); - + // Creating deployment object deployr::Deployment deployment; @@ -81,7 +81,7 @@ int main(int argc, char *argv[]) { // Checking arguments if (argc != 2) - { + { fprintf(stderr, "Error: You need to pass a deployment.json file as parameter.\n"); instanceManager->abort(-1); } @@ -91,25 +91,24 @@ int main(int argc, char *argv[]) // Parsing request file contents to a JSON object std::ifstream ifs(deploymentFilePath); - auto deploymentJs = nlohmann::json::parse(ifs); + auto deploymentJs = nlohmann::json::parse(ifs); // Getting requested topologies from the json file std::vector requestedTopologies; - for (const auto& runner : deploymentJs["Runners"]) requestedTopologies.push_back(HiCR::Topology(runner["Topology"])); + for (const auto &runner : deploymentJs["Runners"]) requestedTopologies.push_back(HiCR::Topology(runner["Topology"])); // Determine best pairing between the detected instances const auto matching = deployr::DeployR::doBipartiteMatching(requestedTopologies, globalTopology); // Check matching if (matching.size() != requestedTopologies.size()) - { + { fprintf(stderr, "Error: The provided instances do not have the sufficient hardware resources to run this job.\n"); instanceManager->abort(-1); } // Creating the runner objects - for (size_t i = 0; i < deploymentJs["Runners"].size(); i++) - deployment.addRunner(deployr::Runner(i, deploymentJs["Runners"][i]["Function"].get(), matching[i])); + for (size_t i = 0; i < deploymentJs["Runners"].size(); i++) deployment.addRunner(deployr::Runner(i, deploymentJs["Runners"][i]["Function"].get(), matching[i])); } // Deploying diff --git a/include/deployr/deployment.hpp b/include/deployr/deployment.hpp index 329239f..16afecc 100644 --- a/include/deployr/deployment.hpp +++ b/include/deployr/deployment.hpp @@ -20,7 +20,7 @@ class Deployment final /** * Add an instance */ - __INLINE__ void addRunner(const Runner& runner) { _runners.push_back(runner); } + __INLINE__ void addRunner(const Runner &runner) { _runners.push_back(runner); } /** * Gets the instance map diff --git a/include/deployr/deployr.hpp b/include/deployr/deployr.hpp index d0d1e9b..8678c23 100644 --- a/include/deployr/deployr.hpp +++ b/include/deployr/deployr.hpp @@ -27,15 +27,11 @@ class DeployR final /** * Default constructor for DeployR. It creates the HiCR management engine and registers the basic functions needed during deployment. */ - DeployR( - HiCR::InstanceManager* instanceManager, - HiCR::frontend::RPCEngine* rpcEngine, - const HiCR::Topology& localTopology) - : - _instanceManager(instanceManager), - _rpcEngine(rpcEngine), - _localTopology(localTopology) - { } + DeployR(HiCR::InstanceManager *instanceManager, HiCR::frontend::RPCEngine *rpcEngine, const HiCR::Topology &localTopology) + : _instanceManager(instanceManager), + _rpcEngine(rpcEngine), + _localTopology(localTopology) + {} ~DeployR() = default; @@ -65,53 +61,57 @@ class DeployR final * * @param[in] deploymnet A deployment object containing the configuration required to deploy a job */ - __INLINE__ void deploy(const Deployment& deployment, const HiCR::Instance::instanceId_t coordinatorInstanceId) + __INLINE__ void deploy(const Deployment &deployment, const HiCR::Instance::instanceId_t coordinatorInstanceId) { // Getting this running instance information - const auto& currentInstance = _instanceManager->getCurrentInstance(); - const auto currentInstanceId = currentInstance->getId(); + const auto ¤tInstance = _instanceManager->getCurrentInstance(); + const auto currentInstanceId = currentInstance->getId(); // Getting runner set - const auto& runners = deployment.getRunners(); + const auto &runners = deployment.getRunners(); // Remembering if the coordinator is assigned a runner role bool coodinatorIsRunner = false; // Gathering required HiCR instances into a set std::set instanceIds; - for (const auto& runner : runners) instanceIds.insert(runner.getId()); + for (const auto &runner : runners) instanceIds.insert(runner.getId()); // Sanity check: make sure there are no repeated instances being used if (runners.size() != instanceIds.size()) HICR_THROW_LOGIC("[DeployR] A repeated HiCR instance was provided.\n"); // Bifurcation point: this is only run by the non-coordinator instance // they are captured until the coordinator syncs up with them - if (currentInstanceId != coordinatorInstanceId) { _rpcEngine->listen(); return; } + if (currentInstanceId != coordinatorInstanceId) + { + _rpcEngine->listen(); + return; + } // Gathering accessible instances from the instance manager - const auto& instances = _instanceManager->getInstances(); - std::map instanceMap; - for (const auto& instance : instances) instanceMap.insert({instance->getId(), instance.get()}); + const auto &instances = _instanceManager->getInstances(); + std::map instanceMap; + for (const auto &instance : instances) instanceMap.insert({instance->getId(), instance.get()}); // Sending RPCs to the paired hosts to start deployment - for (const auto& runner : runners) + for (const auto &runner : runners) { - const auto runnerId = runner.getId(); - const auto& initialFcName = runner.getFunction(); - const auto instanceId = runner.getInstanceId(); - - // Getting instance corresponding to the provided Id - if (instanceMap.contains(instanceId) == false) HICR_THROW_LOGIC("[DeployR] Provided instance id %lu not found in the instance manager provided.\n", instanceId); - const auto instance = instanceMap.at(instanceId); - - // If the pairing refers to this host, assign its function name but delay execution - if (instanceId == currentInstanceId) - { + const auto runnerId = runner.getId(); + const auto &initialFcName = runner.getFunction(); + const auto instanceId = runner.getInstanceId(); + + // Getting instance corresponding to the provided Id + if (instanceMap.contains(instanceId) == false) HICR_THROW_LOGIC("[DeployR] Provided instance id %lu not found in the instance manager provided.\n", instanceId); + const auto instance = instanceMap.at(instanceId); + + // If the pairing refers to this host, assign its function name but delay execution + if (instanceId == currentInstanceId) + { coodinatorIsRunner = true; - _initialFunction = initialFcName; - _runnerId = runnerId; + _initialFunction = initialFcName; + _runnerId = runnerId; continue; - } + } // Sending RPC _rpcEngine->requestRPC(*instance, initialFcName, runnerId); @@ -147,7 +147,7 @@ class DeployR final * * @return The id of the running instance */ - [[nodiscard]] __INLINE__ const Runner::runnerId_t getInstanceId() const + [[nodiscard]] __INLINE__ const Runner::runnerId_t getRunnerId() const { // If I am root, I remembered my instance Id if (_instanceManager->getCurrentInstance()->isRootInstance() == true) return _runnerId; @@ -160,17 +160,14 @@ class DeployR final * Finalizes the deployment. Must be called by the root instance before exiting the applicataion */ __INLINE__ void finalize() - { - // Nothing to do here so far + { + // Nothing to do here so far } /** * Fatally aborts execution. Must be used only in case of unsalvageable errors. */ - __INLINE__ void abort() - { - _instanceManager->abort(-1); - } + __INLINE__ void abort() { _instanceManager->abort(-1); } /** * Retrieves the RPC engine for direct use @@ -179,71 +176,66 @@ class DeployR final */ __INLINE__ HiCR::frontend::RPCEngine *getRPCEngine() { return _rpcEngine; } - /** + /** * Retrieves currently running instance * * @return The current HiCR instance */ - __INLINE__ HiCR::Instance& getCurrentHiCRInstance() const { return *_instanceManager->getCurrentInstance(); } + __INLINE__ HiCR::Instance &getCurrentHiCRInstance() const { return *_instanceManager->getCurrentInstance(); } - /** + /** * Gets the global topology, the sum of all local topologies among the provided instances * * @return A vector containing each of the local topologies, where the index corresponds to the host index in the getHiCRInstances function */ -[[nodiscard]] __INLINE__ std::vector gatherGlobalTopology( - const HiCR::Instance::instanceId_t rootInstanceId, - const std::vector instanceIds - ) -{ - // Storage - std::vector globalTopology; - const auto& currentInstance = _instanceManager->getCurrentInstance(); - const bool isRootInstance = currentInstance->getId() == rootInstanceId; - const auto& instances = _instanceManager->getInstances(); - - // If I am not root and I am among the participating instances, then listen for the incoming RPC and return an empty topology - if (isRootInstance == false) - { - _rpcEngine->listen(); - } - else // If I am root, request topology from all instances + [[nodiscard]] __INLINE__ std::vector gatherGlobalTopology(const HiCR::Instance::instanceId_t rootInstanceId, + const std::vector instanceIds) { - for (const auto& instance : instances) - if (instance->getId() == currentInstance->getId()) // If its me, just push my local topology - { - globalTopology.push_back(_localTopology.serialize()); - } - else // If not, it's another instance: send RPC and deserialize return value - { - // Requesting RPC from the remote instance - _rpcEngine->requestRPC(*instance, __DEPLOYR_GET_TOPOLOGY_RPC_NAME); - - // Getting return value as a memory slot - auto returnValue = _rpcEngine->getReturnValue(*instance); - - // Receiving raw serialized topology information from the worker - std::string serializedTopology = (char *)returnValue->getPointer(); - - // Parsing serialized raw topology into a json object - auto topologyJson = nlohmann::json::parse(serializedTopology); - - // Freeing return value - _rpcEngine->getMemoryManager()->freeLocalMemorySlot(returnValue); - - // Creating new topology object - HiCR::Topology topology(topologyJson); + // Storage + std::vector globalTopology; + const auto ¤tInstance = _instanceManager->getCurrentInstance(); + const bool isRootInstance = currentInstance->getId() == rootInstanceId; + const auto &instances = _instanceManager->getInstances(); + + // If I am not root and I am among the participating instances, then listen for the incoming RPC and return an empty topology + if (isRootInstance == false) { _rpcEngine->listen(); } + else // If I am root, request topology from all instances + { + for (const auto &instance : instances) + if (instance->getId() == currentInstance->getId()) // If its me, just push my local topology + { + globalTopology.push_back(_localTopology.serialize()); + } + else // If not, it's another instance: send RPC and deserialize return value + { + // Requesting RPC from the remote instance + _rpcEngine->requestRPC(*instance, __DEPLOYR_GET_TOPOLOGY_RPC_NAME); + + // Getting return value as a memory slot + auto returnValue = _rpcEngine->getReturnValue(*instance); + + // Receiving raw serialized topology information from the worker + std::string serializedTopology = (char *)returnValue->getPointer(); + + // Parsing serialized raw topology into a json object + auto topologyJson = nlohmann::json::parse(serializedTopology); + + // Freeing return value + _rpcEngine->getMemoryManager()->freeLocalMemorySlot(returnValue); + + // Creating new topology object + HiCR::Topology topology(topologyJson); + + // Pushing topology into the vector + globalTopology.push_back(topology); + } + } - // Pushing topology into the vector - globalTopology.push_back(topology); - } + // Return global topology + return globalTopology; } - // Return global topology - return globalTopology; -} - -/** + /** * Performs a matching between the a set of required topologies and a set of given (existing) topologies and returns, if exists, a possible pairing. * * A pairing consists of a 1:1 mapping of the required topologies and the given topologies. For each pairing the given topology is a equal or a superset of the required one. @@ -252,55 +244,54 @@ class DeployR final * * @return If successful, a vector of size size(requested) containing the indexes of the given topologies that match the requested ones. Otherwise, an empty vector. */ -[[nodiscard]] __INLINE__ static std::vector doBipartiteMatching(const std::vector& requested, const std::vector& given) -{ - // Creating pairings vector - std::vector pairingsVector; + [[nodiscard]] __INLINE__ static std::vector doBipartiteMatching(const std::vector &requested, const std::vector &given) + { + // Creating pairings vector + std::vector pairingsVector; - // Creating one deployment runner per requested runner - for (size_t i = 0; i < requested.size(); i++) pairingsVector.push_back(i); + // Creating one deployment runner per requested runner + for (size_t i = 0; i < requested.size(); i++) pairingsVector.push_back(i); - // Building the matching graph - theAlgorithms::graph::HKGraph graph(pairingsVector.size(), given.size()); - for (size_t i = 0; i < pairingsVector.size(); i++) - for (size_t j = 0; j < given.size(); j++) - if (HiCR::Topology::isSubset(given[j], requested[i])) graph.addEdge(i, j); + // Building the matching graph + theAlgorithms::graph::HKGraph graph(pairingsVector.size(), given.size()); + for (size_t i = 0; i < pairingsVector.size(); i++) + for (size_t j = 0; j < given.size(); j++) + if (HiCR::Topology::isSubset(given[j], requested[i])) graph.addEdge(i, j); - // Finding out if a proper matching exists - auto matchCount = (size_t)graph.hopcroftKarpAlgorithm(); + // Finding out if a proper matching exists + auto matchCount = (size_t)graph.hopcroftKarpAlgorithm(); - // If the number of matchings is smaller than requested, return an empty vector - if (matchCount < pairingsVector.size()) return {}; + // If the number of matchings is smaller than requested, return an empty vector + if (matchCount < pairingsVector.size()) return {}; - // Getting the pairings from the graph - const auto graphPairings = graph.getLeftSidePairings(); - for (size_t i = 0; i < pairingsVector.size(); i++) - { - const auto givenIdx = (size_t)graphPairings[i + 1]; - pairingsVector[i] = givenIdx; - } + // Getting the pairings from the graph + const auto graphPairings = graph.getLeftSidePairings(); + for (size_t i = 0; i < pairingsVector.size(); i++) + { + const auto givenIdx = (size_t)graphPairings[i + 1]; + pairingsVector[i] = givenIdx; + } - return pairingsVector; -} + return pairingsVector; + } -private: + private: __INLINE__ std::shared_ptr createInstance(const HiCR::InstanceTemplate t) { - std::shared_ptr newInstance; - try - { - newInstance = _instanceManager->createInstance(t); - } - catch(const std::exception& e) - { - HICR_THROW_FATAL("[DeployR] Failed to create new instance. Reason: \n + '%s'", e.what()); - } - - if (newInstance.get() == nullptr) - HICR_THROW_FATAL("Failed to create new instance with requested topology: %s\n", t.getTopology().serialize().dump(2).c_str()); + std::shared_ptr newInstance; + try + { + newInstance = _instanceManager->createInstance(t); + } + catch (const std::exception &e) + { + HICR_THROW_FATAL("[DeployR] Failed to create new instance. Reason: \n + '%s'", e.what()); + } + + if (newInstance.get() == nullptr) HICR_THROW_FATAL("Failed to create new instance with requested topology: %s\n", t.getTopology().serialize().dump(2).c_str()); - return newInstance; + return newInstance; } /** @@ -351,10 +342,10 @@ class DeployR final std::map> _registeredFunctions; // Externally-provided Instance Manager to use - HiCR::InstanceManager* const _instanceManager; + HiCR::InstanceManager *const _instanceManager; /// The RPC engine to use for all remote function requests - HiCR::frontend::RPCEngine* const _rpcEngine; + HiCR::frontend::RPCEngine *const _rpcEngine; /// Storage for the local system topology HiCR::Topology _localTopology; diff --git a/include/deployr/host.hpp b/include/deployr/host.hpp index 852f503..bcdda81 100644 --- a/include/deployr/host.hpp +++ b/include/deployr/host.hpp @@ -22,7 +22,7 @@ class Host final * @param[in] instance HiCR Instance corresponding to this host, as given by an instance manager * @param[in] topology The JSON-encoded HiCR topology detected for this host */ - Host(HiCR::Instance* const instance, const nlohmann::json &topology) + Host(HiCR::Instance *const instance, const nlohmann::json &topology) : _instance(instance), _topology(topology) {} @@ -39,17 +39,14 @@ class Host final * * @return true, if this host satisfies the host type; false, otherwise. */ - [[nodiscard]] __INLINE__ bool checkCompatibility(const HiCR::Topology& topology) const - { - return HiCR::Topology::isSubset(_topology, topology); - } + [[nodiscard]] __INLINE__ bool checkCompatibility(const HiCR::Topology &topology) const { return HiCR::Topology::isSubset(_topology, topology); } /** * Retrieves the HiCR instance referenced by this host * * @return A pointer to a HiCR instance */ - [[nodiscard]] HiCR::Instance* getInstance() const { return _instance; } + [[nodiscard]] HiCR::Instance *getInstance() const { return _instance; } /** * Retrieves the host topology @@ -61,7 +58,7 @@ class Host final private: /// Instance Id corresponding to this host - HiCR::Instance* const _instance; + HiCR::Instance *const _instance; /// Host's actual topology, in JSON format const HiCR::Topology _topology; diff --git a/include/deployr/runner.hpp b/include/deployr/runner.hpp index 44fbf74..58e1d86 100644 --- a/include/deployr/runner.hpp +++ b/include/deployr/runner.hpp @@ -8,52 +8,54 @@ namespace deployr */ class Runner { - public: + public: - typedef uint64_t runnerId_t; + typedef uint64_t runnerId_t; - Runner() = delete; - ~Runner() = default; + Runner() = delete; + ~Runner() = default; - /** + /** * Deserializing constructor for the Runner class * */ - Runner(const runnerId_t id, const std::string& function, const HiCR::Instance::instanceId_t instanceId) - : _id(id), _function(function), _instanceId(instanceId) - { } + Runner(const runnerId_t id, const std::string &function, const HiCR::Instance::instanceId_t instanceId) + : _id(id), + _function(function), + _instanceId(instanceId) + {} - /** + /** * Gets the numerical id of the instance, as provided by the user * * @return the id of the instance */ - [[nodiscard]] __INLINE__ const runnerId_t getId() const { return _id; } + [[nodiscard]] __INLINE__ const runnerId_t getId() const { return _id; } - /** + /** * Gets the initial function for this instance * * @return the initial function for this instance */ - [[nodiscard]] __INLINE__ const std::string &getFunction() const { return _function; } + [[nodiscard]] __INLINE__ const std::string &getFunction() const { return _function; } - /** + /** * Gets the topology required by this instance * * @return the topology required by this instance */ - [[nodiscard]] __INLINE__ const HiCR::Instance::instanceId_t getInstanceId() const { return _instanceId; } + [[nodiscard]] __INLINE__ const HiCR::Instance::instanceId_t getInstanceId() const { return _instanceId; } - private: + private: - /// Id assigned to this runner - const runnerId_t _id; + /// Id assigned to this runner + const runnerId_t _id; - /// Function for this run to run as it is deployed - const std::string _function; + /// Function for this run to run as it is deployed + const std::string _function; - /// HiCR instance id assigned to this runner - const HiCR::Instance::instanceId_t _instanceId; + /// HiCR instance id assigned to this runner + const HiCR::Instance::instanceId_t _instanceId; }; // class Runner diff --git a/meson.build b/meson.build index ff5274f..390ad32 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,7 @@ if 'lpf' in engines endif if 'cloudr' in engines + mpirunExecutable = find_program('mpirun', '/usr/bin/mpirun', '/usr/local/bin/mpirun', required : true) CloudRProject = subproject('cloudr', required: true, default_options: [ ]) CloudRBuildDep = CloudRProject.get_variable('CloudRBuildDep') deployrDependencies += CloudRBuildDep