Project
Loading...
Searching...
No Matches
RawParser.h
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#ifndef FRAMEWORK_UTILS_RAWPARSER_H
12#define FRAMEWORK_UTILS_RAWPARSER_H
13
18
20#include "Framework/VariantHelpers.h" // definition of `overloaded`
21#include "Framework/Logger.h"
22#include <functional>
23#include <memory>
24#include <variant>
25#include <stdexcept>
26#include <string>
27#include <type_traits>
28namespace o2::header
29{
30struct DataHeader;
31} // namespace o2::header
32
33// FIXME: probably moved somewhere else
34namespace o2::framework
35{
36
38namespace raw_parser
39{
40
42enum struct FormatSpec {
43 Info, // basic info: version
44 TableHeader, // table header
45 Entry, // table entry, i.e. RDH at current position
46 FullTable, // full table with header and all entiries
47 FullTableInfo, // info and full table with header and all entries
48};
49
50template <typename T>
52 using type = T;
53 static void apply(std::ostream&, type const&, FormatSpec, const char* = "")
54 {
55 }
56};
57
58template <>
59struct RDHFormatter<header::RAWDataHeaderV7> {
61 static void apply(std::ostream&, type const&, FormatSpec, const char* = "");
62};
63
64template <>
67 static void apply(std::ostream&, type const&, FormatSpec, const char* = "");
68};
69
70template <>
71struct RDHFormatter<header::RAWDataHeaderV5> {
73 static const char* sFormatString;
74 static void apply(std::ostream&, type const&, FormatSpec, const char* = "");
75};
76
77template <>
78struct RDHFormatter<header::RAWDataHeaderV4> {
80 static const char* sFormatString;
81 static void apply(std::ostream&, type const&, FormatSpec, const char* = "");
82};
83
85 static int sErrorMode; // 0: no error checking, 1: print error message, 2: throw exception. To be set via O2_DPL_RAWPARSER_ERRORMODE.
86 static int sCheckIncompleteHBF; // Check if HBFs are incomplete, set to 2 to throw in case sErrorMode = 2.
87 static unsigned long sErrors; // Obviously this would need to be atomic to be fully correct, but a race condition is unlikely and would only lead to one extra log message printed.
88 static unsigned long sErrorLimit; // Exponentially downscale error reporting after sErrorLimit errors.
89 static unsigned long sErrorScale; // Exponentionally downscale verbosity.
90
91 static bool checkPrintError(size_t& localCounter);
92 static void warnDeadBeef(const o2::header::DataHeader* dh);
93};
94
107template <typename HeaderType, size_t MAX_SIZE, bool BOUNDS_CHECKS>
109{
110 public:
111 using buffer_type = unsigned char;
112 using header_type = HeaderType;
114 static constexpr size_t max_size = MAX_SIZE;
115
117
120 template <typename T>
121 ConcreteRawParser(T const* buffer, size_t size)
122 : mRawBuffer(reinterpret_cast<buffer_type const*>(buffer)), mSize(size)
123 {
124 static_assert(sizeof(T) == sizeof(buffer_type), "buffer required to be byte-type");
125 if (size < sizeof(header_type)) { // TODO: should be included in sErrorMode treatment, but would need to existing behavior in detail
126 std::runtime_error("buffer too small to fit at least the page header");
127 }
128 next();
129 }
130 // FIXME: add constructor for container type buffer
131
136
138 header_type const& header() const
139 {
140 return *reinterpret_cast<header_type const*>(mPosition);
141 }
142
144 size_t size() const
145 {
146 if (mPosition == mRawBuffer + mSize) {
147 return 0;
148 }
149 header_type const& h = header();
150 if (h.memorySize >= h.headerSize) {
151 return h.memorySize - h.headerSize;
152 }
153 return max_size - h.headerSize;
154 }
155
157 size_t sizeTotal() const
158 {
159 if (mPosition == mRawBuffer + mSize) {
160 return 0;
161 }
162 header_type const& h = header();
163 if (h.memorySize >= h.headerSize) {
164 return h.memorySize;
165 }
166 return max_size;
167 }
168
170 buffer_type const* data() const
171 {
172 size_t size = this->size();
173 if (size == 0) {
174 return nullptr;
175 }
176 header_type const& h = header();
177 return mPosition + h.headerSize;
178 }
179
181 buffer_type const* raw() const
182 {
183 if (mPosition < mRawBuffer + mSize) {
184 return mPosition;
185 }
186 return nullptr;
187 }
188
190 size_t offset() const
191 {
192 if (mPosition < mRawBuffer + mSize) {
193 header_type const& h = header();
194 return h.headerSize;
195 }
196 return 0;
197 }
198
199 bool checkPageInBuffer() const
200 {
201 if (mPosition + sizeof(header_type) > mRawBuffer + mSize) {
202 return false;
203 }
204 header_type const& h = header();
205 if (h.memorySize > MAX_SIZE || h.headerSize > MAX_SIZE) {
206 return false;
207 }
208 size_t pageSize = h.memorySize >= h.headerSize ? h.memorySize : MAX_SIZE;
209 return mPosition + pageSize <= mRawBuffer + mSize;
210 }
211
216 template <typename Processor>
217 void parse(Processor&& processor)
218 {
219 if (!reset()) {
220 return;
221 }
222 if constexpr (BOUNDS_CHECKS) {
225 throw std::runtime_error("Corrupt RDH - RDH parsing ran out of raw data buffer");
226 }
227 if (RawParserHelper::checkPrintError(mNErrors)) {
228 LOG(error) << "RAWPARSER: Corrupt RDH - RDH parsing ran out of raw data buffer (" << RawParserHelper::sErrors << " total RawParser errors)";
229 }
230 }
231 }
232 // auto deleter = [](buffer_type*) {};
233 do {
234 processor(data(), size());
235 // processor(std::unique_ptr<buffer_type, decltype(deleter)>(data(), deleter), size());
236 } while (next());
237 }
238
240 bool next()
241 {
242 int lastPacketCounter = -1;
243 int lastHBFPacketCounter = -1;
244 unsigned int lastFEEID = -1;
245 if (mPosition == nullptr) {
246 mPosition = mRawBuffer;
247 if (mSize == 0) {
248 return false;
249 }
250 } else {
251 auto offset = header().offsetToNext;
252 if ((mPosition + offset + sizeof(header_type) > mRawBuffer + mSize) || (offset < sizeof(header_type))) {
253 mPosition = mRawBuffer + mSize;
254 return false;
255 }
257 lastPacketCounter = header().packetCounter;
258 lastHBFPacketCounter = header().pageCnt;
259 lastFEEID = header().feeId;
260 }
261 mPosition += offset;
262 }
263 if constexpr (BOUNDS_CHECKS) {
266 throw std::runtime_error("Corrupt RDH - RDH parsing ran out of raw data buffer");
267 }
268 if (RawParserHelper::checkPrintError(mNErrors)) {
269 LOG(error) << "RAWPARSER: Corrupt RDH - RDH parsing ran out of raw data buffer (" << RawParserHelper::sErrors << " total RawParser errors)";
270 }
271 mPosition = mRawBuffer + mSize;
272 return false;
273 }
274 }
276 if (header().version != HeaderType().version) {
278 throw std::runtime_error("Corrupt RDH - Invalid RDH version");
279 }
280 if (RawParserHelper::checkPrintError(mNErrors)) {
281 LOG(error) << "RAWPARSER: Corrupt RDH - Invalid RDH Version " << header().version << " (expected " << HeaderType().version << ") (" << RawParserHelper::sErrors << " total RawParser errors)";
282 }
283 mPosition = mRawBuffer + mSize;
284 return false;
285 }
286 // FIXME: The && should be ||, since both packetCounter and pageCnt should be incremental. But currently, UL data with multiple links does not have incremental packetCounter.
287 if (lastPacketCounter != -1 && lastFEEID == header().feeId && ((unsigned char)(lastPacketCounter + 1) != header().packetCounter && (unsigned short)(lastHBFPacketCounter + 1) != header().pageCnt)) {
289 throw std::runtime_error("Incomplete HBF - jump in packet counter");
290 }
291 if (RawParserHelper::checkPrintError(mNErrors)) {
292 LOG(error) << "RAWPARSER: Incomplete HBF - jump in packet counter " << lastPacketCounter << " to " << header().packetCounter << " (" << RawParserHelper::sErrors << " total RawParser errors)";
293 }
294 mPosition = mRawBuffer + mSize;
295 return false;
296 }
297 }
298 return true;
299 }
300
302 bool reset()
303 {
304 mPosition = mRawBuffer;
305 mNErrors = 0;
306 return mSize != 0;
307 }
308
312 void advance(int step)
313 {
314 if (step < 0) {
315 // set beyond the buffer
316 mPosition = mRawBuffer + mSize;
317 } else {
318 while ((step-- > 0) && next()) {
319 };
320 }
321 }
322
323 size_t getNErrors() const
324 {
325 return mNErrors;
326 }
327
330 template <typename T = self_type>
331 bool operator==(T const& other) const
332 {
333 if constexpr (std::is_same<T, self_type>::value == true) {
334 return mRawBuffer == other.mRawBuffer && mPosition == other.mPosition;
335 } else {
336 throw std::runtime_error(std::string("incompatible types for comparison ") + typeid(T).name() + "/" + typeid(self_type).name());
337 }
338 }
339
340 void format(std::ostream& os, FormatSpec choice = FormatSpec::Entry, const char* delimiter = "\n") const
341 {
342 RDHFormatter<header_type>::apply(os, header(), choice, delimiter);
343 }
344
345 private:
346 buffer_type const* mRawBuffer;
347 buffer_type const* mPosition = nullptr;
348 size_t mSize;
349 size_t mNErrors = 0;
350};
351
356// FIXME v3 and v4 are basically the same with v4 defining a few more fields in the otherwise reserved parts
357// needs to be defined in the header, have to check if we need to support this
358// using V3 = header::RAWDataHeaderV3;
359
360template <size_t N, bool BOUNDS_CHECKS>
362template <size_t N, bool BOUNDS_CHECKS>
364template <size_t N, bool BOUNDS_CHECKS>
366template <size_t N, bool BOUNDS_CHECKS>
368// template <size_t N, bool BOUNDS_CHECKS>
369// using V3Parser = ConcreteRawParser<header::RAWDataHeaderV3, N, BOUNDS_CHECKS>;
370
373template <size_t N, bool BOUNDS_CHECKS>
375
377template <size_t PageSize, bool BOUNDS_CHECKS, typename T>
379{
380 // we use v5 for checking the matching version
381 if (buffer == nullptr || size < sizeof(header::RAWDataHeaderV5)) {
382 throw std::runtime_error("can not create RawParser: invalid buffer");
383 }
384
385 V5 const* v5 = reinterpret_cast<V5 const*>(buffer);
386 if (v5->version == 5) {
388 } else if (v5->version == 7) {
390 } else if (v5->version == 6) {
392 } else if (v5->version == 4) {
394 //} else if (v5->version == 3) {
395 // return ConcreteRawParser<V3, PageSize, BOUNDS_CHECKS>(buffer, size);
396 }
397 throw std::runtime_error("can not create RawParser: invalid version " + std::to_string(v5->version));
398}
399
402template <size_t N, typename T, typename P>
403void walk_parse(T& instances, P&& processor, size_t index)
404{
405 if constexpr (N > 0) {
406 if (index == N - 1) {
407 std::get<N - 1>(instances).parse(processor);
408 }
409
410 walk_parse<N - 1>(instances, processor, index);
411 }
412}
413
414template <typename U, typename T, size_t N = std::variant_size_v<T>>
415U const* get_if(T& instances)
416{
417 if constexpr (N > 0) {
418 auto* parser = std::get_if<N - 1>(&instances);
419 if (parser) {
420 // we are in the active instance, return header if type matches
421 using parser_type = typename std::variant_alternative<N - 1, T>::type;
422 using header_type = typename parser_type::header_type;
423 if constexpr (std::is_same<U, header_type>::value == true) {
424 return &(parser->header());
425 }
426 } else {
427 // continue walking through instances until active one is found
428 return get_if<U, T, N - 1>(instances);
429 }
430 }
431 return nullptr;
432}
433
434} // namespace raw_parser
435
464template <size_t MAX_SIZE = 8192, bool BOUNDS_CHECKS = true>
466{
467 public:
468 using buffer_type = unsigned char;
469 static size_t const max_size = MAX_SIZE;
471
472 RawParser() = delete;
473
475 template <typename T>
476 RawParser(T const* buffer, size_t size)
477 : mParser(raw_parser::create<MAX_SIZE, BOUNDS_CHECKS>(buffer, size))
478 {
479 static_assert(sizeof(T) == sizeof(buffer_type), "buffer required to be byte-type");
480 }
481 // FIXME: constructor for container type
482
484 template <typename Processor>
485 void parse(Processor&& processor)
486 {
487 constexpr size_t NofAlternatives = std::variant_size_v<decltype(mParser)>;
488 static_assert(NofAlternatives == 4); // Change this if a new RDH version is added
489 raw_parser::walk_parse<NofAlternatives>(mParser, processor, mParser.index());
490 // it turned out that using a iterative function is faster than using std::visit
491 // std::visit([&processor](auto& parser) { return parser.parse(processor); }, mParser);
492 }
493
495 bool reset()
496 {
497 return std::visit([](auto& parser) { return parser.reset(); }, mParser);
498 }
499
504 uint8_t version = 0;
505 uint8_t headerSize = 0;
506 };
507
514 template <typename T, typename ParentType>
516 {
517 public:
518 using parent_type = ParentType;
520 using iterator_category = std::forward_iterator_tag;
521 using value_type = T;
522 using reference = T&;
523 using pointer = T*;
524
525 Iterator() = delete;
526
527 Iterator(parent_type parser, int start = 0)
528 : mParser(parser)
529 {
530 std::visit([&start](auto& parser) {parser.reset(); parser.advance(start); }, mParser);
531 }
532 ~Iterator() = default;
533
534 // prefix increment
536 {
537 std::visit([](auto& parser) { parser.next(); }, mParser);
538 return *this;
539 }
540 // postfix increment
541 self_type operator++(int /*unused*/)
542 {
543 self_type copy(*this);
544 operator++();
545 return copy;
546 }
547 // return reference
549 {
550 return std::visit([](auto& parser) { return static_cast<reference>(parser.header()); }, mParser);
551 }
552 // comparison
553 bool operator==(const self_type& other) const
554 {
555 return std::visit([&other](auto& parser) { return std::visit([&parser](auto& otherParser) { return parser == otherParser; },
556 other.mParser); },
557 mParser);
558 }
559
560 bool operator!=(const self_type& rh) const
561 {
562 return not operator==(rh);
563 }
564
566 buffer_type const* raw() const
567 {
568 return std::visit([](auto& parser) { return parser.raw(); }, mParser);
569 }
570
572 buffer_type const* data() const
573 {
574 return std::visit([](auto& parser) { return parser.data(); }, mParser);
575 }
576
578 size_t offset() const
579 {
580 return std::visit([](auto& parser) { return parser.offset(); }, mParser);
581 }
582
584 size_t size() const
585 {
586 return std::visit([](auto& parser) { return parser.size(); }, mParser);
587 }
588
590 size_t sizeTotal() const
591 {
592 return std::visit([](auto& parser) { return parser.sizeTotal(); }, mParser);
593 }
594
599 template <typename U>
600 U const* get_if(U const* = nullptr) const
601 {
602 return raw_parser::get_if<U>(mParser);
603 }
604
605 friend std::ostream& operator<<(std::ostream& os, self_type const& it)
606 {
607 std::visit([&os](auto& parser) { return parser.format(os, raw_parser::FormatSpec::Entry, ""); }, it.mParser);
608 return os;
609 }
610
611 private:
612 parent_type mParser;
613 };
614
615 // only define the const_iterator because the parser will allow read-only access
617
619 {
620 return const_iterator(mParser);
621 }
622
624 {
625 return const_iterator(mParser, -1);
626 }
627
628 friend std::ostream& operator<<(std::ostream& os, self_type const& parser)
629 {
630 std::visit([&os](auto& parser) { return parser.format(os, raw_parser::FormatSpec::Info, "\n"); }, parser.mParser);
631 std::visit([&os](auto& parser) { return parser.format(os, raw_parser::FormatSpec::TableHeader); }, parser.mParser);
632 // FIXME: need to decide what kind of information we want to have in the printout
633 // for the moment its problematic, because the parser has only one variable determining the position and all
634 // iterators work with the same instance which is asking for conflicts
635 // this needs to be changed in order to have fully independent iterators over the same constant buffer
636 // for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
637 // os << "\n" << it;
638 //}
639 return os;
640 }
641
642 size_t getNErrors() const
643 {
644 return std::visit([](auto& parser) { return parser.getNErrors(); }, mParser);
645 }
646
651
652 private:
654};
655
656} // namespace o2::framework
657
658#endif // FRAMEWORK_UTILS_RAWPARSER_H
Definition of the RAW Data Header.
uint32_t version
Definition RawData.h:8
Class for time synchronization of RawReader instances.
size_t offset() const
offset of payload at current position
Definition RawParser.h:578
buffer_type const * raw() const
get pointer to raw block at current position, rdh starts here
Definition RawParser.h:566
size_t size() const
get size of payload at current position
Definition RawParser.h:584
size_t sizeTotal() const
get size of payload + header at current position
Definition RawParser.h:590
std::forward_iterator_tag iterator_category
Definition RawParser.h:520
friend std::ostream & operator<<(std::ostream &os, self_type const &it)
Definition RawParser.h:605
bool operator!=(const self_type &rh) const
Definition RawParser.h:560
buffer_type const * data() const
get pointer to payload at current position
Definition RawParser.h:572
bool operator==(const self_type &other) const
Definition RawParser.h:553
U const * get_if(U const *=nullptr) const
Definition RawParser.h:600
Iterator(parent_type parser, int start=0)
Definition RawParser.h:527
size_t getNErrors() const
Definition RawParser.h:642
unsigned char buffer_type
Definition RawParser.h:468
RawParser(T const *buffer, size_t size)
Constructor, raw buffer provided by pointer and size.
Definition RawParser.h:476
const_iterator begin() const
Definition RawParser.h:618
bool reset()
Reset parser and set position to beginning of buffer.
Definition RawParser.h:495
const_iterator end() const
Definition RawParser.h:623
static size_t const max_size
Definition RawParser.h:469
Iterator< RawDataHeaderInfo const, raw_parser::ConcreteParserVariants< MAX_SIZE, BOUNDS_CHECKS > > const_iterator
Definition RawParser.h:616
void parse(Processor &&processor)
Parse complete raw buffer and call processor on payload data for each page.
Definition RawParser.h:485
static void setCheckIncompleteHBF(bool v)
Definition RawParser.h:647
friend std::ostream & operator<<(std::ostream &os, self_type const &parser)
Definition RawParser.h:628
buffer_type const * data() const
Get pointer to payload data at current position.
Definition RawParser.h:170
buffer_type const * raw() const
Get pointer to raw buffer at current position.
Definition RawParser.h:181
bool next()
Move to next page start.
Definition RawParser.h:240
void format(std::ostream &os, FormatSpec choice=FormatSpec::Entry, const char *delimiter="\n") const
Definition RawParser.h:340
void parse(Processor &&processor)
Definition RawParser.h:217
header_type const & header() const
Get header at current position.
Definition RawParser.h:138
bool operator==(T const &other) const
Definition RawParser.h:331
size_t size() const
Get size of payload at current position.
Definition RawParser.h:144
ConcreteRawParser(ConcreteRawParser const &other)=default
size_t offset() const
Get offset of payload in the raw buffer at current position.
Definition RawParser.h:190
ConcreteRawParser(T const *buffer, size_t size)
Definition RawParser.h:121
size_t sizeTotal() const
Get size of header + payload at current position.
Definition RawParser.h:157
bool reset()
Reset the parser, set position to beginning of buffer.
Definition RawParser.h:302
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLintptr offset
Definition glcorearb.h:660
GLuint start
Definition glcorearb.h:469
ConcreteParserVariants< PageSize, BOUNDS_CHECKS > create(T const *buffer, size_t size)
create a raw parser depending on version of RAWDataHeader found at beginning of data
Definition RawParser.h:378
std::variant< V7Parser< N, BOUNDS_CHECKS >, V6Parser< N, BOUNDS_CHECKS >, V5Parser< N, BOUNDS_CHECKS >, V4Parser< N, BOUNDS_CHECKS > > ConcreteParserVariants
Definition RawParser.h:374
U const * get_if(T &instances)
Definition RawParser.h:415
FormatSpec
specifier for printout
Definition RawParser.h:42
void walk_parse(T &instances, P &&processor, size_t index)
Definition RawParser.h:403
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
O2 data header classes and API, v0.1.
Definition DetID.h:49
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static void apply(std::ostream &, type const &, FormatSpec, const char *="")
static void apply(std::ostream &, type const &, FormatSpec, const char *="")
static void apply(std::ostream &, type const &, FormatSpec, const char *="")
static void apply(std::ostream &, type const &, FormatSpec, const char *="")
static void apply(std::ostream &, type const &, FormatSpec, const char *="")
Definition RawParser.h:53
static void warnDeadBeef(const o2::header::DataHeader *dh)
Definition RawParser.cxx:45
static bool checkPrintError(size_t &localCounter)
Definition RawParser.cxx:32
the main header struct
Definition DataHeader.h:618
uint32_t buffer_type
VectorOfTObjectPtrs other
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"