| 1 | ================== |
| 2 | Memblock simulator |
| 3 | ================== |
| 4 | |
| 5 | Introduction |
| 6 | ============ |
| 7 | |
| 8 | Memblock is a boot time memory allocator[1] that manages memory regions before |
| 9 | the actual memory management is initialized. Its APIs allow to register physical |
| 10 | memory regions, mark them as available or reserved, allocate a block of memory |
| 11 | within the requested range and/or in specific NUMA node, and many more. |
| 12 | |
| 13 | Because it is used so early in the booting process, testing and debugging it is |
| 14 | difficult. This test suite, usually referred as memblock simulator, is |
| 15 | an attempt at testing the memblock mechanism. It runs one monolithic test that |
| 16 | consist of a series of checks that exercise both the basic operations and |
| 17 | allocation functionalities of memblock. The main data structure of the boot time |
| 18 | memory allocator is initialized at the build time, so the checks here reuse its |
| 19 | instance throughout the duration of the test. To ensure that tests don't affect |
| 20 | each other, region arrays are reset in between. |
| 21 | |
| 22 | As this project uses the actual memblock code and has to run in user space, |
| 23 | some of the kernel definitions were stubbed by the initial commit that |
| 24 | introduced memblock simulator (commit 16802e55dea9 ("memblock tests: Add |
| 25 | skeleton of the memblock simulator")) and a few preparation commits just |
| 26 | before it. Most of them don't match the kernel implementation, so one should |
| 27 | consult them first before making any significant changes to the project. |
| 28 | |
| 29 | Usage |
| 30 | ===== |
| 31 | |
| 32 | To run the tests, build the main target and run it: |
| 33 | |
| 34 | $ make && ./main |
| 35 | |
| 36 | A successful run produces no output. It is possible to control the behavior |
| 37 | by passing options from command line. For example, to include verbose output, |
| 38 | append the `-v` options when you run the tests: |
| 39 | |
| 40 | $ ./main -v |
| 41 | |
| 42 | This will print information about which functions are being tested and the |
| 43 | number of test cases that passed. |
| 44 | |
| 45 | For the full list of options from command line, see `./main --help`. |
| 46 | |
| 47 | It is also possible to override different configuration parameters to change |
| 48 | the test functions. For example, to simulate enabled NUMA, use: |
| 49 | |
| 50 | $ make NUMA=1 |
| 51 | |
| 52 | For the full list of build options, see `make help`. |
| 53 | |
| 54 | Project structure |
| 55 | ================= |
| 56 | |
| 57 | The project has one target, main, which calls a group of checks for basic and |
| 58 | allocation functions. Tests for each group are defined in dedicated files, as it |
| 59 | can be seen here: |
| 60 | |
| 61 | memblock |
| 62 | |-- asm ------------------, |
| 63 | |-- lib |-- implement function and struct stubs |
| 64 | |-- linux ------------------' |
| 65 | |-- scripts |
| 66 | | |-- Makefile.include -- handles `make` parameters |
| 67 | |-- tests |
| 68 | | |-- alloc_api.(c|h) -- memblock_alloc tests |
| 69 | | |-- alloc_helpers_api.(c|h) -- memblock_alloc_from tests |
| 70 | | |-- alloc_nid_api.(c|h) -- memblock_alloc_try_nid tests |
| 71 | | |-- basic_api.(c|h) -- memblock_add/memblock_reserve/... tests |
| 72 | | |-- common.(c|h) -- helper functions for resetting memblock; |
| 73 | |-- main.c --------------. dummy physical memory definition |
| 74 | |-- Makefile `- test runner |
| 75 | |-- README |
| 76 | |-- TODO |
| 77 | |-- .gitignore |
| 78 | |
| 79 | Simulating physical memory |
| 80 | ========================== |
| 81 | |
| 82 | Some allocation functions clear the memory in the process, so it is required for |
| 83 | memblock to track valid memory ranges. To achieve this, the test suite registers |
| 84 | with memblock memory stored by test_memory struct. It is a small wrapper that |
| 85 | points to a block of memory allocated via malloc. For each group of allocation |
| 86 | tests, dummy physical memory is allocated, added to memblock, and then released |
| 87 | at the end of the test run. The structure of a test runner checking allocation |
| 88 | functions is as follows: |
| 89 | |
| 90 | int memblock_alloc_foo_checks(void) |
| 91 | { |
| 92 | reset_memblock_attributes(); /* data structure reset */ |
| 93 | dummy_physical_memory_init(); /* allocate and register memory */ |
| 94 | |
| 95 | (...allocation checks...) |
| 96 | |
| 97 | dummy_physical_memory_cleanup(); /* free the memory */ |
| 98 | } |
| 99 | |
| 100 | There's no need to explicitly free the dummy memory from memblock via |
| 101 | memblock_free() call. The entry will be erased by reset_memblock_regions(), |
| 102 | called at the beginning of each test. |
| 103 | |
| 104 | Known issues |
| 105 | ============ |
| 106 | |
| 107 | 1. Tests for memblock_alloc_low() can't be easily implemented. The function uses |
| 108 | ARCH_LOW_ADDRESS_LIMIT marco, which can't be changed to point at the low |
| 109 | memory of the memory_block. |
| 110 | |
| 111 | References |
| 112 | ========== |
| 113 | |
| 114 | 1. Boot time memory management documentation page: |
| 115 | https://www.kernel.org/doc/html/latest/core-api/boot-time-mm.html |