Skip to content

Commit

Permalink
Merge pull request #37605 from fwyzard/MPIService_updates
Browse files Browse the repository at this point in the history
Updates to the MPIService
  • Loading branch information
cmsbuild authored Apr 19, 2022
2 parents 4271a27 + fd71e01 commit 8ae9891
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 71 deletions.
6 changes: 6 additions & 0 deletions HeterogeneousCore/MPIServices/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<use name="openmpi"/>
<use name="FWCore/Framework"/>
<use name="FWCore/ParameterSet"/>
<export>
<lib name="1"/>
</export>
15 changes: 15 additions & 0 deletions HeterogeneousCore/MPIServices/interface/MPIService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef HeterogeneousCore_MPIServices_interface_MPIService_h
#define HeterogeneousCore_MPIServices_interface_MPIService_h

#include "FWCore/ParameterSet/interface/ParameterSetfwd.h"

class MPIService {
public:
MPIService(edm::ParameterSet const& config);
~MPIService();

static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
static void required();
};

#endif // HeterogeneousCore_MPIServices_interface_MPIService_h
2 changes: 2 additions & 0 deletions HeterogeneousCore/MPIServices/plugins/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<use name="openmpi"/>
<use name="FWCore/Framework"/>
<use name="FWCore/ParameterSet"/>
<use name="FWCore/ServiceRegistry"/>
<use name="HeterogeneousCore/MPIServices"/>
<flags EDM_PLUGIN="1"/>
72 changes: 1 addition & 71 deletions HeterogeneousCore/MPIServices/plugins/MPIService.cc
Original file line number Diff line number Diff line change
@@ -1,73 +1,3 @@
// -*- C++ -*-

#include <mpi.h>

#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/Utilities/interface/Exception.h"

namespace {
const char* const mpi_thread_support_level[] = {
"MPI_THREAD_SINGLE", // only one thread will execute (the process is single-threaded)
"MPI_THREAD_FUNNELED", // only the thread that called MPI_Init_thread will make MPI calls
"MPI_THREAD_SERIALIZED", // only one thread will make MPI library calls at one time
"MPI_THREAD_MULTIPLE" // multiple threads may call MPI at once with no restrictions
};
}

class MPIService {
public:
MPIService(edm::ParameterSet const& config);
~MPIService();

static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
};

MPIService::MPIService(edm::ParameterSet const& config) {
// initializes the MPI execution environment, requesting multi-threading support
int provided;
MPI_Init_thread(nullptr, nullptr, MPI_THREAD_MULTIPLE, &provided);
if (provided < MPI_THREAD_MULTIPLE) {
throw cms::Exception("UnsupportedFeature")
<< "CMSSW requires the " << mpi_thread_support_level[MPI_THREAD_MULTIPLE]
<< " multithreading support level, but the MPI library provides only the " << mpi_thread_support_level[provided]
<< " level.";
} else {
edm::LogInfo log("MPIService");

// get the number of processes
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
log << "MPI_COMM_WORLD size: " << world_size << '\n';

// get the rank of the process
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
log << "MPI_COMM_WORLD rank: " << world_rank << '\n';

// get the name of the processor
char processor_name[MPI_MAX_PROCESSOR_NAME];
int name_len;
MPI_Get_processor_name(processor_name, &name_len);
log << "MPI processor name: " << processor_name << '\n';

log << "The MPI library provides the " << mpi_thread_support_level[provided] << " multithreading support level\n";
log << "MPI successfully initialised";
}
}

MPIService::~MPIService() {
// terminate the MPI execution environment
MPI_Finalize();
}

void MPIService::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
descriptions.add("MPIService", desc);
descriptions.setComment(R"(This Service provides a common interface to MPI configuration for the CMSSW job.)");
}

