| 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 | } |