Skip to content

Commit 7e81cbf

Browse files
wiechuladavidrohr
authored andcommitted
change fatal to warning, add possibility to dump bad data
1 parent 24437b2 commit 7e81cbf

2 files changed

Lines changed: 148 additions & 24 deletions

File tree

Detectors/TPC/workflow/src/IDCToVectorSpec.cxx

Lines changed: 146 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <stdexcept>
1616
#include <vector>
1717
#include <string>
18+
#include <fstream>
1819
#include <algorithm>
1920
#include <cassert>
2021
#include <cmath>
@@ -30,6 +31,7 @@
3031
#include "Framework/DataProcessorSpec.h"
3132
#include "Framework/WorkflowSpec.h"
3233
#include "Framework/InputRecordWalker.h"
34+
#include "Framework/DataRefUtils.h"
3335
#include "DPLUtils/RawParser.h"
3436
#include "Headers/DataHeader.h"
3537
#include "Headers/DataHeaderHelpers.h"
@@ -45,6 +47,7 @@
4547
#include "TPCBase/Utils.h"
4648
#include "TPCBase/RDHUtils.h"
4749
#include "TPCBase/Mapper.h"
50+
#include "TPCWorkflow/ProcessingHelpers.h"
4851

4952
using namespace o2::framework;
5053
using o2::constants::lhc::LHCMaxBunches;
@@ -65,9 +68,13 @@ class IDCToVectorDevice : public o2::framework::Task
6568
void init(o2::framework::InitContext& ic) final
6669
{
6770
// set up ADC value filling
68-
if (ic.options().get<bool>("write-debug")) {
69-
mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>("idc_vector_debug.root", "recreate");
70-
}
71+
mWriteDebug = ic.options().get<bool>("write-debug");
72+
mWriteDebugOnError = ic.options().get<bool>("write-debug-on-error");
73+
mWriteRawDataOnError = ic.options().get<bool>("write-raw-data-on-error");
74+
mRawDataType = ic.options().get<int>("raw-data-type");
75+
76+
mDebugStreamFileName = ic.options().get<std::string>("debug-file-name").data();
77+
mRawOutputFileName = ic.options().get<std::string>("raw-file-name").data();
7178

7279
mSwapLinks = ic.options().get<bool>("swap-links");
7380

@@ -111,13 +118,32 @@ class IDCToVectorDevice : public o2::framework::Task
111118

112119
void run(o2::framework::ProcessingContext& pc) final
113120
{
121+
const auto runNumber = processing_helpers::getRunNumber(pc);
114122
std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; // TODO: Change to IDC when changed in DD
115123
const auto& mapper = Mapper::instance();
116124

125+
// open files if necessary
126+
if ((mWriteDebug || mWriteDebugOnError) && !mDebugStream) {
127+
const auto debugFileName = fmt::format(mDebugStreamFileName, fmt::arg("run", runNumber));
128+
LOGP(info, "creating debug stream {}", debugFileName);
129+
mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>(debugFileName.data(), "recreate");
130+
}
131+
132+
if (mWriteRawDataOnError && !mRawOutputFile.is_open()) {
133+
std::string_view rawType = (mRawDataType < 2) ? "tf" : "raw";
134+
if (mRawDataType == 4) {
135+
rawType = "idc.raw";
136+
}
137+
const auto rawFileName = fmt::format(mRawOutputFileName, fmt::arg("run", runNumber), fmt::arg("raw_type", rawType));
138+
LOGP(info, "creating raw debug file {}", rawFileName);
139+
mRawOutputFile.open(rawFileName, std::ios::binary);
140+
}
141+
117142
uint32_t heartbeatOrbit = 0;
118143
uint32_t heartbeatBC = 0;
119144
uint32_t tfCounter = 0;
120145
bool first = true;
146+
bool hasErrors = false;
121147

122148
CalPad* pedestals = mPedestal.get();
123149

@@ -187,7 +213,8 @@ class IDCToVectorDevice : public o2::framework::Task
187213
} else if (infoIt == infoVec.end()) {
188214
auto& lastInfo = infoVec.back();
189215
if ((orbit - lastInfo.heartbeatOrbit) != mNOrbitsIDC) {
190-
LOGP(error, "received packet with invalid jump in idc orbit ({} - {} == {} != {})", orbit, lastInfo.heartbeatOrbit, orbit - lastInfo.heartbeatOrbit, mNOrbitsIDC);
216+
LOGP(error, "received packet with invalid jump in idc orbit ({} - {} == {} != {})", orbit, lastInfo.heartbeatOrbit, int(orbit) - int(lastInfo.heartbeatOrbit), mNOrbitsIDC);
217+
hasErrors = true;
191218
}
192219
infoVec.emplace_back(orbit, bc);
193220
infoIt = infoVec.end() - 1;
@@ -265,26 +292,48 @@ class IDCToVectorDevice : public o2::framework::Task
265292
}
266293
}
267294

