New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test inter process random state transfers #29384
Merged
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
314e4bf
Created RandomNumberGeneratorState
Dr15Jones b371595
Added ExternalRandomNumberGeneratorService
Dr15Jones 0646944
Add test for passing random engine state between processes
Dr15Jones 7e943ff
Handle RanecuEngine state setting special
Dr15Jones 287732e
Removed unneeded comments and debug printing
Dr15Jones 5209e29
Put global into anonymous namespace.
Dr15Jones File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef DataFormats_Common_RandomNumberGeneratorState_h | ||
#define DataFormats_Common_RandomNumberGeneratorState_h | ||
|
||
/*---------------------------------------------------------------------- | ||
|
||
RandomNumberGeneratorState is used to communicate with an external process | ||
----------------------------------------------------------------------*/ | ||
|
||
#include <vector> | ||
namespace edm { | ||
struct RandomNumberGeneratorState { | ||
RandomNumberGeneratorState() = default; | ||
RandomNumberGeneratorState(std::vector<unsigned long> iState, long iSeed) | ||
: state_(std::move(iState)), seed_{iSeed} {} | ||
|
||
RandomNumberGeneratorState(RandomNumberGeneratorState const&) = default; | ||
RandomNumberGeneratorState(RandomNumberGeneratorState&&) = default; | ||
|
||
RandomNumberGeneratorState& operator=(RandomNumberGeneratorState const&) = default; | ||
RandomNumberGeneratorState& operator=(RandomNumberGeneratorState&&) = default; | ||
|
||
std::vector<unsigned long> state_; | ||
long seed_; | ||
}; | ||
} // namespace edm | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
#include "boost/program_options.hpp" | ||
|
||
#include <atomic> | ||
#include <csignal> | ||
#include <iostream> | ||
#include <string> | ||
#include <thread> | ||
|
||
//TEMP | ||
//#include "CLHEP/Random/JamesRandom.h" | ||
Dr15Jones marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#include "FWCore/TestProcessor/interface/TestProcessor.h" | ||
#include "DataFormats/TestObjects/interface/ToyProducts.h" | ||
#include "DataFormats/Common/interface/RandomNumberGeneratorState.h" | ||
|
||
#include "FWCore/Services/interface/ExternalRandomNumberGeneratorService.h" | ||
|
||
#include "FWCore/SharedMemory/interface/WriteBuffer.h" | ||
#include "FWCore/SharedMemory/interface/WorkerChannel.h" | ||
#include "FWCore/SharedMemory/interface/ROOTSerializer.h" | ||
#include "FWCore/SharedMemory/interface/ReadBuffer.h" | ||
#include "FWCore/SharedMemory/interface/ROOTDeserializer.h" | ||
#include "FWCore/SharedMemory/interface/WorkerMonitorThread.h" | ||
|
||
static char const* const kMemoryNameOpt = "memory-name"; | ||
static char const* const kMemoryNameCommandOpt = "memory-name,m"; | ||
static char const* const kUniqueIDOpt = "unique-id"; | ||
static char const* const kUniqueIDCommandOpt = "unique-id,i"; | ||
static char const* const kHelpOpt = "help"; | ||
static char const* const kHelpCommandOpt = "help,h"; | ||
|
||
//NOTE: Can use TestProcessor as the harness for the worker | ||
|
||
using SentType = std::pair<edmtest::IntProduct, edm::RandomNumberGeneratorState>; | ||
|
||
using namespace edm::shared_memory; | ||
class Harness { | ||
public: | ||
Harness(std::string const& iConfig, edm::ServiceToken iToken) | ||
: tester_(edm::test::TestProcessor::Config{iConfig}, iToken) {} | ||
|
||
edmtest::IntProduct getBeginLumiValue(unsigned int iLumi) { | ||
auto lumi = tester_.testBeginLuminosityBlock(iLumi); | ||
return *lumi.get<edmtest::IntProduct>("lumi"); | ||
} | ||
|
||
edmtest::IntProduct getEventValue() { | ||
auto event = tester_.test(); | ||
return *event.get<edmtest::IntProduct>(); | ||
} | ||
|
||
private: | ||
edm::test::TestProcessor tester_; | ||
}; | ||
|
||
int main(int argc, char* argv[]) { | ||
std::string descString(argv[0]); | ||
descString += " [--"; | ||
descString += kMemoryNameOpt; | ||
descString += "] memory_name"; | ||
boost::program_options::options_description desc(descString); | ||
|
||
desc.add_options()(kHelpCommandOpt, "produce help message")( | ||
kMemoryNameCommandOpt, boost::program_options::value<std::string>(), "memory name")( | ||
kUniqueIDCommandOpt, boost::program_options::value<std::string>(), "unique id"); | ||
|
||
boost::program_options::positional_options_description p; | ||
p.add(kMemoryNameOpt, 1); | ||
p.add(kUniqueIDOpt, 2); | ||
|
||
boost::program_options::options_description all_options("All Options"); | ||
all_options.add(desc); | ||
|
||
boost::program_options::variables_map vm; | ||
try { | ||
store(boost::program_options::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm); | ||
notify(vm); | ||
} catch (boost::program_options::error const& iException) { | ||
std::cout << argv[0] << ": Error while trying to process command line arguments:\n" | ||
<< iException.what() << "\nFor usage and an options list, please do 'cmsRun --help'."; | ||
return 1; | ||
} | ||
|
||
if (vm.count(kHelpOpt)) { | ||
std::cout << desc << std::endl; | ||
return 0; | ||
} | ||
|
||
if (!vm.count(kMemoryNameOpt)) { | ||
std::cout << " no argument given" << std::endl; | ||
return 1; | ||
} | ||
|
||
if (!vm.count(kUniqueIDOpt)) { | ||
std::cout << " no second argument given" << std::endl; | ||
return 1; | ||
} | ||
|
||
WorkerMonitorThread monitorThread; | ||
|
||
monitorThread.startThread(); | ||
|
||
CMS_SA_ALLOW try { | ||
std::string const memoryName(vm[kMemoryNameOpt].as<std::string>()); | ||
std::string const uniqueID(vm[kUniqueIDOpt].as<std::string>()); | ||
{ | ||
//using namespace boost::interprocess; | ||
//auto controlNameUnique = unique_name(memoryName, uniqueID); | ||
Dr15Jones marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
//This class is holding the lock | ||
WorkerChannel communicationChannel(memoryName, uniqueID); | ||
|
||
WriteBuffer sm_buffer{memoryName, communicationChannel.fromWorkerBufferIndex()}; | ||
ReadBuffer sm_readbuffer{std::string("Rand") + memoryName, communicationChannel.toWorkerBufferIndex()}; | ||
int counter = 0; | ||
|
||
//The lock must be released if there is a catastrophic signal | ||
auto lockPtr = communicationChannel.accessLock(); | ||
monitorThread.setAction([lockPtr]() { | ||
if (lockPtr) { | ||
std::cerr << "SIGNAL CAUGHT: unlock\n"; | ||
lockPtr->unlock(); | ||
} | ||
}); | ||
|
||
using TCSerializer = ROOTSerializer<SentType, WriteBuffer>; | ||
TCSerializer serializer(sm_buffer); | ||
TCSerializer bl_serializer(sm_buffer); | ||
|
||
using TCDeserializer = ROOTDeserializer<edm::RandomNumberGeneratorState, ReadBuffer>; | ||
TCDeserializer random_deserializer(sm_readbuffer); | ||
|
||
std::cerr << uniqueID << " process: initializing " << std::endl; | ||
int nlines; | ||
std::cin >> nlines; | ||
|
||
std::string configuration; | ||
for (int i = 0; i < nlines; ++i) { | ||
std::string c; | ||
std::getline(std::cin, c); | ||
std::cerr << c << "\n"; | ||
configuration += c + "\n"; | ||
} | ||
|
||
edm::ExternalRandomNumberGeneratorService* randomService = new edm::ExternalRandomNumberGeneratorService; | ||
auto serviceToken = | ||
edm::ServiceRegistry::createContaining(std::unique_ptr<edm::RandomNumberGenerator>(randomService)); | ||
|
||
//CLHEP::HepJamesRandom rng(12345); | ||
//randomService->setState(rng.put(), rng.getSeed()); | ||
Dr15Jones marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Harness harness(configuration, serviceToken); | ||
|
||
//Either ROOT or the Framework are overriding the signal handlers | ||
monitorThread.setupSignalHandling(); | ||
|
||
std::cerr << uniqueID << " process: done initializing" << std::endl; | ||
communicationChannel.workerSetupDone(); | ||
|
||
std::cerr << uniqueID << " process: waiting " << counter << std::endl; | ||
communicationChannel.handleTransitions([&](edm::Transition iTransition, unsigned long long iTransitionID) { | ||
++counter; | ||
switch (iTransition) { | ||
case edm::Transition::BeginLuminosityBlock: { | ||
std::cerr << uniqueID << " process: start beginLumi " << std::endl; | ||
auto randState = random_deserializer.deserialize(); | ||
std::cerr << " state " << randState.seed_ << std::endl; | ||
randomService->setState(randState.state_, randState.seed_); | ||
SentType toSend; | ||
toSend.first = harness.getBeginLumiValue(iTransitionID); | ||
toSend.second.state_ = randomService->getState(); | ||
toSend.second.seed_ = randomService->mySeed(); | ||
bl_serializer.serialize(toSend); | ||
std::cerr << uniqueID << " process: end beginLumi " << toSend.first.value << std::endl; | ||
|
||
break; | ||
} | ||
case edm::Transition::Event: { | ||
std::cerr << uniqueID << " process: begin event " << counter << std::endl; | ||
auto randState = random_deserializer.deserialize(); | ||
randomService->setState(randState.state_, randState.seed_); | ||
SentType toSend; | ||
toSend.first = harness.getEventValue(); | ||
toSend.second.state_ = randomService->getState(); | ||
toSend.second.seed_ = randomService->mySeed(); | ||
std::cerr << uniqueID << " process: end event " << counter << std::endl; | ||
|
||
serializer.serialize(toSend); | ||
std::cerr << uniqueID << " process: " << toSend.first.value << " " << counter << std::endl; | ||
//usleep(10000000); | ||
break; | ||
} | ||
default: { | ||
assert(false); | ||
} | ||
} | ||
std::cerr << uniqueID << " process: notifying and waiting" << counter << std::endl; | ||
}); | ||
} | ||
} catch (std::exception const& iExcept) { | ||
std::cerr << "caught exception \n" << iExcept.what() << "\n"; | ||
return 1; | ||
} catch (...) { | ||
std::cerr << "caught unknown exception"; | ||
return 1; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#include "FWCore/Framework/interface/one/EDProducer.h" | ||
#include "FWCore/Framework/interface/MakerMacros.h" | ||
#include "FWCore/Framework/interface/Event.h" | ||
#include "FWCore/Framework/interface/LuminosityBlock.h" | ||
|
||
#include "FWCore/Utilities/interface/RandomNumberGenerator.h" | ||
#include "FWCore/Utilities/interface/EDPutToken.h" | ||
#include "FWCore/Utilities/interface/Transition.h" | ||
#include "FWCore/ServiceRegistry/interface/Service.h" | ||
|
||
#include "DataFormats/TestObjects/interface/ToyProducts.h" | ||
|
||
#include "CLHEP/Random/RandFlat.h" | ||
|
||
namespace edmtest { | ||
class RandomIntProducer : public edm::one::EDProducer<edm::BeginLuminosityBlockProducer> { | ||
public: | ||
RandomIntProducer(edm::ParameterSet const& iPSet); | ||
|
||
void produce(edm::Event&, edm::EventSetup const&) final; | ||
|
||
void beginLuminosityBlockProduce(edm::LuminosityBlock&, edm::EventSetup const&) final; | ||
|
||
private: | ||
edm::EDPutTokenT<IntProduct> const evToken_; | ||
edm::EDPutTokenT<IntProduct> const lumiToken_; | ||
}; | ||
RandomIntProducer::RandomIntProducer(edm::ParameterSet const&) | ||
: evToken_{produces<IntProduct>()}, | ||
lumiToken_{produces<IntProduct, edm::Transition::BeginLuminosityBlock>("lumi")} {} | ||
|
||
void RandomIntProducer::produce(edm::Event& iEvent, edm::EventSetup const&) { | ||
edm::Service<edm::RandomNumberGenerator> gen; | ||
std::cout << gen->getEngine(iEvent.streamID()).name() << std::endl; | ||
Dr15Jones marked this conversation as resolved.
Show resolved
Hide resolved
|
||
iEvent.emplace(evToken_, CLHEP::RandFlat::shootInt(&gen->getEngine(iEvent.streamID()), 10)); | ||
} | ||
|
||
void RandomIntProducer::beginLuminosityBlockProduce(edm::LuminosityBlock& iLumi, edm::EventSetup const&) { | ||
edm::Service<edm::RandomNumberGenerator> gen; | ||
iLumi.emplace(lumiToken_, CLHEP::RandFlat::shootInt(&gen->getEngine(iLumi.index()), 10)); | ||
} | ||
|
||
} // namespace edmtest | ||
|
||
using namespace edmtest; | ||
DEFINE_FWK_MODULE(RandomIntProducer); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would encapsulation of the member data make sense here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a 'real' data format since it never is put in a Principal. It is really an internal detail of how the processes communicate. I put it here since I needed a ROOT dictionary to be generated and this class will be used by the FWCore test as well as the upcoming generator code. That is why I just used a struct.