| //===-- 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 <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <vector> |
| |
| struct Alloc { |
| size_t size, count; |
| }; |
| |
| size_t measureWastage(const std::vector<Alloc> &allocs, |
| const std::vector<size_t> &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<Alloc> &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[] = "<malloc version=\"scudo-1\">\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, "<alloc size=\"%zu\" count=\"%zu\"/>\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<Alloc> 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<size_t> 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); |
| } |