From c3ab42973ef6c153e256113aa043201e29ade0b7 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 27 Mar 2019 19:41:29 +0100 Subject: [PATCH 1/6] Check for ChipHeader only for non-empty lanes --- .../include/ITSMFTReconstruction/RawPixelReader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index 35efcc828a06d..6edbcb3082df0 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -1132,7 +1132,7 @@ class RawPixelReader : public PixelReader #ifdef _RAW_READER_ERROR_CHECKS_ // make sure the lane data starts with chip header or empty chip uint8_t h; - if (!cableData.current(h) || !mCoder.isChipHeaderOrEmpty(h)) { + if (cableData.current(h) && !mCoder.isChipHeaderOrEmpty(h)) { LOG(ERROR) << "FEE#" << decData.ruInfo->idHW << " cable " << icab << " data does not start with ChipHeader or ChipEmpty"; currRU.errorCounts[RUDecodingStat::ErrCableDataHeadWrong]++; } From cc6eae9470853cd154c3929ef648eeaa2027be80 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 28 Mar 2019 21:48:54 +0100 Subject: [PATCH 2/6] add getter for RawBuffer --- .../include/ITSMFTReconstruction/RawPixelReader.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index 6edbcb3082df0..6b7c32d78257a 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -1246,6 +1246,8 @@ class RawPixelReader : public PixelReader const RUDecodeData& getRUDecodeData() const { return mRUDecode; } + PayLoadCont& getRawBuffer() {return mRawBuffer;} + private: std::ifstream mIOFile; Coder mCoder; From 382389cb07bfc908476105d315cad7064acc3945 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 28 Mar 2019 23:00:28 +0100 Subject: [PATCH 3/6] allow different trigger words in RDHs of the same RU/trigger --- .../include/ITSMFTReconstruction/RawPixelReader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index 6b7c32d78257a..64b81e85bf896 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -1108,7 +1108,7 @@ class RawPixelReader : public PixelReader rdhNew->triggerBC != rdhOld->triggerBC || rdhNew->heartbeatOrbit != rdhOld->heartbeatOrbit || rdhNew->heartbeatBC != rdhOld->heartbeatBC || - rdhNew->triggerType != rdhOld->triggerType) { + !(rdhNew->triggerType & rdhOld->triggerType)) { return false; } return true; From ebac55681ee0c1e5f0adc150b404523e316a126f Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 29 Mar 2019 22:34:41 +0100 Subject: [PATCH 4/6] Fixes in decoding/cleaning logics --- .../ITSMFTReconstruction/AlpideCoder.h | 6 +- .../ITSMFTReconstruction/RawPixelReader.h | 70 +++++++++++-------- macro/run_rawdecoding_its.C | 5 +- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index 2e28c2ca2b5b5..6424fdac288e3 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -106,7 +106,6 @@ class AlpideCoder { // read record for single non-empty chip, updating on change module and cycle. // return number of records filled (>0), EOFFlag or Error - // NOTE: decoder does not clean the chipData buffers, should be done outside // uint8_t dataC = 0, timestamp = 0; uint16_t dataS = 0, region = 0; @@ -117,6 +116,8 @@ class AlpideCoder uint32_t expectInp = ExpectChipHeader | ExpectChipEmpty; // data must always start with chip header or chip empty flag + chipData.clear(); + while (buffer.next(dataC)) { // // ---------- chip info ? @@ -226,7 +227,8 @@ class AlpideCoder } if (!dataC) { - break; // 0 padding reached (end of the cable data) + buffer.clear(); // 0 padding reached (end of the cable data), no point in continuing + break; } return unexpectedEOF("Unknown word"); // either error } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index 64b81e85bf896..a9b62a6dd15e6 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -235,7 +235,6 @@ class RawPixelReader : public PixelReader { mPadding128 = v; mGBTWordSize = mPadding128 ? ITSMFT::GBTPaddedWordLength : o2::ITSMFT::GBTWordLength; - imposeMaxPage(mPadding128); } /// CRU pages are of max size of 8KB @@ -244,7 +243,13 @@ class RawPixelReader : public PixelReader ChipPixelData* getNextChipData(std::vector& chipDataVec) override { // decode new RU if no cached non-empty chips - while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired && decodeNextRUData()) { + while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired) { + if (mIOFile) { + loadInput(); // if needed, upload additional data to the buffer + } + if (!decodeNextRUData(mRawBuffer)) { // failure to decode would signal error or EOF + break; + } } if (mRUDecode.lastChipChecked < mRUDecode.nChipsFired) { auto& chipData = mRUDecode.chipsData[mRUDecode.lastChipChecked++]; @@ -570,44 +575,45 @@ class RawPixelReader : public PixelReader } //_____________________________________ - int decodeNextRUData() + int decodeNextRUData(PayLoadCont& buffer) { - if (mIOFile) { - loadInput(); // if needed, upload additional data to the buffer - } int res = 0; - if (!mRawBuffer.isEmpty()) { + if (!buffer.isEmpty()) { bool aborted = false; - //printf("Unused: %d Size: %d Offs: %d\n", mRawBuffer.getUnusedSize(), mRawBuffer.getSize(), mRawBuffer.getOffset() ); - auto ptr = decodeRUData(mRawBuffer.getPtr(), aborted); + //printf("Unused: %d Size: %d Offs: %d\n", buffer.getUnusedSize(), buffer.getSize(), buffer.getOffset() ); + mRUDecode.clear(); + + auto ptr = decodeRUData(buffer.getPtr(), aborted); if (!aborted) { - mRawBuffer.setPtr(ptr); + decodeAlpideData(mRUDecode); // decode Alpide data from the compressed RU Data + + buffer.setPtr(ptr); res = 1; // success - if (mRawBuffer.isEmpty()) { - mRawBuffer.clear(); + if (buffer.isEmpty()) { + buffer.clear(); } } else { // try to seek to the next RDH, can be done only for 128b padded GBT words LOG(ERROR) << "Will seek the next RDH after aborting (unreliable!!)"; - auto ptrTail = mRawBuffer.getPtr() + mRawBuffer.getUnusedSize(); - ptr += ((ptr - mRawBuffer.getPtr()) / mGBTWordSize) * mGBTWordSize; // jump to the next GBT word + auto ptrTail = buffer.getPtr() + buffer.getUnusedSize(); + ptr += ((ptr - buffer.getPtr()) / mGBTWordSize) * mGBTWordSize; // jump to the next GBT word while (ptr + mGBTWordSize <= ptrTail) { auto* rdh = reinterpret_cast(ptr); if (isRDHHeuristic(rdh)) { // this heuristics is not reliable... LOG(WARNING) << "Assuming that found a new RDH"; printRDH(*rdh); - mRawBuffer.setPtr(ptr); + buffer.setPtr(ptr); break; } ptr += mGBTWordSize; } - mRawBuffer.setPtr(ptr); - if (!mRawBuffer.isEmpty()) { + buffer.setPtr(ptr); + if (!buffer.isEmpty()) { res = 1; // found a RDH condidate } else { - mRawBuffer.clear(); // did not find new RDH + buffer.clear(); // did not find new RDH } } // try to seek to the next ... } @@ -633,7 +639,6 @@ class RawPixelReader : public PixelReader /// In case of unrecoverable error set aborted to true aborted = false; - mRUDecode.clear(); // data must start by RDH auto rdh = reinterpret_cast(raw); @@ -830,9 +835,6 @@ class RawPixelReader : public PixelReader // } #endif - // decode Alpide data from the compressed RU Data - decodeAlpideData(mRUDecode); - return raw; } @@ -1122,7 +1124,6 @@ class RawPixelReader : public PixelReader auto* chipData = &decData.chipsData[0]; auto& currRU = mRUDecodingStat[decData.ruInfo->idSW]; - chipData->clear(); decData.nChipsFired = decData.lastChipChecked = 0; int ntot = 0; for (int icab = 0; icab < decData.nCables; icab++) { @@ -1140,7 +1141,6 @@ class RawPixelReader : public PixelReader while ((res = mCoder.decodeChip(*chipData, cableData))) { // we register only chips with hits or errors flags set if (res > 0) { - #ifdef _RAW_READER_ERROR_CHECKS_ // for the IB staves check if the cable ID is the same as the chip ID on the module if (decData.ruInfo->ruType == 0) { // ATTENTION: this is a hack tailored for temporary check @@ -1156,10 +1156,13 @@ class RawPixelReader : public PixelReader chipData->setTrigger(mTrigger); mDecodingStat.nNonEmptyChips++; mDecodingStat.nHitsDecoded += chipData->getData().size(); - // fetch next free chip - chipData = &decData.chipsData[++decData.nChipsFired]; - chipData->clear(); ntot += res; + // fetch next free chip + if (++decData.nChipsFired < MaxChipsPerRU) { + chipData = &decData.chipsData[decData.nChipsFired]; + } else { + break; // last chip decoded + } } } } @@ -1172,8 +1175,15 @@ class RawPixelReader : public PixelReader /// read single chip data to the provided container // decode new RU if no cached non-empty chips - while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired && decodeNextRUData()) { + while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired) { + if (mIOFile) { + loadInput(); // if needed, upload additional data to the buffer + } + if (!decodeNextRUData(mRawBuffer)) { // failure to decode would signal error or EOF + break; + } } + if (mRUDecode.lastChipChecked < mRUDecode.nChipsFired) { chipData.swap(mRUDecode.chipsData[mRUDecode.lastChipChecked++]); return true; @@ -1246,8 +1256,8 @@ class RawPixelReader : public PixelReader const RUDecodeData& getRUDecodeData() const { return mRUDecode; } - PayLoadCont& getRawBuffer() {return mRawBuffer;} - + PayLoadCont& getRawBuffer() { return mRawBuffer; } + private: std::ifstream mIOFile; Coder mCoder; diff --git a/macro/run_rawdecoding_its.C b/macro/run_rawdecoding_its.C index ceedb9d9fbfe8..acc3928ccb33c 100644 --- a/macro/run_rawdecoding_its.C +++ b/macro/run_rawdecoding_its.C @@ -20,13 +20,14 @@ // the data obtained by the removing the 128 bit padding from GBT words void run_rawdecoding_its(std::string inpName = "rawits.bin", - bool padding = true, + bool padding = true, bool page8kb = true, int verbose = 0) { o2::ITSMFT::RawPixelReader rawReader; rawReader.openInput(inpName); - rawReader.setPadding128(padding); + rawReader.setPadding128(padding); // payload GBT words are padded to 16B + rawReader.imposeMaxPage(page8kb); // pages are 8kB in size (no skimming) rawReader.setVerbosity(verbose); o2::ITSMFT::ChipPixelData chipData; From db658926761bd9d985506488c0c44a6a8296155f Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 31 Mar 2019 01:29:03 +0100 Subject: [PATCH 5/6] Support for multiple links per RU --- .../ITSMFTReconstruction/PayLoadCont.h | 34 +- .../include/ITSMFTReconstruction/PayLoadSG.h | 2 +- .../ITSMFTReconstruction/RawPixelReader.h | 561 +++++++++++------- .../common/reconstruction/src/PayLoadCont.cxx | 6 +- macro/run_CRUDataSkimming_its.C | 6 +- macro/run_rawdecoding_its.C | 6 +- 6 files changed, 380 insertions(+), 235 deletions(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h index ce6ea21f3f5d9..0d68b363e3ea4 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadCont.h @@ -31,16 +31,16 @@ class PayLoadCont // Big endian is used. public: - static constexpr int MinCapacity = 16; + static constexpr size_t MinCapacity = 16; ///< allocate buffer - PayLoadCont(int iniSize = MinCapacity) { expand(iniSize); } + PayLoadCont(size_t iniSize = MinCapacity) { expand(iniSize); } ~PayLoadCont() = default; const uint8_t* data() const { return mBuffer.data(); } ///< increase the buffer size - void expand(int sz); + void expand(size_t sz); bool isEmpty() const { return mPtr >= mEnd; } @@ -52,22 +52,22 @@ class PayLoadCont } ///< get unused size - int getUnusedSize() const { return mEnd - mPtr; } + size_t getUnusedSize() const { return mEnd > mPtr ? mEnd - mPtr : 0; } ///< get filled size - int getSize() const { return mEnd - mBuffer.data(); } + size_t getSize() const { return mEnd - mBuffer.data(); } ///< get offset of the current ptr from the head - int getOffset() const { return mPtr - mBuffer.data(); } + size_t getOffset() const { return mPtr - mBuffer.data(); } ///< booked capacity - int getCapacity() const { return mBuffer.size(); } + size_t getCapacity() const { return mBuffer.size(); } ///< number of bytes still can accept w/o expanding the buffer - int getFreeCapacity() const { return mBuffer.size() - getSize(); } + size_t getFreeCapacity() const { return mBuffer.size() - getSize(); } ///< make sure buffer may accept at least n bytes - void ensureFreeCapacity(int n) + void ensureFreeCapacity(size_t n) { if (getFreeCapacity() < n) { expand(getCapacity() + 2 * n); @@ -75,7 +75,7 @@ class PayLoadCont } ///< add n bytes to the buffer w/o checking for the size - void addFast(const uint8_t* ptr, int n) + void addFast(const uint8_t* ptr, size_t n) { std::memcpy(mEnd, ptr, n); mEnd += n; @@ -92,10 +92,10 @@ class PayLoadCont } ///< erase n bytes w/o checking for the underflow - void eraseFast(int n) { mEnd -= n; } + void eraseFast(size_t n) { mEnd -= n; } ///< erase n bytes - void erase(int n) + void erase(size_t n) { if (n > getSize()) { clear(); @@ -105,7 +105,7 @@ class PayLoadCont } ///< add n bytes to the buffer, expand if needed. no check for overlap - void add(const uint8_t* ptr, int n) + void add(const uint8_t* ptr, size_t n) { ensureFreeCapacity(n); addFast(ptr, n); @@ -126,16 +126,16 @@ class PayLoadCont } ///< shrink buffer to requested size, no check on over/under flow - void shrinkToSize(int sz) + void shrinkToSize(size_t sz) { mEnd = mPtr + sz; } ///< direct const access to value at a given slot, w/o checking for overflow - uint8_t operator[](int i) const { return mBuffer[i]; } + uint8_t operator[](size_t i) const { return mBuffer[i]; } ///< direct access to value at a given slot, w/o checking for overflow - uint8_t& operator[](int i) { return mBuffer[i]; } + uint8_t& operator[](size_t i) { return mBuffer[i]; } ///< read current character value from buffer w/o stepping forward bool current(uint8_t& v) const @@ -186,7 +186,7 @@ class PayLoadCont ///< move unused data to the head and upload new chunk of data // (attemtint to use all free capacity) using the method provided via getNext - int append(std::function getNext) + size_t append(std::function getNext) { moveUnusedToHead(); auto nRead = getNext(mEnd, getFreeCapacity()); diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h index be7afea5fa0d5..aa0a82cb0c280 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PayLoadSG.h @@ -33,7 +33,7 @@ class PayLoadSG ~PayLoadSG() = default; ///< add n bytes to the buffer - void add(const uint8_t* ptr, int n) + void add(const uint8_t* ptr, size_t n) { if (n) { mBuffer.emplace_back(ptr, n); diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index a9b62a6dd15e6..3ea77783c3cda 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -43,15 +44,16 @@ namespace o2 namespace ITSMFT { +constexpr int MaxLinksPerRU = 3; // max numbet of GBT links per RU constexpr int MaxCablesPerRU = 28; // max numbet of cables RU can readout constexpr int MaxChipsPerRU = 196; // max number of chips the RU can readout constexpr int MaxGBTPacketBytes = 8 * 1024; // Max size of GBT packet in bytes (8KB) +constexpr int NCRUPagesPerSuperpage = 256; // Number of CRU pages per superpage struct RUDecodingStat { // counters for format checks enum DecErrors : int { - ErrGarbageAfterPayload, // garbage (non-0) detected after CRU page payload is over ErrPageCounterDiscontinuity, // RDH page counters for the same RU/trigger are not continuous ErrRDHvsGBTHPageCnt, // RDH ang GBT header page counters are not consistent ErrMissingGBTHeader, // GBT payload header was expected but not foun @@ -106,7 +108,6 @@ struct RUDecodingStat { } static constexpr std::array ErrNames = { - "Garbage (non-0) detected after CRU page payload is over", // ErrGarbageAfterPayload "RDH page counters for the same RU/trigger are not continuous", // ErrPageCounterDiscontinuity "RDH ang GBT header page counters are not consistent", // ErrRDHvsGBTHPageCnt "GBT payload header was expected but not found", // ErrMissingGBTHeader @@ -182,17 +183,35 @@ struct RUEncodeData { } }; +// support for the GBT single link data +struct RULink { + PayLoadCont data; // data buffer per link + int lastPageSize = 0; // size of last added page = offset from the end to get to the RDH + int nTriggers = 0; // number of triggers loaded (the last one might be incomplete) +}; + struct RUDecodeData { std::array cableData; // cable data in compressed ALPIDE format std::array cableHWID; // HW ID of cable whose data is in the corresponding slot of cableData std::array chipsData; // fully decoded data + std::array, MaxLinksPerRU> links; // data + counters for links of this RU + RUDecodingStat statistics; // decoding statistics - int nCables = 0; // total number of cables + int nCables = 0; // total number of cables decoded for single trigger int nChipsFired = 0; // number of chips with data or with errors int lastChipChecked = 0; // last chips checked among nChipsFired const RUInfo* ruInfo = nullptr; + RUDecodeData() = default; + // RUDecodeData(const RUDecodeData& src) {}; // dummy? + void clear() + { + clearTrigger(); + statistics.clear(); + } + + void clearTrigger() { for (int i = nCables; i--;) { cableData[i].clear(); @@ -201,6 +220,13 @@ struct RUDecodeData { } }; +struct RULinks { + std::array data; // data buffer per link + std::array lastPageSize = { 0 }; // size of last added page = offset from the end to get to the RDH + std::array nTriggers = { 0 }; // number of triggers loaded (the last one might be incomplete) + RULinks() = default; +}; + /// Used both for encoding to and decoding from the alpide raw data format /// Requires as a template parameter a helper class for detector-specific /// mapping between the software global chip ID and HW module ID and chip ID @@ -213,7 +239,11 @@ class RawPixelReader : public PixelReader using Coder = o2::ITSMFT::AlpideCoder; public: - RawPixelReader() = default; + RawPixelReader() + { + mRUEntry.fill(-1); // no known links in the beginning + } + ~RawPixelReader() override { mSWIO.Stop(); @@ -237,43 +267,59 @@ class RawPixelReader : public PixelReader mGBTWordSize = mPadding128 ? ITSMFT::GBTPaddedWordLength : o2::ITSMFT::GBTWordLength; } + /// set min number of triggers to cache per frame + void setMinTriggersToCache(int n) { mMinTriggersToCache = n > NCRUPagesPerSuperpage ? n : NCRUPagesPerSuperpage + 1; } + + int getMinTriggersToCache() const { return mMinTriggersToCache; } + /// CRU pages are of max size of 8KB void imposeMaxPage(bool v) { mImposeMaxPage = v; } + ///______________________________________________________________________ ChipPixelData* getNextChipData(std::vector& chipDataVec) override { // decode new RU if no cached non-empty chips - while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired) { - if (mIOFile) { - loadInput(); // if needed, upload additional data to the buffer - } - if (!decodeNextRUData(mRawBuffer)) { // failure to decode would signal error or EOF - break; + + if (mCurRUDecodeID >= 0) { // make sure current RU has fired chips to extract + for (; mCurRUDecodeID < mNRUs; mCurRUDecodeID++) { + auto& ru = mRUDecodeVec[mCurRUDecodeID]; + if (ru.lastChipChecked < ru.nChipsFired) { + auto& chipData = ru.chipsData[ru.lastChipChecked++]; + int id = chipData.getChipID(); + chipDataVec[id].swap(chipData); + return &chipDataVec[id]; + } } + mCurRUDecodeID = 0; // no more decoded data if reached this place, } - if (mRUDecode.lastChipChecked < mRUDecode.nChipsFired) { - auto& chipData = mRUDecode.chipsData[mRUDecode.lastChipChecked++]; - int id = chipData.getChipID(); - chipDataVec[id].swap(chipData); - // chipDataVec[id].print(); - return &chipDataVec[id]; + // will need to decode new trigger + if (mMinTriggersCached < 2) { // last trigger might be incomplete, need to cache more data + cacheLinksData(mRawBuffer); } - return nullptr; + if (mMinTriggersCached < 1 || !decodeNextTrigger()) { + mCurRUDecodeID = -1; + return nullptr; // nothing left + } + return getNextChipData(chipDataVec); // is it ok to use recursion here? } + ///______________________________________________________________________ void init() override{}; + ///______________________________________________________________________ void clear() { mDecodingStat.clear(); - for (auto& ruStat : mRUDecodingStat) { - ruStat.clear(); + for (auto& rudec : mRUDecodeVec) { + rudec.clear(); } + mNLinks = 0; + mNRUs = 0; mIOFile.close(); mRawBuffer.clear(); - mRUDecode.clear(); } + ///______________________________________________________________________ int digits2raw(const std::vector& digiVec, int from, int ndig, const o2::InteractionRecord& bcData, PayLoadCont& sink, uint8_t ruSWMin = 0, uint8_t ruSWMax = 0xff) { @@ -575,51 +621,187 @@ class RawPixelReader : public PixelReader } //_____________________________________ - int decodeNextRUData(PayLoadCont& buffer) + size_t cacheLinksData(PayLoadCont& buffer) { + // distribute data from the single buffer among the links caches - int res = 0; - if (!buffer.isEmpty()) { - bool aborted = false; + LOG(INFO) << "Cacheding links data, currently in cache: " << mMinTriggersCached << " triggers"; + auto nRead = loadInput(buffer); + if (buffer.isEmpty()) { + return nRead; + } - //printf("Unused: %d Size: %d Offs: %d\n", buffer.getUnusedSize(), buffer.getSize(), buffer.getOffset() ); - mRUDecode.clear(); + bool enoughTriggers[ChipMappingITS::getNRUs()][3] = { false }; // flag that enough triggeres were loaded for this link + int nLEnoughTriggers = 0; // number of links for we which enough number of triggers were loaded + auto ptr = buffer.getPtr(); + o2::header::RAWDataHeader* rdh = reinterpret_cast(ptr); - auto ptr = decodeRUData(buffer.getPtr(), aborted); + do { + if (!isRDHHeuristic(rdh)) { // does it look like RDH? + if (!findNextRDH(buffer)) { // try to recover the pointer + break; // no data to continue + } + ptr = buffer.getPtr(); + } - if (!aborted) { - decodeAlpideData(mRUDecode); // decode Alpide data from the compressed RU Data + int ruIDSW = getMapping().FEEId2RUSW(rdh->feeId); + if (mRUEntry[ruIDSW] < 0) { // do we see this RU for the 1st time + mRUEntry[ruIDSW] = mNRUs++; + mRUDecodeVec[mRUEntry[ruIDSW]].ruInfo = MAP.getRUInfoSW(ruIDSW); // info on the stave/RU + } + auto& ruDecode = mRUDecodeVec[mRUEntry[ruIDSW]]; + + bool newTrigger = true; // check if we see new trigger + auto link = ruDecode.links[rdh->linkID].get(); + if (link) { // was there any data seen on this link before? + const auto rdhPrev = reinterpret_cast(link->data.getEnd() - link->lastPageSize); // last stored RDH + if (isSameRUandTrigger(rdhPrev, rdh)) { + newTrigger = false; + } + } else { // a new link was added + ruDecode.links[rdh->linkID] = std::make_unique(); + link = ruDecode.links[rdh->linkID].get(); + mNLinks++; + } + // copy data to the buffer of the link and memorize its RDH pointer + link->data.add(ptr, rdh->memorySize); + link->lastPageSize = rdh->memorySize; // account new added size + auto rdhC = reinterpret_cast(link->data.getEnd() - link->lastPageSize); + rdhC->offsetToNext = rdh->memorySize; // since we skip 0-s, we have to modify the offset + + if (newTrigger) { + link->nTriggers++; // acknowledge 1st trigger + if (link->nTriggers >= mMinTriggersToCache && !enoughTriggers[ruIDSW][rdh->linkID]) { + nLEnoughTriggers++; + enoughTriggers[ruIDSW][rdh->linkID] = true; + } + } - buffer.setPtr(ptr); - res = 1; // success - if (buffer.isEmpty()) { - buffer.clear(); + mDecodingStat.nBytesProcessed += rdh->memorySize; + mDecodingStat.nPagesProcessed++; + ptr += rdh->offsetToNext; + buffer.setPtr(ptr); + if (buffer.getUnusedSize() < MaxGBTPacketBytes) { + nRead += loadInput(buffer); // update + ptr = buffer.getPtr(); // pointer might have been changed + } + + rdh = reinterpret_cast(ptr); + + if (mNLinks == nLEnoughTriggers) { + break; + } + + } while (!buffer.isEmpty()); + + if (mNLinks == nLEnoughTriggers) { + mMinTriggersCached = mMinTriggersToCache; // wanted number of triggers acquired + } else { // there were no enough triggers to fulfill mMinTriggersToCache requirement + mMinTriggersCached = INT_MAX; + for (int ir = 0; ir < mNRUs; ir++) { + const auto& ruDecData = mRUDecodeVec[ir]; + for (auto& link : ruDecData.links) { + if (link && link->nTriggers < mMinTriggersCached) { + mMinTriggersCached = link->nTriggers; + } } - } else { // try to seek to the next RDH, can be done only for 128b padded GBT words - LOG(ERROR) << "Will seek the next RDH after aborting (unreliable!!)"; - auto ptrTail = buffer.getPtr() + buffer.getUnusedSize(); - ptr += ((ptr - buffer.getPtr()) / mGBTWordSize) * mGBTWordSize; // jump to the next GBT word - while (ptr + mGBTWordSize <= ptrTail) { - auto* rdh = reinterpret_cast(ptr); - if (isRDHHeuristic(rdh)) { // this heuristics is not reliable... - LOG(WARNING) << "Assuming that found a new RDH"; - printRDH(*rdh); - buffer.setPtr(ptr); + } + } + LOG(INFO) << "Cached at least " << mMinTriggersCached << " triggers on " << mNLinks << " links of " << mNRUs << " RUs"; + + return nRead; + } + + //_____________________________________ + int decodeNextTrigger() + { + // Decode next trigger from the cached links data and decrease cached triggers counter, return N links decoded + if (mMinTriggersCached < 1) { + return 0; + } + int nlinks = 0; + for (int ir = mNRUs; ir--;) { + auto& ruDecode = mRUDecodeVec[ir]; + if (!nlinks) { // on 1st occasion extract trigger data + for (auto& link : ruDecode.links) { // loop over links to fill cable buffers + if (link && !link->data.isEmpty()) { + const auto rdh = reinterpret_cast(link->data.getPtr()); + mInteractionRecord.bc = rdh->triggerBC; + mInteractionRecord.orbit = rdh->triggerOrbit; + mTrigger = rdh->triggerType; break; } - ptr += mGBTWordSize; } - buffer.setPtr(ptr); - if (!buffer.isEmpty()) { - res = 1; // found a RDH condidate - } else { - buffer.clear(); // did not find new RDH + } + + nlinks += decodeNextRUData(ruDecode); + mDecodingStat.nRUsProcessed++; + } + mCurRUDecodeID = 0; + mMinTriggersCached--; + return nlinks; + } + + //_____________________________________ + int decodeNextRUData(RUDecodeData& ruDecData) + { + // process data of single RU trigger from its links buffers + int minTriggers = INT_MAX; + int res = 0; + ruDecData.clearTrigger(); + bool aborted = false; + for (auto& link : ruDecData.links) { // loop over links to fill cable buffers + if (link && !link->data.isEmpty()) { + link->data.setPtr(decodeRUData(link->data.getPtr(), ruDecData, aborted)); + // we don't need to check the "abort" status since the checks for links data presence and synchronization + // should have been done in advance + if (--link->nTriggers < minTriggers) { // decrement counter of cached triggers + minTriggers = link->nTriggers; } - } // try to seek to the next ... + res++; + if (link->data.isEmpty()) { + link->data.clear(); + } + } + } + if (ruDecData.nCables) { // there are cables with data to decode + decodeAlpideData(ruDecData); // decode Alpide data from the compressed RU Data } return res; } + //_____________________________________ + bool findNextRDH(PayLoadCont& buffer) + { + // keep reading GRB words until RDH is found + size_t nRead = 0; + int scan = 0; + bool goodRDH = false; + auto ptr = buffer.getPtr(); + o2::header::RAWDataHeader* rdh = nullptr; + do { + if (buffer.isEmpty()) { + auto nrl = loadInput(buffer); + if (!nrl) { + break; + } + nRead += nrl; + ptr = buffer.getPtr(); + } + scan++; + ptr += o2::ITSMFT::GBTPaddedWordLength; + buffer.setPtr(ptr); + if (!buffer.isEmpty()) { + rdh = reinterpret_cast(ptr); + } else { + break; + } + } while (!(goodRDH = isRDHHeuristic(rdh))); + LOG(INFO) << "End of pointer recovery after skipping " << scan << " GBT words, RDH is" + << (goodRDH ? "" : " not") << " found"; + return goodRDH; + } + //_____________________________________ bool isRDHHeuristic(const o2::header::RAWDataHeader* rdh) { @@ -631,9 +813,10 @@ class RawPixelReader : public PixelReader } //_____________________________________ - uint8_t* decodeRUData(uint8_t* raw, bool& aborted) + uint8_t* decodeRUData(uint8_t* raw, RUDecodeData& ruDecData, bool& aborted) { - /// Decode raw data of single RU (possibly in a few GBT packets) + /// Decode raw data of single RU (possibly in a few GBT packets), collecting raw data + /// for every cable in the corresponding slot of the provided ruDecData. /// No check is done if the necessary data are fully contained in the raw buffer. /// Return the pointer on the last raw data byte after decoding the RU /// In case of unrecoverable error set aborted to true @@ -657,21 +840,15 @@ class RawPixelReader : public PixelReader #endif int ruIDSW = MAP.FEEId2RUSW(rdh->feeId); - // LOG(INFO) << "Decoding RU:" << rdh->feeId << " swID: " << ruIDSW << " Orbit:" << rdh->triggerOrbit << " BC: " << rdh->triggerBC; - - mInteractionRecord.bc = rdh->triggerBC; - mInteractionRecord.orbit = rdh->triggerOrbit; - mTrigger = rdh->triggerType; + if (ruIDSW != ruDecData.ruInfo->idSW) { + LOG(ERROR) << "RDG RU IDSW " << ruIDSW << " differs from expected " << ruDecData.ruInfo->idSW; + } - auto& currRU = mRUDecodingStat[ruIDSW]; - currRU.nPackets++; - mDecodingStat.nRUsProcessed++; + auto& ruStat = ruDecData.statistics; + ruStat.nPackets++; - mRUDecode.ruInfo = MAP.getRUInfoSW(ruIDSW); // info on the stave being decoded - mRUDecode.nCables = mRUDecode.ruInfo->nCables; + ruDecData.nCables = ruDecData.ruInfo->nCables; while (1) { - mDecodingStat.nPagesProcessed++; - mDecodingStat.nBytesProcessed += rdh->memorySize; raw += rdh->headerSize; int nGBTWords = (rdh->memorySize - rdh->headerSize) / mGBTWordSize - 2; // number of GBT words excluding header/trailer auto gbtH = reinterpret_cast(raw); // process GBT header @@ -686,28 +863,28 @@ class RawPixelReader : public PixelReader gbtH->printX(mPadding128); LOG(ERROR) << "FEE#" << rdh->feeId << " GBT payload header was expected, abort page decoding"; gbtH->printX(mPadding128); - currRU.errorCounts[RUDecodingStat::ErrMissingGBTHeader]++; + ruStat.errorCounts[RUDecodingStat::ErrMissingGBTHeader]++; aborted = true; return raw; } if (gbtH->getPacketID() != rdh->pageCnt) { LOG(ERROR) << "FEE#" << rdh->feeId << " Different GBT header " << gbtH->getPacketID() << " and RDH page " << rdh->pageCnt << " counters"; - currRU.errorCounts[RUDecodingStat::ErrRDHvsGBTHPageCnt]++; + ruStat.errorCounts[RUDecodingStat::ErrRDHvsGBTHPageCnt]++; } - if (currRU.lanesActive == currRU.lanesStop) { // all lanes received their stop, new page 0 expected + if (ruStat.lanesActive == ruStat.lanesStop) { // all lanes received their stop, new page 0 expected if (rdh->pageCnt) { // flag lanes of this FEE LOG(ERROR) << "FEE#" << rdh->feeId << " Non-0 page counter (" << rdh->pageCnt << ") while all lanes were stopped"; - currRU.errorCounts[RUDecodingStat::ErrNonZeroPageAfterStop]++; + ruStat.errorCounts[RUDecodingStat::ErrNonZeroPageAfterStop]++; } } - currRU.lanesActive = gbtH->getLanes(); // TODO do we need to update this for every page? + ruStat.lanesActive = gbtH->getLanes(); // TODO do we need to update this for every page? if (!rdh->pageCnt) { // reset flags - currRU.lanesStop = 0; - currRU.lanesWithData = 0; + ruStat.lanesStop = 0; + ruStat.lanesWithData = 0; } #endif @@ -726,14 +903,14 @@ class RawPixelReader : public PixelReader } int cableHW = gbtD->getCableID(); - int cableSW = MAP.cableHW2SW(mRUDecode.ruInfo->ruType, cableHW); - mRUDecode.cableData[cableSW].add(gbtD->getW8(), 9); - mRUDecode.cableHWID[cableSW] = cableHW; + int cableSW = MAP.cableHW2SW(ruDecData.ruInfo->ruType, cableHW); + ruDecData.cableData[cableSW].add(gbtD->getW8(), 9); + ruDecData.cableHWID[cableSW] = cableHW; #ifdef _RAW_READER_ERROR_CHECKS_ - currRU.lanesWithData |= 0x1 << cableSW; // flag that the data was seen on this lane - if (currRU.lanesStop & (0x1 << cableSW)) { // make sure stopped lanes do not transmit the data - currRU.errorCounts[RUDecodingStat::ErrDataForStoppedLane]++; + ruStat.lanesWithData |= 0x1 << cableSW; // flag that the data was seen on this lane + if (ruStat.lanesStop & (0x1 << cableSW)) { // make sure stopped lanes do not transmit the data + ruStat.errorCounts[RUDecodingStat::ErrDataForStoppedLane]++; LOG(ERROR) << "FEE#" << rdh->feeId << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")"; } #endif @@ -750,44 +927,17 @@ class RawPixelReader : public PixelReader if (!gbtT->isDataTrailer()) { gbtT->printX(mPadding128); LOG(ERROR) << "FEE#" << rdh->feeId << " GBT payload trailer was expected, abort page decoding NW" << nGBTWords; - currRU.errorCounts[RUDecodingStat::ErrMissingGBTTrailer]++; + ruStat.errorCounts[RUDecodingStat::ErrMissingGBTTrailer]++; aborted = true; return raw; } - currRU.lanesTimeOut |= gbtT->getLanesTimeout(); // register timeouts - currRU.lanesStop |= gbtT->getLanesStop(); // register stops + ruStat.lanesTimeOut |= gbtT->getLanesTimeout(); // register timeouts + ruStat.lanesStop |= gbtT->getLanesStop(); // register stops #endif raw += mGBTWordSize; // we finished the GBT page, see if there is a continuation and if it belongs to the same multipacket -#ifdef _RAW_READER_ERROR_CHECKS_ - // make sure we have only 0's till the end of the page - - // TODO: not clear if the block length is constantly 8KB or can change, at the moment assume it is - int nWLeft = ((mImposeMaxPage ? MaxGBTPacketBytes : rdh->memorySize) - rdh->headerSize) / mGBTWordSize - (nGBTWords + 2); - if (mVerbose) { - LOG(INFO) << "Expect " << nWLeft << " 0-filled GBT words"; - } - - for (int iw = 0; iw < nWLeft; iw++) { - auto gbtD = reinterpret_cast(raw); - raw += mGBTWordSize; - if (mVerbose) { - printf("P%4d |", iw); - gbtD->printX(mPadding128); - } - for (int ib = mGBTWordSize; ib--;) { - if (gbtD->getByte(ib)) { - LOG(ERROR) << "FEE#" << rdh->feeId << " Non-0 data detected after payload trailer"; - currRU.errorCounts[RUDecodingStat::ErrGarbageAfterPayload]++; - nWLeft = 0; // do not continue the check - break; - } - } - } -#endif - if (!rdh->offsetToNext) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0? break; } @@ -799,21 +949,21 @@ class RawPixelReader : public PixelReader #ifdef _RAW_READER_ERROR_CHECKS_ // make sure all lane stops for finished page are received - if (currRU.lanesActive != currRU.lanesStop) { + if (ruStat.lanesActive != ruStat.lanesStop) { if (rdh->triggerType != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes? LOG(ERROR) << "FEE#" << rdh->feeId << " end of FEE data but not all lanes received stop"; - currRU.errorCounts[RUDecodingStat::ErrUnstoppedLanes]++; + ruStat.errorCounts[RUDecodingStat::ErrUnstoppedLanes]++; } } // make sure all active lanes (except those in time-out) have sent some data - if ((~currRU.lanesWithData & currRU.lanesActive) != currRU.lanesTimeOut) { + if ((~ruStat.lanesWithData & ruStat.lanesActive) != ruStat.lanesTimeOut) { LOG(ERROR) << "FEE#" << rdh->feeId << " Lanes not in time-out but not sending data"; - currRU.errorCounts[RUDecodingStat::ErrNoDataForActiveLane]++; + ruStat.errorCounts[RUDecodingStat::ErrNoDataForActiveLane]++; } // accumulate packet states - currRU.packetStates[gbtT->getPacketState()]++; + ruStat.packetStates[gbtT->getPacketState()]++; #endif break; @@ -823,7 +973,7 @@ class RawPixelReader : public PixelReader if (rdhN->pageCnt != rdh->pageCnt + 1) { LOG(ERROR) << "FEE#" << rdh->feeId << " Discontinuity in the RDH page counter of the same RU trigger: old " << rdh->pageCnt << " new: " << rdhN->pageCnt; - currRU.errorCounts[RUDecodingStat::ErrPageCounterDiscontinuity]++; + ruStat.errorCounts[RUDecodingStat::ErrPageCounterDiscontinuity]++; } #endif rdh = rdhN; @@ -842,7 +992,7 @@ class RawPixelReader : public PixelReader int skimNextRUData(PayLoadCont& outBuffer) { if (mIOFile) { - loadInput(); // if needed, upload additional data to the buffer + loadInput(mRawBuffer); // if needed, upload additional data to the buffer } int res = 0; @@ -858,22 +1008,9 @@ class RawPixelReader : public PixelReader mRawBuffer.clear(); } } else { // try to seek to the next RDH, can be done only for 128b padded GBT words - LOG(ERROR) << "Will seek the next RDH after aborting (unreliable!!)"; - auto ptrTail = mRawBuffer.getPtr() + mRawBuffer.getUnusedSize(); - ptr += ((ptr - mRawBuffer.getPtr()) / mGBTWordSize) * mGBTWordSize; // jump to the next GBT word - while (ptr + mGBTWordSize <= ptrTail) { - auto* rdh = reinterpret_cast(ptr); - if (isRDHHeuristic(rdh)) { // this heuristics is not reliable... - LOG(WARNING) << "Assuming that found a new RDH"; - printRDH(*rdh); - mRawBuffer.setPtr(ptr); - break; - } - ptr += mGBTWordSize; - } - mRawBuffer.setPtr(ptr); - if (!mRawBuffer.isEmpty()) { - res = 1; // found a RDH condidate + if (findNextRDH(mRawBuffer)) { + ptr = mRawBuffer.getPtr(); + res = 1; } else { mRawBuffer.clear(); // did not find new RDH } @@ -905,14 +1042,18 @@ class RawPixelReader : public PixelReader #endif int ruIDSW = MAP.FEEId2RUSW(rdh->feeId); + if (mRUEntry[ruIDSW] < 0) { // do we see this RU for the 1st time + mRUEntry[ruIDSW] = mNRUs++; + mRUDecodeVec[mRUEntry[ruIDSW]].ruInfo = MAP.getRUInfoSW(ruIDSW); // info on the stave/RU + } auto ruInfo = MAP.getRUInfoSW(ruIDSW); mInteractionRecord.bc = rdh->triggerBC; mInteractionRecord.orbit = rdh->triggerOrbit; mTrigger = rdh->triggerType; - auto& currRU = mRUDecodingStat[ruIDSW]; - currRU.nPackets++; + auto& ruStat = mRUDecodeVec[mRUEntry[ruIDSW]].statistics; + ruStat.nPackets++; mDecodingStat.nRUsProcessed++; int sizeAtEntry = outBuffer.getSize(); // save the size of outbuffer size at entry, in case of severe error we will need to rewind to it. @@ -935,7 +1076,7 @@ class RawPixelReader : public PixelReader gbtH->printX(true); LOG(ERROR) << "FEE#" << rdh->feeId << " GBT payload header was expected, abort page decoding"; gbtH->printX(true); - currRU.errorCounts[RUDecodingStat::ErrMissingGBTHeader]++; + ruStat.errorCounts[RUDecodingStat::ErrMissingGBTHeader]++; aborted = true; outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state return raw; @@ -943,21 +1084,21 @@ class RawPixelReader : public PixelReader if (gbtH->getPacketID() != rdh->pageCnt) { LOG(ERROR) << "FEE#" << rdh->feeId << " Different GBT header " << gbtH->getPacketID() << " and RDH page " << rdh->pageCnt << " counters"; - currRU.errorCounts[RUDecodingStat::ErrRDHvsGBTHPageCnt]++; + ruStat.errorCounts[RUDecodingStat::ErrRDHvsGBTHPageCnt]++; } - if (currRU.lanesActive == currRU.lanesStop) { // all lanes received their stop, new page 0 expected + if (ruStat.lanesActive == ruStat.lanesStop) { // all lanes received their stop, new page 0 expected if (rdh->pageCnt) { // flag lanes of this FEE LOG(ERROR) << "FEE#" << rdh->feeId << " Non-0 page counter (" << rdh->pageCnt << ") while all lanes were stopped"; - currRU.errorCounts[RUDecodingStat::ErrNonZeroPageAfterStop]++; + ruStat.errorCounts[RUDecodingStat::ErrNonZeroPageAfterStop]++; } } - currRU.lanesActive = gbtH->getLanes(); // TODO do we need to update this for every page? + ruStat.lanesActive = gbtH->getLanes(); // TODO do we need to update this for every page? if (!rdh->pageCnt) { // reset flags - currRU.lanesStop = 0; - currRU.lanesWithData = 0; + ruStat.lanesStop = 0; + ruStat.lanesWithData = 0; } #endif @@ -988,9 +1129,9 @@ class RawPixelReader : public PixelReader outBuffer.addFast(reinterpret_cast(gbtD), mGBTWordSize); // save gbt word w/o 128b padding #ifdef _RAW_READER_ERROR_CHECKS_ - currRU.lanesWithData |= 0x1 << cableSW; // flag that the data was seen on this lane - if (currRU.lanesStop & (0x1 << cableSW)) { // make sure stopped lanes do not transmit the data - currRU.errorCounts[RUDecodingStat::ErrDataForStoppedLane]++; + ruStat.lanesWithData |= 0x1 << cableSW; // flag that the data was seen on this lane + if (ruStat.lanesStop & (0x1 << cableSW)) { // make sure stopped lanes do not transmit the data + ruStat.errorCounts[RUDecodingStat::ErrDataForStoppedLane]++; LOG(ERROR) << "FEE#" << rdh->feeId << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")"; } #endif @@ -1007,14 +1148,14 @@ class RawPixelReader : public PixelReader if (!gbtT->isDataTrailer()) { gbtT->printX(true); LOG(ERROR) << "FEE#" << rdh->feeId << " GBT payload trailer was expected, abort page decoding at NW" << nGBTWords; - currRU.errorCounts[RUDecodingStat::ErrMissingGBTTrailer]++; + ruStat.errorCounts[RUDecodingStat::ErrMissingGBTTrailer]++; aborted = true; outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state return raw; } - currRU.lanesTimeOut |= gbtT->getLanesTimeout(); // register timeouts - currRU.lanesStop |= gbtT->getLanesStop(); // register stops + ruStat.lanesTimeOut |= gbtT->getLanesTimeout(); // register timeouts + ruStat.lanesStop |= gbtT->getLanesStop(); // register stops #endif outBuffer.addFast(reinterpret_cast(gbtT), mGBTWordSize); // save gbt trailer w/o 128b padding @@ -1025,32 +1166,6 @@ class RawPixelReader : public PixelReader rdhS->memorySize = rdhS->headerSize + (2 + nGBTWords) * mGBTWordSize; rdhS->offsetToNext = rdhS->memorySize; -#ifdef _RAW_READER_ERROR_CHECKS_ - // make sure we have only 0's till the end of the page - - // TODO: not clear if the block length is constantly 8KB or can change, at the moment assume it is - int nWLeft = (MaxGBTPacketBytes - rdh->headerSize) / o2::ITSMFT::GBTPaddedWordLength - (nGBTWords + 2); - if (mVerbose) { - LOG(INFO) << "Expect " << nWLeft << " 0-filled GBT words"; - } - for (int iw = 0; iw < nWLeft; iw++) { - auto gbtD = reinterpret_cast(raw); - raw += o2::ITSMFT::GBTPaddedWordLength; - if (mVerbose) { - printf("P%4d |", iw); - gbtD->printX(mPadding128); - } - for (int ib = o2::ITSMFT::GBTPaddedWordLength; ib--;) { - if (gbtD->getByte(ib)) { - LOG(ERROR) << "FEE#" << rdh->feeId << " Non-0 data detected after payload trailer"; - currRU.errorCounts[RUDecodingStat::ErrGarbageAfterPayload]++; - nWLeft = 0; // do not continue the check - break; - } - } - } -#endif - if (!rdh->offsetToNext) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0? break; } @@ -1062,21 +1177,21 @@ class RawPixelReader : public PixelReader #ifdef _RAW_READER_ERROR_CHECKS_ // make sure all lane stops for finished page are received - if (currRU.lanesActive != currRU.lanesStop) { + if (ruStat.lanesActive != ruStat.lanesStop) { if (rdh->triggerType != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes? LOG(ERROR) << "FEE#" << rdh->feeId << " end of FEE data but not all lanes received stop"; - currRU.errorCounts[RUDecodingStat::ErrUnstoppedLanes]++; + ruStat.errorCounts[RUDecodingStat::ErrUnstoppedLanes]++; } } // make sure all active lanes (except those in time-out) have sent some data - if ((~currRU.lanesWithData & currRU.lanesActive) != currRU.lanesTimeOut) { + if ((~ruStat.lanesWithData & ruStat.lanesActive) != ruStat.lanesTimeOut) { LOG(ERROR) << "FEE#" << rdh->feeId << " Lanes not in time-out but not sending data"; - currRU.errorCounts[RUDecodingStat::ErrNoDataForActiveLane]++; + ruStat.errorCounts[RUDecodingStat::ErrNoDataForActiveLane]++; } // accumulate packet states - currRU.packetStates[gbtT->getPacketState()]++; + ruStat.packetStates[gbtT->getPacketState()]++; #endif break; @@ -1086,7 +1201,7 @@ class RawPixelReader : public PixelReader if (rdhN->pageCnt != rdh->pageCnt + 1) { LOG(ERROR) << "FEE#" << rdh->feeId << " Discontinuity in the RDH page counter of the same RU trigger: old " << rdh->pageCnt << " new: " << rdhN->pageCnt; - currRU.errorCounts[RUDecodingStat::ErrPageCounterDiscontinuity]++; + ruStat.errorCounts[RUDecodingStat::ErrPageCounterDiscontinuity]++; } #endif rdh = rdhN; @@ -1122,7 +1237,7 @@ class RawPixelReader : public PixelReader /// decode the ALPIDE data from the buffer of single lane auto* chipData = &decData.chipsData[0]; - auto& currRU = mRUDecodingStat[decData.ruInfo->idSW]; + auto& ruStat = decData.statistics; decData.nChipsFired = decData.lastChipChecked = 0; int ntot = 0; @@ -1135,7 +1250,7 @@ class RawPixelReader : public PixelReader uint8_t h; if (cableData.current(h) && !mCoder.isChipHeaderOrEmpty(h)) { LOG(ERROR) << "FEE#" << decData.ruInfo->idHW << " cable " << icab << " data does not start with ChipHeader or ChipEmpty"; - currRU.errorCounts[RUDecodingStat::ErrCableDataHeadWrong]++; + ruStat.errorCounts[RUDecodingStat::ErrCableDataHeadWrong]++; } #endif @@ -1146,7 +1261,7 @@ class RawPixelReader : public PixelReader if (decData.ruInfo->ruType == 0) { // ATTENTION: this is a hack tailored for temporary check if (chipData->getChipID() != icab) { LOG(ERROR) << "FEE#" << decData.ruInfo->idHW << " IB cable " << icab << " shipped chip ID= " << chipData->getChipID(); - currRU.errorCounts[RUDecodingStat::ErrIBChipLaneMismatch]++; + ruStat.errorCounts[RUDecodingStat::ErrIBChipLaneMismatch]++; } } #endif @@ -1174,21 +1289,25 @@ class RawPixelReader : public PixelReader { /// read single chip data to the provided container - // decode new RU if no cached non-empty chips - while (mRUDecode.lastChipChecked >= mRUDecode.nChipsFired) { - if (mIOFile) { - loadInput(); // if needed, upload additional data to the buffer - } - if (!decodeNextRUData(mRawBuffer)) { // failure to decode would signal error or EOF - break; + if (mCurRUDecodeID >= 0) { // make sure current RU has fired chips to extract + for (; mCurRUDecodeID < mNRUs; mCurRUDecodeID++) { + auto& ru = mRUDecodeVec[mCurRUDecodeID]; + if (ru.lastChipChecked < ru.nChipsFired) { + chipData.swap(ru.chipsData[ru.lastChipChecked++]); + return true; + } } + mCurRUDecodeID = 0; // no more decoded data if reached this place, } - - if (mRUDecode.lastChipChecked < mRUDecode.nChipsFired) { - chipData.swap(mRUDecode.chipsData[mRUDecode.lastChipChecked++]); - return true; + // will need to decode new trigger + if (mMinTriggersCached < 2) { // last trigger might be incomplete, need to cache more data + cacheLinksData(mRawBuffer); } - return false; + if (mMinTriggersCached < 1 || !decodeNextTrigger()) { + mCurRUDecodeID = -1; + return false; // nothing left + } + return getNextChipData(chipData); // is it ok to use recursion here? } //_____________________________________ @@ -1206,7 +1325,7 @@ class RawPixelReader : public PixelReader } //_____________________________________ - int loadInput() + size_t loadInput(PayLoadCont& buffer) { /// assure the buffers are large enough static_assert(RawBufferMargin > MaxGBTPacketBytes * 100 && @@ -1216,33 +1335,31 @@ class RawPixelReader : public PixelReader if (!mIOFile) { return 0; } - if (mRawBuffer.getUnusedSize() > RawBufferMargin) { // bytes read but not used yet are enough + if (buffer.getUnusedSize() > RawBufferMargin) { // bytes read but not used yet are enough return 0; } mSWIO.Start(false); auto readFromFile = [this](uint8_t* ptr, int n) { mIOFile.read(reinterpret_cast(ptr), n); - return (int)mIOFile.gcount(); // fread( ptr, sizeof(uint8_t), n, mIOFile); + return mIOFile.gcount(); // fread( ptr, sizeof(uint8_t), n, mIOFile); }; - auto nread = mRawBuffer.append(readFromFile); + auto nread = buffer.append(readFromFile); + mDecodingStat.nBytesProcessed += nread; mSWIO.Stop(); return nread; } - // get vector of RUs statistics - const std::array& getRUDecodingStat(); - // get statics of FEE with sequential idSW - const RUDecodingStat& getRUDecodingStatSW(uint16_t idSW) const + const RUDecodingStat* getRUDecodingStatSW(uint16_t idSW) const { - return mRUDecodingStat[idSW]; + return mRUEntry[idSW] < 0 ? nullptr : &mRUDecodeVec[mRUEntry[idSW]].statistics; } // get statics of FEE with given HW id - const RUDecodingStat& getRUDecodingStatHW(uint16_t idHW) const + const RUDecodingStat* getRUDecodingStatHW(uint16_t idHW) const { - int idsw = 0xffff; - assert(idHW < mRUDecodingStat.size() && (idsw = MAP.FEEId2RUSW(idHW)) != 0xffff); + int idsw = MAP.FEEId2RUSW(idHW); + assert(idsw != 0xffff); return getRUDecodingStatSW(idsw); } @@ -1254,10 +1371,28 @@ class RawPixelReader : public PixelReader Mapping& getMapping() { return MAP; } - const RUDecodeData& getRUDecodeData() const { return mRUDecode; } + // get currently processed RU container + const RUDecodeData* getCurrRUDecodeData() const { return mCurRUDecodeID < 0 ? nullptr : &mRUDecodeVec[mCurRUDecodeID]; } PayLoadCont& getRawBuffer() { return mRawBuffer; } + // number of links seen in the data + int getNLinks() const { return mNLinks; } + + // number of RUs seen in the data + int getNRUs() const { return mNRUs; } + + // get vector of RU decode containers for RUs seen in the data + const std::vector& getRUDecodeVec() const { return mRUDecodeVec; } + + const std::array& getRUEntries() const { return mRUEntry; } + + // get RU decode container for RU with given SW ID + const RUDecodeData* getRUDecode(int ruSW) const + { + return mRUEntry[ruSW] < 0 ? nullptr : &mRUDecodeVec[mRUEntry[ruSW]]; + } + private: std::ifstream mIOFile; Coder mCoder; @@ -1265,12 +1400,22 @@ class RawPixelReader : public PixelReader int mVerbose = 0; //! verbosity level RUEncodeData mRUEncode; //! buffer for the digits to convert RUEncodeData mRUEncodeEmpty; //! placeholder for empty RU data - RUDecodeData mRUDecode; //! buffer for decoded data - PayLoadCont mRawBuffer; //! buffer for binary raw data + int mCurRUDecodeID = -1; //! index of currently processed RUDecode container + + PayLoadCont mRawBuffer; //! buffer for binary raw data file IO + + std::array mRUDecodeVec; // decoding buffers for all active RUs + std::array mRUEntry; //! entry of the RU with given SW ID in the mRULinks + int mNRUs = 0; //! total number of RUs seen + int mNLinks = 0; //! total number of GBT links seen + + //! min number of triggers to cache per link (keep this > N pages per CRU superpage) + int mMinTriggersToCache = NCRUPagesPerSuperpage + 10; + int mMinTriggersCached = 0; //! actual minimum (among different links) number of triggers to cache // statistics - std::array mRUDecodingStat; //! statics of decoding per FEE + //XXX std::array mRUDecodingStat; //! statics of decoding per FEE RawDecodingStat mDecodingStat; //! global decoding statistics TStopwatch mSWIO; //! timer for IO operations diff --git a/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx b/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx index a83436f2b1420..c87e28f896c8b 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/PayLoadCont.cxx @@ -15,16 +15,16 @@ using namespace o2::ITSMFT; -constexpr int PayLoadCont::MinCapacity; +constexpr size_t PayLoadCont::MinCapacity; -void PayLoadCont::expand(int sz) +void PayLoadCont::expand(size_t sz) { ///< increase the buffer size auto* oldHead = mBuffer.data(); if (sz < MinCapacity) { sz = MinCapacity; } - if (sz < int(mBuffer.size())) { // never decrease the size + if (sz < mBuffer.size()) { // never decrease the size return; } mBuffer.resize(sz); diff --git a/macro/run_CRUDataSkimming_its.C b/macro/run_CRUDataSkimming_its.C index 6719f284e87bf..a26682e1cff67 100644 --- a/macro/run_CRUDataSkimming_its.C +++ b/macro/run_CRUDataSkimming_its.C @@ -47,10 +47,10 @@ void run_CRUDataSkimming_its(std::string inpName = "rawits.bin", const auto& MAP = rawReader.getMapping(); for (int ir = 0; ir < MAP.getNRUs(); ir++) { - const auto& ruStat = rawReader.getRUDecodingStatSW(ir); - if (ruStat.nPackets) { + const auto* ruStat = rawReader.getRUDecodingStatSW(ir); + if (ruStat && ruStat->nPackets) { printf("\nStatistics for RU%3d (HWID:0x%4x)\n", ir, MAP.RUSW2FEEId(ir, 0)); - ruStat.print(); + ruStat->print(); } } diff --git a/macro/run_rawdecoding_its.C b/macro/run_rawdecoding_its.C index acc3928ccb33c..4a1d82d328d62 100644 --- a/macro/run_rawdecoding_its.C +++ b/macro/run_rawdecoding_its.C @@ -45,10 +45,10 @@ void run_rawdecoding_its(std::string inpName = "rawits.bin", const auto& MAP = rawReader.getMapping(); for (int ir = 0; ir < MAP.getNRUs(); ir++) { - const auto& ruStat = rawReader.getRUDecodingStatSW(ir); - if (ruStat.nPackets) { + const auto ruStat = rawReader.getRUDecodingStatSW(ir); + if (ruStat && ruStat->nPackets) { printf("\nStatistics for RU%3d (HWID:0x%4x)\n", ir, MAP.RUSW2FEEId(ir, 0)); - ruStat.print(); + ruStat->print(); } } rawReader.getDecodingStat().print(); From 2361eab6780cfba770614db13e85041cc8941ab9 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 2 Apr 2019 09:16:29 +0200 Subject: [PATCH 6/6] PixelReader got HB int.record on top of Trigger int.record --- .../include/ITSMFTReconstruction/PixelReader.h | 7 ++++++- .../include/ITSMFTReconstruction/RawPixelReader.h | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h index a43da5bf676a6..a63c4482ed701 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelReader.h @@ -46,6 +46,10 @@ class PixelReader { return nullptr; } + const o2::InteractionRecord& getInteractionRecordHB() const + { + return mInteractionRecordHB; + } const o2::InteractionRecord& getInteractionRecord() const { return mInteractionRecord; @@ -57,7 +61,8 @@ class PixelReader // protected: // - o2::InteractionRecord mInteractionRecord = {}; + o2::InteractionRecord mInteractionRecordHB = {}; // interation record for the HB + o2::InteractionRecord mInteractionRecord = {}; // interation record for the trigger uint32_t mTrigger = 0; ClassDef(PixelReader, 1); diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index 3ea77783c3cda..4363cbca3d2cb 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -729,6 +729,8 @@ class RawPixelReader : public PixelReader mInteractionRecord.bc = rdh->triggerBC; mInteractionRecord.orbit = rdh->triggerOrbit; mTrigger = rdh->triggerType; + mInteractionRecordHB.bc = rdh->heartbeatBC; + mInteractionRecordHB.orbit = rdh->heartbeatOrbit; break; } } @@ -1050,8 +1052,12 @@ class RawPixelReader : public PixelReader mInteractionRecord.bc = rdh->triggerBC; mInteractionRecord.orbit = rdh->triggerOrbit; + mTrigger = rdh->triggerType; + mInteractionRecordHB.bc = rdh->heartbeatBC; + mInteractionRecordHB.orbit = rdh->heartbeatOrbit; + auto& ruStat = mRUDecodeVec[mRUEntry[ruIDSW]].statistics; ruStat.nPackets++; mDecodingStat.nRUsProcessed++;