Project
Loading...
Searching...
No Matches
testRawReaderWriter.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
12#define BOOST_TEST_MODULE Test RawReaderWriter class
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15#include <algorithm>
16#include <string>
17#include <iostream>
18#include <fstream>
19#include <TRandom.h>
20#include <boost/test/unit_test.hpp>
27#include "Framework/Logger.h"
32
33// @brief test and demo for RawFileReader and Writer classes
34// @author ruben.shahoyan@cern.ch
35
36namespace o2
37{
38using namespace o2::raw;
39using namespace o2::framework;
42constexpr int NCRU = 3 + 1; // number of CRUs, the last one is a special CRU with preformatted data filled
43constexpr int NLinkPerCRU = 4; // number of links per CRU
44// sizes for preformatted pages filling (RDH size will be subtracted from the payload) in the last special CRU
45constexpr std::array<int, NLinkPerCRU> SpecSize = {512, 1024, 8192, 8192};
46constexpr int NPreformHBFPerTF = 32; // number of HBFs with preformatted input per HBF for special last CRU
47const std::string PLHeader = "HEADER ";
48const std::string PLTrailer = "TRAILER ";
49const std::string HBFEmpty = "EMPTY_HBF ";
50const std::string CFGName = "testRawReadWrite";
51
53
54//
55// ========================= simple detector data writer ================================
56//
57struct TestRawWriter { // simple class to create detector payload for multiple links
58
60 std::string configName = "rawConf.cfg";
61
62 //_________________________________________________________________
63 TestRawWriter(o2::header::DataOrigin origin = "TST", bool isCRU = true, const std::string& cfg = "rawConf.cfg") : writer(origin, isCRU), configName(cfg) {}
64
65 //_________________________________________________________________
66 void init()
67 {
68 // init writer
70 int feeIDShift = writer.isCRUDetector() ? 8 : 9;
71 // register links
72 for (int icru = 0; icru < NCRU; icru++) {
73 std::string outFileName = o2::utils::Str::concat_string("testdata_", writer.isCRUDetector() ? "cru" : "rorc", std::to_string(icru), ".raw");
74 for (int il = 0; il < NLinkPerCRU; il++) {
75 auto& link = writer.registerLink((icru << feeIDShift) + il, icru, il, 0, outFileName);
76 RDHUtils::setDetectorField(link.rdhCopy, 0xff << icru); // if needed, set extra link info, will be copied to all RDHs
77 }
78 }
79
80 if (writer.isCRUDetector()) {
81 writer.setContinuousReadout(); // in case we want to issue StartOfContinuous trigger in the beginning
82 writer.setEmptyPageCallBack(this); // we want the writer to ask the detector code what to put in empty HBFs
83 }
84 writer.setCarryOverCallBack(this); // we want that writer to ask the detector code how to split large payloads
85
86 writer.setApplyCarryOverToLastPage(true); // call CarryOver method also for the last chunk
87 writer.doLazinessCheck(false); // do not apply auto-completion since the test mixes preformatted links filled per HBF and standard links filled per IR.
88 }
89
90 //_________________________________________________________________
91 void run()
92 {
93 // write payload and close outputs
95 // generate interaction records for triggers to write
96 std::vector<o2::InteractionTimeRecord> irs(1000);
98 irSampler.setInteractionRate(12000); // ~1.5 interactions per orbit
99 irSampler.init();
100 irSampler.generateCollisionTimes(irs);
101
102 std::vector<char> buffer;
103 int feeIDShift = writer.isCRUDetector() ? 8 : 9;
104
105 // create payload for every interaction and push it to writer
106 for (const auto& ir : irs) {
107 int nCRU2Fill = writer.isCRUDetector() ? NCRU - 1 : NCRU; // in CRU mode we will fill 1 special CRU with preformatted data
108 for (int icru = 0; icru < nCRU2Fill; icru++) {
109 // we will create non-0 payload for all but 1st link of every CRU, the writer should take care
110 // of creating empty HBFs for the links w/o data
111 for (int il = 0; il < NLinkPerCRU; il++) {
112 buffer.clear();
113 int nGBT = gRandom->Poisson(RDHUtils::MAXCRUPage / RDHUtils::GBTWord128 * (il));
114 if (nGBT) {
115 buffer.resize((nGBT + 2) * RDHUtils::GBTWord128, icru * NLinkPerCRU + il); // reserve 16B words accounting for the Header and Trailer
116 std::memcpy(buffer.data(), PLHeader.c_str(), RDHUtils::GBTWord128);
117 std::memcpy(buffer.data() + buffer.size() - RDHUtils::GBTWord128, PLTrailer.c_str(), RDHUtils::GBTWord128);
118 // we don't care here about the content of the payload, except the presence of header and trailer
119 }
120 writer.addData((icru << feeIDShift) + il, icru, il, 0, ir, buffer);
121 }
122 }
123 }
124 if (writer.isCRUDetector()) {
125 // fill special CRU with preformatted pages
126 auto irHB = HBFUtils::Instance().getFirstIR(); // IR of the TF0/HBF0
127 int cruID = NCRU - 1;
128 while (irHB < irs.back()) {
129 for (int il = 0; il < NLinkPerCRU; il++) {
130 buffer.clear();
131 int pgSize = SpecSize[il] - sizeof(RDHAny);
132 buffer.resize(pgSize);
133 for (int ipg = 2 * (NLinkPerCRU - il); ipg--;) { // just to enforce writing multiple pages per selected HBFs
134 writer.addData((cruID << 8) + il, cruID, il, 0, irHB, buffer, true); // last argument is there to enforce a special "preformatted" mode
136 }
137 }
138 irHB.orbit += HBFUtils::Instance().getNOrbitsPerTF() / NPreformHBFPerTF; // we will write 32 such HBFs per TF
139 }
140 }
141
142 // for further use we write the configuration file
144 writer.close(); // flush buffers and close outputs
145 }
146
147 // optional callback functions to register in the RawFileWriter
148 //_________________________________________________________________
149 void emptyHBFMethod(const RDHAny* rdh, std::vector<char>& toAdd) const
150 {
151 // what we want to add for every empty page
152 toAdd.resize(RDHUtils::GBTWord128);
153 std::memcpy(toAdd.data(), HBFEmpty.c_str(), RDHUtils::GBTWord128);
154 }
155
156 //_________________________________________________________________
157 int carryOverMethod(const RDHAny* rdh, const gsl::span<char> data, const char* ptr, int maxSize, int splitID,
158 std::vector<char>& trailer, std::vector<char>& header) const
159 {
160 // how we want to split the large payloads. The data is the full payload which was sent for writing and
161 // it is already equiped with header and trailer
162 static int verboseCount = 0;
163
164 if (maxSize <= RDHUtils::GBTWord128) { // do not carry over trailer or header only
165 return 0;
166 }
167
168 int bytesLeft = data.size() - (ptr - &data[0]);
169 bool lastPage = bytesLeft <= maxSize;
170 if (verboseCount++ < 100) {
171 LOG(info) << "Carry-over method for chunk of size " << bytesLeft << " is called, MaxSize = " << maxSize << (lastPage ? " : last chunk being processed!" : "");
172 }
173 // here we simply copy the header/trailer of the payload to every CRU page of this payload
174 header.resize(RDHUtils::GBTWord128);
175 std::memcpy(header.data(), &data[0], RDHUtils::GBTWord128);
176 trailer.resize(RDHUtils::GBTWord128);
177 std::memcpy(trailer.data(), &data[data.size() - RDHUtils::GBTWord128], RDHUtils::GBTWord128);
178 // since we write an extra GBT word (trailer) in the end of the CRU page, we ask to write
179 // not the block ptr : ptr+maxSize, but ptr : ptr+maxSize - GBTWord;
180 int sz = maxSize; // if the method is called for the last page, then the trailer is overwritten !!!
181 if (!lastPage) { // otherwise it is added incrementally, so its size must be accounted
182 sz -= trailer.size();
183 }
184 return sz;
185 }
186};
187
188struct TestRawReader { // simple class to read detector raw data for multiple links
189
190 std::unique_ptr<RawFileReader> reader;
191 std::string confName;
192
193 //_________________________________________________________________
194 TestRawReader(const std::string& name = "TST", const std::string& cfg = "rawConf.cfg") : confName(cfg) {}
195
196 //_________________________________________________________________
197 void init()
198 {
199 reader = std::make_unique<RawFileReader>(confName); // init from configuration file
200 uint32_t errCheck = 0xffffffff;
201 errCheck ^= 0x1 << RawFileReader::ErrNoSuperPageForTF; // makes no sense for superpages not interleaved by others
202 reader->setCheckErrors(errCheck);
203 reader->init();
204 }
205
206 //_________________________________________________________________
207 void run()
208 {
209 // read data of all links
210 if (!reader) {
211 init();
212 }
213 int nLinks = reader->getNLinks();
214 BOOST_CHECK(nLinks == NCRU * NLinkPerCRU);
215
216 // make sure no errors detected after initialization
217 for (int il = 0; il < nLinks; il++) {
218 auto& lnk = reader->getLink(il);
219 BOOST_CHECK(lnk.nErrors == 0);
220 }
221
222 std::vector<std::vector<char>> buffers;
223 std::vector<bool> firstHBF;
224 std::string testStr;
225 testStr.resize(RDHUtils::GBTWord128);
226 buffers.resize(nLinks); // 1 buffer per link
227 firstHBF.resize(nLinks, true);
228
229 int nLinksRead = 0, nPreformatRead = 0;
230 do {
231 nLinksRead = 0;
232 for (int il = 0; il < nLinks; il++) {
233 auto& buff = buffers[il];
234 buff.clear();
235 auto& lnk = reader->getLink(il);
236 auto sz = lnk.getNextHBFSize(); // HBF treated as a trigger for RORC detectors
237 if (!sz) {
238 continue;
239 }
240 buff.resize(sz);
241 BOOST_CHECK(lnk.readNextHBF(buff.data()) == sz);
242 nLinksRead++;
243 }
244 if (nLinksRead) {
245 BOOST_CHECK(nLinksRead == nLinks); // all links should have the same number of HBFs or triggers
246
247 const auto rdhRef = *reinterpret_cast<RDHAny*>(buffers[0].data());
248
249 for (int il = 0; il < nLinks; il++) {
250 auto& lnk = reader->getLink(il);
251 auto& buff = buffers[il];
252 int hbsize = buff.size();
253 char* ptr = buff.data();
254 while (ptr < &buff.back()) { // check all RDH open/close and optional headers and trailers
255 const auto rdhi = *reinterpret_cast<RDHAny*>(ptr);
256 if (firstHBF[il]) { // make sure SOT or SOC is there
257 BOOST_CHECK(RDHUtils::getTriggerType(rdhi) & (o2::trigger::SOC | o2::trigger::SOT));
258 }
259 auto memSize = RDHUtils::getMemorySize(rdhi);
260 auto rdhSize = RDHUtils::getHeaderSize(rdhi);
261 BOOST_CHECK(RDHUtils::checkRDH(rdhi)); // check RDH validity
262
263 if (!(RDHUtils::getHeartBeatIR(rdhRef) == RDHUtils::getHeartBeatIR(rdhi))) {
264 RDHUtils::printRDH(rdhRef);
265 RDHUtils::printRDH(rdhi);
266 }
267
268 BOOST_CHECK(RDHUtils::getHeartBeatIR(rdhRef) == RDHUtils::getHeartBeatIR(rdhi)); // make sure the RDH of each link corresponds to the same BC
269 if (RDHUtils::getStop(rdhi)) { // closing page must be empty
270 BOOST_CHECK(memSize == rdhSize);
271 } else {
272 if (!lnk.cruDetector || RDHUtils::getCRUID(rdhi) < NCRU - 1) { // only last CRU of in non-RORC mode was special
273 if (lnk.cruDetector) {
274 BOOST_CHECK(memSize > rdhSize); // in this model all non-closing pages must contain something
275 }
276 if (memSize - rdhSize == RDHUtils::GBTWord128) { // empty HBF will contain just a status word
277 if (lnk.cruDetector) {
278 testStr.assign(ptr + rdhSize, RDHUtils::GBTWord128);
279 BOOST_CHECK(testStr == HBFEmpty);
280 }
281 } else if (memSize > rdhSize) {
282 // pages with real payload should have at least header + trailer + some payload
283 BOOST_CHECK(memSize - rdhSize > 2 * RDHUtils::GBTWord128);
284 testStr.assign(ptr + rdhSize, RDHUtils::GBTWord128);
285 BOOST_CHECK(testStr == PLHeader);
286 testStr.assign(ptr + memSize - RDHUtils::GBTWord128, RDHUtils::GBTWord128);
287 BOOST_CHECK(testStr == PLTrailer);
288 }
289 } else { // for the special CRU with preformatted data make sure the page sizes were not modified
290 if (memSize > rdhSize + RDHUtils::GBTWord128) {
291 auto tfhb = HBFUtils::Instance().getTFandHBinTF({RDHUtils::getHeartBeatBC(rdhi), RDHUtils::getHeartBeatOrbit(rdhi)}); // TF and HBF relative to TF
292 BOOST_CHECK(tfhb.second % (HBFUtils::Instance().getNOrbitsPerTF() / NPreformHBFPerTF) == 0); // we were filling only every NPreformHBFPerTF-th HBF
293 BOOST_CHECK(memSize == SpecSize[RDHUtils::getLinkID(rdhi)]); // check if the size is correct
294 nPreformatRead++;
295 }
296 }
297 }
298 ptr += RDHUtils::getOffsetToNext(rdhi);
299 }
300 firstHBF[il] = false;
301 }
302 }
303 } while (nLinksRead); // read until there is something to read
304
305 BOOST_CHECK(nPreformatRead == nPreformatPages); // make sure no preformatted page was lost
306
307 } // run
308};
309
310BOOST_AUTO_TEST_CASE(RawReaderWriter_CRU)
311{
312 TestRawWriter dw{"TST", true, "test_raw_conf_GBT.cfg"}; // this is a CRU detector with origin TST
313 dw.init();
314 dw.run(); // write output
315 //
316 TestRawReader dr{"TST", "test_raw_conf_GBT.cfg"}; // here we set the reader wrapper name just to deduce the input config name, everything else will be deduced from the config
317 dr.init();
318 dr.run(); // read back and check
319}
320
321BOOST_AUTO_TEST_CASE(RawReaderWriter_RORC)
322{
323 TestRawWriter dw{"TST", false, "test_raw_conf_DDL.cfg"}; // this is RORC detector with origin TST
324 dw.init();
325 dw.run(); // write output
326 //
327 TestRawReader dr{"TST", "test_raw_conf_DDL.cfg"}; // here we set the reader wrapper name just to deduce the input config name, everything else will be deduced from the config
328 dr.init();
329 dr.run(); // read back and check
330}
331
332} // namespace o2
Definition of the 32 Central Trigger System (CTS) Trigger Types defined in https://twiki....
A raw page parser for DPL input.
Utility class to write detectors data to (multiple) raw data file(s) respecting CRU format.
Reader for (multiple) raw data files.
TBranch * ptr
void setCarryOverCallBack(const T *t)
void addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR &ir, const gsl::span< char > data, bool preformatted=false, uint32_t trigger=0, uint32_t detField=0)
LinkData & registerLink(uint16_t fee, uint16_t cru, uint8_t link, uint8_t endpoint, std::string_view outFileName)
o2::header::DataOrigin getOrigin() const
void setEmptyPageCallBack(const T *t)
void writeConfFile(std::string_view origin="FLP", std::string_view description="RAWDATA", std::string_view cfgname="raw.cfg", bool fullPath=true) const
void doLazinessCheck(bool v)
void setApplyCarryOverToLastPage(bool v)
void generateCollisionTimes(std::vector< o2::InteractionTimeRecord > &dest)
void setInteractionRate(float rateHz)
GLuint buffer
Definition glcorearb.h:655
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean * data
Definition glcorearb.h:298
const GLuint * buffers
Definition glcorearb.h:656
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
constexpr uint32_t SOT
Definition Triggers.h:33
constexpr uint32_t SOC
Definition Triggers.h:35
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
constexpr int NCRU
constexpr int NLinkPerCRU
const std::string PLHeader
const std::string HBFEmpty
BOOST_AUTO_TEST_CASE(FlatHisto)
constexpr int NPreformHBFPerTF
const std::string PLTrailer
constexpr std::array< int, NLinkPerCRU > SpecSize
header::RDHAny RDHAny
int nPreformatPages
const std::string CFGName
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
TestRawReader(const std::string &name="TST", const std::string &cfg="rawConf.cfg")
std::unique_ptr< RawFileReader > reader
void emptyHBFMethod(const RDHAny *rdh, std::vector< char > &toAdd) const
TestRawWriter(o2::header::DataOrigin origin="TST", bool isCRU=true, const std::string &cfg="rawConf.cfg")
int carryOverMethod(const RDHAny *rdh, const gsl::span< char > data, const char *ptr, int maxSize, int splitID, std::vector< char > &trailer, std::vector< char > &header) const
static constexpr int MAXCRUPage
Definition RDHUtils.h:53
static void setDetectorField(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:582
static constexpr int GBTWord128
Definition RDHUtils.h:52
static void printRDH(const RDHv4 &rdh)
Definition RDHUtils.cxx:26
static bool checkRDH(const RDHv4 &rdh, bool verbose=true, bool checkZeros=false)
Definition RDHUtils.cxx:133
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
BOOST_CHECK(tree)
o2::InteractionRecord ir(0, 0)