Skip to content

Commit 6282df2

Browse files
authored
Merge branch 'AliceO2Group:dev' into new_new_geometry
2 parents 784bf5a + c985746 commit 6282df2

102 files changed

Lines changed: 3790 additions & 617 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CCDB/src/CcdbApi.cxx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,8 @@ void* CcdbApi::extractFromTFile(TFile& file, TClass const* cl, const char* what)
10081008
auto result = object;
10091009
// We need to handle some specific cases as ROOT ties them deeply
10101010
// to the file they are contained in
1011-
if (cl->InheritsFrom("TObject")) {
1011+
// IsTObject avoids InheritsFrom, which makes cling instantiate STL collection classes
1012+
if (cl->IsTObject()) {
10121013
// make a clone
10131014
// detach from the file
10141015
auto tree = dynamic_cast<TTree*>((TObject*)object);

‎Common/Utils/include/CommonUtils/ShmManager.h‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <list>
2323
#include <cstddef>
2424
#include <atomic>
25+
#include <mutex>
2526

2627
#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__)
2728
#include <boost/interprocess/managed_external_buffer.hpp>
@@ -70,7 +71,8 @@ class ShmManager
7071

7172
// create the local segment
7273
// this will occupy a subregion of an already created global shared mem segment
73-
void occupySegment();
74+
// (all of it for the single process of multithreaded Geant4, whose threads share it)
75+
void occupySegment(bool wholeRegion = false);
7476

7577
// simply attaches to the global segment
7678
bool attachToGlobalSegment();
@@ -88,7 +90,7 @@ class ShmManager
8890
// returns if pointer is part of the shm region under control of this manager
8991
bool isPointerOk(void* ptr) const
9092
{
91-
return mBufferPtr && getPointerOffset(ptr) < SHMPOOLSIZE;
93+
return mBufferPtr && getPointerOffset(ptr) < mPoolSize;
9294
}
9395

9496
// returns if shared mem setup is correctly setup/operational
@@ -114,6 +116,8 @@ class ShmManager
114116
ShmMetaInfo* mSegInfoPtr = nullptr; // pointing to the meta information object
115117
bool mIsMaster = false; // true if the manager who allocated the region
116118
bool mIsOperational = false;
119+
size_t mPoolSize = SHMPOOLSIZE; // size of the region occupied by this process
120+
std::mutex mAllocMutex; // the boost buffer has no locking of its own; threads of multithreaded Geant4 share it
117121
// helper function
118122
void* tryAttach(bool& success);
119123
size_t getPointerOffset(void* ptr) const { return (size_t)((char*)ptr - (char*)mBufferPtr); }

‎Common/Utils/src/ShmManager.cxx‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ bool ShmManager::attachToGlobalSegment()
178178
return b;
179179
}
180180

181-
void ShmManager::occupySegment()
181+
void ShmManager::occupySegment(bool wholeRegion)
182182
{
183183
LOG(info) << "OCCUPYING A SEGMENT IN A SHARED REGION";
184184
// get information about the global shared mem in which to occupy a region
@@ -197,15 +197,17 @@ void ShmManager::occupySegment()
197197
if (b) {
198198
// read meta information in the segment to determine the id of this segment
199199
auto info = static_cast<o2::utils::ShmMetaInfo*>(addr);
200-
const int segmentcounter = info->counter.fetch_add(1);
200+
const int npools = wholeRegion ? (info->allocedbytes - sizeof(ShmMetaInfo)) / SHMPOOLSIZE : 1;
201+
const int segmentcounter = info->counter.fetch_add(npools);
201202
LOG(info) << "SEGMENTCOUNT " << segmentcounter;
202203

203204
const auto offset_in_bytes = sizeof(ShmMetaInfo) + segmentcounter * SHMPOOLSIZE;
204205
mBufferPtr = (void*)(((char*)addr) + offset_in_bytes);
206+
mPoolSize = npools * SHMPOOLSIZE;
205207

206-
assert((unsigned long long)((char*)mBufferPtr - (char*)addr) + SHMPOOLSIZE <= info->allocedbytes);
208+
assert((unsigned long long)((char*)mBufferPtr - (char*)addr) + mPoolSize <= info->allocedbytes);
207209

208-
boostmanagedbuffer = new boost::interprocess::wmanaged_external_buffer(create_only, mBufferPtr, SHMPOOLSIZE);
210+
boostmanagedbuffer = new boost::interprocess::wmanaged_external_buffer(create_only, mBufferPtr, mPoolSize);
209211
boostallocator = new boost::interprocess::allocator<char, wmanaged_external_buffer::segment_manager>(
210212
boostmanagedbuffer->get_segment_manager());
211213

@@ -225,6 +227,7 @@ ShmManager::~ShmManager()
225227
void* ShmManager::getmemblock(size_t size)
226228
{
227229
void* addr = nullptr;
230+
std::lock_guard<std::mutex> lock(mAllocMutex);
228231
try {
229232
addr = (void*)boostallocator->allocate(size).get();
230233
} catch (const std::exception& e) {
@@ -235,6 +238,7 @@ void* ShmManager::getmemblock(size_t size)
235238

236239
void ShmManager::freememblock(void* ptr, size_t s)
237240
{
241+
std::lock_guard<std::mutex> lock(mAllocMutex);
238242
boostallocator->deallocate((char*)ptr, s);
239243
}
240244

‎Detectors/3rdparty/FairRootBase/include/FairMCApplication.h‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ enum class FairMCApplicationState
5757
* @since 12.01.04
5858
*/
5959

60+
class FairModule;
6061
class FairMCApplication : public TVirtualMCApplication
6162
{
6263
public:
@@ -304,16 +305,24 @@ class FairMCApplication : public TVirtualMCApplication
304305

305306
ClassDef(FairMCApplication, 4);
306307

307-
private:
308-
/** Protected copy constructor */
308+
protected:
309+
/** Copy constructor, used to create the application of a worker thread */
309310
FairMCApplication(const FairMCApplication&);
311+
312+
private:
310313
/** Protected assignment operator */
311314
FairMCApplication& operator=(const FairMCApplication&);
312315

313316
FairRunInfo fRunInfo; //!
314317
Bool_t fGeometryIsInitialized;
315318

316319
static FairMCApplication* fgMasterInstance;
320+
321+
protected:
322+
/** True for the application on the master thread, false for a worker clone */
323+
Bool_t IsMasterApplication() const { return !fgMasterInstance || fgMasterInstance == this; }
324+
/** The worker clone of a module of the master application (the module itself on the master) */
325+
FairModule* OwnModule(FairModule* module) const;
317326
};
318327

319328
// inline functions

‎Detectors/3rdparty/FairRootBase/include/FairModule.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ class FairModule : public TNamed
159159
Bool_t fGeoSaved; //! flag for initialisation
160160
TVirtualMC* fMC; //! cahed pointer to MC (available only after initialization)
161161

162+
public:
163+
/** Sets the cached MC, for a module cloned for a worker thread before its MC existed */
164+
void SetMC(TVirtualMC* mc) { fMC = mc; }
165+
162166
ClassDef(FairModule, 4);
163167
};
164168

‎Detectors/3rdparty/FairRootBase/src/FairMCApplication.cxx‎

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,20 @@ TVirtualMCApplication* FairMCApplication::CloneForWorker() const
613613
return workerApplication;
614614
}
615615

616+
//_____________________________________________________________________________
617+
FairModule* FairMCApplication::OwnModule(FairModule* module) const
618+
{
619+
// the worker's clone of a module, found by name
620+
if (!module || IsMasterApplication() || fModules->IndexOf(module) >= 0) {
621+
return module;
622+
}
623+
auto clone = static_cast<FairModule*>(fModules->FindObject(module->GetName()));
624+
if (!clone) {
625+
LOG(fatal) << "FairMCApplication: no worker clone for module " << module->GetName();
626+
}
627+
return clone;
628+
}
629+
616630
//_____________________________________________________________________________
617631
void FairMCApplication::InitOnWorker()
618632
{
@@ -1014,7 +1028,8 @@ void FairMCApplication::InitGeometry()
10141028
while ((obj = fModIter->Next())) {
10151029
detector = dynamic_cast<FairDetector*>(obj);
10161030
module = dynamic_cast<FairModule*>(obj);
1017-
if (module) {
1031+
if (module && IsMasterApplication()) {
1032+
// media cuts are set once on the master; multithreaded Geant4 workers share them
10181033
module->SetSpecialPhysicsCuts();
10191034
}
10201035
if (detector) {
@@ -1101,21 +1116,30 @@ void FairMCApplication::InitGeometry()
11011116
}
11021117
FairVolume* fNewV = new FairVolume(fv->GetName(), id);
11031118
fNewV->setModId(fv->getModId());
1104-
fNewV->SetModule(fv->GetModule());
1119+
fNewV->SetModule(OwnModule(fv->GetModule()));
11051120
fNewV->setCopyNo(fN->GetNumber());
11061121
fNewV->setMCid(id);
11071122
fVolMap.insert(pair<Int_t, FairVolume*>(id, fNewV));
11081123
}
11091124
} else {
11101125
FairVolume* fNewV = new FairVolume(fv->GetName(), id);
11111126
fNewV->setModId(fv->getModId());
1112-
fNewV->SetModule(fv->GetModule());
1127+
fNewV->SetModule(OwnModule(fv->GetModule()));
11131128
fNewV->setCopyNo(1);
11141129
fNewV->setMCid(id);
11151130
fVolMap.insert(pair<Int_t, FairVolume*>(id, fNewV));
11161131
}
1117-
} else {
1132+
} else if (IsMasterApplication()) {
11181133
fVolMap.insert(pair<Int_t, FairVolume*>(id, fv));
1134+
} else {
1135+
// the volume object is shared with the master; a worker needs its own, pointing at its own module
1136+
FairVolume* fNewV = new FairVolume(fv->GetName(), id);
1137+
fNewV->setModId(fv->getModId());
1138+
fNewV->SetModule(OwnModule(fv->GetModule()));
1139+
fNewV->setCopyNo(fv->getCopyNo());
1140+
fNewV->setMCid(id);
1141+
fNewV->setGeoNode(fv->getGeoNode());
1142+
fVolMap.insert(pair<Int_t, FairVolume*>(id, fNewV));
11191143
}
11201144
} // end off loop Fill sensitive volumes
11211145

‎Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ void BarrelAlignmentSpec::init(InitContext& ic)
186186
mTRDTransformer->setApplyXOR();
187187
}
188188
auto prevShift = mTRDTransformer->isShiftApplied();
189-
if (getenv("ALIEN_JDL_LPMPRODUCTIONTYPE") && std::strcmp(getenv("ALIEN_JDL_LPMPRODUCTIONTYPE"), "MC") == 0) {
189+
if ((getenv("ALIEN_JDL_LPMPRODUCTIONTYPE") && std::strcmp(getenv("ALIEN_JDL_LPMPRODUCTIONTYPE"), "MC") == 0) || !ic.options().get<bool>("apply-shift")) {
190190
// apply artificial pad shift in case non-ideal alignment is used to compensate for shift in current alignment from real data
191191
mTRDTransformer->setApplyShift(false);
192192
}
@@ -365,6 +365,7 @@ DataProcessorSpec getBarrelAlignmentSpec(GTrackID::mask_t srcMP, GTrackID::mask_
365365
bool loadTPCCalib = false;
366366
Options opts{
367367
ConfigParamSpec{"apply-xor", o2::framework::VariantType::Bool, false, {"flip the 8-th bit of slope and position (for processing TRD CTFs from 2021 pilot beam)"}},
368+
ConfigParamSpec{"apply-shift", o2::framework::VariantType::Bool, true, {"whether we apply the one pad shift for the TRD in data (never applied in MC)"}},
368369
ConfigParamSpec{"allow-afterburner-tracks", VariantType::Bool, false, {"allow using ITS-TPC afterburner tracks"}},
369370
ConfigParamSpec{"ignore-ccdb-alignment", VariantType::Bool, false, {"do not aplly CCDB alignment to ideal geometry"}},
370371
ConfigParamSpec{"initial-params-file", VariantType::String, "", {"initial parameters file"}},

‎Detectors/Base/CMakeLists.txt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ o2_add_library(DetectorsBase
3535
src/Stack.cxx
3636
src/VMCSeederService.cxx
3737
src/SimRandom.cxx
38+
src/MTWorkerHooks.cxx
3839
src/GlobalParams.cxx
3940
src/O2Tessellated.cxx
4041
src/TGeoGeometryUtils.cxx
@@ -97,6 +98,13 @@ o2_add_test(
9798
PUBLIC_LINK_LIBRARIES O2::DetectorsBase
9899
LABELS detectorsbase)
99100

101+
o2_add_test(
102+
DetImplClone
103+
SOURCES test/testDetImplClone.cxx
104+
COMPONENT_NAME DetectorsBase
105+
PUBLIC_LINK_LIBRARIES O2::DetectorsBase
106+
LABELS detectorsbase)
107+
100108
o2_add_test(
101109
O2Tessellated
102110
SOURCES test/testO2Tessellated.cxx

‎Detectors/Base/include/DetectorsBase/Detector.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ class Detector : public FairDetector
219219
// ... for things that should be setup in each simulation worker separately)
220220
virtual void initializeLate() = 0;
221221

222+
/// whether this detector may run in multithreaded Geant4, with one clone per worker thread
223+
virtual bool isMTSafe() const { return false; }
224+
222225
/// helper wrapper function to register a geometry volume given by name with FairRoot
223226
/// @returns The MonteCarlo ID for the volume
224227
int registerSensitiveVolumeAndGetVolID(std::string const& name);
@@ -334,6 +337,10 @@ class DetImpl : public o2::base::Detector
334337
// offer same constructors as base
335338
using Detector::Detector;
336339

340+
/// copy for a worker thread of multithreaded Geant4; the copy creates its own hit buffers in initializeLate
341+
DetImpl(const DetImpl& rhs) : Detector(rhs) {}
342+
DetImpl& operator=(const DetImpl&) = delete;
343+
337344
// default implementation for getHitBranchNames
338345
std::string getHitBranchNames(int probe) const override
339346
{
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#ifndef ALICEO2_BASE_MTWORKERHOOKS_H
13+
#define ALICEO2_BASE_MTWORKERHOOKS_H
14+
15+
#include <functional>
16+
#include <memory>
17+
#include <fairmq/FwdDecls.h>
18+
19+
class TVirtualMCDecayer;
20+
21+
namespace o2::data
22+
{
23+
class PrimaryChunk;
24+
}
25+
26+
namespace o2::base
27+
{
28+
29+
/// What the simulation setup provides to the transport threads of multithreaded Geant4.
30+
/// Installed once on the master thread before transport starts; each function is called on a worker thread.
31+
struct MTWorkerHooks {
32+
/// Returns the next chunk of primaries for the calling thread, or nullptr when there is no more work
33+
std::function<std::unique_ptr<o2::data::PrimaryChunk>()> fetchChunk;
34+
/// Returns the calling thread's channel to the hit merger
35+
std::function<fair::mq::Channel*()> dataChannel;
36+
/// Creates the external decayer of the calling thread (empty if there is none)
37+
std::function<TVirtualMCDecayer*()> makeDecayer;
38+
/// Ends the event loop of the calling thread after the current event
39+
std::function<void()> stopWorker;
40+
/// Called on a worker thread at the start of each run, after its user actions exist
41+
std::function<void()> beginRunOnWorker;
42+
/// Called once on the master thread after initialisation and before the first transport
43+
std::function<void()> beforeTransport;
44+
/// Called on a worker thread at the start of each track
45+
std::function<void()> beginTrack;
46+
47+
static MTWorkerHooks& instance();
48+
};
49+
50+
} // namespace o2::base
51+
52+
#endif

0 commit comments

Comments
 (0)