Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-05-10 22:24:38

0001 #include "boost/program_options.hpp"
0002 
0003 #include <atomic>
0004 #include <csignal>
0005 #include <iostream>
0006 #include <string>
0007 #include <thread>
0008 #include <memory>
0009 #include <filesystem>
0010 
0011 #include "FWCore/TestProcessor/interface/TestProcessor.h"
0012 
0013 #include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
0014 #include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h"
0015 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoHeader.h"
0016 #include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoProduct.h"
0017 #include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h"
0018 #include "SimDataFormats/GeneratorProducts/interface/ExternalGeneratorEventInfo.h"
0019 #include "SimDataFormats/GeneratorProducts/interface/ExternalGeneratorLumiInfo.h"
0020 
0021 #include "FWCore/Services/interface/ExternalRandomNumberGeneratorService.h"
0022 
0023 #include "FWCore/SharedMemory/interface/WriteBuffer.h"
0024 #include "FWCore/SharedMemory/interface/ReadBuffer.h"
0025 #include "FWCore/SharedMemory/interface/WorkerChannel.h"
0026 #include "FWCore/SharedMemory/interface/ROOTSerializer.h"
0027 #include "FWCore/SharedMemory/interface/ROOTDeserializer.h"
0028 #include "FWCore/SharedMemory/interface/WorkerMonitorThread.h"
0029 
0030 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0031 
0032 static char const* const kMemoryNameOpt = "memory-name";
0033 static char const* const kMemoryNameCommandOpt = "memory-name,m";
0034 static char const* const kUniqueIDOpt = "unique-id";
0035 static char const* const kUniqueIDCommandOpt = "unique-id,i";
0036 static char const* const kHelpOpt = "help";
0037 static char const* const kHelpCommandOpt = "help,h";
0038 static char const* const kVerboseOpt = "verbose";
0039 static char const* const kVerboseCommandOpt = "verbose,v";
0040 
0041 //This application only uses 1 thread
0042 CMS_THREAD_SAFE static std::string s_uniqueID;
0043 
0044 //NOTE: Can use TestProcessor as the harness for the worker
0045 
0046 using namespace edm::shared_memory;
0047 class Harness {
0048 public:
0049   Harness(std::string const& iConfig, edm::ServiceToken iToken)
0050       : tester_(edm::test::TestProcessor::Config{iConfig}, iToken) {}
0051 
0052   ExternalGeneratorLumiInfo getBeginLumiValue(unsigned int iLumi) {
0053     auto lumi = tester_.testBeginLuminosityBlock(iLumi);
0054     ExternalGeneratorLumiInfo returnValue;
0055     returnValue.header_ = *lumi.get<GenLumiInfoHeader>();
0056     return returnValue;
0057   }
0058 
0059   ExternalGeneratorEventInfo getEventValue() {
0060     ExternalGeneratorEventInfo returnValue;
0061     auto event = tester_.test();
0062     returnValue.hepmc_ = *event.get<edm::HepMCProduct>("unsmeared");
0063     returnValue.eventInfo_ = *event.get<GenEventInfoProduct>();
0064     returnValue.keepEvent_ = event.modulePassed();
0065     return returnValue;
0066   }
0067 
0068   GenLumiInfoProduct getEndLumiValue() {
0069     auto lumi = tester_.testEndLuminosityBlock();
0070     return *lumi.get<GenLumiInfoProduct>();
0071   }
0072 
0073   GenRunInfoProduct getEndRunValue() {
0074     auto run = tester_.testEndRun();
0075     return *run.get<GenRunInfoProduct>();
0076   }
0077 
0078 private:
0079   edm::test::TestProcessor tester_;
0080 };
0081 
0082 template <typename T>
0083 using Serializer = ROOTSerializer<T, WriteBuffer>;
0084 
0085 namespace {
0086   //needed for atexit handling
0087   CMS_THREAD_SAFE boost::interprocess::scoped_lock<boost::interprocess::named_mutex>* s_sharedLock = nullptr;
0088 
0089   void atexit_handler() {
0090     if (s_sharedLock) {
0091       std::cerr << s_uniqueID << " process: early exit called: unlock\n";
0092       s_sharedLock->unlock();
0093     }
0094   }
0095 }  // namespace
0096 
0097 int main(int argc, char* argv[]) {
0098   std::string descString(argv[0]);
0099   descString += " [--";
0100   descString += kMemoryNameOpt;
0101   descString += "] memory_name";
0102   boost::program_options::options_description desc(descString);
0103 
0104   desc.add_options()(kHelpCommandOpt, "produce help message")(
0105       kMemoryNameCommandOpt, boost::program_options::value<std::string>(), "memory name")(
0106       kUniqueIDCommandOpt, boost::program_options::value<std::string>(), "unique id")(kVerboseCommandOpt,
0107                                                                                       "verbose output");
0108 
0109   boost::program_options::positional_options_description p;
0110   p.add(kMemoryNameOpt, 1);
0111   p.add(kUniqueIDOpt, 2);
0112 
0113   boost::program_options::options_description all_options("All Options");
0114   all_options.add(desc);
0115 
0116   boost::program_options::variables_map vm;
0117   try {
0118     store(boost::program_options::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm);
0119     notify(vm);
0120   } catch (boost::program_options::error const& iException) {
0121     std::cout << argv[0] << ": Error while trying to process command line arguments:\n"
0122               << iException.what() << "\nFor usage and an options list, please do 'cmsRun --help'.";
0123     return 1;
0124   }
0125 
0126   if (vm.count(kHelpOpt)) {
0127     std::cout << desc << std::endl;
0128     return 0;
0129   }
0130 
0131   bool verbose = false;
0132   if (vm.count(kVerboseOpt)) {
0133     verbose = true;
0134   }
0135 
0136   if (!vm.count(kMemoryNameOpt)) {
0137     std::cout << " no argument given" << std::endl;
0138     return 1;
0139   }
0140 
0141   if (!vm.count(kUniqueIDOpt)) {
0142     std::cout << " no second argument given" << std::endl;
0143     return 1;
0144   }
0145 
0146   using namespace std::string_literals;
0147   using namespace std::filesystem;
0148 
0149   auto newDir = path("thread"s + vm[kUniqueIDOpt].as<std::string>());
0150   create_directory(newDir);
0151   current_path(newDir);
0152 
0153   WorkerMonitorThread monitorThread;
0154 
0155   monitorThread.startThread();
0156 
0157   std::string presentState = "setting up communicationChannel";
0158 
0159   CMS_SA_ALLOW try {
0160     std::string const memoryName(vm[kMemoryNameOpt].as<std::string>());
0161     std::string const uniqueID(vm[kUniqueIDOpt].as<std::string>());
0162     s_uniqueID = uniqueID;
0163     {
0164       //This class is holding the lock
0165       WorkerChannel communicationChannel(memoryName, uniqueID);
0166 
0167       presentState = "setting up read/write buffers";
0168       WriteBuffer sm_buffer{memoryName, communicationChannel.fromWorkerBufferInfo()};
0169       ReadBuffer sm_readbuffer{std::string("Rand") + memoryName, communicationChannel.toWorkerBufferInfo()};
0170       int counter = 0;
0171 
0172       presentState = "setting up monitor thread";
0173       //The lock must be released if there is a catastrophic signal
0174       auto lockPtr = communicationChannel.accessLock();
0175 
0176       monitorThread.setAction([lockPtr]() {
0177         if (lockPtr) {
0178           std::cerr << s_uniqueID << " process: SIGNAL CAUGHT: unlock\n";
0179           lockPtr->unlock();
0180         }
0181       });
0182 
0183       presentState = "setting up termination handler";
0184       //be sure to unset the address of the shared lock before the lock goes away
0185       s_sharedLock = lockPtr;
0186       auto unsetLockPtr = [](void*) { s_sharedLock = nullptr; };
0187       std::unique_ptr<decltype(s_sharedLock), decltype(unsetLockPtr)> sharedLockGuard{&s_sharedLock, unsetLockPtr};
0188       std::atexit(atexit_handler);
0189       auto releaseLock = []() {
0190         if (s_sharedLock) {
0191           std::cerr << s_uniqueID << " process: terminate called: unlock\n";
0192           s_sharedLock->unlock();
0193           s_sharedLock = nullptr;
0194           //deactivate the abort signal
0195 
0196           struct sigaction act;
0197           act.sa_sigaction = nullptr;
0198           act.sa_flags = SA_SIGINFO;
0199           sigemptyset(&act.sa_mask);
0200           sigaction(SIGABRT, &act, nullptr);
0201           std::abort();
0202         }
0203       };
0204       std::set_terminate(releaseLock);
0205 
0206       presentState = "setting up serializers";
0207       Serializer<ExternalGeneratorEventInfo> serializer(sm_buffer);
0208       Serializer<ExternalGeneratorLumiInfo> bl_serializer(sm_buffer);
0209       Serializer<GenLumiInfoProduct> el_serializer(sm_buffer);
0210       Serializer<GenRunInfoProduct> er_serializer(sm_buffer);
0211 
0212       ROOTDeserializer<edm::RandomNumberGeneratorState, ReadBuffer> random_deserializer(sm_readbuffer);
0213 
0214       presentState = "reading configuration";
0215       std::cerr << uniqueID << " process: initializing " << std::endl;
0216       int nlines;
0217       std::cin >> nlines;
0218 
0219       std::string configuration;
0220       for (int i = 0; i < nlines; ++i) {
0221         std::string c;
0222         std::getline(std::cin, c);
0223         if (verbose) {
0224           std::cerr << c << "\n";
0225         }
0226         configuration += c + "\n";
0227       }
0228 
0229       presentState = "setting up random number generator";
0230       edm::ExternalRandomNumberGeneratorService* randomService = new edm::ExternalRandomNumberGeneratorService;
0231       auto serviceToken =
0232           edm::ServiceRegistry::createContaining(std::unique_ptr<edm::RandomNumberGenerator>(randomService));
0233       Harness harness(configuration, serviceToken);
0234 
0235       //Some generator libraries override the signal handlers
0236       monitorThread.setupSignalHandling();
0237       std::set_terminate(releaseLock);
0238 
0239       if (verbose) {
0240         std::cerr << uniqueID << " process: done initializing" << std::endl;
0241       }
0242       presentState = "finished initialization";
0243       communicationChannel.workerSetupDone();
0244 
0245       presentState = "waiting for transition";
0246       if (verbose)
0247         std::cerr << uniqueID << " process: waiting " << counter << std::endl;
0248       communicationChannel.handleTransitions([&](edm::Transition iTransition, unsigned long long iTransitionID) {
0249         ++counter;
0250         switch (iTransition) {
0251           case edm::Transition::BeginRun: {
0252             presentState = "beginRun transition";
0253             if (verbose)
0254               std::cerr << uniqueID << " process: start beginRun " << std::endl;
0255             if (verbose)
0256               std::cerr << uniqueID << " process: end beginRun " << std::endl;
0257 
0258             break;
0259           }
0260           case edm::Transition::BeginLuminosityBlock: {
0261             presentState = "begin lumi";
0262             if (verbose)
0263               std::cerr << uniqueID << " process: start beginLumi " << std::endl;
0264             auto randState = random_deserializer.deserialize();
0265             presentState = "deserialized random state in begin lumi";
0266             if (verbose)
0267               std::cerr << uniqueID << " random " << randState.state_.size() << " " << randState.seed_ << std::endl;
0268             randomService->setState(randState.state_, randState.seed_);
0269             presentState = "processing begin lumi";
0270             auto value = harness.getBeginLumiValue(iTransitionID);
0271             value.randomState_.state_ = randomService->getState();
0272             value.randomState_.seed_ = randomService->mySeed();
0273 
0274             presentState = "serialize lumi";
0275             bl_serializer.serialize(value);
0276             if (verbose)
0277               std::cerr << uniqueID << " process: end beginLumi " << std::endl;
0278             if (verbose)
0279               std::cerr << uniqueID << "   rand " << value.randomState_.state_.size() << " " << value.randomState_.seed_
0280                         << std::endl;
0281             break;
0282           }
0283           case edm::Transition::Event: {
0284             presentState = "begin event";
0285             if (verbose)
0286               std::cerr << uniqueID << " process: event " << counter << std::endl;
0287             presentState = "deserialized random state in event";
0288             auto randState = random_deserializer.deserialize();
0289             randomService->setState(randState.state_, randState.seed_);
0290             presentState = "processing event";
0291             auto value = harness.getEventValue();
0292             value.randomState_.state_ = randomService->getState();
0293             value.randomState_.seed_ = randomService->mySeed();
0294 
0295             if (verbose)
0296               std::cerr << uniqueID << " process: event " << counter << std::endl;
0297 
0298             presentState = "serialize event";
0299             serializer.serialize(value);
0300             if (verbose)
0301               std::cerr << uniqueID << " process: "
0302                         << " " << counter << std::endl;
0303             //usleep(10000000);
0304             break;
0305           }
0306           case edm::Transition::EndLuminosityBlock: {
0307             presentState = "begin end lumi";
0308             if (verbose)
0309               std::cerr << uniqueID << " process: start endLumi " << std::endl;
0310             presentState = "processing end lumi";
0311             auto value = harness.getEndLumiValue();
0312 
0313             presentState = "serialize end lumi";
0314             el_serializer.serialize(value);
0315             if (verbose)
0316               std::cerr << uniqueID << " process: end endLumi " << std::endl;
0317 
0318             break;
0319           }
0320           case edm::Transition::EndRun: {
0321             presentState = "begin end run";
0322             if (verbose)
0323               std::cerr << uniqueID << " process: start endRun " << std::endl;
0324             presentState = "process end run";
0325             auto value = harness.getEndRunValue();
0326 
0327             presentState = "serialize end run";
0328             er_serializer.serialize(value);
0329             if (verbose)
0330               std::cerr << uniqueID << " process: end endRun " << std::endl;
0331 
0332             break;
0333           }
0334           default: {
0335             assert(false);
0336           }
0337         }
0338         presentState = "notifying and waiting after " + presentState;
0339         if (verbose)
0340           std::cerr << uniqueID << " process: notifying and waiting " << counter << std::endl;
0341       });
0342     }
0343   } catch (std::exception const& iExcept) {
0344     std::cerr << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
0345               << s_uniqueID << " process: caught exception \n"
0346               << iExcept.what() << "\n"
0347               << "  while " << presentState << "\n"
0348               << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
0349     return 1;
0350   } catch (...) {
0351     std::cerr << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
0352               << s_uniqueID << " process: caught unknown exception\n  while " << presentState << "\n"
0353               << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
0354     return 1;
0355   }
0356   return 0;
0357 }