268-
if (mDebugStream) {
295+
hasErrors |= snapshotIDCs(pc.outputs(), tfCounter);
296+
297+
if (mWriteDebug || (mWriteDebugOnError && hasErrors)) {
269298
writeDebugOutput(tfCounter);
270299
}
271-
snapshotIDCs(pc.outputs());
300+
301+
if (mWriteRawDataOnError && hasErrors) {
302+
writeRawData(pc.inputs());
303+
}
304+
305+
// clear output
306+
initIDC();
272307
}
273308

274-
void
275-
endOfStream(o2::framework::EndOfStreamContext& ec) final
309+
void closeFiles()
276310
{
277-
LOGP(info, "endOfStream");
278-
ec.services().get<ControlService>().readyToQuit(QuitRequest::Me);
311+
LOGP(info, "closeFiles");
312+
279313
if (mDebugStream) {
280314
// set some default aliases
281315
auto& stream = (*mDebugStream) << "idcs";
282316
auto& tree = stream.getTree();
283317
tree.SetAlias("sector", "int(cru/10)");
284318
mDebugStream->Close();
319+
mDebugStream.reset(nullptr);
320+
mRawOutputFile.close();
285321
}
286322
}
287323

324+
void stop() final
325+
{
326+
LOGP(info, "stop");
327+
closeFiles();
328+
}
329+
330+
void endOfStream(o2::framework::EndOfStreamContext& ec) final
331+
{
332+
LOGP(info, "endOfStream");
333+
// ec.services().get<ControlService>().readyToQuit(QuitRequest::Me);
334+
closeFiles();
335+
}
336+
288337
private:
289338
/// IDC information for each cru
290339
struct IDCInfo {
@@ -307,58 +356,71 @@ class IDCToVectorDevice : public o2::framework::Task
307356
const int mNOrbitsIDC{12}; ///< number of orbits over which IDCs are integrated, TODO: take from IDC header
308357
const int mTimeStampsPerIntegrationInterval{(LHCMaxBunches * mNOrbitsIDC) / LHCBCPERTIMEBIN}; ///< number of time stamps for each integration interval (5346)
309358
const uint32_t mMaxIDCPerTF{uint32_t(std::ceil(256.f / mNOrbitsIDC))}; ///< maximum number of IDCs expected per TF, TODO: better way to get max number of orbits
359+
int mRawDataType{0}; ///< type of raw data to dump in case of errors
310360
bool mSwapLinks{false}; ///< swap links to circumvent bug in FW
361+
bool mWriteDebug{false}; ///< write a debug output
362+
bool mWriteDebugOnError{false}; ///< write a debug output in case of errors
363+
bool mWriteRawDataOnError{false}; ///< write raw data in case of errors
311364
std::vector<uint32_t> mCRUs; ///< CRUs expected for this device
312365
std::unordered_map<uint32_t, std::vector<float>> mIDCvectors; ///< decoded IDCs per cru for each pad in the region over all IDC packets in the TF
313366
std::unordered_map<uint32_t, std::vector<IDCInfo>> mIDCInfos; ///< IDC packet information within the TF
367+
std::string mDebugStreamFileName; ///< name of the debug stream output file
314368
std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugStream; ///< debug output streamer
315369
std::unique_ptr<CalPad> mPedestal{}; ///< noise and pedestal values
370+
std::ofstream mRawOutputFile; ///< raw output file
371+
std::string mRawOutputFileName; ///< name of the raw output file
316372

317373
//____________________________________________________________________________
318-
void snapshotIDCs(DataAllocator& output)
374+
bool snapshotIDCs(DataAllocator& output, uint32_t tfCounter)
319375
{
320376
LOGP(debug, "snapshotIDCs");
321377

322378
// check integrety of data between CRUs
323-
size_t orbitsInTF = 0;
379+
size_t packetsInTF = 0;
324380
std::vector<IDCInfo> const* infVecComp = nullptr;
325381
std::vector<uint64_t> orbitBCInfo;
382+
bool hasErrors = false;
383+
384+
for (const auto& [cru, infVec] : mIDCInfos) {
385+
packetsInTF = std::max(infVec.size(), packetsInTF);
386+
}
326387

327388
for (const auto& [cru, infVec] : mIDCInfos) {
328389

329390
for (const auto& inf : infVec) {
330391
if (!inf.hasBothEPs()) {
331-
LOGP(fatal, "IDC CRU {:3}: data missing at ({:8}, {:4}) for one or both end points {:02b}", cru, inf.heartbeatOrbit, inf.heartbeatBC, inf.epSeen);
392+
LOGP(error, "IDC CRU {:3}: data missing at ({:8}, {:4}) for one or both end points {:02b} in TF {}", cru, inf.heartbeatOrbit, inf.heartbeatBC, inf.epSeen, tfCounter);
393+
hasErrors = true;
332394
}
333395
}
334396

335397
if (!infVecComp) {
336398
infVecComp = &infVec;
337-
orbitsInTF = infVec.size();
338399
std::for_each(infVec.begin(), infVec.end(), [&orbitBCInfo](const auto& inf) { orbitBCInfo.emplace_back((uint64_t(inf.heartbeatOrbit) << 32) + uint64_t(inf.heartbeatBC)); });
339400
continue;
340401
}
341402

342-
if (orbitsInTF != infVec.size()) {
343-
LOGP(fatal, "IDC CRU {:3}: unequal number of IDC values {} != {}", cru, orbitsInTF, infVec.size());
403+
if (packetsInTF != infVec.size()) {
404+
LOGP(error, "IDC CRU {:3}: number of IDC packets {} does not match max over all CRUs {} in TF {}", cru, packetsInTF, infVec.size(), tfCounter);
405+
hasErrors = true;
344406
}
345407

346408
if (!std::equal(infVecComp->begin(), infVecComp->end(), infVec.begin())) {
347-
LOGP(fatal, "IDC CRU {:3}: mismatch in orbits");
409+
LOGP(error, "IDC CRU {:3}: mismatch in orbit numbers", cru);
410+
hasErrors = true;
348411
}
349412
}
350413

351414
// send data
352415
for (auto& [cru, idcVec] : mIDCvectors) {
353-
idcVec.resize(Mapper::PADSPERREGION[CRU(cru).region()] * orbitsInTF);
416+
idcVec.resize(Mapper::PADSPERREGION[CRU(cru).region()] * packetsInTF);
354417
const header::DataHeader::SubSpecificationType subSpec{cru << 7};
355418
LOGP(debug, "Sending IDCs for CRU {} of size {}", cru, idcVec.size());
356419
output.snapshot(Output{gDataOriginTPC, "IDCVECTOR", subSpec}, idcVec);
357420
output.snapshot(Output{gDataOriginTPC, "IDCORBITS", subSpec}, orbitBCInfo);
358421
}
359422

360-
// clear output
361-
initIDC();
423+
return hasErrors;
362424
}
363425

364426
//____________________________________________________________________________
@@ -444,6 +506,64 @@ class IDCToVectorDevice : public o2::framework::Task
444506
}
445507
}
446508
}
509+
510+
void writeRawData(InputRecord& inputs)
511+
{
512+
if (!mRawOutputFile.is_open()) {
513+
return;
514+
}
515+
516+
using DataHeader = o2::header::DataHeader;
517+
518+
std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; // TODO: Change to IDC when changed in DD
519+
for (auto const& ref : InputRecordWalker(inputs, filter)) {
520+
auto dh = DataRefUtils::getHeader<header::DataHeader*>(ref);
521+
// LOGP(info, "write header: {}/{}/{}, payload size: {} / {}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dh->payloadSize, ref.payloadSize);
522+
if (((mRawDataType == 1) || (mRawDataType == 3)) && (dh->payloadSize == 2 * sizeof(o2::header::RAWDataHeader))) {
523+
continue;
524+
}
525+
526+
if (mRawDataType < 2) {
527+
mRawOutputFile.write(ref.header, sizeof(DataHeader));
528+
}
529+
if (mRawDataType < 4) {
530+
mRawOutputFile.write(ref.payload, ref.payloadSize);
531+
}
532+
533+
if (mRawDataType == 4) {
534+
const gsl::span<const char> raw = inputs.get<gsl::span<char>>(ref);
535+
try {
536+
o2::framework::RawParser parser(raw.data(), raw.size());
537+
for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
538+
const auto size = it.size();
539+
// skip empty packages (HBF open)
540+
if (size == 0) {
541+
continue;
542+
}
543+
544+
auto* rdhPtr = it.get_if<o2::header::RAWDataHeaderV6>();
545+
if (!rdhPtr) {
546+
throw std::runtime_error("could not get RDH from packet");
547+
}
548+
549+
// ---| extract hardware information to do the processing |---
550+
const auto feeId = (FEEIDType)RDHUtils::getFEEID(*rdhPtr);
551+
const auto link = rdh_utils::getLink(feeId);
552+
const auto detField = RDHUtils::getDetectorField(*rdhPtr);
553+
554+
// only select IDCs
555+
if ((detField != (decltype(detField))RawDataType::IDC) || (link != rdh_utils::IDCLinkID)) {
556+
continue;
557+
}
558+
559+
// write out raw data
560+
mRawOutputFile.write((const char*)it.raw(), rdhPtr->memorySize);
561+
}
562+
} catch (...) {
563+
}
564+
}
565+
}
566+
}
447567
};
448568

