Project
Loading...
Searching...
No Matches
DataBlockBase.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//
12// file DataBlockBase.h base class for RAW data format data blocks
13//
14// Artur.Furs
15// afurs@cern.ch
16// DataBlockWrapper - wrapper for raw data structures
17// There should be three static fields in raw data structs, which defines its "signature":
18// payloadSize - actual payload size per one raw data struct element (can be larger than GBTword size!)
19// payloadPerGBTword - maximum payload per one GBT word
20// MaxNelements - maximum number of elements per data block(for header it should be equal to 1)
21// MinNelements - minimum number of elements per data block(for header it should be equal to 1)
22
23// Also it requares several methods:
24// print() - for printing raw data structs
25// getIntRec() - for InteractionRecord extraction, should be in Header struct
26
27// DataBlockBase - base class for making composition of raw data structures, uses CRTP(static polyporphism)
28// usage:
29// class DataBlockOfYourModule: public DataBlockBase< DataBlockOfYourModule, RawHeaderStruct, RawDataStruct ...>
30// define "deserialization" method with deserialization logic for current DataBlock
31// define "sanityCheck" method for checking if the DataBlock is correct
32// Warning! Classes should be simple, without refs and pointers!
33// TODO:
34// need to use references on the DataBlock fileds, with fast access
35// traites for classes and structs
36//
37
38#ifndef ALICEO2_FIT_DATABLOCKBASE_H_
39#define ALICEO2_FIT_DATABLOCKBASE_H_
40#include <iostream>
41#include <vector>
42#include <Rtypes.h>
46#include <gsl/span>
47#include <boost/mpl/inherit.hpp>
48#include <boost/mpl/vector.hpp>
49#include <Framework/Logger.h>
50#include <vector>
51#include <tuple>
52#include <array>
53#include <iostream>
54#include <cassert>
55#include <type_traits>
56namespace o2
57{
58namespace fit
59{
60
61static constexpr size_t SIZE_WORD = 16;
62static constexpr size_t SIZE_WORD_GBT = 10; // should be changed to gloabal variable
63static constexpr size_t SIZE_MAX_PAGE = 8192; // should be changed to gloabal variable
64static constexpr size_t SIZE_MAX_PAYLOAD = SIZE_MAX_PAGE - sizeof(o2::header::RAWDataHeader); // should be changed to gloabal variable
65
66template <bool isPadded = true>
68 constexpr static bool sIsPadded = isPadded;
70};
71
72template <typename T>
74 template <typename, typename = void>
75 struct CheckTypeMaxNelem : std::false_type {
76 };
77 template <typename U>
78 struct CheckTypeMaxNelem<U, std::enable_if_t<std::is_same<decltype(U::MaxNelements), const std::size_t>::value>> : std::true_type {
79 };
80
81 template <typename, typename = void>
82 struct CheckTypeMinNelem : std::false_type {
83 };
84 template <typename U>
85 struct CheckTypeMinNelem<U, std::enable_if_t<std::is_same<decltype(U::MinNelements), const std::size_t>::value>> : std::true_type {
86 };
87
88 template <typename, typename = void>
89 struct CheckTypePayloadSize : std::false_type {
90 };
91 template <typename U>
92 struct CheckTypePayloadSize<U, std::enable_if_t<std::is_same<decltype(U::PayloadSize), const std::size_t>::value>> : std::true_type {
93 };
94
95 template <typename, typename = void>
96 struct CheckTypePayloadPerGBTword : std::false_type {
97 };
98 template <typename U>
99 struct CheckTypePayloadPerGBTword<U, std::enable_if_t<std::is_same<decltype(U::PayloadPerGBTword), const std::size_t>::value>> : std::true_type {
100 };
101
102 template <typename, typename = void>
103 struct CheckMaxElemSize : std::false_type {
104 };
105 template <typename U>
106 struct CheckMaxElemSize<U, std::enable_if_t<((T::MaxNelements * T::PayloadSize <= SIZE_MAX_PAYLOAD) && (T::MaxNelements * T::PayloadPerGBTword <= SIZE_MAX_PAYLOAD))>> : std::true_type {
107 };
108
109 template <typename, typename = void>
110 struct CheckNelemRange : std::false_type {
111 };
112 template <typename U>
113 struct CheckNelemRange<U, std::enable_if_t<(T::MaxNelements >= T::MinNelements)>> : std::true_type {
114 };
115
116 static constexpr bool check()
117 {
118 static_assert(CheckTypeMaxNelem<T>::value, "Error! MaxNelements type should be \"static constexpr std::size_t\"!");
119 static_assert(CheckTypeMinNelem<T>::value, "Error! MinNelements type should be \"static constexpr std::size_t\"!");
120 static_assert(CheckTypePayloadSize<T>::value, "Error! PayloadSize type should be \"static constexpr std::size_t\"!");
121 static_assert(CheckTypePayloadPerGBTword<T>::value, "Error! PayloadPerGBTword type should be \"static constexpr std::size_t\"!");
122 static_assert(CheckMaxElemSize<T>::value, "Error! Check maximum number of elements, they are larger than payload size!");
123 static_assert(CheckNelemRange<T>::value, "Error! Check range for number of elements, max should be bigger or equal to min!");
125 }
126};
127
128template <typename ConfigType, typename T, typename = typename std::enable_if_t<DataBlockHelper<T>::check()>>
130 DataBlockWrapper() = default;
132 typedef T Data_t;
133 typedef ConfigType Config_t;
134 constexpr static bool sIsPadded = Config_t::sIsPadded;
135 static constexpr std::size_t getWordSize()
136 {
137 if constexpr (sIsPadded) {
138 return SIZE_WORD;
139 } else {
140 return SIZE_WORD_GBT;
141 }
142 }
143
144 constexpr static std::size_t sSizeWord = getWordSize();
145 void serialize(std::vector<char>& vecBytes, size_t nWords, size_t& destPos) const
146 {
147 const auto nBytesToWrite = nWords * sSizeWord;
148 if ((vecBytes.size() - destPos) < nBytesToWrite || nWords < MinNwords || nWords > MaxNwords) {
149 LOG(info) << "Warning! Incorrect serialisation procedure!";
150 return;
151 } else if (nWords == 0) {
152 // nothing to do
153 return;
154 }
155 const uint8_t* srcAddress = (uint8_t*)mData;
156 gsl::span<char> serializedBytes(vecBytes);
157 if constexpr (sIsPadded) { // in case of padding one need to use byte map
158 int nSteps = std::get<kNSTEPS>(sReadingLookupTable[nWords]);
159 for (int iStep = 0; iStep < nSteps; iStep++) {
160 memcpy(serializedBytes.data() + std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]) + destPos, srcAddress + std::get<kDESTBYTEPOS>(sByteLookupTable[iStep]), std::get<kNBYTES>(sByteLookupTable[iStep]));
161 }
162 } else { // no need in byte map
163 memcpy(serializedBytes.data() + destPos, srcAddress, nBytesToWrite);
164 }
165 destPos += nBytesToWrite;
166 }
167
168 void deserialize(const gsl::span<const uint8_t> inputBytes, size_t nWords, size_t& srcPos)
169 {
170 mNelements = 0;
171 const auto nBytesToRead = nWords * sSizeWord;
172 if ((inputBytes.size() - srcPos) < nBytesToRead || nWords < MinNwords || nWords > MaxNwords) {
173 // in case of bad fields responsible for deserialization logic, byte position will be pushed to the end of binary sequence
174 LOG(error) << "Incomplete payload! |N GBT words " << nWords << " |bytes to read " << nBytesToRead << " |src pos " << srcPos << " |payload size " << inputBytes.size() << " |";
175 srcPos = inputBytes.size();
177 mIsIncorrect = true;
178 return;
179 }
180 uint8_t* destAddress = (uint8_t*)mData;
181 mNelements = std::get<kNELEMENTS>(sReadingLookupTable[nWords]);
182 if constexpr (sIsPadded) { // in case of padding one need to use byte map
183 int nSteps = std::get<kNSTEPS>(sReadingLookupTable[nWords]);
184 for (int iStep = 0; iStep < nSteps; iStep++) {
185 memcpy(destAddress + std::get<kDESTBYTEPOS>(sByteLookupTable[iStep]), inputBytes.data() + std::get<kSRCBYTEPOS>(sByteLookupTable[iStep]) + srcPos, std::get<kNBYTES>(sByteLookupTable[iStep]));
186 }
187 } else { // no need in byte map
188 memcpy(destAddress, inputBytes.data() + srcPos, nBytesToRead);
189 }
190 srcPos += nBytesToRead;
191 }
192
193 static constexpr int MaxNwords = Data_t::PayloadSize * Data_t::MaxNelements / Data_t::PayloadPerGBTword + (Data_t::PayloadSize * Data_t::MaxNelements % Data_t::PayloadPerGBTword > 0); // calculating max GBT words per block
194 static constexpr int MaxNbytes = SIZE_WORD * MaxNwords;
195
196 static constexpr int MinNwords = Data_t::PayloadSize * Data_t::MinNelements / Data_t::PayloadPerGBTword + (Data_t::PayloadSize * Data_t::MinNelements % Data_t::PayloadPerGBTword > 0); // calculating min GBT words per block
197 static constexpr int MinNbytes = SIZE_WORD * MinNwords;
198
199 // get number of byte reading steps
200 static constexpr size_t getNsteps()
201 {
202 int count = 0;
203 size_t payloadFull = Data_t::MaxNelements * Data_t::PayloadSize;
204 size_t payloadInWord = Data_t::PayloadPerGBTword;
205 size_t payloadPerElem = Data_t::PayloadSize;
206 while (payloadFull > 0) {
207 if (payloadPerElem < payloadInWord) {
208 count++;
209 payloadFull -= payloadPerElem;
210 payloadInWord -= payloadPerElem;
211 payloadPerElem = 0;
212 } else {
213 count++;
214 payloadFull -= payloadInWord;
215 payloadPerElem -= payloadInWord;
216 payloadInWord = 0;
217 }
218 if (payloadInWord == 0) {
219 payloadInWord = Data_t::PayloadPerGBTword;
220 }
221 if (payloadPerElem == 0) {
222 payloadPerElem = Data_t::PayloadSize;
223 }
224 }
225 return count;
226 }
227 // enumerator for tuple access:
228 //[Index] is index of step to read bytes
229 // kNBYTES - number of bytes to read from source and to write into destination
230 // kSRCBYTEPOS - Byte position in the source(binary raw data sequence)
231 // kDESTBYTEPOS - Byte position to write at destionation(memory allocation of T-element array)
232 // kELEMENTINDEX - element index at current step
233 // kWORDINDEX - word index at current step
234 //
240 static constexpr std::array<std::tuple<size_t, size_t, size_t, int, int>, getNsteps()> GetByteLookupTable()
241 {
242 std::array<std::tuple<size_t, size_t, size_t, int, int>, getNsteps()> seqBytes{};
243 int count = 0;
244 int countElement = 0;
245 int countWord = 0;
246 size_t destBytePosPerElem = 0;
247 size_t srcBytePos = 0;
248 size_t payloadFull = Data_t::MaxNelements * Data_t::PayloadSize;
249
250 size_t bytesInWord = SIZE_WORD;
251 size_t payloadInWord = Data_t::PayloadPerGBTword;
252
253 size_t payloadPerElem = Data_t::PayloadSize;
254
255 uint64_t indexElem = 0;
256 uint64_t indexLastElem = Data_t::MaxNelements - 1;
257
258 while (payloadFull > 0) {
259 if (payloadPerElem < payloadInWord) { // new element
260 std::get<kNBYTES>(seqBytes[count]) = payloadPerElem;
261 std::get<kSRCBYTEPOS>(seqBytes[count]) = srcBytePos;
262 std::get<kDESTBYTEPOS>(seqBytes[count]) = destBytePosPerElem;
263 std::get<kELEMENTINDEX>(seqBytes[count]) = countElement;
264 std::get<kWORDINDEX>(seqBytes[count]) = countWord;
265 srcBytePos += payloadPerElem;
266 count++;
267 payloadFull -= payloadPerElem;
268 payloadInWord -= payloadPerElem;
269 bytesInWord -= payloadPerElem;
270 payloadPerElem = 0;
271
272 } else {
273 std::get<kNBYTES>(seqBytes[count]) = payloadInWord;
274 std::get<kSRCBYTEPOS>(seqBytes[count]) = srcBytePos;
275 std::get<kDESTBYTEPOS>(seqBytes[count]) = destBytePosPerElem;
276 std::get<kELEMENTINDEX>(seqBytes[count]) = countElement;
277 std::get<kWORDINDEX>(seqBytes[count]) = countWord;
278 srcBytePos += bytesInWord;
279 count++;
280 destBytePosPerElem += payloadInWord;
281
282 payloadFull -= payloadInWord;
283 payloadPerElem -= payloadInWord;
284 payloadInWord = 0;
285 bytesInWord = 0;
286 }
287
288 if (payloadInWord == 0) {
289 payloadInWord = Data_t::PayloadPerGBTword;
290 }
291 if (payloadPerElem == 0) {
292 payloadPerElem = Data_t::PayloadSize;
293 countElement++;
294 destBytePosPerElem = countElement * sizeof(T);
295 }
296 if (bytesInWord == 0) {
297 bytesInWord = SIZE_WORD;
298 countWord++;
299 }
300 }
301 return seqBytes;
302 }
303 static constexpr std::array<std::tuple<size_t, size_t, size_t, int, int>, getNsteps()> sByteLookupTable = GetByteLookupTable();
304
305 // enumerator for tuple access:
306 //[Index] is word index position, i.e. "Index" number of words will be deserialized
307 // kNELEMENTS - number of T elements will be fully deserialized in "Index+1" words
308 // kNSTEPS - number of steps for reading "Index" words
309 // kISPARTED - if one T-element is parted at current word,i.e. current word contains partially deserialized T element at the end of the word
310 enum AccessReadingLUT { kNELEMENTS,
312 kISPARTED };
313 static constexpr std::array<std::tuple<unsigned int, unsigned int, bool>, MaxNwords + 1> GetReadingLookupTable()
314 {
315 std::array<std::tuple<unsigned int, unsigned int, bool>, MaxNwords + 1> readingScheme{};
316 size_t payloadPerElem = Data_t::PayloadSize;
317 std::get<kNSTEPS>(readingScheme[0]) = 0;
318 std::get<kNELEMENTS>(readingScheme[0]) = 0;
319 std::get<kISPARTED>(readingScheme[0]) = false;
320 int countWord = 1;
321 for (int iStep = 0; iStep < getNsteps(); iStep++) {
322 if (countWord - 1 < std::get<kWORDINDEX>((GetByteLookupTable())[iStep])) { // new word
323 std::get<kNSTEPS>(readingScheme[countWord]) = iStep;
324 std::get<kNELEMENTS>(readingScheme[countWord]) = std::get<kELEMENTINDEX>((GetByteLookupTable())[iStep]);
325 if (payloadPerElem > 0) {
326 std::get<kISPARTED>(readingScheme[countWord]) = true;
327 } else {
328 std::get<kISPARTED>(readingScheme[countWord]) = false;
329 }
330 countWord++;
331 }
332 if (payloadPerElem == 0) {
333 payloadPerElem = Data_t::PayloadSize;
334 }
335 payloadPerElem -= std::get<kNBYTES>((GetByteLookupTable())[iStep]);
336 }
337 // Last step checking
338 std::get<kNSTEPS>(readingScheme[countWord]) = getNsteps();
339 if (payloadPerElem > 0) {
340 std::get<kISPARTED>(readingScheme[countWord]) = true;
341 std::get<kNELEMENTS>(readingScheme[countWord]) = std::get<kELEMENTINDEX>((GetByteLookupTable())[getNsteps() - 1]);
342 } else {
343 std::get<kISPARTED>(readingScheme[countWord]) = false;
344 std::get<kNELEMENTS>(readingScheme[countWord]) = std::get<kELEMENTINDEX>((GetByteLookupTable())[getNsteps() - 1]) + 1;
345 }
346 return readingScheme;
347 }
348 static constexpr std::array<std::tuple<unsigned int, unsigned int, bool>, MaxNwords + 1> sReadingLookupTable = GetReadingLookupTable();
349 //
350 // Printing LookupTables
351 static void printLUT()
352 {
353 LOG(info) << "-------------------------------------------";
354 LOG(info) << "kNELEMENTS|kNSTEPS|kISPARTED";
355 for (int i = 0; i < MaxNwords + 1; i++) {
356 LOG(info) << std::get<kNELEMENTS>(sReadingLookupTable[i]) << "|"
357 << std::get<kNSTEPS>(sReadingLookupTable[i]) << "|"
358 << std::get<kISPARTED>(sReadingLookupTable[i]);
359 }
360 LOG(info) << "-------------------------------------------";
361 LOG(info) << "kELEMENTINDEX|kWORDINDEX|kNBYTES|kSRCBYTEPOS|kDESTBYTEPOS";
362 for (int i = 0; i < getNsteps(); i++) {
363 LOG(info) << std::get<kELEMENTINDEX>(sByteLookupTable[i]) << "|"
364 << std::get<kWORDINDEX>(sByteLookupTable[i]) << "|"
365 << std::get<kNBYTES>(sByteLookupTable[i]) << "|"
366 << std::get<kSRCBYTEPOS>(sByteLookupTable[i]) << "|"
367 << std::get<kDESTBYTEPOS>(sByteLookupTable[i]);
368 }
369 }
370 void print() const
371 {
372 assert(mNelements <= Data_t::MaxNelements);
373 for (int i = 0; i < mNelements; i++) {
374 LOG(info) << "Printing element number: " << i;
375 mData[i].print();
376 }
377 }
378 Data_t mData[Data_t::MaxNelements];
379 unsigned int mNelements; // number of deserialized elements;
380 typename RawDataMetric::Status_t mStatusBits{}; // Contains status bits
382};
383
384// CRTP(static polymorphism) + Composition over multiple inheritance(Header + multiple data structures)
385template <template <typename...> class DataBlock, typename ConfigType, class Header, class... DataStructures>
386class DataBlockBase : public boost::mpl::inherit<DataBlockWrapper<ConfigType, Header>, DataBlockWrapper<ConfigType, DataStructures>...>::type
387{
388 // typedef boost::mpl::vector<DataStructures...> DataBlockTypes;
389 typedef DataBlockBase<DataBlock, ConfigType, Header, DataStructures...> TemplateHeader;
390 typedef typename boost::mpl::inherit<DataBlockWrapper<ConfigType, Header>, DataBlockWrapper<ConfigType, DataStructures>...>::type DataBlockDerivedBase;
391
392 public:
393 typedef DataBlock<ConfigType, Header, DataStructures...> DataBlock_t;
395 typedef ConfigType Config_t;
396 constexpr static bool sIsPadded = Config_t::sIsPadded;
397 DataBlockBase() = default;
398 DataBlockBase(const DataBlockBase&) = default;
399 // typedef DataBlock<typename Padded::Inverted,Header,DataStructures...> DataBlockInverted_t;
400 typedef DataBlock<typename Config_t::InvertedPadding_t, Header, DataStructures...> DataBlockInvertedPadding_t;
401 constexpr static std::size_t sHeaderSize = sizeof(Header);
402 bool isOnlyHeader() const
403 {
404 return sHeaderSize == mSize;
405 }
406 static void printLUT()
407 {
410 }
411
412 void print() const
413 {
414 LOG(info) << "HEADER";
416 LOG(info) << "DATA";
417 (static_cast<void>(DataBlockWrapper<Config_t, DataStructures>::print()), ...);
418 }
419
421 {
422 return DataBlockWrapperHeader_t::mData[0].getIntRec();
423 }
424
426 {
427 DataBlockWrapperHeader_t::mData[0].setIntRec(intRec);
428 }
429 //
430 // use this for block decoding
431 void decodeBlock(gsl::span<const uint8_t> payload, size_t srcPos)
432 {
433 mSize = 0;
434 size_t bytePos = srcPos;
435 static_cast<DataBlock_t*>(this)->deserialize(payload, bytePos);
436 mSize = bytePos - srcPos;
437 // checking sanity and updating
438 update();
439 }
440
441 bool isCorrect() const { return mIsCorrect; }
442
443 void update()
444 {
445 mIsCorrect = true;
446 checkDeserialization(mIsCorrect, DataBlockWrapperHeader_t::mIsIncorrect); // checking deserialization status for header
447 (checkDeserialization(mIsCorrect, DataBlockWrapper<Config_t, DataStructures>::mIsIncorrect), ...); // checking deserialization status for sub-block
448 mergeStatusBits(mStatusBitsAll, DataBlockWrapperHeader_t::mStatusBits); // checking deserialization status for header
449 (mergeStatusBits(mStatusBitsAll, DataBlockWrapper<Config_t, DataStructures>::mStatusBits), ...); // checking deserialization status for sub-block
450 static_cast<DataBlock_t*>(this)->sanityCheck(mIsCorrect, mStatusBitsAll);
451 }
452
453 size_t mSize{0}; // deserialized size
454 bool mIsCorrect{false};
456
457 protected:
458 // check if there are sub blocks with zero number of elements
459 void isNonZeroBlockSizes(bool& flag, unsigned int nElements) { flag &= (bool)nElements; }
460 void checkDeserialization(bool& flag, bool isIncorrect) { flag &= !(isIncorrect); }
461 void mergeStatusBits(uint8_t& statusBitsResult, uint8_t statusBits) { statusBitsResult |= statusBits; }
462};
463
464} // namespace fit
465} // namespace o2
466#endif
int32_t i
Definition of the RAW Data Header.
DataBlock< typename Config_t::InvertedPadding_t, Header, DataStructures... > DataBlockInvertedPadding_t
static constexpr std::size_t sHeaderSize
RawDataMetric::Status_t mStatusBitsAll
static constexpr bool sIsPadded
void decodeBlock(gsl::span< const uint8_t > payload, size_t srcPos)
DataBlockWrapper< ConfigType, Header > DataBlockWrapperHeader_t
DataBlock< ConfigType, Header, DataStructures... > DataBlock_t
InteractionRecord getInteractionRecord() const
void mergeStatusBits(uint8_t &statusBitsResult, uint8_t statusBits)
void setInteractionRecord(const InteractionRecord &intRec)
void isNonZeroBlockSizes(bool &flag, unsigned int nElements)
DataBlockBase(const DataBlockBase &)=default
void checkDeserialization(bool &flag, bool isIncorrect)
GLint GLsizei count
Definition glcorearb.h:399
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
RAWDataHeaderV7 RAWDataHeader
TFitResultPtr fit(const size_t nBins, const T *arr, const T xMin, const T xMax, TF1 &func, std::string_view option="")
Definition fit.h:59
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
DataBlockConfig<!sIsPadded > InvertedPadding_t
static constexpr bool sIsPadded
static constexpr bool check()
void deserialize(const gsl::span< const uint8_t > inputBytes, size_t nWords, size_t &srcPos)
static constexpr std::array< std::tuple< size_t, size_t, size_t, int, int >, getNsteps()> GetByteLookupTable()
void serialize(std::vector< char > &vecBytes, size_t nWords, size_t &destPos) const
Data_t mData[Data_t::MaxNelements]
DataBlockWrapper(const DataBlockWrapper &)=default
static constexpr std::array< std::tuple< unsigned int, unsigned int, bool >, MaxNwords+1 > GetReadingLookupTable()
RawDataMetric::Status_t mStatusBits
static constexpr std::size_t getWordSize()
static constexpr size_t getNsteps()
static void setStatusBit(Status_t &metric, EStatusBits statusBit, bool val=true)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"