CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
externalGenerator.cc
Go to the documentation of this file.
1 #include "boost/program_options.hpp"
2 
3 #include <atomic>
4 #include <csignal>
5 #include <iostream>
6 #include <string>
7 #include <thread>
8 #include <memory>
9 #include <filesystem>
10 
12 
20 
22 
29 
30 static char const* const kMemoryNameOpt = "memory-name";
31 static char const* const kMemoryNameCommandOpt = "memory-name,m";
32 static char const* const kUniqueIDOpt = "unique-id";
33 static char const* const kUniqueIDCommandOpt = "unique-id,i";
34 static char const* const kHelpOpt = "help";
35 static char const* const kHelpCommandOpt = "help,h";
36 static char const* const kVerboseOpt = "verbose";
37 static char const* const kVerboseCommandOpt = "verbose,v";
38 
39 //NOTE: Can use TestProcessor as the harness for the worker
40 
41 using namespace edm::shared_memory;
42 class Harness {
43 public:
45  : tester_(edm::test::TestProcessor::Config{iConfig}, iToken) {}
46 
48  auto lumi = tester_.testBeginLuminosityBlock(iLumi);
49  ExternalGeneratorLumiInfo returnValue;
50  returnValue.header_ = *lumi.get<GenLumiInfoHeader>();
51  return returnValue;
52  }
53 
55  ExternalGeneratorEventInfo returnValue;
56  auto event = tester_.test();
57  returnValue.hepmc_ = *event.get<edm::HepMCProduct>("unsmeared");
58  returnValue.eventInfo_ = *event.get<GenEventInfoProduct>();
59  returnValue.keepEvent_ = event.modulePassed();
60  return returnValue;
61  }
62 
64  auto lumi = tester_.testEndLuminosityBlock();
65  return *lumi.get<GenLumiInfoProduct>();
66  }
67 
69  auto run = tester_.testEndRun();
70  return *run.get<GenRunInfoProduct>();
71  }
72 
73 private:
75 };
76 
77 template <typename T>
79 
80 namespace {
81  //needed for atexit handling
82  boost::interprocess::scoped_lock<boost::interprocess::named_mutex>* s_sharedLock = nullptr;
83 
84  void atexit_handler() {
85  if (s_sharedLock) {
86  std::cerr << "early exit called: unlock\n";
87  s_sharedLock->unlock();
88  }
89  }
90 } // namespace
91 
92 int main(int argc, char* argv[]) {
93  std::string descString(argv[0]);
94  descString += " [--";
95  descString += kMemoryNameOpt;
96  descString += "] memory_name";
97  boost::program_options::options_description desc(descString);
98 
99  desc.add_options()(kHelpCommandOpt, "produce help message")(
100  kMemoryNameCommandOpt, boost::program_options::value<std::string>(), "memory name")(
101  kUniqueIDCommandOpt, boost::program_options::value<std::string>(), "unique id")(kVerboseCommandOpt,
102  "verbose output");
103 
104  boost::program_options::positional_options_description p;
105  p.add(kMemoryNameOpt, 1);
106  p.add(kUniqueIDOpt, 2);
107 
108  boost::program_options::options_description all_options("All Options");
109  all_options.add(desc);
110 
111  boost::program_options::variables_map vm;
112  try {
113  store(boost::program_options::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm);
114  notify(vm);
115  } catch (boost::program_options::error const& iException) {
116  std::cout << argv[0] << ": Error while trying to process command line arguments:\n"
117  << iException.what() << "\nFor usage and an options list, please do 'cmsRun --help'.";
118  return 1;
119  }
120 
121  if (vm.count(kHelpOpt)) {
122  std::cout << desc << std::endl;
123  return 0;
124  }
125 
126  bool verbose = false;
127  if (vm.count(kVerboseOpt)) {
128  verbose = true;
129  }
130 
131  if (!vm.count(kMemoryNameOpt)) {
132  std::cout << " no argument given" << std::endl;
133  return 1;
134  }
135 
136  if (!vm.count(kUniqueIDOpt)) {
137  std::cout << " no second argument given" << std::endl;
138  return 1;
139  }
140 
141  using namespace std::string_literals;
142  using namespace std::filesystem;
143 
144  auto newDir = path("thread"s + vm[kUniqueIDOpt].as<std::string>());
145  create_directory(newDir);
146  current_path(newDir);
147 
148  WorkerMonitorThread monitorThread;
149 
150  monitorThread.startThread();
151 
152  CMS_SA_ALLOW try {
153  std::string const memoryName(vm[kMemoryNameOpt].as<std::string>());
154  std::string const uniqueID(vm[kUniqueIDOpt].as<std::string>());
155  {
156  //This class is holding the lock
157  WorkerChannel communicationChannel(memoryName, uniqueID);
158 
159  WriteBuffer sm_buffer{memoryName, communicationChannel.fromWorkerBufferInfo()};
160  ReadBuffer sm_readbuffer{std::string("Rand") + memoryName, communicationChannel.toWorkerBufferInfo()};
161  int counter = 0;
162 
163  //The lock must be released if there is a catastrophic signal
164  auto lockPtr = communicationChannel.accessLock();
165 
166  monitorThread.setAction([lockPtr]() {
167  if (lockPtr) {
168  std::cerr << "SIGNAL CAUGHT: unlock\n";
169  lockPtr->unlock();
170  }
171  });
172 
173  //be sure to unset the address of the shared lock before the lock goes away
174  s_sharedLock = lockPtr;
175  auto unsetLockPtr = [](void*) { s_sharedLock = nullptr; };
176  std::unique_ptr<decltype(s_sharedLock), decltype(unsetLockPtr)> sharedLockGuard{&s_sharedLock, unsetLockPtr};
177  std::atexit(atexit_handler);
178  auto releaseLock = []() {
179  if (s_sharedLock) {
180  std::cerr << "terminate called: unlock\n";
181  s_sharedLock->unlock();
182  s_sharedLock = nullptr;
183  //deactivate the abort signal
184 
185  struct sigaction act;
186  act.sa_sigaction = nullptr;
187  act.sa_flags = SA_SIGINFO;
188  sigemptyset(&act.sa_mask);
189  sigaction(SIGABRT, &act, nullptr);
190  std::abort();
191  }
192  };
193  std::set_terminate(releaseLock);
194 
195  Serializer<ExternalGeneratorEventInfo> serializer(sm_buffer);
196  Serializer<ExternalGeneratorLumiInfo> bl_serializer(sm_buffer);
197  Serializer<GenLumiInfoProduct> el_serializer(sm_buffer);
198  Serializer<GenRunInfoProduct> er_serializer(sm_buffer);
199 
200  ROOTDeserializer<edm::RandomNumberGeneratorState, ReadBuffer> random_deserializer(sm_readbuffer);
201 
202  std::cerr << uniqueID << " process: initializing " << std::endl;
203  int nlines;
204  std::cin >> nlines;
205 
207  for (int i = 0; i < nlines; ++i) {
208  std::string c;
209  std::getline(std::cin, c);
210  if (verbose) {
211  std::cerr << c << "\n";
212  }
213  configuration += c + "\n";
214  }
215 
217  auto serviceToken =
218  edm::ServiceRegistry::createContaining(std::unique_ptr<edm::RandomNumberGenerator>(randomService));
219  Harness harness(configuration, serviceToken);
220 
221  //Some generator libraries override the signal handlers
222  monitorThread.setupSignalHandling();
223  std::set_terminate(releaseLock);
224 
225  if (verbose) {
226  std::cerr << uniqueID << " process: done initializing" << std::endl;
227  }
228  communicationChannel.workerSetupDone();
229 
230  if (verbose)
231  std::cerr << uniqueID << " process: waiting " << counter << std::endl;
232  communicationChannel.handleTransitions([&](edm::Transition iTransition, unsigned long long iTransitionID) {
233  ++counter;
234  switch (iTransition) {
236  if (verbose)
237  std::cerr << uniqueID << " process: start beginRun " << std::endl;
238  if (verbose)
239  std::cerr << uniqueID << " process: end beginRun " << std::endl;
240 
241  break;
242  }
244  if (verbose)
245  std::cerr << uniqueID << " process: start beginLumi " << std::endl;
246  auto randState = random_deserializer.deserialize();
247  if (verbose)
248  std::cerr << uniqueID << " random " << randState.state_.size() << " " << randState.seed_ << std::endl;
249  randomService->setState(randState.state_, randState.seed_);
250  auto value = harness.getBeginLumiValue(iTransitionID);
251  value.randomState_.state_ = randomService->getState();
252  value.randomState_.seed_ = randomService->mySeed();
253 
254  bl_serializer.serialize(value);
255  if (verbose)
256  std::cerr << uniqueID << " process: end beginLumi " << std::endl;
257  if (verbose)
258  std::cerr << uniqueID << " rand " << value.randomState_.state_.size() << " " << value.randomState_.seed_
259  << std::endl;
260  break;
261  }
262  case edm::Transition::Event: {
263  if (verbose)
264  std::cerr << uniqueID << " process: event " << counter << std::endl;
265  auto randState = random_deserializer.deserialize();
266  randomService->setState(randState.state_, randState.seed_);
267  auto value = harness.getEventValue();
268  value.randomState_.state_ = randomService->getState();
269  value.randomState_.seed_ = randomService->mySeed();
270 
271  if (verbose)
272  std::cerr << uniqueID << " process: event " << counter << std::endl;
273 
274  serializer.serialize(value);
275  if (verbose)
276  std::cerr << uniqueID << " process: "
277  << " " << counter << std::endl;
278  //usleep(10000000);
279  break;
280  }
282  if (verbose)
283  std::cerr << uniqueID << " process: start endLumi " << std::endl;
284  auto value = harness.getEndLumiValue();
285 
286  el_serializer.serialize(value);
287  if (verbose)
288  std::cerr << uniqueID << " process: end endLumi " << std::endl;
289 
290  break;
291  }
293  if (verbose)
294  std::cerr << uniqueID << " process: start endRun " << std::endl;
295  auto value = harness.getEndRunValue();
296 
297  er_serializer.serialize(value);
298  if (verbose)
299  std::cerr << uniqueID << " process: end endRun " << std::endl;
300 
301  break;
302  }
303  default: {
304  assert(false);
305  }
306  }
307  if (verbose)
308  std::cerr << uniqueID << " process: notifying and waiting " << counter << std::endl;
309  });
310  }
311  } catch (std::exception const& iExcept) {
312  std::cerr << "caught exception \n" << iExcept.what() << "\n";
313  return 1;
314  } catch (...) {
315  std::cerr << "caught unknown exception";
316  return 1;
317  }
318  return 0;
319 }
edmtest::ThingCollection getEndLumiValue()
Definition: interprocess.cc:47
const edm::EventSetup & c
#define CMS_SA_ALLOW
edmtest::ThingCollection getEventValue()
Definition: interprocess.cc:42
boost::interprocess::scoped_lock< boost::interprocess::named_mutex > * accessLock()
the lock is made accessible so that the WorkerMonitorThread can be used to unlock it in the event of ...
Definition: WorkerChannel.h:48
ExternalGeneratorEventInfo getEventValue()
static char const *const kHelpOpt
static char const *const kMemoryNameCommandOpt
edmtest::ThingCollection getBeginLumiValue(unsigned int iLumi)
Definition: interprocess.cc:37
void setState(std::vector< unsigned long > const &, long seed)
GenRunInfoProduct getEndRunValue()
static char const *const kMemoryNameOpt
assert(be >=bs)
static char const *const kHelpCommandOpt
GenLumiInfoProduct getEndLumiValue()
static constexpr int verbose
BufferInfo * toWorkerBufferInfo()
This can be used with ReadBuffer to keep Controller and Worker in sync.
Definition: WorkerChannel.h:51
void workerSetupDone()
Matches the ControllerChannel::setupWorker call.
Definition: WorkerChannel.h:56
Transition
Definition: Transition.h:12
static ServiceToken createContaining(std::unique_ptr< T > iService)
create a service token that holds the service defined by iService
static char const *const kVerboseOpt
ExternalGeneratorLumiInfo getBeginLumiValue(unsigned int iLumi)
list lumi
Definition: dqmdumpme.py:53
static char const *const kVerboseCommandOpt
BufferInfo * fromWorkerBufferInfo()
This can be used with WriteBuffer to keep Controller and Worker in sync.
Definition: WorkerChannel.h:53
static char const *const kUniqueIDCommandOpt
Harness(std::string const &iConfig, edm::ServiceToken iToken)
tuple argc
Definition: dir2webdir.py:39
edmtest::ThingCollection getEndRunValue()
Definition: interprocess.cc:52
static char const *const kUniqueIDOpt
static std::atomic< unsigned int > counter
tuple cout
Definition: gather_cfg.py:144
tuple Config
Definition: helper.py:10