449569
o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec, std::vector<uint32_t> const& crus)
@@ -463,7 +583,12 @@ o2::framework::DataProcessorSpec getIDCToVectorSpec(const std::string inputSpec,
463583
outputs,
464584
AlgorithmSpec{adaptFromTask<device>(crus)},
465585
Options{
466-
{"write-debug", VariantType::Bool, false, {"write a debug output tree."}},
586+
{"write-debug", VariantType::Bool, false, {"write a debug output tree"}},
587+
{"write-debug-on-error", VariantType::Bool, false, {"write a debug output tree in case errors occurred"}},
588+
{"debug-file-name", VariantType::String, "/tmp/idc_vector_debug.{run}.root", {"name of the debug output file"}},
589+
{"write-raw-data-on-error", VariantType::Bool, false, {"dump raw data in case errors occurred"}},
590+
{"raw-file-name", VariantType::String, "/tmp/idc_debug.{run}.{raw_type}", {"name of the raw output file"}},
591+
{"raw-data-type", VariantType::Int, 0, {"Which raw data to dump: 0-full TPC with DH, 1-full TPC with DH skip empty, 2-full TPC no DH, 3-full TPC no DH skip empty, 4-IDC raw only"}},
467592
{"pedestal-url", VariantType::String, "ccdb-default", {"ccdb-default: load from NameConf::getCCDBServer() OR ccdb url (must contain 'ccdb' OR pedestal file name"}},
468593
{"swap-links", VariantType::Bool, false, {"swap links to circumvent bug in FW"}},
469594
} // end Options

Detectors/TPC/workflow/src/tpc-idc-to-vector.cxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,13 @@ void customize(std::vector<o2::framework::CompletionPolicy>& policies)
4040
// we need to add workflow options before including Framework/runDataProcessing
4141
void customize(std::vector<ConfigParamSpec>& workflowOptions)
4242
{
43-
std::string sectorDefault = "0-" + std::to_string(CRU::MaxCRU - 1);
44-
int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2);
43+
std::string crusDefault = "0-" + std::to_string(CRU::MaxCRU - 1);
4544

4645
std::vector<ConfigParamSpec> options{
4746
{"input-spec", VariantType::String, "A:TPC/RAWDATA", {"selection string input specs"}},
4847
{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}},
4948
{"configFile", VariantType::String, "", {"configuration file for configurable parameters"}},
50-
{"crus", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}},
49+
{"crus", VariantType::String, crusDefault.c_str(), {"List of TPC crus, comma separated ranges, e.g. 0-3,7,9-15"}},
5150
};
5251

5352
std::swap(workflowOptions, options);

0 commit comments

Comments
 (0)