Add fill mode in memtool
This commit is contained in:
parent
6c8d6354bc
commit
91080535f8
19
JOURNAL.md
19
JOURNAL.md
@ -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.
|
||||||
|
@ -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
144
memtool.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user