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/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/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 35efcc828a06d..4363cbca3d2cb 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(); @@ -235,40 +265,61 @@ class RawPixelReader : public PixelReader { mPadding128 = v; mGBTWordSize = mPadding128 ? ITSMFT::GBTPaddedWordLength : o2::ITSMFT::GBTWordLength; - imposeMaxPage(mPadding128); } + /// 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 && decodeNextRUData()) { + + 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) { @@ -570,50 +621,189 @@ class RawPixelReader : public PixelReader } //_____________________________________ - int decodeNextRUData() + size_t cacheLinksData(PayLoadCont& buffer) { - if (mIOFile) { - loadInput(); // if needed, upload additional data to the buffer + // distribute data from the single buffer among the links caches + + LOG(INFO) << "Cacheding links data, currently in cache: " << mMinTriggersCached << " triggers"; + auto nRead = loadInput(buffer); + if (buffer.isEmpty()) { + return nRead; } - int res = 0; - if (!mRawBuffer.isEmpty()) { - bool aborted = false; + 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); - //printf("Unused: %d Size: %d Offs: %d\n", mRawBuffer.getUnusedSize(), mRawBuffer.getSize(), mRawBuffer.getOffset() ); - auto ptr = decodeRUData(mRawBuffer.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) { - mRawBuffer.setPtr(ptr); - res = 1; // success - if (mRawBuffer.isEmpty()) { - mRawBuffer.clear(); + 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 { // 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); + } 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; + } + } + + 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; + } + } + } + } + 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; + mInteractionRecordHB.bc = rdh->heartbeatBC; + mInteractionRecordHB.orbit = rdh->heartbeatOrbit; break; } - ptr += mGBTWordSize; } - mRawBuffer.setPtr(ptr); - if (!mRawBuffer.isEmpty()) { - res = 1; // found a RDH condidate - } else { - mRawBuffer.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) { @@ -625,15 +815,15 @@ 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 aborted = false; - mRUDecode.clear(); // data must start by RDH auto rdh = reinterpret_cast(raw); @@ -652,21 +842,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 @@ -681,28 +865,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 @@ -721,14 +905,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 @@ -745,44 +929,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; } @@ -794,21 +951,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; @@ -818,7 +975,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; @@ -830,9 +987,6 @@ class RawPixelReader : public PixelReader // } #endif - // decode Alpide data from the compressed RU Data - decodeAlpideData(mRUDecode); - return raw; } @@ -840,7 +994,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; @@ -856,22 +1010,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 } @@ -903,14 +1044,22 @@ 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++; + mInteractionRecordHB.bc = rdh->heartbeatBC; + mInteractionRecordHB.orbit = rdh->heartbeatOrbit; + + 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. @@ -933,7 +1082,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; @@ -941,21 +1090,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 @@ -986,9 +1135,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 @@ -1005,14 +1154,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 @@ -1023,32 +1172,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; } @@ -1060,21 +1183,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; @@ -1084,7 +1207,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; @@ -1108,7 +1231,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; @@ -1120,9 +1243,8 @@ 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; - chipData->clear(); decData.nChipsFired = decData.lastChipChecked = 0; int ntot = 0; for (int icab = 0; icab < decData.nCables; icab++) { @@ -1132,21 +1254,20 @@ 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]++; + ruStat.errorCounts[RUDecodingStat::ErrCableDataHeadWrong]++; } #endif 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 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 @@ -1156,10 +1277,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 + } } } } @@ -1171,14 +1295,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 && decodeNextRUData()) { + 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? } //_____________________________________ @@ -1196,7 +1331,7 @@ class RawPixelReader : public PixelReader } //_____________________________________ - int loadInput() + size_t loadInput(PayLoadCont& buffer) { /// assure the buffers are large enough static_assert(RawBufferMargin > MaxGBTPacketBytes * 100 && @@ -1206,33 +1341,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); } @@ -1244,7 +1377,27 @@ 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; @@ -1253,12 +1406,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 ceedb9d9fbfe8..4a1d82d328d62 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; @@ -44,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();