diff --git a/JOURNAL.md b/JOURNAL.md index 6080c78..54e6c2f 100644 --- a/JOURNAL.md +++ b/JOURNAL.md @@ -966,3 +966,8 @@ And it hangs just after exiting the tool. If the problem that we are observing is somehow related to the recursive segfault of the kernel in Cincoranch, we may be able to see the printk ring buffer by directly poking at the memory from the host. + +### QUESTION: Can we crash the CPU by exercising the memory? + +I did a small tool `memtool` that performs allocations and +deallocations. diff --git a/lagarto-ox.nix b/lagarto-ox.nix index 4a750a1..4b3be5d 100644 --- a/lagarto-ox.nix +++ b/lagarto-ox.nix @@ -81,9 +81,10 @@ kernelModules = [ ]; # Add the csrtool to the initrd so we can change the - # in-order/out-of-order. + # in-order/out-of-order, and memtool to stress the memory. extraUtilsCommands = '' cp -a ${pkgs.csrtool}/bin/csrtool $out/bin + cp -a ${pkgs.memtool}/bin/memtool $out/bin ''; # Write a counter to the DMA region, so we can check the kernel is not diff --git a/memtool.c b/memtool.c new file mode 100644 index 0000000..b5b6f2a --- /dev/null +++ b/memtool.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: MIT + * Author: Rodrigo Arias Mallo */ + +/* This is just a small tool to exercise the memory which attempts to + * stress the virtual memory, in a crude attempt to reproduce the hangs + * that we were observing while booting NixOS. */ + +#include +#include +#include + +#define MAX_SIZE (1024L * 1024L) + +struct block { + struct block *next; + size_t size; + uint32_t data[]; +}; + +struct block *front = NULL; +struct block *tail = NULL; +long nblocks = 0; +long nbytes = 0; + +static int +allocate(void) +{ + long n = (long) rand() % MAX_SIZE; + /* Constraint the size */ + n = n % MAX_SIZE; + + size_t size = sizeof(struct block) + n * sizeof(uint32_t); + + struct block *b = malloc(size); + + /* No mem */ + if (b == NULL) + return -1; + + b->size = size; + b->next = NULL; + + /* Populate the block with some data */ + for (long i = 0; i < n; i++) + b->data[i] = rand(); + + /* Add it to the chain */ + if (tail) + tail->next = b; + + tail = b; + + /* And to the front if it is the first */ + if (!front) + front = b; + + nblocks++; + nbytes += size; + + return 0; +} + +static int +deallocate(void) +{ + /* May run out of blocks */ + if (!front) + return -1; + + struct block *b = front; + + front = b->next; + + /* Last block */ + if (tail == b) + tail = NULL; + + nblocks--; + nbytes -= b->size; + + free(b); + + return 0; +} + +static void +torture(void) +{ + srand(123); + + for (long iter = 0; ; iter++) { + int p = rand() % 100; + int is_alloc = (p > 10); + int ret = 0; + char c; + if (is_alloc) { + if (allocate() == 0) + c = 'A'; + else + c = '-'; + } else { + if (deallocate() == 0) + c = 'D'; + else + c = '-'; + } + + printf("iter %ld, nblocks %ld, nbytes %.1fM (%c)\n", + iter, nblocks, (double) nbytes / (1024. * 1024.), + c); + } +} + +int main(int argc, char *argv[]) +{ + torture(); + return 0; +} diff --git a/overlay.nix b/overlay.nix index 1614a9a..5813639 100644 --- a/overlay.nix +++ b/overlay.nix @@ -53,6 +53,22 @@ final: prev: ''; }; + memtool = prev.pkgsStatic.stdenv.mkDerivation { + name = "memtool"; + src = ./memtool.c; + unpackPhase = '' + cp ${./memtool.c} memtool.c + ''; + dontConfigure = true; + buildPhase = '' + $CC -static memtool.c -o memtool + ''; + installPhase = '' + mkdir -p $out/bin + cp memtool $out/bin/ + ''; + }; + bitstreams = builtins.fetchGit { url = "git@bscpm03.bsc.es:rarias/bitstreams.git"; rev = "ad901b0c21ffbdb310ff1dfb269f169f6ac6bde6";