Project
Loading...
Searching...
No Matches
GBTRawDataChecker.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
18
19#include <sstream>
20#include <fmt/format.h>
22
23namespace o2
24{
25namespace mid
26{
27
28void GBTRawDataChecker::init(uint16_t gbtUniqueId, uint8_t mask)
29{
31 mGBTUniqueId = gbtUniqueId;
32 mCrateMask = mask;
33}
34
35bool GBTRawDataChecker::checkLocalBoardSize(const ROBoard& board)
36{
38
39 // This test only make sense when we have a self-trigger,
40 // since in this case we expect to have a variable number of non-zero pattern
41 // as indicated by the corresponding word.
42 for (int ich = 0; ich < 4; ++ich) {
43 bool isExpectedNull = (((board.firedChambers >> ich) & 0x1) == 0);
44 bool isNull = (board.patternsBP[ich] == 0 && board.patternsNBP[ich] == 0);
45 if (isExpectedNull != isNull) {
46 std::stringstream ss;
47 ss << "wrong size for local board:\n";
48 ss << board << "\n";
49 mEventDebugMsg += ss.str();
50 return false;
51 }
52 }
53 return true;
54}
55
56bool GBTRawDataChecker::checkLocalBoardSize(const std::vector<ROBoard>& boards)
57{
59 for (auto& board : boards) {
60 if (!checkLocalBoardSize(board)) {
61 return false;
62 }
63 }
64 return true;
65}
66
67bool GBTRawDataChecker::checkConsistency(const ROBoard& board)
68{
70
71 bool isSoxOrReset = board.triggerWord & (raw::sSOX | raw::sEOX | raw::sRESET);
72 bool isCalib = raw::isCalibration(board.triggerWord);
73 bool isPhys = board.triggerWord & raw::sPHY;
74
75 // FIXME: During data acquisition we do not expect a calibration trigger
76 // in coincidence with a physics trigger.
77 // However, this situation can happen in the tests with the LTU.
78 // So, let us remove these tests for the time being
79
80 // if (isPhys) {
81 // if (isCalib) {
82 // mEventDebugMsg += "inconsistent trigger: calibration and physics trigger cannot be fired together\n";
83 // return false;
84 // }
85 // if (raw::isLoc(board.statusWord)) {
86 // if (board.firedChambers) {
87 // mEventDebugMsg += "inconsistent trigger: fired chambers should be 0\n";
88 // return false;
89 // }
90 // }
91 // }
92 if (isSoxOrReset && (isCalib || isPhys)) {
93 mEventDebugMsg += "inconsistent trigger: cannot be SOX and calibration\n";
94 return false;
95 }
96
97 return true;
98}
99
100bool GBTRawDataChecker::checkConsistency(const std::vector<ROBoard>& boards)
101{
103 for (auto& board : boards) {
104 if (!checkConsistency(board)) {
105 std::stringstream ss;
106 ss << board << "\n";
107 mEventDebugMsg += ss.str();
108 return false;
109 }
110 }
111 return true;
112}
113
114bool GBTRawDataChecker::checkMasks(const std::vector<ROBoard>& locs)
115{
117 for (auto loc : locs) {
118 // The board patterns coincide with the masks ("overwritten" mode)
119 if (loc.statusWord & raw::sOVERWRITTEN) {
120 auto maskItem = mMasks.find(loc.boardId);
121 for (int ich = 0; ich < 4; ++ich) {
122 uint16_t maskBP = 0;
123 uint16_t maskNBP = 0;
124 if (maskItem != mMasks.end()) {
125 maskBP = maskItem->second.patternsBP[ich];
126 maskNBP = maskItem->second.patternsNBP[ich];
127 }
128 if (maskBP != loc.patternsBP[ich] || maskNBP != loc.patternsNBP[ich]) {
129 std::stringstream ss;
130 ss << "Pattern is not compatible with mask for:\n";
131 ss << loc << "\n";
132 mEventDebugMsg += ss.str();
133 return false;
134 }
135 }
136 }
137 }
138 return true;
139}
140
141bool GBTRawDataChecker::checkRegLocConsistency(const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir)
142{
144 uint8_t regFired{0};
145 bool isTrig = false;
146 for (auto& reg : regs) {
147 uint8_t ireg = raw::getLocId(reg.boardId) % 2;
148 if (reg.triggerWord == 0) {
149 // Self-triggered event: check the decision
150 regFired |= (reg.firedChambers << (4 * ireg));
151 } else {
152 // Triggered event: all active boards must answer
153 regFired |= (mCrateMask & (0xF << (4 * ireg)));
154 isTrig = true;
155 }
156 }
157 uint8_t locFired{0};
158 for (auto& loc : locs) {
159 auto linkId = getElinkId(loc);
160 uint8_t mask = (1 << linkId);
161 if (loc.triggerWord == 0) {
162 // Self-triggered event: check the decision
163 if (loc.firedChambers) {
164 locFired |= mask;
165 }
166 } else {
167 // Triggered event: all active boards must answer
168 locFired |= mask;
169 isTrig = true;
170 }
171 }
172
173 // The XOR returns 1 in case of a difference
174 uint8_t problems = (regFired ^ locFired);
175
176 if (problems) {
177 // It can be that a busy signal was raised by one of the board in previous events
178 // If the board is still busy it will not answer.
179 uint8_t busy{0};
180 for (uint8_t iboard = 0; iboard < crateparams::sNELinksPerGBT; ++iboard) {
181 auto rawIr = getRawIR(iboard, isTrig, ir);
182 bool isBusy = false;
183 for (auto& busyInfo : mBusyPeriods[iboard]) {
184 if (busyInfo.interactionRecord > rawIr) {
185 break;
186 }
187 isBusy = busyInfo.isBusy;
188 }
189 if (isBusy) {
190 busy |= (iboard < crateparams::sMaxNBoardsInLink) ? (1 << iboard) : (0xF << (4 * (iboard % 2)));
191 }
192 }
193
194 if (problems & ~busy) {
195 std::stringstream ss;
196 ss << fmt::format("loc-reg inconsistency: fired locals ({:08b}) != expected from reg ({:08b});\n", locFired, regFired);
197 ss << printBoards(regs);
198 ss << printBoards(locs);
199 mEventDebugMsg += ss.str();
200 return false;
201 }
202 }
203 return true;
204}
205
206std::string GBTRawDataChecker::printBoards(const std::vector<ROBoard>& boards) const
207{
209 std::stringstream ss;
210 for (auto& board : boards) {
211 ss << board << "\n";
212 }
213 return ss.str();
214}
215
216bool GBTRawDataChecker::checkEvent(bool isTriggered, const std::vector<ROBoard>& regs, const std::vector<ROBoard>& locs, const InteractionRecord& ir)
217{
219 mEventDebugMsg.clear();
220 if (!checkRegLocConsistency(regs, locs, ir)) {
221 return false;
222 }
223
224 if (!checkConsistency(regs) || !checkConsistency(locs)) {
225 return false;
226 }
227
228 if (!isTriggered) {
229 if (!checkLocalBoardSize(locs)) {
230 return false;
231 }
232
233 if (!checkMasks(locs)) {
234 return false;
235 }
236 }
237
238 return true;
239}
240
241InteractionRecord GBTRawDataChecker::getRawIR(uint8_t id, bool isTrigger, InteractionRecord ir) const
242{
244 if (isTrigger) {
245 return ir;
246 }
247 auto delay = mElectronicsDelay.localToBC;
248 if (id >= crateparams::sMaxNBoardsInLink) {
249 delay -= mElectronicsDelay.localToReg;
250 }
251 applyElectronicsDelay(ir.orbit, ir.bc, -delay, mResetVal);
252 return ir;
253}
254
255uint8_t GBTRawDataChecker::getElinkId(const ROBoard& board) const
256{
258 if (raw::isLoc(board.statusWord)) {
259 return board.boardId % 8;
260 }
261 return 8 + board.boardId % 8;
262}
263
264void GBTRawDataChecker::clearChecked(bool isTriggered, bool clearTrigEvents)
265{
267
268 auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig;
269 auto& lastIndexes = isTriggered ? mLastIndexTrig : mLastIndexSelfTrig;
270 // Create a new board map with the checked events stripped
271 for (auto& lastIdxItem : lastIndexes) {
272 auto firstIdx = lastIdxItem.second + 1;
273 auto& boardVec = boards[lastIdxItem.first];
274 boards[lastIdxItem.first].erase(boardVec.begin(), boardVec.begin() + firstIdx);
275 }
276
277 if (clearTrigEvents) {
278 // Clears the map with the processed triggers
279 auto& lastCompleteTrigIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig;
280 auto up = mTrigEvents.upper_bound(lastCompleteTrigIR);
281 mTrigEvents.erase(mTrigEvents.begin(), up);
282 for (auto& busyInfoVec : mBusyPeriods) {
283 auto upBusy = std::upper_bound(busyInfoVec.begin(), busyInfoVec.end(), lastCompleteTrigIR, [](const InteractionRecord& ir, const BusyInfo& busyInfo) { return ir <= busyInfo.interactionRecord; });
284 if (upBusy != busyInfoVec.begin()) {
285 --upBusy;
286 }
287 busyInfoVec.erase(busyInfoVec.begin(), upBusy);
288 }
289 }
290}
291
292bool GBTRawDataChecker::isCompleteSelfTrigEvent(const o2::InteractionRecord& ir) const
293{
295
296 // The regional board information in self-triggered events is delayed
297 // compared to triggered events.
298 // So, we expect information from a previous orbit after having received an orbit trigger.
299 // Let us check that we have all boards with the same orbit
300
301 bool isIncluded = false;
302 for (uint8_t ireg = 8; ireg < crateparams::sNELinksPerGBT; ++ireg) {
303 auto& boards = mBoardsSelfTrig[ireg];
304 if (!boards.empty()) {
305 if (boards.back().interactionRecord.orbit == ir.orbit) {
306 return false;
307 }
308 if (boards.front().interactionRecord.orbit <= ir.orbit) {
309 isIncluded = true;
310 }
311 }
312 }
313 return isIncluded;
314}
315
316unsigned int GBTRawDataChecker::getLastCompleteTrigEvent()
317{
321
322 // The information for an event comes at different times for different boards,
323 // depending on the length of the self-triggered event for that board.
324 // So, before testing the consistency of the event,
325 // we must wait to have received the information from all boards.
326 // This can be checked in triggered events, since all boards should be present.
327
328 unsigned int completeMask = 0;
329
330 // Check if we have a triggered event with the information from all active boards
331 mLastCompleteIRSelfTrig = o2::InteractionRecord();
332 uint16_t fullMask = (3 << 8) | mCrateMask;
333 auto trigEventIt = mTrigEvents.rbegin();
334 auto end = mTrigEvents.rend();
335 for (; trigEventIt != end; ++trigEventIt) {
336 if ((trigEventIt->second & fullMask) == fullMask) {
337 // The trigger events contain the unprocessed events for both triggered and self-triggered events
338 // These might not be synchronized (typically the latest complete self-triggered events lie behind)
339 // If the latest IR in memory is more recent than the current complete event found,
340 // then it means that we need to wait for more HBs.
341 if (mLastCompleteIRTrig.isDummy() || mLastCompleteIRTrig < trigEventIt->first) {
342 completeMask |= 1;
343 mLastCompleteIRTrig = trigEventIt->first;
344 }
345 auto trIt = trigEventIt;
346 while (trIt != end) {
347 if (isCompleteSelfTrigEvent(trIt->first)) {
348 completeMask |= (1 << 1);
349 mLastCompleteIRSelfTrig = trIt->first;
350 break;
351 }
352 ++trIt;
353 }
354
355 return completeMask;
356 }
357 }
358
359 return completeMask;
360}
361
362bool GBTRawDataChecker::runCheckEvents(unsigned int completeMask)
363{
365
366 bool isOk = true;
367
368 if (completeMask & 0x1) {
369 sortEvents(true);
370 isOk &= checkEvents(true);
371 // This is needed to clear vectors in runs with no self-triggered events
372 bool clearTrigger = true;
373 for (auto infos : mBoardsSelfTrig) {
374 if (!infos.empty()) {
375 clearTrigger = false;
376 break;
377 }
378 }
379 clearChecked(true, clearTrigger);
380 }
381
382 if (completeMask & 0x2) {
383 sortEvents(false);
384 isOk &= checkEvents(false);
385 clearChecked(false, true);
386 }
387
388 return isOk;
389}
390
391void GBTRawDataChecker::sortEvents(bool isTriggered)
392{
394 auto& orderedIndexes = isTriggered ? mOrderedIndexesTrig : mOrderedIndexesSelfTrig;
395 auto& lastIndexes = isTriggered ? mLastIndexTrig : mLastIndexSelfTrig;
396 auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig;
397 auto& lastCompleteTrigEventIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig;
398 orderedIndexes.clear();
399 lastIndexes.clear();
400 for (uint8_t ilink = 0; ilink < crateparams::sNELinksPerGBT; ++ilink) {
401 long int lastIdx = -1;
402 for (auto boardIt = boards[ilink].begin(), end = boards[ilink].end(); boardIt != end; ++boardIt) {
403 if (boardIt->interactionRecord > lastCompleteTrigEventIR) {
404 break;
405 }
406 lastIdx = std::distance(boards[ilink].begin(), boardIt);
407 orderedIndexes[boardIt->interactionRecord.toLong()].emplace_back(ilink, lastIdx);
408 }
409 lastIndexes[ilink] = lastIdx;
410 }
411}
412
413bool GBTRawDataChecker::checkEvents(bool isTriggered)
414{
416 bool isOk = true;
417 auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig;
418 auto& orderedIndexes = isTriggered ? mOrderedIndexesTrig : mOrderedIndexesSelfTrig;
419 // Loop on the event indexes
421 for (auto& evtIdxItem : orderedIndexes) {
422 // All of these boards have the same timestamp
423 GBT gbtEvent;
424 for (auto& evtPair : evtIdxItem.second) {
425 auto& boardInfo = boards[evtPair.first][evtPair.second];
426
427 if (raw::isLoc(boardInfo.board.statusWord)) {
428 gbtEvent.locs.push_back(boardInfo.board);
429 } else {
430 gbtEvent.regs.push_back(boardInfo.board);
431 }
432 if (boardInfo.page >= 0) {
433 if (std::find(gbtEvent.pages.begin(), gbtEvent.pages.end(), boardInfo.page) == gbtEvent.pages.end()) {
434 gbtEvent.pages.push_back(boardInfo.page);
435 }
436 }
437 }
438 ++mStatistics[0];
439 ir.setFromLong(evtIdxItem.first);
440 if (!checkEvent(isTriggered, gbtEvent.regs, gbtEvent.locs, ir)) {
441 std::stringstream ss;
442 ss << fmt::format("BCid: 0x{:x} Orbit: 0x{:x}", ir.bc, ir.orbit);
443 if (!gbtEvent.pages.empty()) {
444 ss << " [in";
445 for (auto& page : gbtEvent.pages) {
446 ss << std::dec << " page: " << page << " (line: " << 512 * page + 1 << ") ";
447 }
448 ss << "]";
449 }
450 ss << "\n";
451 isOk = false;
452 ss << mEventDebugMsg << "\n";
453 mDebugMsg += ss.str();
454 ++mStatistics[1];
455 }
456 }
457
458 return isOk;
459}
460
461bool GBTRawDataChecker::process(gsl::span<const ROBoard> localBoards, gsl::span<const ROFRecord> rofRecords, gsl::span<const ROFRecord> pageRecords)
462{
464 mDebugMsg.clear();
465
466 // Fill board information
467 for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) {
468 if (rofIt->interactionRecord.orbit == 0xffffffff) {
469 // Protection for event with orbit 0
470 continue;
471 }
472 for (auto locIt = localBoards.begin() + rofIt->firstEntry; locIt != localBoards.begin() + rofIt->firstEntry + rofIt->nEntries; ++locIt) {
473 // Find what page this event corresponds to.
474 // This is useful for debugging.
475 long int page = -1;
476 for (auto& rofPage : pageRecords) {
477 if (rofIt->firstEntry >= rofPage.firstEntry && rofIt->firstEntry < rofPage.firstEntry + rofPage.nEntries) {
478 page = rofPage.interactionRecord.orbit;
479 break;
480 }
481 }
482
483 // Store the information per local board.
484 // The information should be already ordered in time
485 auto id = getElinkId(*locIt);
486 auto& elinkVec = (locIt->triggerWord == 0) ? mBoardsSelfTrig[id] : mBoardsTrig[id];
487 elinkVec.push_back({*locIt, rofIt->interactionRecord, page});
488
489 auto& busyVec = mBusyPeriods[id];
490 bool wasBusy = !busyVec.empty() && busyVec.back().isBusy;
491 bool isBusy = locIt->statusWord & raw::sREJECTING;
492 if (isBusy != wasBusy) {
493 if (isBusy) {
494 ++mStatistics[2];
495 }
496 busyVec.push_back({isBusy, getRawIR(id, locIt->triggerWord != 0, rofIt->interactionRecord)});
497 }
498
499 if (locIt->triggerWord == 0) {
500 continue;
501 }
502
503 // Keep track of the trigger chosen for synchronisation
504 if (locIt->triggerWord & mSyncTrigger) {
505 mTrigEvents[rofIt->interactionRecord] |= (1 << id);
506 }
507 if (locIt->triggerWord & raw::sORB) {
508 mResetVal = rofIt->interactionRecord.bc + 1;
509 }
510
511 // Compute the masks
512 if (locIt->triggerWord & raw::sSOX) {
513 if (raw::isLoc(locIt->statusWord)) {
514 auto maskItem = mMasks.find(locIt->boardId);
515 // Check if we have already a mask for this
516 if (maskItem == mMasks.end()) {
517 // If not, read the map
518 auto& mask = mMasks[locIt->boardId];
519 for (int ich = 0; ich < 4; ++ich) {
520 mask.patternsBP[ich] = locIt->patternsBP[ich];
521 mask.patternsNBP[ich] = locIt->patternsNBP[ich];
522 }
523 }
524 }
525 }
526 } // loop on local boards
527 } // loop on ROF records
528
529 return runCheckEvents(getLastCompleteTrigEvent());
530}
531
533{
535 if (all) {
536 mMasks.clear();
537 }
538 mStatistics.fill(0);
539}
540
541} // namespace mid
542} // namespace o2
MID RO crate parameters.
Class to check the raw data from a GBT link.
bool process(gsl::span< const ROBoard > localBoards, gsl::span< const ROFRecord > rofRecords, gsl::span< const ROFRecord > pageRecords)
void init(uint16_t gbtUniqueId, uint8_t mask)
GLuint GLuint end
Definition glcorearb.h:469
GLint GLuint mask
Definition glcorearb.h:291
GLuint id
Definition glcorearb.h:650
bool isOk(ResultWas::OfType resultType)
uint8_t itsSharedClusterMap uint8_t
bool isCalibration(uint8_t triggerWord)
Definition ROBoard.h:70
bool isLoc(uint8_t statusWord)
Definition ROBoard.h:65
uint8_t getLocId(uint8_t uniqueLocId)
Definition ROBoard.h:80
void applyElectronicsDelay(uint32_t &orbit, uint16_t &bc, int16_t delay, uint16_t maxBunches=constants::lhc::LHCMaxBunches)
@ GBT
GBT encoded raw data.
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:173
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
bool isBusy()
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
void setFromLong(int64_t l)
int16_t localToReg
Delay between regional board and local board answers.
int16_t localToBC
Delay between collision BC and local clock.
std::array< uint16_t, 4 > patternsNBP
Bending plane pattern.
Definition ROBoard.h:33
std::array< uint16_t, 4 > patternsBP
Fired chambers.
Definition ROBoard.h:32
uint8_t firedChambers
Board ID in crate.
Definition ROBoard.h:31
o2::InteractionRecord ir(0, 0)