15#ifndef GPUCA_STANDALONE
44#include <oneapi/tbb.h>
49using namespace std::string_literals;
53 memset((
void*)&native, 0,
sizeof(native));
55 for (uint32_t
j = 0;
j < nRawClusters[
i];
j++) {
67 for (uint32_t
j = 0;
j < nRawClusters[
i];
j++) {
86 for (uint32_t k = 0; k < native.
nClusters[
i][
j]; k++) {
100 for (uint32_t k = 0; k <
digits.nTPCDigits[
i]; k++) {
123 if (hdr2->
flags & TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8) {
170 void ZSfillEmpty(
void*
ptr, int32_t shift, uint32_t feeId, int32_t
orbit, int32_t linkid);
171 static void ZSstreamOut(uint16_t* bufIn, uint32_t& lenIn, uint8_t* bufOut, uint32_t& lenOut, uint32_t nBits);
175inline void zsEncoder::ZSfillEmpty(
void*
ptr, int32_t shift, uint32_t feeId, int32_t
orbit, int32_t linkid)
179 o2::raw::RDHUtils::setHeartBeatBC(*rdh, shift);
189inline void zsEncoder::ZSstreamOut(uint16_t* bufIn, uint32_t& lenIn, uint8_t* bufOut, uint32_t& lenOut, uint32_t nBits)
191 uint32_t
byte = 0,
bits = 0;
192 uint32_t
mask = (1 << nBits) - 1;
193 for (uint32_t
i = 0;
i < lenIn;
i++) {
197 bufOut[lenOut++] = (
uint8_t)(
byte & 0xFF);
203 bufOut[lenOut++] = byte;
210#ifndef GPUCA_STANDALONE
212static inline auto ZSEncoderGetDigits(
const DigitArray& in, int32_t
i) {
return in[
i].data(); }
213static inline auto ZSEncoderGetNDigits(
const DigitArray& in, int32_t
i) {
return in[
i].size(); }
218struct zsEncoderRow :
public zsEncoder {
228 constexpr static int32_t RAWLNK = rdh_utils::UserLogicLinkID;
230 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
234 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
237 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage*
page, uint32_t
endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
242 int32_t endpointa = GPUTPCGeometry::GetRegion(
a.getRow());
243 int32_t endpointb = GPUTPCGeometry::GetRegion(
b.getRow());
244 endpointa = 2 * endpointa + (
a.getRow() >= GPUTPCGeometry::GetRegionStart(endpointa) + GPUTPCGeometry::GetRegionRows(endpointa) / 2);
245 endpointb = 2 * endpointb + (
b.getRow() >= GPUTPCGeometry::GetRegionStart(endpointb) + GPUTPCGeometry::GetRegionRows(endpointb) / 2);
246 if (endpointa != endpointb) {
247 return endpointa <= endpointb;
249 if (
a.getTimeStamp() !=
b.getTimeStamp()) {
250 return a.getTimeStamp() <
b.getTimeStamp();
252 if (
a.getRow() !=
b.getRow()) {
253 return a.getRow() <
b.getRow();
255 return a.getPad() <
b.getPad();
258bool zsEncoderRow::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
261 if (
lastRow != tmpBuffer[k].getRow()) {
269 for (uint32_t l = k + 1; l < tmpBuffer.size(); l++) {
270 if (tmpBuffer[l].getRow() == tmpBuffer[k].getRow() && tmpBuffer[l].
getTimeStamp() == tmpBuffer[k].
getTimeStamp() && tmpBuffer[l].getPad() == tmpBuffer[l - 1].getPad() + 1) {
284 sizeChk += (tmpBuffer[k].getTimeStamp() !=
lastTime || tmpBuffer[k].getRow() !=
lastRow) ? 3 : 0;
299bool zsEncoderRow::writeSubPage()
306 throw std::runtime_error(
"internal error during ZS encoding");
309 for (int32_t l = 1; l <
nRowsInTB; l++) {
316uint32_t zsEncoderRow::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
332 if (tmpBuffer[k].getRow() !=
lastRow) {
345 for (int32_t l = 0; l <
seqLen; l++) {
351void zsEncoderRow::decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
353 const uint8_t* decPagePtr =
reinterpret_cast<const uint8_t*
>(decPage);
360 decPagePtr +=
sizeof(*decHDR);
362 throw std::runtime_error(
"invalid ZS version "s +
std::to_string(decHDR->
version) +
" (1 or 2 expected)"s);
364 const float decodeBitsFactor = 1.f / (1 << (
encodeBits - 10));
366 int32_t cruid = decHDR->
cruID;
367 uint32_t sector = cruid / 10;
369 throw std::runtime_error(
"invalid TPC sector");
371 int32_t region = cruid % 10;
372 if ((uint32_t)region != decEndpoint / 2) {
373 throw std::runtime_error(
"CRU ID / endpoint mismatch");
375 int32_t nRowsRegion = GPUTPCGeometry::GetRegionRows(region);
379 if ((decPagePtr -
reinterpret_cast<const uint8_t*
>(decPage)) & 1) {
383 bool upperRows = tbHdr->
rowMask & 0x8000;
384 if (tbHdr->
rowMask != 0 && ((upperRows) ^ ((decEndpoint & 1) != 0))) {
385 throw std::runtime_error(
"invalid endpoint");
387 const int32_t rowOffset = GPUTPCGeometry::GetRegionStart(region) + (upperRows ? (nRowsRegion / 2) : 0);
388 const int32_t
nRows = upperRows ? (nRowsRegion - nRowsRegion / 2) : (nRowsRegion / 2);
389 const int32_t nRowsUsed = __builtin_popcount((uint32_t)(tbHdr->
rowMask & 0x7FFF));
390 decPagePtr += nRowsUsed ? (2 * nRowsUsed) : 2;
392 for (int32_t
m = 0;
m <
nRows;
m++) {
393 if ((tbHdr->
rowMask & (1 <<
m)) == 0) {
396 const uint8_t* rowData = rowPos == 0 ? decPagePtr : (
reinterpret_cast<const uint8_t*
>(decPage) + tbHdr->rowAddr1()[rowPos - 1]);
397 const int32_t nSeqRead = *rowData;
398 const uint8_t* adcData = rowData + 2 * nSeqRead + 1;
399 int32_t nADC = (rowData[2 * nSeqRead] *
encodeBits + 7) / 8;
400 decPagePtr += 1 + 2 * nSeqRead + nADC;
401 uint32_t
byte = 0,
bits = 0, posXbits = 0;
402 std::array<uint16_t, TPCZSHDR::TPC_ZS_PAGE_SIZE> decBuffer;
403 for (int32_t
n = 0;
n < nADC;
n++) {
404 byte |= *(adcData++) <<
bits;
407 decBuffer[posXbits++] =
byte &
mask;
413 for (int32_t
n = 0;
n < nSeqRead;
n++) {
414 const int32_t decSeqLen = rowData[(
n + 1) * 2] - (
n ? rowData[
n * 2] : 0);
415 for (int32_t o = 0; o < decSeqLen; o++) {
426#ifndef GPUCA_STANDALONE
427struct zsEncoderLinkBased :
public zsEncoder {
437 void createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
442void zsEncoderLinkBased::init()
445 for (int32_t
i = 0;
i < 5;
i++) {
446 for (int32_t
j = 0;
j < 32;
j++) {
450 for (int32_t iCRU = 0; iCRU < 2; iCRU++) {
451 for (int32_t iChannel = 0; iChannel < 80; iChannel++) {
452 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
455 GPUError(
"ERROR: Channel conflict: %d %d: %d vs %d", sampaOnFEC, channelOnSAMPA,
inverseChannelMapping[sampaOnFEC][channelOnSAMPA], iChannel);
456 throw std::runtime_error(
"ZS error");
461 for (int32_t
i = 0;
i < 5;
i++) {
462 for (int32_t
j = 0;
j < 32;
j++) {
464 GPUError(
"ERROR: Map missing for sampa %d channel %d",
i,
j);
465 throw std::runtime_error(
"ZS error");
471void zsEncoderLinkBased::createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
478 for (l = k; l < tmpBuffer.size(); l++) {
479 const auto&
a = tmpBuffer[l];
480 int32_t cruinsector = GPUTPCGeometry::GetRegion(
a.getRow());
484 int32_t fecInPartition = fec.
getIndex() - mapper.getPartitionInfo(cru.
partition()).getSectorFECOffset();
485 int32_t tmpEndpoint = 2 * cruinsector + (fecInPartition >= (mapper.getPartitionInfo(cru.
partition()).getNumberOfFECs() + 1) / 2);
487 link = fecInPartition;
502 int32_t cruinsectora = GPUTPCGeometry::GetRegion(
a.getRow());
503 int32_t cruinsectorb = GPUTPCGeometry::GetRegion(
b.getRow());
504 if (cruinsectora != cruinsectorb) {
505 return cruinsectora < cruinsectorb;
513 int32_t fecInPartitiona = feca.
getIndex() - mapper.getPartitionInfo(cru.
partition()).getSectorFECOffset();
514 int32_t fecInPartitionb = fecb.
getIndex() - mapper.getPartitionInfo(cru.
partition()).getSectorFECOffset();
516 int32_t endpointa = 2 * cruinsectora + (fecInPartitiona >= (mapper.getPartitionInfo(cru.
partition()).getNumberOfFECs() + 1) / 2);
517 int32_t endpointb = 2 * cruinsectorb + (fecInPartitionb >= (mapper.getPartitionInfo(cru.
partition()).getNumberOfFECs() + 1) / 2);
518 if (endpointa != endpointb) {
519 return endpointa < endpointb;
521 if (
a.getTimeStamp() !=
b.getTimeStamp()) {
522 return a.getTimeStamp() <
b.getTimeStamp();
524 if (fecInPartitiona != fecInPartitionb) {
525 return fecInPartitiona < fecInPartitionb;
532struct zsEncoderImprovedLinkBased :
public zsEncoderLinkBased {
533 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
534 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
535 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage*
page, uint32_t
endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
539 constexpr static int32_t RAWLNK = rdh_utils::ILBZSLinkID;
542bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
544 createBitmask(tmpBuffer, k);
564uint32_t zsEncoderImprovedLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
571 tbHdr->
bitMaskLow = (
bitmask & std::bitset<80>(0xFFFFFFFFFFFFFFFFlu)).to_ulong();
575 hdr->nTimebinHeaders++;
583 uint64_t* payloadPtr = (uint64_t*)
pagePtr;
595bool zsEncoderImprovedLinkBased::writeSubPage()
600void zsEncoderImprovedLinkBased::initPage()
603 hdr->nTimebinHeaders = 0;
604 hdr->firstZSDataOffset = 0;
607void zsEncoderImprovedLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
610 const uint8_t* decPagePtr =
reinterpret_cast<const uint8_t*
>(decPage);
617 decPagePtr +=
sizeof(*decHDR);
618 if (decHDR->
version != ZSVersion::ZSVersionLinkBasedWithMeta) {
622 throw std::runtime_error(
"Magic word missing");
624 const float decodeBitsFactor = 1.f / (1 << (
encodeBits - 10));
626 int32_t cruid = decHDR->
cruID;
627 uint32_t sector = cruid / 10;
629 throw std::runtime_error(
"invalid TPC sector");
631 int32_t region = cruid % 10;
637 const int32_t feeLink = tbHdr->
fecInPartition - (decEndpoint & 1) * ((mapper.getPartitionInfo(cru.
partition()).getNumberOfFECs() + 1) / 2);
638 auto fillADC = [&outputBuffer](int32_t cru, int32_t rowInSector, int32_t padInRow, int32_t timeBin,
float adcValue) {
639 outputBuffer.emplace_back(
o2::tpc::Digit{cruid, adcValue, rowInSector, padInRow, timeBin});
643 raw_processing_helpersa::processZSdata((
const char*)decPagePtr,
size, rdh_utils::getFEEID(cruid, decEndpoint & 1, feeLink), o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit, decHDR->
timeOffset, fillADC);
646 throw std::runtime_error(
"ZS TB Hdr does not have linkZS magic word");
650 LOGP(
debug,
"zsEncoderImprovedLinkBased::decodePage skipping digits hdr->tOff {} + hdr->bc {} + (orbit {} - firstOrbit {}) * maxBunch {} - triggerBC {} = {} < 0", decHDR->
timeOffset, tbHdr->
bunchCrossing, o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit,
o2::constants::lhc::LHCMaxBunches, triggerBC, timeBin);
653 const uint8_t* adcData = (
const uint8_t*)(decPagePtr +
sizeof(*tbHdr));
655 int32_t nADC =
bitmask.count();
656 std::vector<uint16_t> decBuffer(nADC);
658 uint32_t
byte = 0,
bits = 0, posXbits = 0;
659 while (posXbits < nADC) {
660 byte |= *(adcData++) <<
bits;
663 decBuffer[posXbits++] =
byte &
mask;
669 const uint64_t* adcData64 = (
const uint64_t*)adcData;
670 for (int32_t
j = 0;
j < nADC;
j++) {
674 for (int32_t
j = 0, k = 0;
j <
bitmask.size();
j++) {
676 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
677 mapper.getSampaAndChannelOnFEC(cruid,
j, sampaOnFEC, channelOnSAMPA);
678 const auto padSecPos = mapper.padSecPos(cruid, tbHdr->
fecInPartition, sampaOnFEC, channelOnSAMPA);
679 const auto& padPos = padSecPos.getPadPos();
690struct zsEncoderDenseLinkBased :
public zsEncoderLinkBased {
691 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
692 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
693 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage*
page, uint32_t
endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
696 void amendPageErrorMessage(std::ostringstream& oss,
const o2::header::RAWDataHeader* rdh,
const TPCZSHDRV2* decHDR,
const uint8_t* payloadEnd,
const uint8_t* decPagePtr, uint32_t nOutput);
702 constexpr static int32_t RAWLNK = rdh_utils::DLBZSLinkID;
703 constexpr static int32_t v2nbits = 10;
706bool zsEncoderDenseLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
708 createBitmask(tmpBuffer, k);
715uint32_t zsEncoderDenseLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
719 if (
zsVersion == ZSVersion::ZSVersionDenseLinkBasedV2) {
727 hdr->flags |= TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8;
729 hdr->nTimebinHeaders++;
736 std::bitset<10> bitmaskL2;
737 for (int32_t
i = 9;
i >= 0;
i--) {
738 bitmaskL2.set(
i, ((
bitmask >> (
i * 8)) & std::bitset<80>(0xFF)).any());
740 if (bitmaskL2.all()) {
741 *plink |= 0b00100000;
743 *plink |= (bitmaskL2.to_ulong() >> 2) & 0b11000000;
747 for (int32_t
i = 0;
i < 10;
i++) {
748 if (bitmaskL2.test(
i)) {
761bool zsEncoderDenseLinkBased::writeSubPage()
765 bool need12bit =
zsVersion != ZSVersion::ZSVersionDenseLinkBasedV2;
766 uint32_t needNow = 0;
767 if (
zsVersion == ZSVersion::ZSVersionDenseLinkBasedV2) {
777 encodeBitsBlock = v2nbits;
790 uint32_t fill = std::min(sizeLeft,
size);
805void zsEncoderDenseLinkBased::initPage()
808 hdr->nTimebinHeaders = 0;
816void zsEncoderDenseLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer,
const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
819 const uint8_t* decPagePtr =
reinterpret_cast<const uint8_t*
>(decPage);
826 if (decHDR->
version < ZSVersion::ZSVersionDenseLinkBased || decHDR->
version > ZSVersion::ZSVersionDenseLinkBasedV2) {
830 throw std::runtime_error(
"Magic word missing");
833 const float decodeBitsFactor = 1.f / (1 << (
encodeBits - 10));
834 int32_t cruid = decHDR->
cruID;
835 uint32_t sector = cruid / 10;
837 throw std::runtime_error(
"invalid TPC sector");
839 int32_t region = cruid % 10;
841 std::vector<uint8_t> tmpBuffer;
842 bool extendFailure =
false;
843 uint32_t nOutput = 0;
844 uint32_t minTimeBin = -1, maxTimeBin = 0;
846 int32_t sizeLeftInPage = payloadEnd - decPagePtr;
847 if (sizeLeftInPage <= 0) {
848 throw std::runtime_error(
"Decoding ran beyond end of page before processing extended timebin");
852 throw std::runtime_error(
"pageExtends signaled, but current page is not full");
858 if ((uint16_t)(o2::raw::RDHUtils::getPageCounter(*rdh) + 1) != o2::raw::RDHUtils::getPageCounter(*rdhNext)) {
859 GPUError(
"Incomplete HBF: Payload extended to next page, but next page missing in stream (packet counters %d %d)", (int32_t)o2::raw::RDHUtils::getPageCounter(*rdh), (int32_t)o2::raw::RDHUtils::getPageCounter(*rdhNext));
860 extendFailure =
true;
861 decPagePtr = payloadEnd;
867 memcpy(tmpBuffer.data(), decPagePtr, sizeLeftInPage);
869 decPagePtr = tmpBuffer.data();
870 payloadEnd = decPagePtr + tmpBuffer.size();
873 uint16_t linkBC = (*((
const uint16_t*)decPagePtr) & 0xFFF0) >> 4;
874 bool v2Flag = decHDR->
version == ZSVersion::ZSVersionDenseLinkBasedV2 && *((
const uint8_t*)decPagePtr) & 0x10;
875 if (decHDR->
version == ZSVersion::ZSVersionDenseLinkBasedV2) {
878 decPagePtr +=
sizeof(uint16_t);
879 std::vector<int32_t>
links;
880 std::vector<std::bitset<80>> bitmasks;
881 uint32_t nTotalSamples = 0;
882 for (uint32_t l = 0; l < linkCount; l++) {
885 uint8_t decLink = decLinkX & 0b00011111;
886 std::bitset<10> bitmaskL2;
887 if (decLinkX & 0b00100000) {
890 bitmaskL2 = std::bitset<10>(((((uint16_t)decLinkX) & 0b11000000) << 2) | (uint16_t)*((
const uint8_t*)decPagePtr));
895 for (int32_t
i = 0;
i < 10;
i++) {
896 if (bitmaskL2.test(
i)) {
897 bitmask |= std::bitset<80>(*((
const uint8_t*)decPagePtr)) <<
i * 8;
901 links.emplace_back(decLink);
902 bitmasks.emplace_back(
bitmask);
903 nTotalSamples +=
bitmask.count();
907 int32_t encodeBitsBlock = v2Flag ? v2nbits :
encodeBits;
908 decPagePtr += (nTotalSamples * encodeBitsBlock + 7) / 8;
911 int32_t timeBin = (int32_t(linkBC) + (int32_t)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) *
o2::constants::lhc::LHCMaxBunches - int32_t(triggerBC)) / LHCBCPERTIMEBIN;
912 if (timeBin < 0 || nTotalSamples == 0) {
913 if (timeBin < 0 && nTotalSamples > 0) {
914 LOGP(
debug,
"zsEncoderDenseLinkBased::decodePage skipping digits (linkBC {} + orbit {} - firstOrbit {}) * maxBunch {} - triggerBC {} = {} < 0, nTotalSamples {}", linkBC, o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit,
o2::constants::lhc::LHCMaxBunches, triggerBC, timeBin, nTotalSamples);
918 if (timeBin > maxTimeBin) {
919 maxTimeBin = timeBin;
921 if (timeBin < minTimeBin) {
922 minTimeBin = timeBin;
925 std::vector<uint16_t>
samples(nTotalSamples);
926 uint32_t
mask = (1 << encodeBitsBlock) - 1;
927 uint32_t
byte = 0,
bits = 0, posXbits = 0;
928 while (posXbits < nTotalSamples) {
929 byte |= *(adcData++) <<
bits;
931 while (
bits >= encodeBitsBlock && posXbits < nTotalSamples) {
933 byte =
byte >> encodeBitsBlock;
934 bits -= encodeBitsBlock;
937 uint32_t samplePos = 0;
939 for (uint32_t l = 0; l < linkCount; l++) {
941 const auto&
bitmask = bitmasks[l];
942 int32_t nADC =
bitmask.count();
944 for (int32_t
j = 0;
j <
bitmask.size();
j++) {
946 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
947 mapper.getSampaAndChannelOnFEC(cruid,
j, sampaOnFEC, channelOnSAMPA);
948 const auto padSecPos = mapper.padSecPos(cruid, decLink, sampaOnFEC, channelOnSAMPA);
949 const auto& padPos = padSecPos.getPadPos();
958 if (triggerBC > 0 && hdrMinTimeBin < 0) {
962 int32_t hdrMaxTimeBin = hdrMinTimeBin + decHDR->
nTimeBinSpan + ((decHDR->
flags & TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8) ? 256 : 0);
964 if (!extendFailure && nOutput != decHDR->
nADCsamples) {
965 std::ostringstream oss;
966 oss <<
"Number of decoded digits " << nOutput <<
" does not match value from MetaInfo " << decHDR->
nADCsamples;
967 amendPageErrorMessage(oss, rdh, decHDR,
nullptr,
nullptr, nOutput);
968 throw std::runtime_error(oss.str());
971 if (decHDR->
nADCsamples && (minTimeBin < hdrMinTimeBin || maxTimeBin > hdrMaxTimeBin)) {
972 std::ostringstream oss;
973 oss <<
"Incorrect time bin range in MetaInfo, header reports " << hdrMinTimeBin <<
" - " << hdrMaxTimeBin <<
"(timeOffset: " << decHDR->
timeOffset <<
" + (orbit: " << o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) <<
" - firstOrbit " << firstOrbit <<
") * LHCMaxBunches - triggerBC: " << triggerBC <<
", decoded data is " << minTimeBin <<
" - " << maxTimeBin;
974 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
975 throw std::runtime_error(oss.str());
979 std::ostringstream oss;
980 oss <<
"Decoding ran over end of page";
981 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
982 throw std::runtime_error(oss.str());
985 std::ostringstream oss;
986 oss <<
"Decoding didn't reach end of page";
987 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
988 throw std::runtime_error(oss.str());
992void zsEncoderDenseLinkBased::amendPageErrorMessage(std::ostringstream& oss,
const o2::header::RAWDataHeader* rdh,
const TPCZSHDRV2* decHDR,
const uint8_t* payloadEnd,
const uint8_t* decPagePtr, uint32_t nOutput)
994 if (payloadEnd && decPagePtr) {
995 oss <<
" (payloadEnd " << (
void*)payloadEnd <<
" - decPagePtr " << (
void*)decPagePtr <<
" - " << (payloadEnd - decPagePtr) <<
" bytes left, " << nOutput <<
" of " << decHDR->
nADCsamples <<
" digits decoded)\n";
999 constexpr size_t bufferSize = 3 * std::max(
sizeof(*rdh),
sizeof(*decHDR)) + 1;
1001 for (
size_t i = 0;
i <
sizeof(*rdh);
i++) {
1002 snprintf(dumpBuffer + 3 *
i, 4,
"%02X ", (int32_t)((uint8_t*)rdh)[
i]);
1004 oss <<
"RDH of page: " <<
dumpBuffer <<
"\n";
1005 for (
size_t i = 0;
i <
sizeof(*decHDR);
i++) {
1006 snprintf(dumpBuffer + 3 *
i, 4,
"%02X ", (int32_t)((uint8_t*)decHDR)[
i]);
1008 oss <<
"Meta header of page: " <<
dumpBuffer <<
"\n";
1016struct zsEncoderRun :
public T {
1017 uint32_t run(std::vector<zsPage>*
buffer, std::vector<o2::tpc::Digit>& tmpBuffer,
size_t* totalSize =
nullptr);
1018 size_t compare(std::vector<zsPage>*
buffer, std::vector<o2::tpc::Digit>& tmpBuffer);
1020 using T::bcShiftInFirstHBF;
1021 using T::checkInput;
1023 using T::decodePage;
1024 using T::encodeBits;
1025 using T::encodeBitsFactor;
1026 using T::encodeSequence;
1028 using T::firstTimebinInPage;
1036 using T::lastEndpoint;
1039 using T::needAnotherPage;
1041 using T::outputEndpoint;
1042 using T::outputRegion;
1043 using T::packetCounter;
1046 using T::pageCounter;
1051 using T::writeSubPage;
1052 using T::ZSfillEmpty;
1057inline uint32_t zsEncoderRun<T>::run(std::vector<zsPage>*
buffer, std::vector<o2::tpc::Digit>& tmpBuffer,
size_t* totalSize)
1059 uint32_t totalPages = 0;
1060 zsPage singleBuffer;
1061#ifndef GPUCA_STANDALONE
1066 int32_t orbitShift =
ir ?
ir->
orbit : 0;
1068 int32_t rawendpoint = 0;
1069 (
void)(rawcru + rawendpoint);
1073 for (uint32_t k = 0; k <= tmpBuffer.size();) {
1074 bool mustWritePage =
false, mustWriteSubPage =
false;
1077 mustWritePage =
true;
1079 if (k < tmpBuffer.size()) {
1083 throw std::runtime_error(
"Received digit before the defined first orbit");
1087 mustWritePage =
true;
1090 if (
lastRow != tmpBuffer[k].getRow()) {
1091 curRegion = GPUTPCGeometry::GetRegion(tmpBuffer[k].getRow());
1093 mustWriteSubPage = checkInput(tmpBuffer, k);
1096 mustWritePage =
true;
1099 if (mustWritePage || mustWriteSubPage) {
1100 mustWritePage |= writeSubPage();
1102 if (
page && mustWritePage) {
1103 if constexpr (std::is_same_v<T, struct zsEncoderDenseLinkBased>) {
1107 uint8_t* triggerWord =
nullptr;
1118 needAnotherPage =
true;
1131 throw std::runtime_error(
"TPC ZS page overflow");
1133 memcpy(pagehdr,
hdr,
sizeof(*
hdr));
1143 size = CAMath::nextMultipleOf<o2::raw::RDHUtils::GBTWord128>(
size);
1144#ifndef GPUCA_STANDALONE
1147 maxhbf = std::max<int32_t>(maxhbf,
hbf);
1148 minhbf = std::min<int32_t>(minhbf,
hbf);
1168 if (mustWritePage) {
1180 page = &singleBuffer;
1194 std::fill(
page->begin(),
page->end(), 0);
1196 if constexpr (std::is_same_v<T, struct zsEncoderDenseLinkBased>) {
1216 uint32_t nEncoded = encodeSequence(tmpBuffer, k);
1217 lastTime = tmpBuffer[k].getTimeStamp();
1218 lastRow = tmpBuffer[k].getRow();
1223#ifndef GPUCA_STANDALONE
1225 for (int32_t
i = minhbf;
i <= maxhbf;
i++) {
1243size_t zsEncoderRun<T>::compare(std::vector<zsPage>*
buffer, std::vector<o2::tpc::Digit>& tmpBuffer)
1246 std::vector<o2::tpc::Digit> compareBuffer;
1247 compareBuffer.reserve(tmpBuffer.size());
1249 uint32_t firstOrbit =
ir ?
ir->
orbit : 0;
1250 for (uint32_t k = 0; k <
buffer[
j].size(); k++) {
1251 zsPage* decPage = &
buffer[
j][k];
1252 decodePage(compareBuffer, decPage,
j, firstOrbit);
1255 if (tmpBuffer.size() != compareBuffer.size()) {
1256 nErrors += tmpBuffer.size();
1257 printf(
"Number of clusters mismatch %d %d\n", (int32_t)tmpBuffer.size(), (int32_t)compareBuffer.size());
1259 for (uint32_t
j = 0;
j < tmpBuffer.size();
j++) {
1260 const float decodeBitsFactor = (1 << (
encodeBits - 10));
1261 const float c = CAMath::Round(tmpBuffer[
j].getChargeFloat() * decodeBitsFactor) / decodeBitsFactor;
1262 int32_t ok =
c == compareBuffer[
j].getChargeFloat() && (int32_t)tmpBuffer[
j].
getTimeStamp() == (int32_t)compareBuffer[
j].
getTimeStamp() && (int32_t)tmpBuffer[
j].getPad() == (int32_t)compareBuffer[
j].getPad() && (int32_t)tmpBuffer[
j].getRow() == (int32_t)compareBuffer[
j].getRow();
1267 printf(
"%4u: OK %d: Charge %3d %3d Time %4d %4d Pad %3d %3d Row %3d %3d\n",
j, ok,
1268 (int32_t)
c, (int32_t)compareBuffer[
j].getChargeFloat(), (int32_t)tmpBuffer[
j].
getTimeStamp(), (int32_t)compareBuffer[
j].
getTimeStamp(), (int32_t)tmpBuffer[
j].getPad(), (int32_t)compareBuffer[
j].getPad(), (int32_t)tmpBuffer[
j].getRow(), (int32_t)compareBuffer[
j].getRow());
1279void GPUReconstructionConvert::RunZSEncoder(
const S& in, std::unique_ptr<uint64_t[]>* outBuffer, uint32_t* outSizes,
o2::raw::RawFileWriter* raw,
const o2::InteractionRecord*
ir,
const GPUParam&
param, int32_t
version,
bool verify,
float threshold,
bool padding, std::function<
void(std::vector<o2::tpc::Digit>&)> digitsFilter)
1283 if (((outBuffer ==
nullptr) ^ (outSizes ==
nullptr)) || ((
raw !=
nullptr) && (
ir ==
nullptr)) || !((outBuffer ==
nullptr) ^ (
raw ==
nullptr)) || (
raw && verify)) {
1284 throw std::runtime_error(
"Invalid parameters");
1288 struct tmpReductionResult {
1289 uint32_t totalPages = 0;
1290 size_t totalSize = 0;
1292 size_t digitsInput = 0;
1293 size_t digitsEncoded = 0;
1295 auto reduced = tbb::parallel_reduce(tbb::blocked_range<uint32_t>(0,
NSECTORS), tmpReductionResult(), [&](
const auto range,
auto red) {
1297 std::vector<o2::tpc::Digit> tmpBuffer;
1298 red.digitsInput += ZSEncoderGetNDigits(in,
i);
1299 tmpBuffer.resize(ZSEncoderGetNDigits(in,
i));
1300 if (threshold > 0.f && !digitsFilter) {
1301 auto it = std::copy_if(ZSEncoderGetDigits(in,
i), ZSEncoderGetDigits(in,
i) + ZSEncoderGetNDigits(in,
i), tmpBuffer.begin(), [threshold](
auto&
v) { return v.getChargeFloat() >= threshold; });
1302 tmpBuffer.resize(std::distance(tmpBuffer.begin(), it));
1304 std::copy(ZSEncoderGetDigits(in,
i), ZSEncoderGetDigits(in,
i) + ZSEncoderGetNDigits(in,
i), tmpBuffer.begin());
1308 digitsFilter(tmpBuffer);
1309 if (threshold > 0.f) {
1310 std::vector<o2::tpc::Digit> tmpBuffer2 = std::move(tmpBuffer);
1311 tmpBuffer = std::vector<o2::tpc::Digit>(tmpBuffer2.size());
1312 auto it = std::copy_if(tmpBuffer2.begin(), tmpBuffer2.end(), tmpBuffer.begin(), [threshold](
auto&
v) { return v.getChargeFloat() >= threshold; });
1313 tmpBuffer.resize(std::distance(tmpBuffer.begin(), it));
1316 red.digitsEncoded += tmpBuffer.size();
1318 auto runZS = [&](
auto& encoder) {
1321 red.totalPages += encoder.run(
buffer[
i], tmpBuffer, &red.totalSize);
1323 red.nErrors += encoder.compare(
buffer[
i], tmpBuffer);
1327 if (
version >= ZSVersion::ZSVersionRowBased10BitADC &&
version <= ZSVersion::ZSVersionRowBased12BitADC) {
1328 zsEncoderRun<zsEncoderRow> enc{{{.iSector =
i, .raw =
raw, .ir =
ir, .param = &
param, .padding =
padding}}};
1330 }
else if (
version >= ZSVersion::ZSVersionLinkBasedWithMeta &&
version <= ZSVersion::ZSVersionDenseLinkBasedV2) {
1331#ifndef GPUCA_STANDALONE
1332 if (
version == ZSVersion::ZSVersionLinkBasedWithMeta) {
1333 zsEncoderRun<zsEncoderImprovedLinkBased> enc{{{{.iSector =
i, .raw =
raw, .ir =
ir, .param = &
param, .padding =
padding}}}};
1335 }
else if (
version >= ZSVersion::ZSVersionDenseLinkBased &&
version <= ZSVersion::ZSVersionDenseLinkBasedV2) {
1336 zsEncoderRun<zsEncoderDenseLinkBased> enc{{{{.iSector =
i, .raw =
raw, .ir =
ir, .param = &
param, .padding =
padding}}}};
1340 throw std::runtime_error(
"Link based ZS encoding not supported in standalone build");
1346 return red; }, [&](
const auto& red1,
const auto& red2) {
1348 red.totalPages += red2.totalPages;
1349 red.totalSize += red2.totalSize;
1350 red.nErrors += red2.nErrors;
1351 red.digitsInput += red2.digitsInput;
1352 red.digitsEncoded += red2.digitsEncoded;
1366 if (reduced.nErrors) {
1367 GPUError(
"ERROR: %lu INCORRECT SAMPLES DURING ZS ENCODING VERIFICATION!!!", reduced.nErrors);
1368 }
else if (verify) {
1369 GPUInfo(
"ENCODING VERIFICATION PASSED");
1371 GPUInfo(
"TOTAL ENCODED SIZE: %lu (%lu of %lu digits encoded)", reduced.totalSize, reduced.digitsEncoded, reduced.digitsInput);
1375template void GPUReconstructionConvert::RunZSEncoder<GPUTrackingInOutDigits>(
const GPUTrackingInOutDigits&, std::unique_ptr<uint64_t[]>*, uint32_t*,
o2::raw::RawFileWriter*,
const o2::InteractionRecord*,
const GPUParam&, int32_t,
bool,
float,
bool, std::function<
void(std::vector<o2::tpc::Digit>&)> digitsFilter);
1376#ifndef GPUCA_STANDALONE
1377template void GPUReconstructionConvert::RunZSEncoder<DigitArray>(
const DigitArray&, std::unique_ptr<uint64_t[]>*, uint32_t*,
o2::raw::RawFileWriter*,
const o2::InteractionRecord*,
const GPUParam&, int32_t,
bool,
float,
bool, std::function<
void(std::vector<o2::tpc::Digit>&)> digitsFilter);
1397 if (
buffers[
i].get() != ptrs[
i] || nsb != ns) {
1398 throw std::runtime_error(
"Not owning digits");
1402 const float decodeBitsFactor = (1 << (decodeBits - 10));
1403 for (uint32_t k = 0; k < ns[
i]; k++) {
1404 if (
buffers[
i][k].getChargeFloat() >= threshold) {
1409 buffers[
i][
j].setCharge(CAMath::Round(
buffers[
i][
j].getChargeFloat() * decodeBitsFactor) / decodeBitsFactor);
1420#ifndef GPUCA_STANDALONE
1426 std::shared_ptr<T> enc = std::make_shared<T>();
1427 if (
param ==
nullptr) {
1429 param = &dummyParam;
1434 return [enc](std::vector<o2::tpc::Digit>& outBuffer,
const void*
page, uint32_t firstTfOrbit, uint32_t triggerBC = 0) {
1439 if (o2::raw::RDHUtils::getDetectorField(rdh) != 2) {
1443 enc->iSector = cru.sector();
1444 int32_t
endpoint = cru.region() * 2 + o2::tpc::rdh_utils::getEndPoint(rdh);
1445 enc->decodePage(outBuffer, (
const zsPage*)
page,
endpoint, firstTfOrbit, triggerBC);
1453 return o2::gpu::internal::GetDecoder_internal<zsEncoderRow>(
param,
version);
1455 return o2::gpu::internal::GetDecoder_internal<zsEncoderImprovedLinkBased>(
param,
version);
1457 return o2::gpu::internal::GetDecoder_internal<zsEncoderDenseLinkBased>(
param,
version);
1459 throw std::runtime_error(
"Invalid ZS version "s +
std::to_string(
version) +
", cannot create decoder"s);
std::array< uint8_t, TPCZSHDR::TPC_ZS_PAGE_SIZE > streamBuffer8
std::array< uint16_t, TPCZSHDR::TPC_ZS_PAGE_SIZE > streamBuffer
std::bitset< 80 > bitmask
int32_t inverseChannelMapping[5][32]
int32_t bcShiftInFirstHBF
std::vector< uint8_t > sequenceBuffer
std::vector< uint16_t > sequenceBufferADC
std::vector< uint16_t > adcValues
int32_t firstTimebinInPage
o2::raw::RawFileWriter * raw
Header to collect LHC related constants.
Utility class to write detectors data to (multiple) raw data file(s) respecting CRU format.
definitions to deal with the link based zero suppression format
Definitions of TPC Zero Suppression Data Headers.
static void RunZSEncoder(const S &in, std::unique_ptr< uint64_t[]> *outBuffer, uint32_t *outSizes, o2::raw::RawFileWriter *raw, const o2::InteractionRecord *ir, const GPUParam ¶m, int32_t version, bool verify, float threshold=0.f, bool padding=false, std::function< void(std::vector< o2::tpc::Digit > &)> digitsFilter=nullptr)
static std::function< void(std::vector< o2::tpc::Digit > &, const void *, uint32_t, uint32_t)> GetDecoder(int32_t version, const GPUParam *param)
static void RunZSFilter(std::unique_ptr< o2::tpc::Digit[]> *buffers, const o2::tpc::Digit *const *ptrs, size_t *nsb, const size_t *ns, const GPUParam ¶m, bool zs12bit, float threshold)
static int32_t GetMaxTimeBin(const o2::tpc::ClusterNativeAccess &native)
static constexpr uint32_t NSECTORS
static void RunZSEncoderCreateMeta(const uint64_t *buffer, const uint32_t *sizes, void **ptrs, GPUTrackingInOutZS *out)
static void ConvertRun2RawToNative(o2::tpc::ClusterNativeAccess &native, std::unique_ptr< o2::tpc::ClusterNative[]> &nativeBuffer, const AliHLTTPCRawCluster **rawClusters, uint32_t *nRawClusters)
static constexpr uint32_t NROWS
void addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR &ir, const gsl::span< char > data, bool preformatted=false, uint32_t trigger=0, uint32_t detField=0)
unsigned char partition() const
unsigned char getSampaChannel() const
unsigned char getIndex() const
unsigned char getSampaChip() const
static Mapper & instance(const std::string mappingDir="")
static constexpr void getSampaAndChannelOnFEC(const int cruID, const size_t rawFECChannel, int &sampaOnFEC, int &channelOnSAMPA)
static constexpr int MAXSECTOR
std::array< gsl::span< const o2::tpc::Digit >, Sector::MAXSECTOR > DigitArray
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLboolean GLboolean GLboolean b
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
uint8_t itsSharedClusterMap uint8_t
constexpr int LHCMaxBunches
const GBTLinkAttributes links[kNGBTLinks]
void dumpBuffer(gsl::span< const std::byte > buffer, std::ostream &out=std::cout, size_t maxbytes=std::numeric_limits< size_t >::max())
constexpr int LHCBCPERTIMEBIN
uint64_t getTimeStamp(o2::framework::ProcessingContext &pc)
Global TPC definitions and constants.
@ ZSVersionDenseLinkBased
@ ZSVersionLinkBasedWithMeta
@ ZSVersionDenseLinkBasedV2
@ ZSVersionRowBased10BitADC
@ ZSVersionRowBased12BitADC
unsigned short GlobalPadNumber
global pad number
constexpr std::array< int, nLayers > nRows
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
int32_t GetCharge() const
uint16_t GetFlags() const
float GetSigmaTime2() const
int32_t GetPadRow() const
float GetSigmaPad2() const
uint16_t bc
bunch crossing ID of interaction
const o2::tpc::Digit * tpcDigits[NSECTORS]
size_t nTPCDigits[NSECTORS]
const void *const * zsPtr[NENDPOINTS]
uint32_t count[NENDPOINTS]
const uint32_t * nZSPtr[NENDPOINTS]
GPUTrackingInOutZSSector sector[NSECTORS]
static constexpr uint32_t NENDPOINTS
static void setLinkID(H &rdh, uint8_t v, NOTPTR(H))
static void setDetectorField(H &rdh, uint32_t v, NOTPTR(H))
static constexpr int GBTWord128
static void setPageCounter(H &rdh, uint16_t v, NOTPTR(H))
static void setMemorySize(H &rdh, uint16_t v, NOTPTR(H))
static void setVersion(H &rdh, uint8_t v, NOTPTR(H))
static void setPacketCounter(H &rdh, uint8_t v, NOTPTR(H))
static void setHeartBeatOrbit(RDHv4 &rdh, uint32_t v)
static void setFEEID(RDHv4 &rdh, uint16_t v)
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClustersTotal
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
@ payloadExtendsToNextPage
unsigned short nTimebinHeaders
unsigned short firstZSDataOffset
static constexpr bool TIGHTLY_PACKED_V3
static constexpr unsigned int TPC_ZS_NBITS_V34
static constexpr unsigned int SAMPLESPER64BIT
static constexpr unsigned int TRIGGER_WORD_SIZE
unsigned char nTimeBinSpan
unsigned short timeOffset
static constexpr unsigned int TPC_ZS_NBITS_V1
static constexpr unsigned int TPC_ZS_NBITS_V2
static constexpr size_t TPC_ZS_PAGE_SIZE
unsigned short nADCsamples
void compare(std::string_view s1, std::string_view s2)
o2::InteractionRecord ir(0, 0)
std::vector< Digit > digits