From 91080535f882716105d80bf73bf92ab63b11c6c9 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Wed, 10 Jul 2024 11:01:32 +0200 Subject: [PATCH] Add fill mode in memtool --- JOURNAL.md | 19 +++++++ lagarto-ox.nix | 3 +- memtool.c | 144 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 135 insertions(+), 31 deletions(-) diff --git a/JOURNAL.md b/JOURNAL.md index 0630708..c2b819a 100644 --- a/JOURNAL.md +++ b/JOURNAL.md @@ -1072,3 +1072,22 @@ and see if it has any effect? iter=292 nblocks=229 allocated=58599K (A) Has changed, but not much. + + aaaiter=291 nblocks=228 allocated=58480K (A) + allocating... + filling... + aaaaaaaaiter=292 nblocks=229 allocated=58599K (A) + allocating... + aafilling... + +It seems to be getting stuck in the filling phase. Can we trace it down with +ftrace? It should be generating page faults. + +### 2024-07-10 + +So, if we manage to crash in the filling phase, we can further pinpoint the +issue and remove any effect of `malloc()`. It would be only related to a page +fault and the MMU at this point. + +Let's make a much simpler program that only allocates once a buffer of N bytes +and then begins filling it, printing the progress in the output. diff --git a/lagarto-ox.nix b/lagarto-ox.nix index 58248ad..faff021 100644 --- a/lagarto-ox.nix +++ b/lagarto-ox.nix @@ -88,7 +88,8 @@ export PATH=${config.system.build.extraUtils}/bin - memtool $((512 * 1024)) + #memtool chain $((512 * 1024)) + memtool fill $((512 * 1024 * 1024)) # Unlikely to reach this point exec /init diff --git a/memtool.c b/memtool.c index b718e63..f961c71 100644 --- a/memtool.c +++ b/memtool.c @@ -6,9 +6,14 @@ * stress the virtual memory, in a crude attempt to reproduce the hangs * that we were observing while booting NixOS. */ +/* Changelog: + * v0.0.1 (2024-07-10): Start version with "chain" and "fill" tests. + */ + #include #include #include +#include #define MAX_SIZE (1024L * 1024L) @@ -18,17 +23,19 @@ struct block { uint32_t data[]; }; -struct block *front = NULL; -struct block *tail = NULL; -long nblocks = 0; -long nbytes = 0; -long maxsize = MAX_SIZE; +struct chain { + struct block *front; + struct block *tail; + long maxsize; + long nbytes; + long nblocks; +}; static int -allocate(void) +allocate(struct chain *chain) { /* Constraint the number of elements based on the maxsize */ - long maxn = maxsize / sizeof(uint32_t); + long maxn = chain->maxsize / sizeof(uint32_t); long n = (long) rand() % maxn; size_t size = sizeof(struct block) + n * sizeof(uint32_t); @@ -50,38 +57,38 @@ allocate(void) b->data[i] = rand(); /* Add it to the chain */ - if (tail) - tail->next = b; + if (chain->tail) + chain->tail->next = b; - tail = b; + chain->tail = b; /* And to the front if it is the first */ - if (!front) - front = b; + if (!chain->front) + chain->front = b; - nblocks++; - nbytes += size; + chain->nblocks++; + chain->nbytes += size; return 0; } static int -deallocate(void) +deallocate(struct chain *chain) { /* May run out of blocks */ - if (!front) + if (!chain->front) return -1; - struct block *b = front; + struct block *b = chain->front; - front = b->next; + chain->front = b->next; /* Last block */ - if (tail == b) - tail = NULL; + if (chain->tail == b) + chain->tail = NULL; - nblocks--; - nbytes -= b->size; + chain->nblocks--; + chain->nbytes -= b->size; printf("deallocating...\n"); free(b); @@ -90,8 +97,18 @@ deallocate(void) } static void -torture(void) +do_chain(int argc, char *argv[]) { + struct chain chain = {0}; + + /* Default 1 MiB */ + chain.maxsize = 1024L * 1024L; + + if (argc > 0) + chain.maxsize = atol(argv[0]); + + printf("mode chain: maxsize=%ldK\n", chain.maxsize / 1024); + srand(123); for (long iter = 0; ; iter++) { @@ -100,31 +117,98 @@ torture(void) int ret = 0; char c; if (is_alloc) { - if (allocate() == 0) + if (allocate(&chain) == 0) c = 'A'; else c = '-'; } else { - if (deallocate() == 0) + if (deallocate(&chain) == 0) c = 'D'; else c = '-'; } printf("iter=%ld nblocks=%ld allocated=%ldK (%c)\n", - iter, nblocks, nbytes / 1024, + iter, chain.nblocks, chain.nbytes / 1024, c); } } +static void +do_fill(int argc, char *argv[]) +{ + /* Default: 256 MiB */ + long nbytes = 256L * 1024L * 1024L; + + if (argc > 0) + nbytes = atol(argv[0]); + + long n = nbytes / sizeof(int); + + printf("mode fill: nbytes=%ldM, n=%ld\n", + nbytes / (1024L * 1024L), n); + + int *buf = malloc(nbytes); + + if (!buf) { + perror("malloc failed"); + exit(1); + } + + for (long i = 0; i < n; i++) { + buf[i] = i; + if ((i % (1024L * 1024L)) == 0) + printf("written=%ldK, addr=%p OK\n", + i * sizeof(int) / 1024L, + &buf[i]); + } + + free(buf); + + printf("fill test OK\n"); +} + +static void +usage(void) +{ + printf( +"Usage: memtool [...]\n" +"\n" +"Available commands:\n" +" chain []\n" +" Creates a chain of blocks of random size, each up to maxsize\n" +" or 1MiB if not given. Blocks are freed with 10% probability\n" +" starting from the oldest.\n" +"\n" +" fill []\n" +" Allocates a vector of the given size (or 256 MiB if not given)\n" +" and initializes it with a increasing value per element.\n" +"\n"); + + exit(1); +} + int main(int argc, char *argv[]) { - if (argc > 1) - maxsize = atol(argv[1]); + printf("memtool v0.0.1 - Rodrigo Arias Mallo \n"); - printf("memtool v1.0.0 maxsize=%ldK\n", maxsize / 1024); + if (argc < 2) + usage(); - torture(); + /* Skip program name */ + argc--; argv++; + + const char *mode = argv[0]; + + /* Skip mode */ + argc--; argv++; + + if (strcmp(mode, "chain") == 0) + do_chain(argc, argv); + else if (strcmp(mode, "fill") == 0) + do_fill(argc, argv); + else + usage(); return 0; }