Add fill mode in memtool

This commit is contained in:
Rodrigo Arias 2024-07-10 11:01:32 +02:00
parent 6c8d6354bc
commit 91080535f8
3 changed files with 135 additions and 31 deletions

View File

@ -1072,3 +1072,22 @@ and see if it has any effect?
iter=292 nblocks=229 allocated=58599K (A) iter=292 nblocks=229 allocated=58599K (A)
Has changed, but not much. 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.

View File

@ -88,7 +88,8 @@
export PATH=${config.system.build.extraUtils}/bin export PATH=${config.system.build.extraUtils}/bin
memtool $((512 * 1024)) #memtool chain $((512 * 1024))
memtool fill $((512 * 1024 * 1024))
# Unlikely to reach this point # Unlikely to reach this point
exec /init exec /init

144
memtool.c
View File

@ -6,9 +6,14 @@
* stress the virtual memory, in a crude attempt to reproduce the hangs * stress the virtual memory, in a crude attempt to reproduce the hangs
* that we were observing while booting NixOS. */ * that we were observing while booting NixOS. */
/* Changelog:
* v0.0.1 (2024-07-10): Start version with "chain" and "fill" tests.
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#define MAX_SIZE (1024L * 1024L) #define MAX_SIZE (1024L * 1024L)
@ -18,17 +23,19 @@ struct block {
uint32_t data[]; uint32_t data[];
}; };
struct block *front = NULL; struct chain {
struct block *tail = NULL; struct block *front;
long nblocks = 0; struct block *tail;
long nbytes = 0; long maxsize;
long maxsize = MAX_SIZE; long nbytes;
long nblocks;
};
static int static int
allocate(void) allocate(struct chain *chain)
{ {
/* Constraint the number of elements based on the maxsize */ /* 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; long n = (long) rand() % maxn;
size_t size = sizeof(struct block) + n * sizeof(uint32_t); size_t size = sizeof(struct block) + n * sizeof(uint32_t);
@ -50,38 +57,38 @@ allocate(void)
b->data[i] = rand(); b->data[i] = rand();
/* Add it to the chain */ /* Add it to the chain */
if (tail) if (chain->tail)
tail->next = b; chain->tail->next = b;
tail = b; chain->tail = b;
/* And to the front if it is the first */ /* And to the front if it is the first */
if (!front) if (!chain->front)
front = b; chain->front = b;
nblocks++; chain->nblocks++;
nbytes += size; chain->nbytes += size;
return 0; return 0;
} }
static int static int
deallocate(void) deallocate(struct chain *chain)
{ {
/* May run out of blocks */ /* May run out of blocks */
if (!front) if (!chain->front)
return -1; return -1;
struct block *b = front; struct block *b = chain->front;
front = b->next; chain->front = b->next;
/* Last block */ /* Last block */
if (tail == b) if (chain->tail == b)
tail = NULL; chain->tail = NULL;
nblocks--; chain->nblocks--;
nbytes -= b->size; chain->nbytes -= b->size;
printf("deallocating...\n"); printf("deallocating...\n");
free(b); free(b);
@ -90,8 +97,18 @@ deallocate(void)
} }
static 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); srand(123);
for (long iter = 0; ; iter++) { for (long iter = 0; ; iter++) {
@ -100,31 +117,98 @@ torture(void)
int ret = 0; int ret = 0;
char c; char c;
if (is_alloc) { if (is_alloc) {
if (allocate() == 0) if (allocate(&chain) == 0)
c = 'A'; c = 'A';
else else
c = '-'; c = '-';
} else { } else {
if (deallocate() == 0) if (deallocate(&chain) == 0)
c = 'D'; c = 'D';
else else
c = '-'; c = '-';
} }
printf("iter=%ld nblocks=%ld allocated=%ldK (%c)\n", printf("iter=%ld nblocks=%ld allocated=%ldK (%c)\n",
iter, nblocks, nbytes / 1024, iter, chain.nblocks, chain.nbytes / 1024,
c); 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 <command> [<options>...]\n"
"\n"
"Available commands:\n"
" chain [<maxsize>]\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 [<size>]\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[]) int main(int argc, char *argv[])
{ {
if (argc > 1) printf("memtool v0.0.1 - Rodrigo Arias Mallo <rodrigo.arias@bsc.es>\n");
maxsize = atol(argv[1]);
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; return 0;
} }