/* Verify the bucket prediction. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <unistd.h>

#define N_SPRAY 5000

static long read_objs(const char *cache_name) {
    FILE *f = fopen("/proc/slabinfo", "r");
    if (!f) { perror("slabinfo"); return -1; }
    char line[512];
    long active = -1;
    while (fgets(line, sizeof(line), f)) {
        if (strncmp(line, cache_name, strlen(cache_name)) == 0 &&
            line[strlen(cache_name)] == ' ') {
            sscanf(line + strlen(cache_name), "%ld", &active);
            break;
        }
    }
    fclose(f);
    return active;
}

int main(void) {
    /* Bump fd limit */
    struct rlimit rl = {.rlim_cur = N_SPRAY + 100, .rlim_max = N_SPRAY + 100};
    setrlimit(RLIMIT_NOFILE, &rl);

    const char *caches[] = {
        "kmalloc-rnd-01-256", "kmalloc-rnd-04-256",
        "kmalloc-rnd-01-512", "kmalloc-rnd-04-512", "kmalloc-rnd-08-512",
        "kmalloc-rnd-01-1k",  "kmalloc-rnd-04-1k",
        NULL
    };

    long pre[16];
    for (int i = 0; caches[i]; i++) pre[i] = read_objs(caches[i]);

    int *fds = malloc(N_SPRAY * sizeof(int));
    int n = 0;
    for (int i = 0; i < N_SPRAY; i++) {
        fds[i] = epoll_create1(0);
        if (fds[i] < 0) { fprintf(stderr, "epoll_create at %d: %s\n", i, strerror(errno)); break; }
        n++;
    }
    fprintf(stderr, "allocated %d epolls\n", n);

    /* Read post stats while fds still held */
    long post[16];
    for (int i = 0; caches[i]; i++) post[i] = read_objs(caches[i]);

    fprintf(stderr, "%-25s %10s %10s %10s\n", "cache", "before", "after", "delta");
    for (int i = 0; caches[i]; i++) {
        fprintf(stderr, "%-25s %10ld %10ld %+10ld\n",
                caches[i], pre[i], post[i], post[i] - pre[i]);
    }

    for (int i = 0; i < n; i++) close(fds[i]);
    free(fds);
    return 0;
}
