Project
Loading...
Searching...
No Matches
pageparser.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
17#define BOOST_TEST_MODULE Test Algorithm Parser
18#define BOOST_TEST_MAIN
19#define BOOST_TEST_DYN_LINK
20#include <boost/test/unit_test.hpp>
21#include <iostream>
22#include <iomanip>
23#include <vector>
24#include "Headers/DataHeader.h" // hexdump
25#include "../include/Algorithm/PageParser.h"
27
28struct PageHeader {
29 uint32_t magic = 0x45474150;
30 uint32_t pageid;
31
32 PageHeader(uint32_t id) : pageid(id) {}
33};
34
36 uint32_t magic = 0x54534c43;
37 uint32_t clusterid;
38 uint16_t x;
39 uint16_t y;
40 uint16_t z;
41 uint8_t e;
42
44 : clusterid(0), x(0), y(0), z(0), e(0)
45 {
46 }
47
48 ClusterData(uint32_t _id, uint16_t _x, uint16_t _y, uint16_t _z, uint8_t _e)
49 : clusterid(_id), x(_x), y(_y), z(_z), e(_e)
50 {
51 }
52
53 bool operator==(const ClusterData& rhs) const
54 {
55 return clusterid == rhs.clusterid && x == rhs.x && y == rhs.y && z == rhs.z && e == rhs.e;
56 }
57};
58
59template <typename ListT,
60 typename PageHeaderT,
61 typename GroupT = void,
62 bool GroupHeaderPerPage = false>
63std::pair<std::unique_ptr<uint8_t[]>, size_t> MakeBuffer(size_t pagesize,
64 PageHeaderT pageheader,
65 const ListT& dataset)
66{
67 static_assert(std::is_void<GroupT>::value || std::is_integral<GroupT>::value,
68 "Invalid group type");
69 auto totalSize = dataset.size() * sizeof(typename ListT::value_type);
70 totalSize += o2::algorithm::pageparser::sizeofGroupHeader<GroupT>();
71 auto maxElementsPerPage = pagesize - (sizeof(pageheader) + o2::algorithm::pageparser::sizeofGroupHeader<GroupT>());
72 maxElementsPerPage /= sizeof(typename ListT::value_type);
73
74 if (std::is_void<GroupT>::value || !GroupHeaderPerPage) {
75 unsigned nPages = 0;
76 do {
77 totalSize += sizeof(PageHeaderT);
78 ++nPages;
79 } while (nPages * pagesize < totalSize);
80 } else {
81 auto nRequiredPages = dataset.size() / maxElementsPerPage;
82 if (dataset.size() % maxElementsPerPage > 0) {
83 ++nRequiredPages;
84 }
85 totalSize = (nRequiredPages > 0 ? nRequiredPages : 1) * pagesize;
86 }
87
88 auto buffer = std::make_unique<uint8_t[]>(totalSize);
89 memset(buffer.get(), 0, totalSize);
90
91 unsigned position = 0;
92 auto target = buffer.get();
93 GroupT* groupHeader = nullptr;
94 size_t nElementsInCurrentGroup = 0;
95 for (auto element : dataset) {
96 if (GroupHeaderPerPage && nElementsInCurrentGroup == maxElementsPerPage) {
97 // write the number of elements in the group and forward to next
98 // page boundary
99 o2::algorithm::pageparser::set(groupHeader, nElementsInCurrentGroup);
100 nElementsInCurrentGroup = 0;
101 if (position % pagesize) {
102 target += pagesize - (position % pagesize);
103 position += pagesize - (position % pagesize);
104 }
105 }
106 auto source = reinterpret_cast<uint8_t*>(&element);
107 auto copySize = sizeof(typename ListT::value_type);
108 if ((position % pagesize) == 0) {
109 memcpy(target, &pageheader, sizeof(PageHeaderT));
110 position += sizeof(PageHeaderT);
111 target += sizeof(PageHeaderT);
112 }
113 if (!std::is_void<GroupT>::value &&
114 (position % pagesize) == sizeof(PageHeader) &&
115 (GroupHeaderPerPage || position < pagesize)) {
116 // write one GroupHeader at the beginning of the data, currently
117 // GroupHeader must be of integral type
118 groupHeader = reinterpret_cast<GroupT*>(target);
119 position += o2::algorithm::pageparser::sizeofGroupHeader<GroupT>();
120 target += o2::algorithm::pageparser::sizeofGroupHeader<GroupT>();
121 }
122 ++nElementsInCurrentGroup;
123 if ((position % pagesize) + copySize > pagesize) {
124 copySize -= ((position % pagesize) + copySize) - pagesize;
125 }
126 if (copySize > 0) {
127 memcpy(target, source, copySize);
128 position += copySize;
129 target += copySize;
130 source += copySize;
131 }
132 copySize = sizeof(typename ListT::value_type) - copySize;
133 if (copySize > 0) {
134 memcpy(target, &pageheader, sizeof(PageHeaderT));
135 position += sizeof(PageHeaderT);
136 target += sizeof(PageHeaderT);
137 memcpy(target, source, copySize);
138 }
139 position += copySize;
140 target += copySize;
141 }
142 if (!std::is_void<GroupT>::value) {
143 o2::algorithm::pageparser::set(groupHeader, nElementsInCurrentGroup);
144 }
145
146 std::pair<std::unique_ptr<uint8_t[]>, size_t> result;
147 result.first = std::move(buffer);
148 result.second = totalSize;
149 return result;
150}
151
152template <typename ListT>
153void FillData(ListT& dataset, unsigned entries)
154{
155 for (unsigned i = 0; i < entries; i++) {
156 dataset.emplace_back(i, 0xaa, 0xbb, 0xcc, 0xd);
157 }
158}
159
160template <typename DataSetT,
161 typename PageHeaderT,
162 typename GroupHeaderT,
163 size_t pagesize,
164 bool GroupHeaderPerPage = false>
165void runParserTest(const DataSetT& dataset)
166{
167 std::cout << std::endl
168 << "Testing PageParser in grouped mode and "
169 << (GroupHeaderPerPage ? "multiple" : "single")
170 << " group header(s)" << std::endl
171 << " pagesize " << pagesize << std::endl;
172 auto buffer = MakeBuffer<DataSetT, PageHeaderT, GroupHeaderT, GroupHeaderPerPage>(pagesize, PageHeaderT(0), dataset);
173 o2::header::hexDump("pagebuffer", buffer.first.get(), buffer.second);
174
176 const RawParser parser(buffer.first.get(), buffer.second);
177
178 unsigned dataidx = 0;
179 for (auto i : parser) {
180 o2::header::hexDump("clusterdata", &i, sizeof(ClusterData));
181 BOOST_REQUIRE(i == dataset[dataidx++]);
182 }
183}
184
185BOOST_AUTO_TEST_CASE(test_pageparser)
186{
187 constexpr unsigned pagesize = 128;
188 std::vector<ClusterData> dataset;
189 FillData(dataset, 20);
190 auto buffer = MakeBuffer(pagesize, PageHeader(0), dataset);
191 o2::header::hexDump("pagebuffer", buffer.first.get(), buffer.second);
192
194 const RawParser parser(buffer.first.get(), buffer.second);
195
196 unsigned dataidx = 0;
197 for (auto i : parser) {
198 o2::header::hexDump("clusterdata", &i, sizeof(ClusterData));
199 BOOST_REQUIRE(i == dataset[dataidx++]);
200 }
201
202 std::vector<RawParser::value_type> linearizedData;
203 linearizedData.insert(linearizedData.begin(), parser.begin(), parser.end());
204 dataidx = 0;
205 for (auto i : linearizedData) {
206 BOOST_REQUIRE(i == dataset[dataidx++]);
207 }
208
209 dataidx = 0;
210 RawParser writer(buffer.first.get(), buffer.second);
211 std::vector<std::pair<unsigned, unsigned>> xvalues;
212 for (auto& i : writer) {
213 i.x = (dataidx * 3) % 7;
214 xvalues.emplace_back(i.x, dataidx);
215 ++dataidx;
216 }
217 o2::header::hexDump("changed buffer", buffer.first.get(), buffer.second);
218
219 dataidx = 0;
220 for (auto i : parser) {
221 o2::header::hexDump("clusterdata", &i, sizeof(ClusterData));
222 BOOST_REQUIRE(i.x == xvalues[dataidx++].first);
223 }
224}
225
226BOOST_AUTO_TEST_CASE(test_pageparser_group)
227{
228 using DataSetT = std::vector<ClusterData>;
229 DataSetT dataset;
230 FillData(dataset, 20);
231
232 runParserTest<DataSetT, PageHeader, int, 128, false>(dataset);
233 runParserTest<DataSetT, PageHeader, int, 100, false>(dataset);
234 runParserTest<DataSetT, PageHeader, int, 89, false>(dataset);
235}
236
237BOOST_AUTO_TEST_CASE(test_pageparser_group_perpage)
238{
239 using DataSetT = std::vector<ClusterData>;
240 DataSetT dataset;
241 FillData(dataset, 20);
242
243 runParserTest<DataSetT, PageHeader, int, 128, true>(dataset);
244 runParserTest<DataSetT, PageHeader, int, 100, true>(dataset);
245 runParserTest<DataSetT, PageHeader, int, 89, true>(dataset);
246}
int32_t i
An allocator for static sequences of object types.
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint buffer
Definition glcorearb.h:655
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLenum target
Definition glcorearb.h:1641
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
void set(T *h, size_t v)
Definition PageParser.h:107
void hexDump(const char *desc, const void *voidaddr, size_t len, size_t max=0)
helper function to print a hex/ASCII dump of some memory
void FillData(ListT &dataset, unsigned entries)
void runParserTest(const DataSetT &dataset)
BOOST_AUTO_TEST_CASE(test_pageparser)
std::pair< std::unique_ptr< uint8_t[]>, size_t > MakeBuffer(size_t pagesize, PageHeaderT pageheader, const ListT &dataset)
uint16_t x
uint32_t clusterid
ClusterData(uint32_t _id, uint16_t _x, uint16_t _y, uint16_t _z, uint8_t _e)
uint32_t magic
uint16_t z
uint16_t y
bool operator==(const ClusterData &rhs) const
uint32_t magic
PageHeader(uint32_t id)
uint32_t pageid