#include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
#include "HeterogeneousCore/MPIServices/interface/MPIService.h"
DEFINE_FWK_SERVICE_MAKER(MPIService, edm::serviceregistry::ParameterSetMaker<MPIService>);
109 changes: 109 additions & 0 deletions HeterogeneousCore/MPIServices/src/MPIService.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// -*- C++ -*-
#include <cstdlib>
#include <string>

#include <mpi.h>

#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/ServiceRegistry/interface/Service.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "HeterogeneousCore/MPIServices/interface/MPIService.h"

namespace {

// list the MPI thread support levels
const char* const mpi_thread_support_level[] = {
"MPI_THREAD_SINGLE", // only one thread will execute (the process is single-threaded)
"MPI_THREAD_FUNNELED", // only the thread that called MPI_Init_thread will make MPI calls
"MPI_THREAD_SERIALIZED", // only one thread will make MPI library calls at one time
"MPI_THREAD_MULTIPLE" // multiple threads may call MPI at once with no restrictions
};

} // namespace

MPIService::MPIService(edm::ParameterSet const& config) {
/* As of Open MPI 4.1.0, `MPI_THREAD_MULTIPLE` is supported by the following transports:
* - the `ob1` PML, with the following BTLs:
* - `self`
* - `sm`
* - `smcuda`
* - `tcp`
* - `ugni`
* - `usnic`
* - the `cm` PML, with the following MTLs:
* - `ofi` (Libfabric)
* - `portals4`
* - the `ucx` PML
*
* MPI File operations are not thread safe even if MPI is initialized for `MPI_THREAD_MULTIPLE` support.
*
* See https://github.com/open-mpi/ompi/blob/v4.1.0/README .
*/

// set the pmix_server_uri MCA parameter if specified in the configuration and not already set in the environment
if (config.existsAs<std::string>("pmix_server_uri", false)) {
std::string uri = config.getUntrackedParameter<std::string>("pmix_server_uri");
// do not overwrite the environment variable if it is already set
setenv("OMPI_MCA_pmix_server_uri", uri.c_str(), false);
}

// initializes the MPI execution environment, requesting multi-threading support
int provided;
MPI_Init_thread(nullptr, nullptr, MPI_THREAD_MULTIPLE, &provided);
if (provided < MPI_THREAD_MULTIPLE) {
throw cms::Exception("UnsupportedFeature")
<< "CMSSW requires the " << mpi_thread_support_level[MPI_THREAD_MULTIPLE]
<< " multithreading support level, but the MPI library provides only the " << mpi_thread_support_level[provided]
<< " level.";
} else {
edm::LogInfo log("MPIService");
log << "The MPI library provides the " << mpi_thread_support_level[provided] << " multithreading support level\n";

// get the number of processes
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
log << "MPI_COMM_WORLD size: " << world_size << '\n';

// get the rank of the process
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
log << "MPI_COMM_WORLD rank: " << world_rank << '\n';

// get the name of the processor
char processor_name[MPI_MAX_PROCESSOR_NAME];
int name_len;
MPI_Get_processor_name(processor_name, &name_len);
log << "MPI processor name: " << processor_name << '\n';

// initialisation done
log << '\n';
log << "MPI successfully initialised";
}
}

MPIService::~MPIService() {
// terminate the MPI execution environment
MPI_Finalize();
}

void MPIService::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.addOptionalUntracked<std::string>("pmix_server_uri")
->setComment("Set the OpenMPI MCA pmix_server_uri parameter if not already set in the environment");
descriptions.add("MPIService", desc);
descriptions.setComment(R"(This Service provides a common interface to MPI configuration for the CMSSW job.)");
}

void MPIService::required() {
edm::Service<MPIService> s;
if (not s.isAvailable()) {
throw cms::Exception("Configuration") << R"(The MPIService is required by this module.
Please add it to the configuration, for example via
process.load("HeterogeneousCore.MPIServices.MPIService_cfi")
)";
}
}

0 comments on commit 8ae9891

Please sign in to comment.