From c1b9f69e840f981ab47a9a8648ec00a115dd87c2 Mon Sep 17 00:00:00 2001 From: Dinyar Rabady <dinyar@cern.ch> Date: Thu, 27 Oct 2022 19:02:43 +0200 Subject: [PATCH] Perform BX map decoding on the fly Belongs to #35. --- src/processor.cc | 188 +++++++++++++++++++++++++---------------------- src/processor.h | 12 +-- 2 files changed, 105 insertions(+), 95 deletions(-) diff --git a/src/processor.cc b/src/processor.cc index 02f08f18..f490a1f1 100644 --- a/src/processor.cc +++ b/src/processor.cc @@ -24,19 +24,6 @@ BrilHistoQueue<std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader>> StreamProcessor::BrilQueue; -// Loops over each word in the orbit trailer BX map and fills a vector with the -// non-empty BX values -void bit_check(std::vector<unsigned int> *bx_vect, uint32_t word, - uint32_t offset) { - for (uint32_t i = 0; i < 32; i++) { - if (word & 1) { - bx_vect->push_back(i + offset); - } - word >>= 1; - } - return; -} - StreamProcessor::~StreamProcessor() {} // checks that the packet size is an integer multiple of the BX block size, @@ -88,32 +75,16 @@ bool StreamProcessor::CheckFrameMultBlock(size_t inputSize) { return true; } -// Looks for orbit trailer then counts the non-empty bunch crossings and fills a -// vector with their values The bool (.second) is used to determine valididy of -// the BX count -std::vector<unsigned int> StreamProcessor::CountBX(Slice &input, char *rd_ptr, - bool &trailerError) { - +bool StreamProcessor::GetTrailer(Slice &input, char *&rd_ptr) { rd_ptr += 32; // +32 to account for orbit header - std::vector<unsigned int> bx_vect; - trailerError = false; while (rd_ptr != input.end()) { - blockMuon *bl = reinterpret_cast<blockMuon *>(rd_ptr); - if (bl->orbit[0] == constants::beefdead) { // found orbit trailer - orbit_trailer *ot = (orbit_trailer *)(rd_ptr); - for (unsigned int k = 0; k < (14 * 8); - k++) { // 14*8 = 14 frames, 8 links of orbit trailer containing BX - // hitmap - bit_check( - &bx_vect, ot->bx_map[k], - (k * 32 + 1)); // +1 added to account for BX counting starting at 1 - } - return bx_vect; + orbit_trailer *ot = reinterpret_cast<orbit_trailer *>(rd_ptr); + if (ot->beefdead[0] == constants::beefdead) { // found orbit trailer + return true; } rd_ptr += sizeof(blockMuon); } - trailerError = true; - return bx_vect; + return false; } inline std::pair<uint32_t, bool> @@ -134,32 +105,59 @@ StreamProcessor::ProcessOrbitHeader(char *rd_ptr) { // Goes through orbit worth of data and fills the output memory with the calo // data corresponding to the non-empty bunchcrossings, as marked in bx_vect StreamProcessor::fillOrbitMetadata -StreamProcessor::FillOrbitCalo(const std::vector<unsigned int> &bx_vect, - char *rd_ptr, char *wr_ptr) { +StreamProcessor::FillOrbitCalo(orbit_trailer *trailer, char *rd_ptr, + char *wr_ptr) { std::pair<uint32_t, bool> orbit_header = std::pair<uint32_t, bool>{ ProcessOrbitHeader(rd_ptr)}; //.second is the warning test enable bit rd_ptr += 32; // +32 to account for orbit header - uint32_t relbx = uint32_t{0}; + uint32_t orbit = + uint32_t{orbit_header.first} - + 1; // Starting with orbit number one lower than what is in the header + // because the "link orbit" contains a few BXs of the previous orbit uint32_t counts = uint32_t{0}; - uint32_t orbit = uint32_t{orbit_header.first}; - while (relbx < bx_vect.size()) { // total number of non-empty BXs in orbit is - // given by bx_vect.size() + uint32_t filled_bxs = 0; + // We loop over the BX map from the orbit trailer and then match the filled + // BXs to the data we got. The logic below is annoyingly convoluted: The first + // BX we get in the data stream is from BX 3555, however the BX map starts at + // BX 1, we therefore need to start reading the BX map from the 3555th bit. + // 3555//32 = 111, so we start at the 111th word; 3555 mod 32 = 3, however we + // start counting at BX1, so the start bit is 2. + uint32_t bx = 3554; // We start at 3554 here, because we increment by 1 + // immediately after starting the loops. + size_t word = 111; + size_t bit = 1; // Will be incremented immediately after starting the loop + for (size_t pseudo_bx = 0; pseudo_bx < 3564; + ++pseudo_bx) { // Looping over at most an entire orbit here. + if (word == 14 * 8 - 1 && + bit == 11) { // Bit 11 in word 111 is the last valid BX (3564), so we + // roll over afterwards. (== 11 because that's the one we + // worked on in the previous loop iteration) + word = 0; + bit = 0; + bx = 0; // Will be immediately incremented to 1. + ++orbit; + } else if (bit < 31) { + ++bit; + } else { + bit = 0; + ++word; + } + ++bx; + if ((trailer->bx_map[word] & (1 << bit)) == 0) { + continue; // If the bit is zero that BX was empty and we continue. + } + ++filled_bxs; blockCalo *bl = reinterpret_cast<blockCalo *>(rd_ptr); if (bl->calo0[0] == constants::beefdead) { break; } // orbit trailer has been reached, end of orbit data - uint32_t bx = uint32_t{bx_vect[relbx]}; - uint32_t orbit_ = uint32_t{orbit_header.first}; - if (bx > 3554) { - --orbit_; - } // fix for the fact that bx 3555 - 3564 are from the previous orbit uint32_t header = uint32_t{orbit_header.second}; // header can be added to later memcpy(wr_ptr, (char *)&header, 4); wr_ptr += 4; memcpy(wr_ptr, (char *)&bx, 4); wr_ptr += 4; - memcpy(wr_ptr, (char *)&orbit_, 4); + memcpy(wr_ptr, (char *)&orbit, 4); wr_ptr += 4; for (uint32_t i = 0; i < 8; i++) { memcpy(wr_ptr, (char *)&i, 4); @@ -179,13 +177,9 @@ StreamProcessor::FillOrbitCalo(const std::vector<unsigned int> &bx_vect, } counts += 1; rd_ptr += sizeof(blockCalo); - relbx++; } - StreamProcessor::fillOrbitMetadata meta = { - counts, - orbit, - }; + StreamProcessor::fillOrbitMetadata meta = {counts, orbit, filled_bxs}; return meta; } @@ -249,16 +243,48 @@ uint32_t StreamProcessor::FillBril(char *rd_ptr, char *wr_ptr, char *end_ptr) { // Goes through orbit worth of data and fills the output memory with the muons // corresponding to the non-empty bunchcrossings, as marked in bx_vect StreamProcessor::fillOrbitMetadata -StreamProcessor::FillOrbitMuon(const std::vector<unsigned int> &bx_vect, - char *rd_ptr, char *wr_ptr) { +StreamProcessor::FillOrbitMuon(orbit_trailer *trailer, char *rd_ptr, + char *wr_ptr) { std::pair<uint32_t, bool> orbit_header = std::pair<uint32_t, bool>{ ProcessOrbitHeader(rd_ptr)}; //.second is the warning test enable bit rd_ptr += 32; // +32 to account for orbit header - uint32_t orbit = uint32_t{orbit_header.first}; - uint32_t relbx = uint32_t{0}; + uint32_t orbit = + uint32_t{orbit_header.first} - + 1; // Starting with orbit number one lower than what is in the header + // because the "link orbit" contains a few BXs of the previous orbit uint32_t counts = uint32_t{0}; - while (relbx < bx_vect.size()) { // total number of non-empty BXs in orbit is - // given by bx_vect.size() + uint32_t filled_bxs = 0; + // We loop over the BX map from the orbit trailer and then match the filled + // BXs to the data we got. The logic below is annoyingly convoluted: The first + // BX we get in the data stream is from BX 3555, however the BX map starts at + // BX 1, we therefore need to start reading the BX map from the 3555th bit. + // 3555//32 = 111, so we start at the 111th word; 3555 mod 32 = 3, however we + // start counting at BX1, so the start bit is 2. + uint32_t bx = 3554; // We start at 3554 here, because we increment by 1 + // immediately after starting the loops. + size_t word = 111; + size_t bit = 1; // Will be incremented immediately after starting the loop + for (size_t pseudo_bx = 0; pseudo_bx < 3564; + ++pseudo_bx) { // Looping over at most an entire orbit here. + if (word == 14 * 8 - 1 && + bit == 11) { // Bit 11 in word 111 is the last valid BX (3564), so we + // roll over afterwards. (== 11 because that's the one we + // worked on in the previous loop iteration) + word = 0; + bit = 0; + bx = 0; // Will be immediately incremented to 1. + ++orbit; + } else if (bit < 31) { + ++bit; + } else { + bit = 0; + ++word; + } + ++bx; + if ((trailer->bx_map[word] & (1 << bit)) == 0) { + continue; // If the bit is zero that BX was empty and we continue. + } + ++filled_bxs; blockMuon *bl = reinterpret_cast<blockMuon *>(rd_ptr); if (bl->orbit[0] == constants::beefdead) { break; @@ -267,19 +293,14 @@ StreamProcessor::FillOrbitMuon(const std::vector<unsigned int> &bx_vect, int mBcount = 0; bool AblocksOn[8]; bool BblocksOn[8]; - uint32_t bx = uint32_t{bx_vect[relbx]}; - if (bx > 3554) { - --orbit; - } // fix for the fact that bx 3555 - 3564 are from the previous orbit for (unsigned int i = 0; i < 8; i++) { uint32_t bxA = (bl->bx[i] >> shifts::bx) & masks::bx; - if ((bxA != bx) && (i == 0) && (bx < 3555) && - control.verbosity) { // only prints warning when BX < 3555 i.e from - // the same orbit + if ((bxA != bx) && (i == 0) && control.verbosity) { LOG(WARNING) << "BX mismatch, uGMT data word BX = " << std::hex << bxA << ", BX extracted from trailer = " << bx << ", orbitN is " << std::dec << orbit; } + uint32_t orbitA = bl->orbit[i]; uint32_t pt = uint32_t{(bl->mu1f[i] >> shifts::pt) & masks::pt}; @@ -342,15 +363,9 @@ StreamProcessor::FillOrbitMuon(const std::vector<unsigned int> &bx_vect, wr_ptr += 4; // set bit 0 to 1 for second muon } } - rd_ptr += sizeof(blockMuon); - - relbx++; } - StreamProcessor::fillOrbitMetadata meta = { - counts, - orbit, - }; + StreamProcessor::fillOrbitMetadata meta = {counts, orbit, filled_bxs}; return meta; } @@ -372,10 +387,7 @@ void StreamProcessor::process(Slice &input, Slice &out) { bool endofpacket = false; uint32_t orbit_per_packet_count = 0; bool firstOrbit = true; - StreamProcessor::fillOrbitMetadata meta{ - 0, - 0, - }; + StreamProcessor::fillOrbitMetadata meta{0, 0, 0}; if (processorType == ProcessorType::PASS_THROUGH) { memcpy(wr_ptr, rd_ptr, input.size()); out.set_end(out.begin() + input.size()); @@ -394,9 +406,9 @@ void StreamProcessor::process(Slice &input, Slice &out) { } while (endofpacket == false) { uint32_t orbitCount = 0; - bool trailerError = false; - std::vector<unsigned int> bx_vect = CountBX(input, rd_ptr, trailerError); - if (trailerError == true) { + char *trailer_ptr = rd_ptr; + bool trailerFound = GetTrailer(input, trailer_ptr); + if (!trailerFound) { stats.orbit_trailer_error_count++; LOG(WARNING) << "Orbit trailer error: orbit trailer not found before end of data " @@ -404,36 +416,34 @@ void StreamProcessor::process(Slice &input, Slice &out) { << stats.orbit_trailer_error_count; return; } - std::sort(bx_vect.begin(), bx_vect.end()); + orbit_trailer *trailer = reinterpret_cast<orbit_trailer *>(trailer_ptr); if (processorType == ProcessorType::GMT) { - meta = FillOrbitMuon(bx_vect, rd_ptr, wr_ptr); + meta = FillOrbitMuon(trailer, rd_ptr, wr_ptr); orbitCount = meta.counts; ++orbit_per_packet_count; - wr_ptr += orbitCount * 12 + - 12 * bx_vect.size(); // 12 bytes for each muon/count then 12 - // bytes for each bx header + wr_ptr += meta.counts * 12 + + 12 * meta.filled_bxs; // 12 bytes for each muon/count then 12 + // bytes for each bx header } else if (processorType == ProcessorType::CALO) { - meta = FillOrbitCalo(bx_vect, rd_ptr, wr_ptr); + meta = FillOrbitCalo(trailer, rd_ptr, wr_ptr); orbitCount = meta.counts; ++orbit_per_packet_count; // size of calo packet is 4bytes*(8links*7dataWords + 3headerWords)=236 // bytes Note 7 data words per link because we have the "link number" word // + 6 words from calo L2 - wr_ptr += 4 * ((8 * 7) + 3) * bx_vect.size(); - + wr_ptr += 4 * ((8 * 7) + 3) * meta.filled_bxs; } else { LOG(ERROR) << "UNKNOWN PROCESSOR_TYPE, EXITING"; throw std::invalid_argument("ERROR: PROCESSOR_TYPE NOT RECOGNISED"); } - rd_ptr += 32 + bx_vect.size() * sizeof(blockMuon) + + rd_ptr += 32 + meta.filled_bxs * sizeof(blockMuon) + constants::orbit_trailer_size; // 32 for orbit header, + nBXs + // orbit trailer counts += orbitCount; if (firstOrbit) { out.set_firstOrbitN(meta.orbit); firstOrbit = false; - }; - bx_vect.clear(); + } if (rd_ptr < input.end()) { diff --git a/src/processor.h b/src/processor.h index c85f34d0..2398e7ff 100644 --- a/src/processor.h +++ b/src/processor.h @@ -31,16 +31,16 @@ private: struct fillOrbitMetadata { uint32_t counts; uint32_t orbit; + uint32_t filled_bxs; }; void process(Slice &input, Slice &out); bool CheckFrameMultBlock(size_t inputSize); - std::vector<unsigned int> CountBX(Slice &input, char *rd_ptr, - bool &trailerError); + bool GetTrailer(Slice &input, char *&rd_ptr); inline std::pair<uint32_t, bool> ProcessOrbitHeader(char *rd_ptr); - fillOrbitMetadata FillOrbitMuon(std::vector<unsigned int> &bx_vect, - char *rd_ptr, char *wr_ptr); - fillOrbitMetadata FillOrbitCalo(std::vector<unsigned int> &bx_vect, - char *rd_ptr, char *wr_ptr); + fillOrbitMetadata FillOrbitMuon(orbit_trailer *trailer, char *rd_ptr, + char *wr_ptr); + fillOrbitMetadata FillOrbitCalo(orbit_trailer *trailer, char *rd_ptr, + char *wr_ptr); uint32_t FillBril(char *rd_ptr, char *wr_ptr, char *end_ptr); size_t max_size; uint64_t nbPackets; -- GitLab