//===-- compute_size_class_config.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include #include #include #include #include #include struct Alloc { size_t size, count; }; size_t measureWastage(const std::vector &allocs, const std::vector &classes, size_t pageSize, size_t headerSize) { size_t totalWastage = 0; for (auto &a : allocs) { size_t sizePlusHeader = a.size + headerSize; size_t wastage = -1ull; for (auto c : classes) if (c >= sizePlusHeader && c - sizePlusHeader < wastage) wastage = c - sizePlusHeader; if (wastage == -1ull) continue; if (wastage > 2 * pageSize) wastage = 2 * pageSize; totalWastage += wastage * a.count; } return totalWastage; } void readAllocs(std::vector &allocs, const char *path) { FILE *f = fopen(path, "r"); if (!f) { fprintf(stderr, "compute_size_class_config: could not open %s: %s\n", path, strerror(errno)); exit(1); } const char header[] = "\n"; char buf[sizeof(header) - 1]; if (fread(buf, 1, sizeof(header) - 1, f) != sizeof(header) - 1 || memcmp(buf, header, sizeof(header) - 1) != 0) { fprintf(stderr, "compute_size_class_config: invalid input format\n"); exit(1); } Alloc a; while (fscanf(f, "\n", &a.size, &a.count) == 2) allocs.push_back(a); fclose(f); } size_t log2Floor(size_t x) { return sizeof(long) * 8 - 1 - __builtin_clzl(x); } void usage() { fprintf(stderr, "usage: compute_size_class_config [-p pageSize] [-c largestClass] " "[-h headerSize] [-n numClasses] [-b numBits] profile...\n"); exit(1); } int main(int argc, char **argv) { size_t pageSize = 4096; size_t largestClass = 65552; size_t headerSize = 16; size_t numClasses = 32; size_t numBits = 5; std::vector allocs; for (size_t i = 1; i != argc;) { auto matchArg = [&](size_t &arg, const char *name) { if (strcmp(argv[i], name) == 0) { if (i + 1 != argc) { arg = atoi(argv[i + 1]); i += 2; } else { usage(); } return true; } return false; }; if (matchArg(pageSize, "-p") || matchArg(largestClass, "-c") || matchArg(headerSize, "-h") || matchArg(numClasses, "-n") || matchArg(numBits, "-b")) continue; readAllocs(allocs, argv[i]); ++i; } if (allocs.empty()) usage(); std::vector classes; classes.push_back(largestClass); for (size_t i = 1; i != numClasses; ++i) { size_t minWastage = -1ull; size_t minWastageClass; for (size_t newClass = 16; newClass != largestClass; newClass += 16) { // Skip classes with more than numBits bits, ignoring leading or trailing // zero bits. if (__builtin_ctzl(newClass - headerSize) + __builtin_clzl(newClass - headerSize) < sizeof(long) * 8 - numBits) continue; classes.push_back(newClass); size_t newWastage = measureWastage(allocs, classes, pageSize, headerSize); classes.pop_back(); if (newWastage < minWastage) { minWastage = newWastage; minWastageClass = newClass; } } classes.push_back(minWastageClass); } std::sort(classes.begin(), classes.end()); size_t minSizeLog = log2Floor(headerSize); size_t midSizeIndex = 0; while (classes[midSizeIndex + 1] - classes[midSizeIndex] == (1 << minSizeLog)) midSizeIndex++; size_t midSizeLog = log2Floor(classes[midSizeIndex] - headerSize); size_t maxSizeLog = log2Floor(classes.back() - headerSize - 1) + 1; printf(R"(// wastage = %zu struct MySizeClassConfig { static const uptr NumBits = %zu; static const uptr MinSizeLog = %zu; static const uptr MidSizeLog = %zu; static const uptr MaxSizeLog = %zu; static const u16 MaxNumCachedHint = 14; static const uptr MaxBytesCachedLog = 14; static constexpr u32 Classes[] = {)", measureWastage(allocs, classes, pageSize, headerSize), numBits, minSizeLog, midSizeLog, maxSizeLog); for (size_t i = 0; i != classes.size(); ++i) { if ((i % 8) == 0) printf("\n "); else printf(" "); printf("0x%05zx,", classes[i]); } printf(R"( }; static const uptr SizeDelta = %zu; }; )", headerSize); }