add citation information
[LbmBenchmarkKernelsPublic.git] / src / Padding.c
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
19 PadInfo * 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
195 int 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
246 void 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
264 void 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
275 int 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.060533 seconds and 4 git commands to generate.