Skip to content

Commit f6abaed

Browse files
authored
Merge branch 'AliceO2Group:dev' into fd3_digits
2 parents ecfaef1 + 133c2ec commit f6abaed

10 files changed

Lines changed: 144 additions & 19 deletions

File tree

Common/SimConfig/src/SimConfig.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,11 @@ bool SimConfig::determineActiveModulesList(const std::string& version, std::vect
200200
return false;
201201
}
202202
modules = map[version];
203-
LOGP(info, "Running with official detector version '{}'", version);
203+
static std::string last_version{}; // prevent multiple printouts of same message
204+
if (last_version != version) {
205+
LOGP(info, "Running with official detector version '{}'", version);
206+
last_version = version;
207+
}
204208
}
205209
// check if specified modules are in list
206210
if (inputargs.size() != 1 || inputargs[0] != "all") {

Detectors/TPC/base/include/TPCBase/CalArray.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
#include <boost/format.hpp>
2727
#endif
2828

29+
#ifdef NDEBUG
30+
#undef NDEBUG
31+
#include <cassert>
32+
#endif
33+
2934
namespace o2
3035
{
3136
namespace tpc
@@ -93,7 +98,11 @@ class CalArray
9398
int getPadSubsetNumber() const { return mPadSubsetNumber; }
9499

95100
void setValue(const size_t channel, const T& value) { mData[channel] = value; }
96-
const T getValue(const size_t channel) const { return mData[channel]; }
101+
const T getValue(const size_t channel) const
102+
{
103+
assert(channel < mData.size());
104+
return mData[channel];
105+
}
97106

98107
void setValue(const size_t row, const size_t pad, const T& value);
99108
const T getValue(const size_t row, const size_t pad) const;

Detectors/TPC/base/include/TPCBase/CalDet.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
#include "Rtypes.h"
3131
#endif
3232

33+
#ifndef NDEBUG
34+
#undef NDEBUG
35+
// always enable assert
36+
#include <cassert>
37+
#endif
38+
3339
namespace o2
3440
{
3541
namespace tpc
@@ -211,7 +217,26 @@ inline const T CalDet<T>::getValue(const ROC roc, const size_t row, const size_t
211217
}
212218
case PadSubset::Region: {
213219
const auto globalRow = roc.isOROC() ? mappedRow + mapper.getNumberOfRowsROC(ROC(0)) : mappedRow;
214-
return mData[Mapper::REGION[globalRow] + roc.getSector() * Mapper::NREGIONS].getValue(Mapper::OFFSETCRUGLOBAL[globalRow] + mappedPad);
220+
const auto dataRow = Mapper::REGION[globalRow] + roc.getSector() * Mapper::NREGIONS;
221+
const auto index = Mapper::OFFSETCRUGLOBAL[globalRow] + mappedPad;
222+
assert(dataRow < mData.size());
223+
if (index >= mData[dataRow].getData().size()) {
224+
// S. Wenzel: We shouldn't come here but we do. For instance for CalDet calibrations loaded from
225+
// creator.loadIDCPadFlags(1731274461770);
226+
227+
// In this case there is an index overflow, leading to invalid reads and potentially a segfault.
228+
// To increase stability, for now returning a trivial answer. This can be removed once either the algorithm
229+
// or the calibration data has been fixed.
230+
#ifndef GPUCA_ALIGPUCODE // hide from GPU standalone compilation
231+
static bool printMsg = true;
232+
if (printMsg) {
233+
LOG(error) << "Out of bound access in TPC CalDet ROC " << roc << " row " << row << " pad " << pad << " (no more messages printed)";
234+
}
235+
printMsg = false;
236+
#endif
237+
return T{};
238+
}
239+
return mData[dataRow].getValue(index);
215240
break;
216241
}
217242
}

Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ static __attribute__((used)) int _R__dummyStreamer_3 =
6969
([]() {
7070
auto cl = TClass::GetClass<o2::tpc::CalArray<o2::tpc::PadFlags>>();
7171
if (cl) {
72-
cl->AdoptMemberStreamer("mData", new TMemberStreamer(MemberVectorPadFlagsStreamer));
72+
if (!getenv("TPC_PADFLAGS_STREAMER_OFF")) {
73+
cl->AdoptMemberStreamer("mData", new TMemberStreamer(MemberVectorPadFlagsStreamer));
74+
}
7375
} else {
7476
// we should never come here ... and if we do we should assert/fail
7577
assert(false);

Detectors/TPC/base/test/testTPCCalDet.cxx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "TPCBase/CalDet.h"
2525
#include "TFile.h"
2626
#include "Framework/TypeTraits.h"
27+
#include "TPCBase/DeadChannelMapCreator.h"
2728

2829
namespace o2::tpc
2930
{
@@ -344,4 +345,12 @@ BOOST_AUTO_TEST_CASE(CalDetTypeTest)
344345
BOOST_CHECK(testDict == true);
345346
}
346347

348+
BOOST_AUTO_TEST_CASE(CalDetStreamerTest)
349+
{
350+
// simple code executing the TPC IDCPadFlags loading in a standalone env --> easy to valgrind
351+
o2::tpc::DeadChannelMapCreator creator{};
352+
creator.init("https://alice-ccdb.cern.ch");
353+
creator.loadIDCPadFlags(1731274461770);
354+
}
355+
347356
} // namespace o2::tpc

Framework/Core/test/test_MessageSet.cxx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,43 @@ TEST_CASE("MessageSetAddPartRef") {
9393
REQUIRE(msgSet.pairMap[0].partIndex == 0);
9494
REQUIRE(msgSet.pairMap[0].payloadIndex == 0);
9595
}
96+
97+
TEST_CASE("MessageSetAddMultiple")
98+
{
99+
std::vector<fair::mq::MessagePtr> ptrs;
100+
std::unique_ptr<fair::mq::Message> msg(nullptr);
101+
std::unique_ptr<fair::mq::Message> msg2(nullptr);
102+
ptrs.emplace_back(std::move(msg));
103+
ptrs.emplace_back(std::move(msg2));
104+
PartRef ref{std::move(msg), std::move(msg2)};
105+
o2::framework::MessageSet msgSet;
106+
msgSet.add(std::move(ref));
107+
PartRef ref2{std::move(msg), std::move(msg2)};
108+
msgSet.add(std::move(ref2));
109+
std::vector<fair::mq::MessagePtr> msgs;
110+
msgs.push_back(std::unique_ptr<fair::mq::Message>(nullptr));
111+
msgs.push_back(std::unique_ptr<fair::mq::Message>(nullptr));
112+
msgs.push_back(std::unique_ptr<fair::mq::Message>(nullptr));
113+
msgSet.add([&msgs](size_t i) {
114+
return std::move(msgs[i]);
115+
}, 3);
116+
117+
REQUIRE(msgSet.messages.size() == 7);
118+
REQUIRE(msgSet.messageMap.size() == 3);
119+
REQUIRE(msgSet.pairMap.size() == 4);
120+
REQUIRE(msgSet.messageMap[0].position == 0);
121+
REQUIRE(msgSet.messageMap[0].size == 1);
122+
REQUIRE(msgSet.messageMap[1].position == 2);
123+
REQUIRE(msgSet.messageMap[1].size == 1);
124+
REQUIRE(msgSet.messageMap[2].position == 4);
125+
REQUIRE(msgSet.messageMap[2].size == 2);
126+
127+
REQUIRE(msgSet.pairMap[0].partIndex == 0);
128+
REQUIRE(msgSet.pairMap[0].payloadIndex == 0);
129+
REQUIRE(msgSet.pairMap[1].partIndex == 1);
130+
REQUIRE(msgSet.pairMap[1].payloadIndex == 0);
131+
REQUIRE(msgSet.pairMap[2].partIndex == 2);
132+
REQUIRE(msgSet.pairMap[2].payloadIndex == 0);
133+
REQUIRE(msgSet.pairMap[3].partIndex == 2);
134+
REQUIRE(msgSet.pairMap[3].payloadIndex == 1);
135+
}

run/O2HitMerger.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,29 @@ namespace o2
8888
namespace devices
8989
{
9090

91+
// Function communicating to primary particle server that it is now safe to shutdown.
92+
// From the perspective of o2-sim, this is the case when all configs have been propagated and the system
93+
// is running ok: For instance after the HitMerger is initialized and got it's first data from Geant workers.
94+
bool primaryServer_sendShutdownPermission(fair::mq::Channel& channel)
95+
{
96+
std::unique_ptr<fair::mq::Message> request(channel.NewSimpleMessage((int)o2::O2PrimaryServerInfoRequest::AllowShutdown));
97+
std::unique_ptr<fair::mq::Message> reply(channel.NewMessage());
98+
99+
int timeoutinMS = 100;
100+
if (channel.Send(request, timeoutinMS) > 0) {
101+
LOG(info) << "Sending Shutdown permission to particle server";
102+
if (channel.Receive(reply, timeoutinMS) > 0) {
103+
// the answer is a simple ack with a status code
104+
LOG(info) << "Shutdown permission was acknowledged";
105+
} else {
106+
LOG(error) << "No answer received within " << timeoutinMS << "ms\n";
107+
return false;
108+
}
109+
return true;
110+
}
111+
return false;
112+
}
113+
91114
class O2HitMerger : public fair::mq::Device
92115
{
93116

@@ -129,6 +152,9 @@ class O2HitMerger : public fair::mq::Device
129152
if (o2::devices::O2SimDevice::querySimConfig(GetChannels().at("o2sim-primserv-info").at(0))) {
130153
outfilename = o2::base::NameConf::getMCKinematicsFileName(o2::conf::SimConfig::Instance().getOutPrefix().c_str());
131154
mNExpectedEvents = o2::conf::SimConfig::Instance().getNEvents();
155+
} else {
156+
// we didn't manage to get a configuration --> better to fail
157+
LOG(fatal) << "No configuration received. Aborting";
132158
}
133159
mAsService = o2::conf::SimConfig::Instance().asService();
134160
mForwardKine = o2::conf::SimConfig::Instance().forwardKine();
@@ -354,6 +380,13 @@ class O2HitMerger : public fair::mq::Device
354380
// for the next batch
355381
return waitForControlInput();
356382
}
383+
384+
static bool initAcknowledged = false;
385+
if (!initAcknowledged) {
386+
primaryServer_sendShutdownPermission(GetChannels().at("o2sim-primserv-info").at(0));
387+
initAcknowledged = true;
388+
}
389+
357390
return more;
358391
}
359392

@@ -413,10 +446,6 @@ class O2HitMerger : public fair::mq::Device
413446
};
414447
}
415448
}
416-
if (!expectmore) {
417-
// somehow FairMQ has difficulties shutting down; helping manually
418-
// raise(SIGINT);
419-
}
420449
return expectmore;
421450
}
422451

