2525#include " CommandLineUtilities/Program.h"
2626#include " Common/Iommu.h"
2727#include " Common/SuffixOption.h"
28+ #include " Cru/DataFormat.h"
2829#include " ExceptionInternal.h"
2930#include " InfoLogger/InfoLogger.hxx"
3031#include " folly/ProducerConsumerQueue.h"
@@ -45,6 +46,10 @@ namespace b = boost;
4546namespace po = boost::program_options;
4647
4748namespace {
49+ // / Initial value for link counters
50+ constexpr auto LINK_COUNTER_INITIAL_VALUE = std::numeric_limits<uint64_t >::max();
51+ // / Maximum supported links
52+ constexpr auto MAX_LINKS = 32 ;
4853// / Interval for low priority thread (display updates, etc)
4954constexpr auto LOW_PRIORITY_INTERVAL = 10ms;
5055// / Resting time if push thread has nothing to do
@@ -60,7 +65,7 @@ const std::string PROGRESS_FORMAT(" %02s:%02s:%02s %-12s %-12s %-12s %-5.1
6065// / Path for error log
6166auto READOUT_ERRORS_PATH = " readout_errors.txt" ;
6267// / Max amount of errors that are recorded into the error stream
63- constexpr int64_t MAX_RECORDED_ERRORS = 1000 ;
68+ constexpr int64_t MAX_RECORDED_ERRORS = 10000 ;
6469// / End InfoLogger message alias
6570constexpr auto endm = InfoLogger::endm;
6671} // Anonymous namespace
@@ -159,6 +164,10 @@ class ProgramDmaBench: public Program
159164
160165 virtual void run (const po::variables_map& map)
161166 {
167+ for (auto & i : mLinkCounters ) {
168+ i = LINK_COUNTER_INITIAL_VALUE;
169+ }
170+
162171 auto params = Options::getOptionsParameterMap (map);
163172 auto cardId = Options::getOptionCardId (map);
164173 mLogger << " DMA channel: " << mOptions .dmaChannel << endm;
@@ -259,7 +268,8 @@ class ProgramDmaBench: public Program
259268 // Note that we can force unlock because we know for sure this process is not holding the lock. If we did not know
260269 // this, it would be very dangerous to force the lock.
261270 params.setForcedUnlockEnabled (true );
262- params.setLinkMask (Parameters::linkMaskFromString (mOptions .links ));
271+ mLinkMask = Parameters::linkMaskFromString (mOptions .links );
272+ params.setLinkMask (mLinkMask );
263273
264274 mInfinitePages = (mOptions .maxBytes <= 0 );
265275 mMaxPages = mOptions .maxBytes / mPageSize ;
@@ -508,6 +518,17 @@ class ProgramDmaBench: public Program
508518 return value;
509519 }
510520
521+ uint32_t getDataGeneratorCounterFromPage (uintptr_t pageAddress)
522+ {
523+ switch (mCardType ) {
524+ case CardType::Crorc:
525+ return get32bitFromPage (pageAddress, 0 );
526+ case CardType::Cru:
527+ return get32bitFromPage (pageAddress, 23 );
528+ default : throw std::runtime_error (" Error checking unsupported for this card type" );
529+ }
530+ };
531+
511532 void readoutPage (uintptr_t pageAddress, size_t pageSize, int64_t readoutCount)
512533 {
513534 // Read out to file
@@ -517,25 +538,39 @@ class ProgramDmaBench: public Program
517538
518539 // Data error checking
519540 if (!mOptions .noErrorCheck ) {
520- auto getDataGeneratorCounterFromPage = [&]{
521- switch (mCardType ) {
522- case CardType::Crorc:
523- return get32bitFromPage (pageAddress, 0 );
524- case CardType::Cru:
525- return get32bitFromPage (pageAddress, 23 );
526- default : throw std::runtime_error (" Error checking unsupported for this card type" );
541+
542+ // Get link ID if needed
543+ int linkId = 0 ; // Use 0 for non-CRU cards
544+ if (mCardType == CardType::Cru) {
545+ linkId = Cru::DataFormat::getLinkId (reinterpret_cast <const char *>(pageAddress));
546+ if (linkId >= mLinkCounters .size ()) {
547+ BOOST_THROW_EXCEPTION (Exception ()
548+ << ErrorInfo::Message (" Link ID from superpage out of range" )
549+ << ErrorInfo::Index (linkId));
527550 }
528- };
551+ }
529552
530- if (mDataGeneratorCounter == -1 ) {
531- // First page initializes the counter
532- mDataGeneratorCounter = getDataGeneratorCounterFromPage ();
553+ // First received page initializes the counter
554+ if (mLinkCounters [linkId] == LINK_COUNTER_INITIAL_VALUE) {
555+ mLinkCounters [linkId] = getDataGeneratorCounterFromPage (pageAddress);
556+ }
557+
558+ // Check for errors
559+ bool hasError = true ;
560+ switch (mCardType ) {
561+ case CardType::Crorc:
562+ hasError = checkErrorsCrorc (pageAddress, pageSize, readoutCount, linkId);
563+ break ;
564+ case CardType::Cru:
565+ hasError = checkErrorsCru (pageAddress, pageSize, readoutCount, linkId);
566+ break ;
567+ default :
568+ throw std::runtime_error (" Error checking unsupported for this card type" );
533569 }
534570
535- bool hasError = checkErrors (pageAddress, pageSize, readoutCount);
536571 if (hasError && !mOptions .noResyncCounter ) {
537572 // Resync the counter
538- mDataGeneratorCounter = getDataGeneratorCounterFromPage ();
573+ mLinkCounters [linkId] = getDataGeneratorCounterFromPage (pageAddress );
539574 }
540575 }
541576
@@ -545,39 +580,40 @@ class ProgramDmaBench: public Program
545580 }
546581 }
547582
548- bool checkErrorsCru (uintptr_t pageAddress, size_t pageSize, int64_t eventNumber)
583+ bool checkErrorsCru (uintptr_t pageAddress, size_t pageSize, int64_t eventNumber, int linkId )
549584 {
550- auto counter = mDataGeneratorCounter ;
585+ uint64_t counter = mLinkCounters [linkId] ;
551586 // Get stuff from the header
552- auto words = get32bitFromPage (pageAddress, 4 ); // Amount of 256 bit words in DMA page
553- auto wordsBytes = words * 256 / 8 ;
587+ auto words256 = Cru::DataFormat::getEventSize ( reinterpret_cast < const char *>(pageAddress) ); // Amount of 256 bit words in DMA page
588+ auto wordsBytes = words256 * ( 256 / 8 ) ;
554589
555- if (words < 2 || wordsBytes > pageSize) {
590+ if (words256 < 2 || wordsBytes > pageSize) {
556591 // Report error
557592 mErrorCount ++;
558593 if (mErrorCount < MAX_RECORDED_ERRORS) {
559- mErrorStream << b::format (" event:%d cnt:%d size out of range\n " ) % eventNumber % counter;
594+ mErrorStream << b::format (" event:%1% l:%2% cnt:%3% words:%4% size:%5% words out of range\n " ) % eventNumber
595+ % linkId % counter % words256 % pageSize;
560596 }
561597 return false ;
562598 }
563599
564- mDataGeneratorCounter += words - 2 ;
565-
566600 auto page = reinterpret_cast <const volatile uint32_t *>(pageAddress);
567- constexpr uint32_t HEADER_WORDS = 2 ; // We skip the 2 header words
601+ constexpr size_t HEADER_WORDS_256 = Cru::DataFormat::getHeaderSizeWords (); // We skip the header
602+
603+ mLinkCounters [linkId] += words256 - HEADER_WORDS_256;
568604
569- for (uint32_t i = 0 ; (i + HEADER_WORDS ) < words ; ++i) {
570- constexpr uint32_t INTS_PER_WORD = 8 ; // Each word should contain 8 identical 32-bit integers
571- for (uint32_t j = 0 ; j < INTS_PER_WORD ; ++j) {
605+ for (uint32_t i = 0 ; (i + HEADER_WORDS_256 ) < words256 ; ++i) {
606+ constexpr uint32_t INTS_PER_WORD_256 = 8 ; // Each word should contain 8 identical 32-bit integers
607+ for (uint32_t j = 0 ; j < INTS_PER_WORD_256 ; ++j) {
572608 uint32_t expectedValue = counter + i;
573- uint32_t actualValue = page[(i + HEADER_WORDS ) * INTS_PER_WORD + j];
609+ uint32_t actualValue = page[(i + HEADER_WORDS_256 ) * INTS_PER_WORD_256 + j];
574610
575611 if (actualValue != expectedValue) {
576612 // Report error
577613 mErrorCount ++;
578614 if (mErrorCount < MAX_RECORDED_ERRORS) {
579- mErrorStream << b::format (" event:%d i:%d cnt:%d exp:0x%x val:0x%x\n " )
580- % eventNumber % i % counter % expectedValue % actualValue;
615+ mErrorStream << b::format (" event:%d l:%d i:%d cnt:%d exp:0x%x val:0x%x\n " )
616+ % eventNumber % linkId % i % counter % expectedValue % actualValue;
581617 }
582618 return true ;
583619 }
@@ -625,10 +661,10 @@ class ProgramDmaBench: public Program
625661 }
626662 }
627663
628- bool checkErrorsCrorc (uintptr_t pageAddress, size_t pageSize, int64_t eventNumber)
664+ bool checkErrorsCrorc (uintptr_t pageAddress, size_t pageSize, int64_t eventNumber, int linkId )
629665 {
630- auto counter = mDataGeneratorCounter ;
631- mDataGeneratorCounter ++;
666+ uint64_t counter = mLinkCounters [linkId] ;
667+ mLinkCounters [linkId] ++;
632668
633669 auto check = [&](auto patternFunction) {
634670 auto page = reinterpret_cast <const volatile uint32_t *>(pageAddress);
@@ -665,19 +701,6 @@ class ProgramDmaBench: public Program
665701 << ErrorInfo::GeneratorPattern (mOptions .generatorPattern ));
666702 }
667703
668- // / Checks and reports errors
669- bool checkErrors (uintptr_t pageAddress, size_t pageSize, int64_t eventNumber)
670- {
671- switch (mCardType ) {
672- case CardType::Crorc:
673- return checkErrorsCrorc (pageAddress, pageSize, eventNumber);
674- case CardType::Cru:
675- return checkErrorsCru (pageAddress, pageSize, eventNumber);
676- default :
677- throw std::runtime_error (" Error checking unsupported for this card type" );
678- }
679- }
680-
681704 void resetPage (uintptr_t pageAddress, size_t pageSize)
682705 {
683706 auto page = reinterpret_cast <volatile uint32_t *>(pageAddress);
@@ -891,7 +914,6 @@ class ProgramDmaBench: public Program
891914 std::atomic<uint64_t > mPushCount { 0 };
892915 std::atomic<uint64_t > mReadoutCount { 0 };
893916 int64_t mErrorCount = 0 ;
894- int64_t mDataGeneratorCounter = -1 ;
895917 size_t mSuperpageSize = 0 ;
896918 size_t mMaxSuperpages = 0 ;
897919 size_t mPagesPerSuperpage = 0 ;
@@ -930,7 +952,12 @@ class ProgramDmaBench: public Program
930952
931953 InfoLogger mLogger ;
932954
955+ std::set<uint32_t > mLinkMask ;
956+
933957 std::shared_ptr<DmaChannelInterface> mChannel ;
958+
959+ // / Page counters per link. Indexed by link ID.
960+ std::array<std::atomic<uint64_t >, MAX_LINKS> mLinkCounters ;
934961};
935962
936963int main (int argc, char ** argv)
0 commit comments