add citation information
[LbmBenchmarkKernelsPublic.git] / src / Padding.c
CommitLineData
e3f82424
MW
1#include "Base.h"
2#include "Kernel.h"
3#include "Padding.h"
4
5#include <errno.h>
6#include <limits.h>
7
8// Generates a PadInfo struct from padStr. If padStr is NULL then a NULL
9// pointer is returned.
10//
11// Padding string is either "auto" or in the format of
12// <modulus>+<remainder>(,<modulus>+<remainder>)*.
13//
14// If modulus is 0 then the remainder will just be added and no modulo will be
15// applied.
16//
17// Returned PadInfo structs must be freed with PadInfoFree.
18
19PadInfo * PadInfoFromStr(const char * padStr)
20{
21 if (padStr == NULL) {
22 return NULL;
23 }
24 else if (!strncmp("auto", padStr, 4)) {
25
26 PadInfo * padInfo = (PadInfo *)malloc(sizeof(PadInfo) + 4 * sizeof(int));
27 Assert(padInfo != NULL);
28
29 padInfo->nEntries = 2;
30 padInfo->Modulus = (int *)(padInfo + 1);
31 padInfo->Offset = ((int *)(padInfo + 1)) + 2;
32
33 // Intel TLB 2 MiB pages
34 padInfo->Modulus[0] = 2 * 1024 * 1024 * 8;
35 padInfo->Offset[0] = 2 * 1024 * 1024 + 512;
36
37 // Intel L2, 256 sets
38 padInfo->Modulus[1] = 256 * 64;
39 padInfo->Offset[1] = 128;
40
41 return padInfo;
42 }
43 else if (!strncmp("no", padStr, 2) || !strncmp("off", padStr, 3)) {
44 PadInfo * padInfo = (PadInfo *)malloc(sizeof(PadInfo));
45 Assert(padInfo != NULL);
46
47 padInfo->nEntries = 0;
48 padInfo->Modulus = NULL;
49 padInfo->Offset = NULL;
50
51 return padInfo;
52 }
53
54 // Count number of commas. Number of commas + 1 gives us the number of
55 // padding entries.
56 const char * tmp = padStr;
57 int nCommas = 0;
58
59 while (*tmp != 0x00) {
60 if (*tmp == ',') ++nCommas;
61 ++tmp;
62 }
63
64 // Number of padding entries = nCommas + 1.
65 size_t padInfoSize = sizeof(PadInfo) + (nCommas + 1) * 2 * sizeof(int);
66 PadInfo * padInfo = (PadInfo *)malloc(padInfoSize);
67 Assert(padInfo != NULL);
68
69 memset(padInfo, 0x00, padInfoSize);
70
71 padInfo->Modulus = (int *)(padInfo + 1);
72 padInfo->Offset = ((int *)(padInfo + 1)) + nCommas + 1;
73
74 tmp = padStr;
75
76 int padEntryIndex = 0;
77 int entriesSeen = 0;
78
79 int modulusSeen = 0;
80 int offsetSeen = 0;
81
82 // TODO: parsing is currently a mess. We assume a fixed format, which
83 // should be easier to parse now.
84 while (*tmp != 0x00) {
85
86 if (*tmp == ',') {
87 // Check if modulus was seen in this section, then move to the next.
88
89 if (!modulusSeen) {
90 fprintf(stderr, "ERROR: modulus missing before next section in padding string.\n");
91 exit(1);
92 }
93
94 modulusSeen = 0;
95 offsetSeen = 0;
96 ++padEntryIndex;
97 ++tmp;
98 }
99 else if (*tmp == '+') {
100 // Check if modulus was seen in this section and no offset yet.
101
102 if (!modulusSeen) {
103 fprintf(stderr, "ERROR: modulus missing before offset in padding string.\n");
104 exit(1);
105 }
106
107 if (offsetSeen) {
108 fprintf(stderr, "ERROR: offset is only allowed to be specified once per section in padding string.\n");
109 exit(1);
110 }
111
112 ++tmp;
113 }
114 else if (*tmp >= '0' && *tmp <= '9') {
115 // Parse number and check for all the errors.
116
117 char * endPtr;
118
119 errno = 0;
120
121 int value = strtol(tmp, &endPtr, 10);
122
123 if ((value == LONG_MIN || value == LONG_MAX) && errno != 0) {
124 fprintf(stderr, "ERROR: over- or underflow in modulus/offset of padding string.\n");
125 exit(1);
126 }
127 else if (value == 0 && errno != 0) {
128 fprintf(stderr, "ERROR: error parsing modulus/offset of padding string: %d - %s\n", errno, strerror(errno));
129 exit(1);
130 }
131 else if (tmp == endPtr) {
132 // No digits found: empty string or invalid pad string.
133 fprintf(stderr, "ERROR: modulus or offset missing in padding string.\n");
134 exit(1);
135 }
136
137 if (value < 0) {
138 fprintf(stderr, "ERROR: modulus and offset must be >= 0 in padding string.\n");
139 exit(1);
140 }
141
142 if (!modulusSeen) {
143 if (offsetSeen) {
144 fprintf(stderr, "ERROR: offset already seen, but not modulus in padding string.\n");
145 exit(1);
146 }
147
148 Verify(padEntryIndex < (nCommas + 1));
149
150 padInfo->Modulus[padEntryIndex] = value;
151
152 modulusSeen = 1;
153 ++entriesSeen;
154 }
155 else {
156 if (offsetSeen) {
157 fprintf(stderr, "ERROR: offset is only allowed to be specified once per section in padding string.\n");
158 exit(1);
159 }
160
161 Verify(padEntryIndex < (nCommas + 1));
162
163 padInfo->Offset[padEntryIndex] = value;
164
165 offsetSeen = 1;
166 }
167 // No increment of tmp needed, as endPtr points already to the first
168 // character which is not part of the number.
169 tmp = endPtr;
170 }
171 else {
172 fprintf(stderr, "ERROR: padding string contains invalid characters.\n");
173 exit(1);
174 }
175
176 }
177
178 if (entriesSeen != nCommas + 1) {
179 fprintf(stderr, "ERROR: did not find all padding entries.\n");
180 exit(1);
181 }
182
183 for (int i = 0; i < nCommas + 1; ++i) {
184 if (padInfo->Offset[i] >= padInfo->Modulus[i]) {
185 fprintf(stderr, "ERROR: offset in padding entry %d is equal or larger than modulus.\n", i);
186 exit(1);
187 }
188 }
189
190 padInfo->nEntries = entriesSeen;
191
192 return padInfo;
193}
194
195int PadCells(int nCells, int cellSizeBytes, PadInfo ** padInfoPtr)
196{
197 Assert(padInfoPtr != NULL);
198
199 // If the padInfo is NULL determine if we use the "auto" configuration.
200 const int defaultAutoPadding = 1;
201
202
203 if (*padInfoPtr == NULL) {
204 if (!defaultAutoPadding) {
205 return nCells;
206 }
207
208 *padInfoPtr = PadInfoFromStr("auto");
209 }
210
211 PadInfo * padInfo = *padInfoPtr;
212
213 Assert(padInfo->nEntries >= 0);
214
215 for (int i = 0; i < padInfo->nEntries; ++i) {
216 Assert(padInfo->Modulus[i] >= 0);
217 Assert(padInfo->Offset[i] >= 0);
218
219 int nPadCells = 0;
220
221 if (padInfo->Modulus[i] == 0) {
222 // When the modulus is just zero then we only add the offset.
223 nPadCells = padInfo->Offset[i] * cellSizeBytes;
224 }
225 else {
226 int nModCells = padInfo->Modulus[i] / cellSizeBytes;
227
228 if (nModCells == 0) {
229 fprintf(stderr, "ERROR: modulus of %d byte in padding entry %d becomes zero for PDF size %d byte.\n",
230 padInfo->Modulus[i], i, cellSizeBytes);
231 exit(1);
232 }
233
234 int nOffsetCells = padInfo->Offset[i] / cellSizeBytes;
235 int nRemainder = nCells % nModCells;
236
237 nPadCells = (nOffsetCells + nModCells - nRemainder) % nModCells;
238 }
239
240 nCells += nPadCells;
241 }
242
243 return nCells;
244}
245
246void PadInfoPrint(PadInfo * padInfo, FILE * f, const char * prefix)
247{
248 Assert(padInfo != NULL);
249 Assert(padInfo->nEntries >= 0);
250 Assert(f != NULL);
251 Assert(prefix != NULL);
252
253 for (int i = 0; i < padInfo->nEntries; ++i) {
254 fprintf(f, "%sm: %10d b o: %10d b m: %f KiB o: %f KiB m: %f MiB o: %f MiB\n",
255 prefix,
256 padInfo->Modulus[i], padInfo->Offset[i],
257 padInfo->Modulus[i] / 1024.0, padInfo->Offset[i] / 1024.0,
258 padInfo->Modulus[i] / 1024.0 / 1024.0, padInfo->Offset[i] / 1024.0 / 1024.0);
259 }
260
261 return;
262}
263
264void PadInfoFree(PadInfo * padInfo)
265{
266 if (padInfo != NULL) {
267 free(padInfo);
268 }
269
270 return;
271}
272
273// Returns the new padded cell size and reports if padding was performed and how.
274
275int PadCellsAndReport(int nCells, int cellSizeBytes, PadInfo ** padInfoPtr)
276{
277 // Apply padding.
278 int nNewCells = PadCells(nCells, sizeof(PdfT), padInfoPtr);
279
280 if (nCells != nNewCells) {
281 printf("# padding info:\n");
282 PadInfoPrint(*padInfoPtr, stdout, "# ");
283 // int nPaddedCells = nNewCells - nCells;
284 // printf("# padding per dir.: %10d nodes (%f MiB)\n", nPaddedCells, nPaddedCells / 1024.0 / 1024.0 * sizeof(PdfT));
285 // printf("# padding total: %10d nodes (%f MiB)\n", 19 * nPaddedCells, 19 * nPaddedCells / 1024.0 / 1024.0 * sizeof(PdfT));
286
287 int nPadCells = nNewCells - nCells;
288
289 printf("#\n# padding %d nodes with %d nodes, %f MiB per direction, %f MiB in total\n",
290 nCells,
291 nPadCells,
292 nPadCells * sizeof(PdfT) / 1024.0 / 1024.0,
293 nPadCells * sizeof(PdfT) / 1024.0 / 1024.0 * 19);
294 }
295 else {
296 printf("# padding info: no padding used\n");
297 }
298
299 return nNewCells;
300}
This page took 0.124378 seconds and 5 git commands to generate.