run/O2PrimaryServerDevice.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,10 @@ class O2PrimaryServerDevice final : public fair::mq::Device
247247
}
248248
}
249249

250-
// launches a thread that listens for status requests from outside asynchronously
250+
// launches a thread that listens for status/config/shutdown requests from outside asynchronously
251251
void launchInfoThread()
252252
{
253253
static std::vector<std::thread> threads;
254-
255254
auto sendErrorReply = [](fair::mq::Channel& channel) {
256255
LOG(error) << "UNKNOWN REQUEST";
257256
std::unique_ptr<fair::mq::Message> reply(channel.NewSimpleMessage((int)(404)));
@@ -260,7 +259,9 @@ class O2PrimaryServerDevice final : public fair::mq::Device
260259

261260
LOG(info) << "LAUNCHING STATUS THREAD";
262261
auto lambda = [this, sendErrorReply]() {
263-
while (mState != O2PrimaryServerState::Stopped) {
262+
bool canShutdown{false};
263+
// Exit only when both: serving stopped and allowed from outside.
264+
while (!(mState == O2PrimaryServerState::Stopped && canShutdown)) {
264265
auto& channel = GetChannels().at("o2sim-primserv-info").at(0);
265266
if (!channel.IsValid()) {
266267
LOG(error) << "channel primserv-info not valid";
@@ -285,6 +286,11 @@ class O2PrimaryServerDevice final : public fair::mq::Device
285286
}
286287
} else if (request_payload == (int)O2PrimaryServerInfoRequest::Config) {
287288
HandleConfigRequest(channel);
289+
} else if (request_payload == (int)O2PrimaryServerInfoRequest::AllowShutdown) {
290+
LOG(info) << "Got info that we may shutdown";
291+
std::unique_ptr<fair::mq::Message> ack(channel.NewSimpleMessage(200));
292+
channel.Send(ack);
293+
canShutdown = true;
288294
} else {
289295
sendErrorReply(channel);
290296
}
@@ -518,10 +524,13 @@ class O2PrimaryServerDevice final : public fair::mq::Device
518524

519525
void PostRun() override
520526
{
527+
// We shouldn't shut down immediately when all events have been served
528+
// Instead we also need to wait until the info thread running some communication server
529+
// with other processes is finished.
521530
while (!mInfoThreadStopped) {
522531
LOG(info) << "Waiting info thread";
523532
using namespace std::chrono_literals;
524-
std::this_thread::sleep_for(100ms);
533+
std::this_thread::sleep_for(1000ms);
525534
}
526535
}
527536

@@ -534,7 +543,7 @@ class O2PrimaryServerDevice final : public fair::mq::Device
534543
if (mEventCounter >= mMaxEvents && mNeedNewEvent) {
535544
workavailable = false;
536545
}
537-
if (!(mState == O2PrimaryServerState::ReadyToServe || mState == O2PrimaryServerState::WaitingEvent)) {
546+
if (!(mState.load() == O2PrimaryServerState::ReadyToServe || mState.load() == O2PrimaryServerState::WaitingEvent)) {
538547
// send a zero answer
539548
workavailable = false;
540549
}

run/O2SimDevice.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ class O2SimDevice final : public fair::mq::Device
9595
// returns true if successful / false if not
9696
static bool querySimConfig(fair::mq::Channel& channel)
9797
{
98-
// auto text = new std::string("configrequest");
99-
// std::unique_ptr<fair::mq::Message> request(channel.NewMessage(const_cast<char*>(text->c_str()),
100-
// text->length(), CustomCleanup, text));
10198
std::unique_ptr<fair::mq::Message> request(channel.NewSimpleMessage((int)O2PrimaryServerInfoRequest::Config));
10299
std::unique_ptr<fair::mq::Message> reply(channel.NewMessage());
103100

run/PrimaryServerState.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ enum class O2PrimaryServerState {
2525
};
2626
static const char* PrimStateToString[5] = {"INIT", "SERVING", "WAITEVENT", "IDLE", "STOPPED"};
2727

28-
/// enum class for type of info request
28+
/// enum class for request to o2sim-primserv-info channel of the O2PrimaryServerDevice
2929
enum class O2PrimaryServerInfoRequest {
30-
Status = 1,
31-
Config = 2
30+
Status = 1, // asks to retrieve current status of O2PrimaryServerDevice --> will send O2PrimaryServerState
31+
Config = 2, // asks for o2-sim config reply
32+
AllowShutdown = 3 // can be used to let particle server know that shutdown is now safe (once all components initialized)
3233
};
3334

3435
/// Struct to be used as payload when making a request

0 commit comments

Comments
 (0)