Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4TaskRunManager.cc
Go to the documentation of this file.
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 "G4TaskRunManager.hh"
29
30#include "G4AutoLock.hh"
31#include "G4EnvironmentUtils.hh"
33#include "G4Run.hh"
34#include "G4ScoringManager.hh"
35#include "G4StateManager.hh"
36#include "G4Task.hh"
37#include "G4TaskGroup.hh"
38#include "G4TaskManager.hh"
41#include "G4ThreadPool.hh"
42#include "G4Threading.hh"
43#include "G4Timer.hh"
45#include "G4UImanager.hh"
46#include "G4UserRunAction.hh"
48#include "G4UserTaskQueue.hh"
52#include "G4WorkerThread.hh"
53
54#include <cstdlib>
55#include <cstring>
56#include <iterator>
57
58//============================================================================//
59
60namespace
61{
62G4Mutex scorerMergerMutex;
63G4Mutex runMergerMutex;
64G4Mutex setUpEventMutex;
65} // namespace
66
67//============================================================================//
68
73
74//============================================================================//
75
77 : PTL::TaskRunManager(useTBB), eventGrainsize(grainsize)
78{
79 if (task_queue != nullptr) taskQueue = task_queue;
80
81 // override default of 2 from G4MTRunManager
83 fMasterRM = this;
84 MTkernel = static_cast<G4TaskRunManagerKernel*>(kernel);
85
86 G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
87 if (numberOfStaticAllocators > 0) {
89 msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n"
90 << "In multi-threaded mode, all G4Allocator objects must "
91 << "be dynamicly instantiated.";
92 G4Exception("G4TaskRunManager::G4TaskRunManager", "Run1035", FatalException, msg1);
93 }
94
97
98 // use default RandomNumberGenerator if created by user, or create default
99 masterRNGEngine = G4Random::getTheEngine();
100
103
104 //------------------------------------------------------------------------//
105 // handle threading
106 //------------------------------------------------------------------------//
107 auto _nthread_env = G4GetEnv<G4String>("G4FORCENUMBEROFTHREADS", "");
108 for (auto& itr : _nthread_env)
109 itr = (char)std::tolower(itr);
110
111 if (_nthread_env == "max")
113 else if (!_nthread_env.empty()) {
114 std::stringstream ss;
115 G4int _nthread_val = -1;
116 ss << _nthread_env;
117 ss >> _nthread_val;
118 if (_nthread_val > 0) forcedNwokers = _nthread_val;
119
121 }
122
123 //------------------------------------------------------------------------//
124 // option for forcing TBB
125 //------------------------------------------------------------------------//
126#ifdef GEANT4_USE_TBB
127 G4int _useTBB = G4GetEnv<G4int>("G4FORCE_TBB", (G4int)useTBB);
128 if (_useTBB > 0) useTBB = true;
129#else
130 if (useTBB) {
132 msg << "TBB was requested but Geant4 was not built with TBB support";
133 G4Exception("G4TaskRunManager::G4TaskRunManager(...)", "Run0131", JustWarning, msg);
134 }
135 useTBB = false;
136#endif
137}
138
139//============================================================================//
140
142
143//============================================================================//
144
146{
147 // terminate all the workers
149
150 // trigger all G4AutoDelete instances
151 G4ThreadLocalSingleton<void>::Clear();
152
153 // delete the task-group
154 delete workTaskGroup;
155 workTaskGroup = nullptr;
156
157 // destroy the thread-pool
158 if (threadPool != nullptr) threadPool->destroy_threadpool();
159
161}
162
163//============================================================================//
164
169
170//============================================================================//
171
173{
174 std::ostringstream os;
175 os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
176 G4Random::saveEngineStatus(os.str().c_str());
177}
178
179//============================================================================//
180
182{
183 if (forcedNwokers > 0) {
184 if (verboseLevel > 0) {
186 msg << "\n### Number of threads is forced to " << forcedNwokers
187 << " by G4FORCENUMBEROFTHREADS environment variable. G4TaskRunManager::" << __FUNCTION__
188 << "(" << n << ") ignored ###";
189 G4Exception("G4TaskRunManager::SetNumberOfThreads(G4int)", "Run0132", JustWarning, msg);
190 }
192 }
193 else {
194 nworkers = n;
195 if (poolInitialized) {
196 if (verboseLevel > 0) {
197 std::stringstream ss;
198 ss << "\n### Thread-pool already initialized. Resizing to " << nworkers << "threads ###";
199 G4cout << ss.str() << "\n" << G4endl;
200 }
201 GetThreadPool()->resize(n);
202 }
203 }
204}
205
206//============================================================================//
207
209{
210 // If the ThreadPool isn't initialized, it will return 0 even if we've already
211 // set nworkers
213}
214
215//============================================================================//
216
218{
219 G4bool firstTime = (threadPool == nullptr);
220 if (firstTime) InitializeThreadPool();
221
223
224 // make sure all worker threads are set up.
226 if (firstTime) G4RunManager::SetRunIDCounter(0);
227 // G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true);
228}
229
230//============================================================================//
231
233{
234 if (poolInitialized && (threadPool != nullptr) && (workTaskGroup != nullptr)) {
235 G4Exception("G4TaskRunManager::InitializeThreadPool", "Run1040", JustWarning,
236 "Threadpool already initialized. Ignoring...");
237 return;
238 }
239
241
242 // create the joiners
243 if (workTaskGroup == nullptr) {
245 }
246
247 if (verboseLevel > 0) {
248 std::stringstream ss;
249 ss.fill('=');
250 ss << std::setw(90) << "";
251 G4cout << "\n" << ss.str() << G4endl;
252
253 if (threadPool->is_tbb_threadpool()) {
254 G4cout << "G4TaskRunManager :: Using TBB..." << G4endl;
255 }
256 else {
257 G4cout << "G4TaskRunManager :: Using G4ThreadPool..." << G4endl;
258 }
259
260 G4cout << ss.str() << "\n" << G4endl;
261 }
262}
263
264//============================================================================//
265
267{
268 // Nothing to do
269}
270
271//============================================================================//
272
274{
275 // Nothing to do
276}
277
278//============================================================================//
279
281{
282 G4int grainSize = (eventGrainsize == 0) ? (G4int)threadPool->size() : eventGrainsize;
283 grainSize = G4GetEnv<G4int>("G4FORCE_GRAINSIZE", grainSize, "Forcing grainsize...");
284 if (grainSize == 0) grainSize = 1;
285
286 G4int nEvtsPerTask =
287 (numberOfEventToBeProcessed > grainSize) ? (numberOfEventToBeProcessed / grainSize) : 1;
288
289 if (eventModuloDef > 0) {
291 }
292 else {
294 if (eventModulo < 1) eventModulo = 1;
295 }
296 if (eventModulo > nEvtsPerTask) {
297 G4int oldMod = eventModulo;
298 eventModulo = nEvtsPerTask;
299
301 msgd << "Event modulo is reduced to " << eventModulo << " (was " << oldMod << ")"
302 << " to distribute events to all threads.";
303 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10035", JustWarning, msgd);
304 }
305 nEvtsPerTask = eventModulo;
306
307 if (fakeRun)
308 nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask,
309 "Forcing number of events per task (overrides grainsize)...");
310 else
311 nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask);
312
313 if (nEvtsPerTask < 1) nEvtsPerTask = 1;
314
316 numberOfEventsPerTask = nEvtsPerTask;
318
319 if (fakeRun && verboseLevel > 2) {
320 std::stringstream msg;
321 msg << "--> G4TaskRunManager::ComputeNumberOfTasks() --> " << numberOfTasks << " tasks with "
322 << numberOfEventsPerTask << " events/task...";
323
324 std::stringstream ss;
325 ss.fill('=');
326 ss << std::setw((G4int)msg.str().length()) << "";
327 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
328 }
329}
330
331//============================================================================//
332
334{
335 // Now loop on requested number of workers
336 // This will also start the workers
337 // Currently we do not allow to change the
338 // number of threads: threads area created once
339 // Instead of pthread based workers, create tbbTask
340 static bool initializeStarted = false;
341
343
344 if (fakeRun) {
345 if (initializeStarted) {
346 auto initCmdStack = GetCommandStack();
347 if (!initCmdStack.empty()) {
348 threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() {
349 for (auto& itr : cmds)
352 });
353 }
354 }
355 else {
356 if (verboseLevel > 0) {
357 std::stringstream msg;
358 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
359 << "Initializing workers...";
360
361 std::stringstream ss;
362 ss.fill('=');
363 ss << std::setw((G4int)msg.str().length()) << "";
364 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
365 }
366
368 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::InitializeWorker(); });
369 }
370 initializeStarted = true;
371 }
372 else {
373 auto initCmdStack = GetCommandStack();
374 if (!initCmdStack.empty()) {
375 threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() {
376 for (auto& itr : cmds)
378 });
379 }
380
381 // cleans up a previous run and events in case a thread
382 // does not execute any tasks
383 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::ExecuteWorkerInit(); });
384
385 if (verboseLevel > 0) {
386 std::stringstream msg;
387 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
388 << "Creating " << numberOfTasks << " tasks with " << numberOfEventsPerTask
389 << " events/task...";
390
391 std::stringstream ss;
392 ss.fill('=');
393 ss << std::setw((G4int)msg.str().length()) << "";
394 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
395 }
396
398 for (G4int nt = 0; nt < numberOfTasks + 1; ++nt) {
399 if (remaining > 0) AddEventTask(nt);
400 remaining -= numberOfEventsPerTask;
401 }
402 workTaskGroup->wait();
403 }
404}
405
406//============================================================================//
407
409{
410 if (verboseLevel > 3) G4cout << "Adding task " << nt << " to task-group..." << G4endl;
411 workTaskGroup->exec([this, nt]() {
412 if (verboseLevel > 3) G4cout << "Starting task " << nt << "..." << G4endl;
414 });
415}
416
417//============================================================================//
418
420{
422 G4int nFill = 0;
423 switch (SeedOncePerCommunication()) {
424 case 0:
426 break;
427 case 1:
428 nFill = numberOfTasks - nSeedsFilled;
429 break;
430 case 2:
431 default:
433 }
434 // Generates up to nSeedsMax seed pairs only.
435 if (nFill > nSeedsMax) nFill = nSeedsMax;
436 masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl);
437 helper->Refill(randDbl, nFill);
438 nSeedsFilled += nFill;
439}
440
441//============================================================================//
442
443void G4TaskRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select)
444{
445 MTkernel->SetUpDecayChannels();
448
449 if (!fakeRun) {
450 nSeedsUsed = 0;
451 nSeedsFilled = 0;
452
453 if (verboseLevel > 0) timer->Start();
454
455 n_select_msg = n_select;
456 if (macroFile != nullptr) {
457 if (n_select_msg < 0) n_select_msg = n_event;
458
459 msgText = "/control/execute ";
460 msgText += macroFile;
461 selectMacro = macroFile;
462 }
463 else {
464 n_select_msg = -1;
465 selectMacro = "";
466 }
467
469
470 // initialize seeds
471 // If user did not implement InitializeSeeds,
472 // use default: nSeedsPerEvent seeds per event
473
474 if (n_event > 0) {
475 G4bool _overload = InitializeSeeds(n_event);
476 G4bool _functor = false;
477 if (!_overload) _functor = initSeedsCallback(n_event, nSeedsPerEvent, nSeedsFilled);
478 if (!_overload && !_functor) {
480 switch (SeedOncePerCommunication()) {
481 case 0:
482 nSeedsFilled = n_event;
483 break;
484 case 1:
486 break;
487 case 2:
488 nSeedsFilled = n_event / eventModulo + 1;
489 break;
490 default:
492 msgd << "Parameter value <" << SeedOncePerCommunication()
493 << "> of seedOncePerCommunication is invalid. It is reset "
494 "to 0.";
495 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd);
497 nSeedsFilled = n_event;
498 }
499
500 // Generates up to nSeedsMax seed pairs only.
503 helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent);
504 }
505 }
506 }
507
508 // Now initialize workers. Check if user defined a WorkerThreadInitialization
509 if (userWorkerThreadInitialization == nullptr)
511
512 // Prepare UI commands for threads
514
515 // Start worker threads
517}
518
519//============================================================================//
520
522{
523 // Wait for all worker threads to have finished the run
524 // i.e. wait for them to return from RunTermination()
525 // This guarantee that userrunaction for workers has been called
526
527 // Wait now for all threads to finish event-loop
529 // Now call base-class methof
532}
533
534//============================================================================//
535
537{
539 // Call base class stuff...
541
542 GetMasterWorlds().clear();
543 auto nWorlds = (G4int)G4TransportationManager::GetTransportationManager()->GetNoWorlds();
545 for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) {
546 addWorld(iWorld, *itrW);
547 ++itrW;
548 }
549}
550
551//============================================================================//
552
553void G4TaskRunManager::MergeScores(const G4ScoringManager* localScoringManager)
554{
555 G4AutoLock l(&scorerMergerMutex);
556 if (masterScM != nullptr) masterScM->Merge(localScoringManager);
557}
558
559//============================================================================//
560
562{
563 G4AutoLock l(&runMergerMutex);
564 if (currentRun != nullptr) currentRun->Merge(localRun);
565}
566
567//============================================================================//
568
570 G4bool reseedRequired)
571{
572 G4AutoLock l(&setUpEventMutex);
575 if (reseedRequired) {
577 G4int idx_rndm = nSeedsPerEvent * nSeedsUsed;
578 s1 = helper->GetSeed(idx_rndm);
579 s2 = helper->GetSeed(idx_rndm + 1);
580 if (nSeedsPerEvent == 3) s3 = helper->GetSeed(idx_rndm + 2);
581 ++nSeedsUsed;
583 }
585 return true;
586 }
587 return false;
588}
589
590//============================================================================//
591
593{
594 G4AutoLock l(&setUpEventMutex);
597 G4int nmod = eventModulo;
601 }
603
604 if (reseedRequired) {
606 G4int nevRnd = nmod;
607 if (SeedOncePerCommunication() > 0) nevRnd = 1;
608 for (G4int i = 0; i < nevRnd; ++i) {
609 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed));
610 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1));
611 if (nSeedsPerEvent == 3) seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2));
612 nSeedsUsed++;
614 }
615 }
617 return nevt;
618 }
619 return 0;
620}
621
622//============================================================================//
623
625{
626 // Force workers to execute (if any) all UI commands left in the stack
628
629 if (workTaskGroup != nullptr) {
630 workTaskGroup->join();
631 if (!fakeRun)
632 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::TerminateWorker(); });
633 }
634}
635
636//============================================================================//
637
639{
640 // This method is valid only for GeomClosed or EventProc state
642 if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) {
643 runAborted = true;
644 MTkernel->BroadcastAbortRun(softAbort);
645 }
646 else {
647 G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
648 }
649}
650
651//============================================================================//
652
654{
655 // nothing to do in the master thread
656}
657
658//============================================================================//
659
661{
662 if (workTaskGroup != nullptr) {
663 workTaskGroup->join();
664 if (!fakeRun)
665 threadPool->execute_on_all_threads(
667 }
668}
669
670//============================================================================//
671
673{
675
676 auto process_commands_stack = []() {
678 if (mrm != nullptr) {
679 auto cmds = mrm->GetCommandStack();
680 for (const auto& itr : cmds)
681 G4UImanager::GetUIpointer()->ApplyCommand(itr); // TLS instance
683 }
684 };
685
686 if (threadPool != nullptr) threadPool->execute_on_all_threads(process_commands_stack);
687}
688
689//============================================================================//
690
692
693//============================================================================//
G4ApplicationState
@ G4State_EventProc
@ G4State_GeomClosed
G4TemplateAutoLock< G4Mutex > G4AutoLock
_Tp G4GetEnv(const std::string &env_id, _Tp _default=_Tp())
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
std::queue< G4long > G4SeedsQueue
G4TemplateRNGHelper< G4long > G4RNGHelper
G4Thread::id G4ThreadId
std::mutex G4Mutex
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
PTL::VUserTaskQueue G4VUserTaskQueue
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
void SetEventID(G4int i)
Definition G4Event.hh:81
static G4int SeedOncePerCommunication()
static void SetSeedOncePerCommunication(G4int val)
G4int numberOfEventToBeProcessed
virtual void ThisWorkerProcessCommandsStackDone()
static void addWorld(G4int counter, G4VPhysicalVolume *w)
virtual void PrepareCommandsStack()
static G4MTRUN_DLL G4ScoringManager * masterScM
static G4MTRUN_DLL G4MTRunManager * fMasterRM
static G4MTRunManager * GetMasterRunManager()
static G4ThreadId GetMasterThreadId()
static masterWorlds_t & GetMasterWorlds()
std::vector< G4String > GetCommandStack()
virtual void Initialize()
G4Timer * timer
void SetRunIDCounter(G4int i)
G4UserWorkerThreadInitialization * userWorkerThreadInitialization
G4int numberOfEventProcessed
G4RunManagerKernel * kernel
G4Run * currentRun
G4String msgText
virtual void BeamOn(G4int n_event, const char *macroFile=nullptr, G4int n_select=-1)
G4String selectMacro
virtual void RunTermination()
G4String randomNumberStatusDir
virtual void TerminateEventLoop()
virtual void ConstructScoringWorlds()
Definition G4Run.hh:48
static G4ScoringManager * GetScoringManagerIfExist()
const G4ApplicationState & GetCurrentState() const
static G4StateManager * GetStateManager()
static std::vector< G4String > & InitCommandStack()
G4int GetNumberOfThreads() const override
void ConstructScoringWorlds() override
void InitializeThreadPool() override
void CreateAndStartWorkers() override
G4bool InitializeSeeds(G4int) override
static G4TaskRunManager * GetMasterRunManager()
void ThisWorkerProcessCommandsStackDone() override
void MergeRun(const G4Run *localRun) override
G4int SetUpNEvents(G4Event *, G4SeedsQueue *seedsQueue, G4bool reseedRequired=true) override
G4VUserTaskQueue *& taskQueue
void SetNumberOfThreads(G4int n) override
void AbortRun(G4bool softAbort=false) override
InitializeSeedsCallback initSeedsCallback
void RefillSeeds() override
void RequestWorkersProcessCommandsStack() override
virtual void AddEventTask(G4int)
static G4ThreadId GetMasterThreadId()
void TerminateOneEvent() override
RunTaskGroup * workTaskGroup
CLHEP::HepRandomEngine * masterRNGEngine
void TerminateWorkers() override
void AbortEvent() override
~G4TaskRunManager() override
void InitializeEventLoop(G4int n_event, const char *macroFile=nullptr, G4int n_select=-1) override
void Initialize() override
void MergeScores(const G4ScoringManager *localScoringManager) override
void StoreRNGStatus(const G4String &filenamePrefix) override
G4TaskRunManagerKernel * MTkernel
void RunTermination() override
void WaitForEndEventLoopWorkers() override
G4TaskGroup< void > RunTaskGroup
G4ThreadPool *& threadPool
static G4TaskRunManagerKernel * GetMTMasterRunManagerKernel()
void ProcessOneEvent(G4int i_event) override
virtual void ComputeNumberOfTasks()
G4TaskRunManager(G4bool useTBB=G4GetEnv< G4bool >("G4USE_TBB", false))
G4bool SetUpAnEvent(G4Event *, G4long &s1, G4long &s2, G4long &s3, G4bool reseedRequired=true) override
static G4TemplateRNGHelper< G4long > * GetInstance()
virtual const T GetSeed(const G4int &sdId)
void Fill(G4double *dbl, G4int nev, G4int nev_tot, G4int nrpe)
void Refill(G4double *dbl, G4int nev)
static G4TransportationManager * GetTransportationManager()
std::vector< G4VPhysicalVolume * >::iterator GetWorldsIterator()
G4int ApplyCommand(const char *aCommand)
void SetMasterUIManager(G4bool val)
static G4UImanager * GetUIpointer()
static G4WorkerTaskRunManager * GetWorkerRunManager()
virtual void Terminate()
virtual int GetNumberOfThreads() const
TaskRunManager(bool useTBB=false)
virtual void Initialize(uint64_t n=std::thread::hardware_concurrency())
ThreadPool * GetThreadPool() const
void resize(size_type _n)
G4int G4GetNumberOfCores()
Backports of C++ language features for use with C++11 compilers.
Definition AutoLock.hh:255