ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4MTRunManager.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4MTRunManager.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 
28 #include "G4MTRunManager.hh"
29 #include "G4MTRunManagerKernel.hh"
30 #include "G4Timer.hh"
31 #include "G4StateManager.hh"
32 #include "G4ScoringManager.hh"
37 #include "G4WorkerThread.hh"
38 #include "G4Run.hh"
39 #include "G4UImanager.hh"
40 #include "G4AutoLock.hh"
41 #include "G4WorkerRunManager.hh"
42 #include "G4UserRunAction.hh"
43 #include "G4ProductionCutsTable.hh"
44 #include "G4Timer.hh"
45 #include "G4TiMemory.hh"
46 
51 
52 namespace {
53  G4Mutex cmdHandlingMutex = G4MUTEX_INITIALIZER;
54  G4Mutex scorerMergerMutex = G4MUTEX_INITIALIZER;
55  G4Mutex runMergerMutex = G4MUTEX_INITIALIZER;
56  G4Mutex setUpEventMutex = G4MUTEX_INITIALIZER;
57 }
58 
60 {
62  return fMasterRM;
66 }
67 
69 {
70  return fMasterRM->kernel;
71 }
72 
74 {
75  return fMasterRM->MTkernel;
76 }
77 
79  nworkers(2),forcedNwokers(-1),pinAffinity(0),
80  masterRNGEngine(0),
81  nextActionRequest(WorkerActionRequest::UNDEFINED),
82  eventModuloDef(0),eventModulo(1),
83  nSeedsUsed(0),nSeedsFilled(0),
84  nSeedsMax(10000),nSeedsPerEvent(2)
85 {
86  if ( fMasterRM )
87  {
88  G4Exception("G4MTRunManager::G4MTRunManager", "Run0110",FatalException,
89  "Another instance of a G4MTRunManager already exists.");
90  }
91  fMasterRM = this;
92  MTkernel = static_cast<G4MTRunManagerKernel*>(kernel);
93 #ifndef G4MULTITHREADED
95  msg << "Geant4 code is compiled without multi-threading support"
96  << "(-DG4MULTITHREADED is set to off).\n";
97  msg << "G4MTRunManager can only be used in multi-threaded applications.";
98  G4Exception("G4MTRunManager::G4MTRunManager","Run0111",FatalException,msg);
99 #endif
100 
101  G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
102  if(numberOfStaticAllocators>0)
103  {
105  msg1 << "There are " << numberOfStaticAllocators
106  << " static G4Allocator objects detected.\n"
107  << "In multi-threaded mode, all G4Allocator objects must be dynamicly instantiated.";
108  G4Exception("G4MTRunManager::G4MTRunManager","Run1035",FatalException,msg1);
109  }
112 
113  //Check if a default RandomNumberGenerator has been created by user,
114  // if not create default one
115  //Note this call forces creation of defaults if not already there
116  //G4Random::getTheEngine(); //User did not specify RNG, create defaults
117  //Now remember the master instance of the RNG Engine
118  masterRNGEngine = G4Random::getTheEngine();
119 
121  randDbl = new double[nSeedsPerEvent*nSeedsMax];
122 
123  char* env = std::getenv("G4FORCENUMBEROFTHREADS");
124  if(env)
125  {
126  G4String envS = env;
127  if(envS=="MAX"||envS=="max")
129  else
130  {
131  std::istringstream is(env);
132  G4int val = -1;
133  is >> val;
134  if(val>0)
135  { forcedNwokers = val; }
136  else
137  {
139  msg2 << "Environment variable G4FORCENUMBEROFTHREADS has an invalid value <"
140  << envS << ">. It has to be an integer or a word \"max\".\n"
141  << "G4FORCENUMBEROFTHREADS is ignored.";
142  G4Exception("G4MTRunManager::G4MTRunManager","Run1039",JustWarning,msg2);
143  }
144  }
145  if(forcedNwokers>0)
146  {
148  G4cout << "### Number of threads is forced to " << forcedNwokers
149  << " by Environment variable G4FORCENUMBEROFTHREADS." << G4endl;
150  }
151  }
152 }
153 
155 {
156  //TODO: Currently does not work due to concurrent deletion of something
157  // that is shared:
158  //G4ProcessTable::DeleteMessenger from ~G4RunManager
159  //G4cout<<"Destroy MTRunManager"<<G4endl;//ANDREA
161  delete [] randDbl;
162 }
163 
165 {
166  std::ostringstream os;
167  os << randomNumberStatusDir << "G4Master_"<<fn <<".rndm";
168  G4Random::saveEngineStatus(os.str().c_str());
169 }
170 
172 {
173  G4int runNumber = 0;
174  if(currentRun) runNumber = currentRun->GetRunID();
176  {
177  G4cerr << "Warning from G4RunManager::rndmSaveThisRun():"
178  << " Random number status was not stored prior to this run."
179  << G4endl << "/random/setSavingFlag command must be issued. "
180  << "Command ignored." << G4endl;
181  return;
182  }
183 
184  G4String fileIn = randomNumberStatusDir + "G4Worker_currentRun.rndm";
185 
186  std::ostringstream os;
187  os << "run" << runNumber << ".rndm" << '\0';
188  G4String fileOut = randomNumberStatusDir + os.str();
189 #ifdef WIN32
190  G4String copCmd = "/control/shell copy " + fileIn + " " + fileOut;
191 #else
192  G4String copCmd = "/control/shell cp " + fileIn + " " + fileOut;
193 #endif
195  if(verboseLevel > 0)
196  { G4cout << fileIn << " is copied to " << fileOut << G4endl; }
197 }
198 
200 {
201  G4Exception("G4MTRunManager::rndmSaveThisEvent","RUN_RNDM001",
202  FatalException,"This method shall not be invoked !!");
203 }
204 
206 {
207  if ( threads.size() != 0 )
208  {
210  msg << "Number of threads cannot be changed at this moment \n"
211  << "(old threads are still alive). Method ignored.";
212  G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)",
213  "Run0112", JustWarning, msg);
214  }
215  else if ( forcedNwokers > 0 )
216  {
218  msg << "Number of threads is forced to " << forcedNwokers
219  << " by G4FORCENUMBEROFTHREADS shell variable.\n"
220  << "Method ignored.";
221  G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)",
222  "Run0113", JustWarning, msg);
223  }
224  else
225  {
226  nworkers = n;
227  }
228 }
229 
231 {
233 
234  // make sure all worker threads are set up.
235  BeamOn(0);
236  SetRunIDCounter(0);
238 }
239 
245 {
246  //Nothing to do
247 }
249 {
250  //Nothing to do
251 }
252 
254  G4AutoLock l(&cmdHandlingMutex);
255  uiCmdsForWorkers.clear();
256  std::vector<G4String>* cmdCopy = G4UImanager::GetUIpointer()->GetCommandStack();
257  for ( std::vector<G4String>::const_iterator it = cmdCopy->begin() ;
258  it != cmdCopy->end(); ++it )
259  uiCmdsForWorkers.push_back(*it);
260  cmdCopy->clear();
261  delete cmdCopy;
262 }
263 
264 std::vector<G4String> G4MTRunManager::GetCommandStack()
265 {
266  G4AutoLock l(&cmdHandlingMutex);
267  return uiCmdsForWorkers;
268 }
269 
271 {
272  //Now loop on requested number of workers
273  //This will also start the workers
274  //Currently we do not allow to change the
275  //number of threads: threads area created once
276  if ( threads.size() == 0 ) {
277  for ( G4int nw = 0 ; nw<nworkers; ++nw) {
278  //Create a new worker and remember it
280  context->SetNumberThreads(nworkers);
281  context->SetThreadId(nw);
283  threads.push_back(thread);
284  }
285  }
286  //Signal to threads they can start a new run
287  NewActionRequest(WorkerActionRequest::NEXTITERATION);
288 }
289 
290 
291 void G4MTRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select)
292 {
295  numberOfEventToBeProcessed = n_event;
297 
298  if(!fakeRun)
299  {
300  nSeedsUsed = 0;
301  nSeedsFilled = 0;
302 
303  if(verboseLevel>0)
304  { timer->Start(); }
305 
306  n_select_msg = n_select;
307  if(macroFile!=0)
308  {
309  if(n_select_msg<0) n_select_msg = n_event;
310  msgText = "/control/execute ";
311  msgText += macroFile;
312  selectMacro = macroFile;
313  }
314  else
315  {
316  n_select_msg = -1;
317  selectMacro = "";
318  }
319 
320  //initialize seeds
321  //If user did not implement InitializeSeeds,
322  // use default: nSeedsPerEvent seeds per event
323  if( eventModuloDef > 0 )
324  {
327  {
329  if(eventModulo<1) eventModulo =1;
331  msgd << "Event modulo is reduced to " << eventModulo
332  << " to distribute events to all threads.";
333  G4Exception("G4MTRunManager::InitializeEventLoop()",
334  "Run10035", JustWarning, msgd);
335  }
336  }
337  else
338  {
339  eventModulo = int(std::sqrt(double(numberOfEventToBeProcessed/nworkers)));
340  if(eventModulo<1) eventModulo =1;
341  }
342  if ( InitializeSeeds(n_event) == false && n_event>0 )
343  {
346  {
347  case 0:
348  nSeedsFilled = n_event;
349  break;
350  case 1:
352  break;
353  case 2:
354  nSeedsFilled = n_event/eventModulo + 1;
355  break;
356  default:
358  msgd << "Parameter value <" << seedOncePerCommunication
359  << "> of seedOncePerCommunication is invalid. It is reset to 0." ;
360  G4Exception("G4MTRunManager::InitializeEventLoop()",
361  "Run10036", JustWarning, msgd);
362  seedOncePerCommunication = 0;
363  nSeedsFilled = n_event;
364  }
365 
366  // Generates up to nSeedsMax seed pairs only.
369  helper->Fill(randDbl,nSeedsFilled,n_event,nSeedsPerEvent);
370  }
371  }
372 
373  //Now initialize workers. Check if user defined a WorkerThreadInitialization
376 
377  //Prepare UI commands for threads
379 
380  //Start worker threads
382 
383  // We need a barrier here. Wait for workers to start event loop.
384  //This will return only when all workers have started processing events.
386 }
387 
389 {
391  G4int nFill = 0;
393  {
394  case 0:
396  break;
397  case 1:
398  nFill = nworkers - nSeedsFilled;
399  break;
400  case 2:
401  default:
402  nFill = (numberOfEventToBeProcessed - nSeedsFilled*eventModulo)/eventModulo + 1;
403  }
404  // Generates up to nSeedsMax seed pairs only.
405  if(nFill>nSeedsMax) nFill=nSeedsMax;
407  helper->Refill(randDbl,nFill);
408  nSeedsFilled += nFill;
409 //G4cout<<"helper->Refill() for "<<nFill<<" events."<<G4endl;
410 }
411 
413 {
414  //Wait for all worker threads to have finished the run
415  //i.e. wait for them to return from RunTermination()
416  //This guarantee that userrunaction for workers has been called
417 
418  // Wait now for all threads to finish event-loop
420  //Now call base-class methof
423 }
424 
426 {
428  //Call base class stuff...
430 
431  masterWorlds.clear();
433  std::vector<G4VPhysicalVolume*>::iterator itrW
435  for(size_t iWorld=0;iWorld<nWorlds;iWorld++)
436  {
437  addWorld(iWorld,*itrW);
438  itrW++;
439  }
440 }
441 
443 {
444  userWorkerInitialization = userInit;
445 }
446 
448 {
450 }
451 
453 {
454  userActionInitialization = userInit;
456 }
457 
459 {
461  //Needed for MT, to be moved in kernel
462 }
463 
465 {
467 }
468 
470 {
471  G4RunManager::SetUserAction(userAction);
472  if(userAction) userAction->SetMaster();
473 }
474 
476 {
477  G4Exception("G4MTRunManager::SetUserAction()", "Run0123", FatalException,
478  "For multi-threaded version, define G4VUserPrimaryGeneratorAction in G4VUserActionInitialization.");
479 }
480 
482 {
483  G4Exception("G4MTRunManager::SetUserAction()", "Run0124", FatalException,
484  "For multi-threaded version, define G4UserEventAction in G4VUserActionInitialization.");
485 }
486 
488 {
489  G4Exception("G4MTRunManager::SetUserAction()", "Run0125", FatalException,
490  "For multi-threaded version, define G4UserStackingAction in G4VUserActionInitialization.");
491 }
492 
494 {
495  G4Exception("G4MTRunManager::SetUserAction()", "Run0126", FatalException,
496  "For multi-threaded version, define G4UserTrackingAction in G4VUserActionInitialization.");
497 }
498 
500 {
501  G4Exception("G4MTRunManager::SetUserAction()", "Run0127", FatalException,
502  "For multi-threaded version, define G4UserSteppingAction in G4VUserActionInitialization.");
503 }
504 
505 void G4MTRunManager::MergeScores(const G4ScoringManager* localScoringManager)
506 {
507  G4AutoLock l(&scorerMergerMutex);
508  if(masterScM) masterScM->Merge(localScoringManager);
509 }
510 
511 void G4MTRunManager::MergeRun(const G4Run* localRun)
512 {
513  G4AutoLock l(&runMergerMutex);
514  if(currentRun) currentRun->Merge(localRun);
515 }
516 
517 G4bool G4MTRunManager::SetUpAnEvent(G4Event* evt,long& s1,long& s2,long& s3,G4bool reseedRequired)
518 {
519  G4AutoLock l(&setUpEventMutex);
521  {
523  if(reseedRequired)
524  {
526  G4int idx_rndm = nSeedsPerEvent*nSeedsUsed;
527  s1 = helper->GetSeed(idx_rndm);
528  s2 = helper->GetSeed(idx_rndm+1);
529  if(nSeedsPerEvent==3) s3 = helper->GetSeed(idx_rndm+2);
530  nSeedsUsed++;
531  if(nSeedsUsed==nSeedsFilled) RefillSeeds();
532  }
534  return true;
535  }
536  return false;
537 }
538 
540 {
541  G4AutoLock l(&setUpEventMutex);
543  {
544  G4int nev = eventModulo;
548  if(reseedRequired)
549  {
551  G4int nevRnd = nev;
552  if(seedOncePerCommunication>0) nevRnd = 1;
553  for(int i=0;i<nevRnd;i++)
554  {
555  seedsQueue->push(helper->GetSeed(nSeedsPerEvent*nSeedsUsed));
556  seedsQueue->push(helper->GetSeed(nSeedsPerEvent*nSeedsUsed+1));
557  if(nSeedsPerEvent==3)
558  seedsQueue->push(helper->GetSeed(nSeedsPerEvent*nSeedsUsed+2));
559  nSeedsUsed++;
560  if(nSeedsUsed==nSeedsFilled) RefillSeeds();
561  }
562  }
563  numberOfEventProcessed += nev;
564  return nev;
565  }
566  return 0;
567 }
568 
570 {
571  //Force workers to execute (if any) all UI commands left in the stack
573  //Ask workers to exit
574  NewActionRequest( WorkerActionRequest::ENDWORKER );
575  //Now join threads.
576 #ifdef G4MULTITHREADED //protect here to prevent warning in compilation
577  while ( ! threads.empty() )
578  {
579  G4Thread* t = * ( threads.begin() );
580  threads.pop_front();
582  //G4THREADJOIN(*t);
583  delete t;
584  }
585 #endif
586  threads.clear();
587 }
588 
590 {
591  // This method is valid only for GeomClosed or EventProc state
592  G4ApplicationState currentState =
594  if(currentState==G4State_GeomClosed || currentState==G4State_EventProc)
595  {
596  runAborted = true;
597  MTkernel->BroadcastAbortRun(softAbort);
598  }
599  else
600  {
601  G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
602  }
603 }
604 
606 {
607  // nothing to do in the master thread
608 }
609 
614 }
615 
618 }
619 
624 }
625 
628 }
629 
632  //nextActionRequest is a shared resource, but there is no
633  //data-race thanks to the barrier: all threads are waiting
634  nextActionRequest = newRequest;
636 }
637 
640  return nextActionRequest;
641 }
642 
645  NewActionRequest(WorkerActionRequest::PROCESSUI);
648 }
649 
652 }
654 {
655  if ( n == 0 )
656  {
657  G4Exception("G4MTRunManager::SetPinAffinity",
658  "Run0114",FatalException,
659  "Pin affinity must be >0 or <0.");
660  }
661  pinAffinity = n;
662  return;
663 }