memblock tests: add NUMA tests for memblock_alloc_try_nid*
v2 cover memblock tests: add NUMA tests for memblock_alloc_try_nid*
These patches add additional tests for memblock_alloc_try_nid() and memblock_alloc_try_nid_raw() that use a simulated physical memory that is set up with multiple NUMA nodes. Additionally, most of these tests set nid != NUMA_NO_NODE.
To set up a simulated physical memory with multiple NUMA nodes, patch 1 introduces setup_numa_memblock_generic() and setup_numa_memblock(). These functions use a previously allocated dummy physical memory. They can be used in place of setup_memblock() in tests that need to simulate a NUMA system.
These tests are run twice, once for memblock_alloc_try_nid() and once for memblock_alloc_try_nid_raw(), so that both functions are tested with the same set of tests. When the tests run memblock_alloc_try_nid(), they test that the entire memory region is zero. When the tests run memblock_alloc_try_nid_raw(), they test that the entire memory region is nonzero.
Note:
This patch set depends on the following patch set:
https://lore.kernel.org/all/[email protected]
---
Changelog
v1 -> v2
Updates based on changes to the dependent patch set noted above:
PATCH 2, PATCH 3, PATCH 4:
- tests/alloc_nid_api.c:
- Update calls to verify_mem_content() to include the flags parameter required by the new, common verify_mem_content() function.
---
Rebecca Mckeever (4):
memblock tests: add simulation of physical memory with multiple NUMA
nodes
memblock tests: add top-down NUMA tests for memblock_alloc_try_nid* memblock tests: add bottom-up NUMA tests for memblock_alloc_try_nid* memblock tests: add generic NUMA tests for memblock_alloc_try_nid*
.../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/alloc_nid_api.c | 1489 ++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.c | 38 + tools/testing/memblock/tests/common.h | 27 +- 5 files changed, 1559 insertions(+), 13 deletions(-)
Signature · 1 line
2.25.1
PATCH v2 1/4 memblock tests: add simulation of physical memory with multiple NUMA nodes
Add functions setup_numa_memblock_generic() and setup_numa_memblock() for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place of setup_memblock() in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layout
Introduce constant MEM_FACTOR, which is used to scale the default memory layout based on MEM_SIZE.
Set CONFIG_NODES_SHIFT to 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.
--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)
tools/testing/memblock/scripts/Makefile.include +1 -1
@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.
tools/testing/memblock/tests/common.c +38 -0
@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;
@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor) +{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i]; + +memblock_add_node (base, size, i, flags); + base += size; + } +fill_memblock (); +} + +void setup_numa_memblock (void ) +{ +setup_numa_memblock_generic (node_sizes,NUMA_NODES ,MEM_FACTOR ); +} +void dummy_physical_memory_init (void ) { memory_block.base =malloc (MEM_SIZE );
tools/testing/memblock/tests/common.h +8 -1
@@ -10,7 +10,11 @@#include <linux/printk.h> #include <../selftests/kselftest.h> -#define MEM_SIZE SZ_16K +#define MEM_SIZE SZ_16K +#define NUMA_NODES 8 + +/* used to resize values that need to scale with MEM_SIZE */ +#define MEM_FACTOR (MEM_SIZE / SZ_16K)enum test_flags {TEST_ZEROED =0x0 ,
@@ -100,6 +104,9 @@ struct region {void reset_memblock_regions (void );void reset_memblock_attributes (void );void setup_memblock (void ); +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor); +void setup_numa_memblock (void );void dummy_physical_memory_init (void );void dummy_physical_memory_cleanup (void );void parse_args (int argc,char **argv);
Signature · 1 line
2.25.1
PATCH v2 2/4 memblock tests: add top-down NUMA tests for memblock_alloc_try_nid*
In reply to Rebecca MckeeverAdd tests for memblock_alloc_try_nid() and memblock_alloc_try_nid_raw() where the simulated physical memory is set up with multiple NUMA nodes. Additionally, all of these tests set nid != NUMA_NO_NODE. These tests are run with a top-down allocation direction.
The tested scenarios are:
Range unrestricted:
- region can be allocated in the specific node requested:
+ there are no previously reserved regions
+ the requested node is partially reserved but has enough space
- the specific node requested cannot accommodate the request, but the region can be allocated in a different node:
+ there are no previously reserved regions, but node is too small
+ the requested node is fully reserved
+ the requested node is partially reserved and does not have enough space
Range restricted:
- region can be allocated in the specific node requested after dropping min_addr:
+ range partially overlaps with two different nodes, where the first node is the requested node
+ range partially overlaps with two different nodes, where the requested node ends before min_addr
- region cannot be allocated in the specific node requested, but it can be allocated in the requested range:
+ range overlaps with multiple nodes along node boundaries, and the requested node ends before min_addr
+ range overlaps with multiple nodes along node boundaries, and the requested node starts after max_addr
- region cannot be allocated in the specific node requested, but it can be allocated after dropping min_addr:
+ range partially overlaps with two different nodes, where the second node is the requested node
--- tools/testing/memblock/tests/alloc_nid_api.c | 702 ++++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.h | 18 + 3 files changed, 725 insertions(+), 11 deletions(-)
tools/testing/memblock/tests/alloc_nid_api.c +691 -11
@@ -1102,7 +1102,7 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)return 0 ; } -/* Test case wrappers */ +/* Test case wrappers for range tests */ static int alloc_try_nid_simple_check (void ) {test_print ("\tRunning %s...\n" , __func__);
@@ -1234,17 +1234,10 @@ static int alloc_try_nid_low_max_check(void)return 0 ; } -static int memblock_alloc_nid_checks_internal (int flags) +static int memblock_alloc_nid_range_checks (void ) { -const char *func =get_func_testing (flags); - - alloc_nid_test_flags = flags; -prefix_reset (); -prefix_push (func); -test_print ("Running %s tests...\n" , func); - -reset_memblock_attributes (); -dummy_physical_memory_init (); +test_print ("Running %s range tests...\n" , +get_func_testing (alloc_nid_test_flags));alloc_try_nid_simple_check ();alloc_try_nid_misaligned_check ();
@@ -1261,6 +1254,693 @@ static int memblock_alloc_nid_checks_internal(int flags)alloc_try_nid_reserved_all_check ();alloc_try_nid_low_max_check (); +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* has enough memory to allocate a region of the requested size. +* Expect to allocate an aligned region at the end of the requested node. +*/ +static int alloc_try_nid_top_down_numa_simple_check (void ) +{ +int nid_req =3 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_4 ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (req_node) - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* does not have enough memory to allocate a region of the requested size: +* +* | +-----+ +------------------+ | +* | | req | | expected | | +* +---+-----+----------+------------------+-----+ +* +* | +---------+ | +* | | rgn | | +* +-----------------------------+---------+-----+ +* +* Expect to allocate an aligned region at the end of the last node that has +* enough memory (in this case, nid = 6) after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_top_down_numa_small_node_check (void ) +{ +int nid_req =1 ; +int nid_exp =6 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_2K *MEM_FACTOR ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (exp_node) - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is fully reserved: +* +* | +---------+ +------------------+ | +* | |requested| | expected | | +* +--------------+---------+------------+------------------+-----+ +* +* | +---------+ +---------+ | +* | | reserved| | new | | +* +--------------+---------+---------------------+---------+-----+ +* +* Expect to allocate an aligned region at the end of the last node that is +* large enough and has enough unreserved memory (in this case, nid = 6) after +* falling back to NUMA_NO_NODE. The region count and total size get updated. +*/ +static int alloc_try_nid_top_down_numa_node_reserved_check (void ) +{ +int nid_req =2 ; +int nid_exp =6 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[1 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_2K *MEM_FACTOR ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + +memblock_reserve (req_node->base, req_node->size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (exp_node) - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,2 ); +ASSERT_EQ (memblock.reserved.total_size, size + req_node->size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is partially reserved but has enough memory for the allocated region: +* +* | +---------------------------------------+ | +* | | requested | | +* +-----------+---------------------------------------+----------+ +* +* | +------------------+ +-----+ | +* | | reserved | | new | | +* +-----------+------------------+--------------+-----+----------+ +* +* Expect to allocate an aligned region at the end of the requested node. The +* region count and total size get updated. +*/ +static int alloc_try_nid_top_down_numa_part_reserved_check (void ) +{ +int nid_req =4 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[1 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; +struct region r1; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + r1.base = req_node->base; + r1.size =SZ_512 *MEM_FACTOR ; + size =SZ_128 *MEM_FACTOR ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + +memblock_reserve (r1.base, r1.size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (req_node) - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,2 ); +ASSERT_EQ (memblock.reserved.total_size, size + r1.size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is partially reserved and does not have enough contiguous memory for the +* allocated region: +* +* | +-----------------------+ +----------------------| +* | | requested | | expected | +* +-----------+-----------------------+---------+----------------------+ +* +* | +----------+ +-----------| +* | | reserved | | new | +* +-----------------+----------+---------------------------+-----------+ +* +* Expect to allocate an aligned region at the end of the last node that is +* large enough and has enough unreserved memory (in this case, +* nid = NUMA_NODES - 1) after falling back to NUMA_NO_NODE. The region count +* and total size get updated. +*/ +static int alloc_try_nid_top_down_numa_part_reserved_fallback_check (void ) +{ +int nid_req =4 ; +int nid_exp =NUMA_NODES -1 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[1 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; +struct region r1; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_512 *MEM_FACTOR ; + r1.base = req_node->base +SZ_256 *MEM_FACTOR ; + r1.size = size; + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + +memblock_reserve (r1.base, r1.size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (exp_node) - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,2 ); +ASSERT_EQ (memblock.reserved.total_size, size + r1.size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the first +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* | +-----------------------+-----------+ | +* | | requested | node3 | | +* +-----------+-----------------------+-----------+--------------+ +* + + +* | +-----------+ | +* | | rgn | | +* +-----------------------+-----------+--------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that +* ends at the end of the requested node. +*/ +static int alloc_try_nid_top_down_numa_split_range_low_check (void ) +{ +int nid_req =2 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t req_node_end; + +setup_numa_memblock (); + + req_node_end =region_end (req_node); + min_addr = req_node_end -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, req_node_end - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the second +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* | +--------------------------+---------+ | +* | | expected |requested| | +* +------+--------------------------+---------+----------------+ +* + + +* | +---------+ | +* | | rgn | | +* +-----------------------+---------+--------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that +* ends at the end of the first node that overlaps with the range. +*/ +static int alloc_try_nid_top_down_numa_split_range_high_check (void ) +{ +int nid_req =3 ; +int nid_exp = nid_req -1 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +setup_numa_memblock (); + + exp_node_end =region_end (exp_node); + min_addr = exp_node_end -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node_end - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the requested +* node ends before min_addr: +* +* min_addr +* | max_addr +* | | +* v v +* | +---------------+ +-------------+---------+ | +* | | requested | | node1 | node2 | | +* +----+---------------+--------+-------------+---------+----------+ +* + + +* | +---------+ | +* | | rgn | | +* +----------+---------+-------------------------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that +* ends at the end of the requested node. +*/ +static int alloc_try_nid_top_down_numa_no_overlap_split_check (void ) +{ +int nid_req =2 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *node2 = &memblock.memory.regions[6 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_512 ; + min_addr = node2->base -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (req_node) - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_add range when +* the requested node and the range do not overlap, and requested node ends +* before min_addr. The range overlaps with multiple nodes along node +* boundaries: +* +* min_addr +* | max_addr +* | | +* v v +* |-----------+ +----------+----...----+----------+ | +* | requested | | min node | ... | max node | | +* +-----------+-----------+----------+----...----+----------+------+ +* + + +* | +-----+ | +* | | rgn | | +* +---------------------------------------------------+-----+------+ +* +* Expect to allocate a cleared memory region at the end of the final node in +* the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_numa_top_down_no_overlap_low_check (void ) +{ +int nid_req =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *min_node = &memblock.memory.regions[2 ]; +struct memblock_region *max_node = &memblock.memory.regions[5 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + min_addr = min_node->base; + max_addr =region_end (max_node); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, max_addr - size); +ASSERT_LE (max_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_add range when +* the requested node and the range do not overlap, and requested node starts +* after max_addr. The range overlaps with multiple nodes along node +* boundaries: +* +* min_addr +* | max_addr +* | | +* v v +* | +----------+----...----+----------+ +-----------+ | +* | | min node | ... | max node | | requested | | +* +-----+----------+----...----+----------+--------+-----------+---+ +* + + +* | +-----+ | +* | | rgn | | +* +---------------------------------+-----+------------------------+ +* +* Expect to allocate a cleared memory region at the end of the final node in +* the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_numa_top_down_no_overlap_high_check (void ) +{ +int nid_req =7 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *min_node = &memblock.memory.regions[2 ]; +struct memblock_region *max_node = &memblock.memory.regions[5 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + min_addr = min_node->base; + max_addr =region_end (max_node); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, max_addr - size); +ASSERT_LE (max_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* Test case wrappers for NUMA tests */ +static int alloc_try_nid_numa_simple_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_simple_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_small_node_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_small_node_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_node_reserved_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_node_reserved_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_part_reserved_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_part_reserved_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_part_reserved_fallback_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_part_reserved_fallback_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_split_range_low_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_split_range_low_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_split_range_high_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_split_range_high_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_no_overlap_split_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_top_down_numa_no_overlap_split_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_no_overlap_low_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_numa_top_down_no_overlap_low_check (); + +return 0 ; +} + +static int alloc_try_nid_numa_no_overlap_high_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +memblock_set_bottom_up (false); +alloc_try_nid_numa_top_down_no_overlap_high_check (); + +return 0 ; +} + +int __memblock_alloc_nid_numa_checks (void ) +{ +test_print ("Running %s NUMA tests...\n" , +get_func_testing (alloc_nid_test_flags)); + +alloc_try_nid_numa_simple_check (); +alloc_try_nid_numa_small_node_check (); +alloc_try_nid_numa_node_reserved_check (); +alloc_try_nid_numa_part_reserved_check (); +alloc_try_nid_numa_part_reserved_fallback_check (); +alloc_try_nid_numa_split_range_low_check (); +alloc_try_nid_numa_split_range_high_check (); + +alloc_try_nid_numa_no_overlap_split_check (); +alloc_try_nid_numa_no_overlap_low_check (); +alloc_try_nid_numa_no_overlap_high_check (); + +return 0 ; +} + +static int memblock_alloc_nid_checks_internal (int flags) +{ + alloc_nid_test_flags = flags; +prefix_reset (); +prefix_push (get_func_testing (flags)); + +reset_memblock_attributes (); +dummy_physical_memory_init (); + +memblock_alloc_nid_range_checks (); +memblock_alloc_nid_numa_checks (); +dummy_physical_memory_cleanup ();prefix_pop ();
tools/testing/memblock/tests/alloc_nid_api.h +16 -0
@@ -5,5 +5,21 @@#include "common.h" int memblock_alloc_nid_checks (void ); +int __memblock_alloc_nid_numa_checks (void ); + +#ifdef CONFIG_NUMA +static inline int memblock_alloc_nid_numa_checks (void ) +{ +__memblock_alloc_nid_numa_checks (); +return 0 ; +} + +#else +static inline int memblock_alloc_nid_numa_checks (void ) +{ +return 0 ; +} + +#endif /* CONFIG_NUMA */ #endif
tools/testing/memblock/tests/common.h +18 -0
@@ -60,6 +60,19 @@ enum test_flags {assert ((_expected) < (_seen)); \ }while (0 ) +/** +* ASSERT_LE(): +* Check the condition +* @_expected <= @_seen +* If false, print failed test message (if running with --verbose) and then +* assert. + */ +#define ASSERT_LE (_expected, _seen) do { \ + if ((_expected) > (_seen)) \ + test_fail(); \ + assert((_expected) <= (_seen)); \ +} while (0) +/** * ASSERT_MEM_EQ(): * Check that the first @_size bytes of @_seen are all equal to @_expected.
@@ -101,6 +114,11 @@ struct region {phys_addr_t size; }; +static inline phys_addr_t __maybe_unused region_end (struct memblock_region *rgn) +{ +return rgn->base + rgn->size; +} +void reset_memblock_regions (void );void reset_memblock_attributes (void );void setup_memblock (void );
Signature · 1 line
2.25.1
PATCH v2 3/4 memblock tests: add bottom-up NUMA tests for memblock_alloc_try_nid*
In reply to Rebecca MckeeverAdd tests for memblock_alloc_try_nid() and memblock_alloc_try_nid_raw() where the simulated physical memory is set up with multiple NUMA nodes. Additionally, all of these tests set nid != NUMA_NO_NODE. These tests are run with a bottom-up allocation direction.
The tested scenarios are:
Range unrestricted:
- region can be allocated in the specific node requested:
+ there are no previously reserved regions
+ the requested node is partially reserved but has enough space
- the specific node requested cannot accommodate the request, but the region can be allocated in a different node:
+ there are no previously reserved regions, but node is too small
+ the requested node is fully reserved
+ the requested node is partially reserved and does not have enough space
Range restricted:
- region can be allocated in the specific node requested after dropping min_addr:
+ range partially overlaps with two different nodes, where the first node is the requested node
+ range partially overlaps with two different nodes, where the requested node ends before min_addr
- region cannot be allocated in the specific node requested, but it can be allocated in the requested range:
+ range overlaps with multiple nodes along node boundaries, and the requested node ends before min_addr
+ range overlaps with multiple nodes along node boundaries, and the requested node starts after max_addr
- region cannot be allocated in the specific node requested, but it can be allocated after dropping min_addr:
+ range partially overlaps with two different nodes, where the second node is the requested node
--- tools/testing/memblock/tests/alloc_nid_api.c | 584 +++++++++++++++++++ 1 file changed, 584 insertions(+)
tools/testing/memblock/tests/alloc_nid_api.c +584 -0
@@ -1818,12 +1818,578 @@ static int alloc_try_nid_numa_top_down_no_overlap_high_check(void)return 0 ; } +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* has enough memory to allocate a region of the requested size. +* Expect to allocate an aligned region at the beginning of the requested node. +*/ +static int alloc_try_nid_bottom_up_numa_simple_check (void ) +{ +int nid_req =3 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_4 ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, req_node->base); +ASSERT_LE (region_end (new_rgn),region_end (req_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* does not have enough memory to allocate a region of the requested size: +* +* |----------------------+-----+ | +* | expected | req | | +* +----------------------+-----+----------------+ +* +* |---------+ | +* | rgn | | +* +---------+-----------------------------------+ +* +* Expect to allocate an aligned region at the beginning of the first node that +* has enough memory (in this case, nid = 0) after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_bottom_up_numa_small_node_check (void ) +{ +int nid_req =1 ; +int nid_exp =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_2K *MEM_FACTOR ; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node->base); +ASSERT_LE (region_end (new_rgn),region_end (exp_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is fully reserved: +* +* |----------------------+ +-----------+ | +* | expected | | requested | | +* +----------------------+-----+-----------+--------------------+ +* +* |-----------+ +-----------+ | +* | new | | reserved | | +* +-----------+----------------+-----------+--------------------+ +* +* Expect to allocate an aligned region at the beginning of the first node that +* is large enough and has enough unreserved memory (in this case, nid = 0) +* after falling back to NUMA_NO_NODE. The region count and total size get +* updated. +*/ +static int alloc_try_nid_bottom_up_numa_node_reserved_check (void ) +{ +int nid_req =2 ; +int nid_exp =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_2K *MEM_FACTOR ; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + +memblock_reserve (req_node->base, req_node->size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node->base); +ASSERT_LE (region_end (new_rgn),region_end (exp_node)); + +ASSERT_EQ (memblock.reserved.cnt,2 ); +ASSERT_EQ (memblock.reserved.total_size, size + req_node->size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is partially reserved but has enough memory for the allocated region: +* +* | +---------------------------------------+ | +* | | requested | | +* +-----------+---------------------------------------+---------+ +* +* | +------------------+-----+ | +* | | reserved | new | | +* +-----------+------------------+-----+------------------------+ +* +* Expect to allocate an aligned region in the requested node that merges with +* the existing reserved region. The total size gets updated. +*/ +static int alloc_try_nid_bottom_up_numa_part_reserved_check (void ) +{ +int nid_req =4 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; +struct region r1; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t total_size; + +setup_numa_memblock (); + + r1.base = req_node->base; + r1.size =SZ_512 *MEM_FACTOR ; + size =SZ_128 *MEM_FACTOR ; + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + total_size = size + r1.size; + +memblock_reserve (r1.base, r1.size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, total_size); +ASSERT_EQ (new_rgn->base, req_node->base); +ASSERT_LE (region_end (new_rgn),region_end (req_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, total_size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* is partially reserved and does not have enough contiguous memory for the +* allocated region: +* +* |----------------------+ +-----------------------+ | +* | expected | | requested | | +* +----------------------+-------+-----------------------+---------+ +* +* |-----------+ +----------+ | +* | new | | reserved | | +* +-----------+------------------------+----------+----------------+ +* +* Expect to allocate an aligned region at the beginning of the first +* node that is large enough and has enough unreserved memory (in this case, +* nid = 0) after falling back to NUMA_NO_NODE. The region count and total size +* get updated. +*/ +static int alloc_try_nid_bottom_up_numa_part_reserved_fallback_check (void ) +{ +int nid_req =4 ; +int nid_exp =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; +struct region r1; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_512 *MEM_FACTOR ; + r1.base = req_node->base +SZ_256 *MEM_FACTOR ; + r1.size = size; + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + +memblock_reserve (r1.base, r1.size); + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node->base); +ASSERT_LE (region_end (new_rgn),region_end (exp_node)); + +ASSERT_EQ (memblock.reserved.cnt,2 ); +ASSERT_EQ (memblock.reserved.total_size, size + r1.size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the first +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* | +-----------------------+-----------+ | +* | | requested | node3 | | +* +-----------+-----------------------+-----------+--------------+ +* + + +* | +-----------+ | +* | | rgn | | +* +-----------+-----------+--------------------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region at the +* beginning of the requested node. +*/ +static int alloc_try_nid_bottom_up_numa_split_range_low_check (void ) +{ +int nid_req =2 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t req_node_end; + +setup_numa_memblock (); + + req_node_end =region_end (req_node); + min_addr = req_node_end -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, req_node->base); +ASSERT_LE (region_end (new_rgn), req_node_end); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the second +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* |------------------+ +----------------------+---------+ | +* | expected | | previous |requested| | +* +------------------+--------+----------------------+---------+------+ +* + + +* |---------+ | +* | rgn | | +* +---------+---------------------------------------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region at the +* beginning of the first node that has enough memory. +*/ +static int alloc_try_nid_bottom_up_numa_split_range_high_check (void ) +{ +int nid_req =3 ; +int nid_exp =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +setup_numa_memblock (); + + exp_node_end =region_end (req_node); + min_addr = req_node->base -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node->base); +ASSERT_LE (region_end (new_rgn), exp_node_end); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the requested +* node ends before min_addr: +* +* min_addr +* | max_addr +* | | +* v v +* | +---------------+ +-------------+---------+ | +* | | requested | | node1 | node2 | | +* +----+---------------+--------+-------------+---------+---------+ +* + + +* | +---------+ | +* | | rgn | | +* +----+---------+------------------------------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that +* starts at the beginning of the requested node. +*/ +static int alloc_try_nid_bottom_up_numa_no_overlap_split_check (void ) +{ +int nid_req =2 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *node2 = &memblock.memory.regions[6 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + size =SZ_512 ; + min_addr = node2->base -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, req_node->base); +ASSERT_LE (region_end (new_rgn),region_end (req_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_add range when +* the requested node and the range do not overlap, and requested node ends +* before min_addr. The range overlaps with multiple nodes along node +* boundaries: +* +* min_addr +* | max_addr +* | | +* v v +* |-----------+ +----------+----...----+----------+ | +* | requested | | min node | ... | max node | | +* +-----------+-----------+----------+----...----+----------+------+ +* + + +* | +-----+ | +* | | rgn | | +* +-----------------------+-----+----------------------------------+ +* +* Expect to allocate a cleared memory region at the beginning of the first node +* in the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_numa_bottom_up_no_overlap_low_check (void ) +{ +int nid_req =0 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *min_node = &memblock.memory.regions[2 ]; +struct memblock_region *max_node = &memblock.memory.regions[5 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + min_addr = min_node->base; + max_addr =region_end (max_node); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, min_addr); +ASSERT_LE (region_end (new_rgn),region_end (min_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_add range when +* the requested node and the range do not overlap, and requested node starts +* after max_addr. The range overlaps with multiple nodes along node +* boundaries: +* +* min_addr +* | max_addr +* | | +* v v +* | +----------+----...----+----------+ +---------+ | +* | | min node | ... | max node | |requested| | +* +-----+----------+----...----+----------+---------+---------+---+ +* + + +* | +-----+ | +* | | rgn | | +* +-----+-----+---------------------------------------------------+ +* +* Expect to allocate a cleared memory region at the beginning of the first node +* in the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_numa_bottom_up_no_overlap_high_check (void ) +{ +int nid_req =7 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *min_node = &memblock.memory.regions[2 ]; +struct memblock_region *max_node = &memblock.memory.regions[5 ]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + min_addr = min_node->base; + max_addr =region_end (max_node); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, min_addr); +ASSERT_LE (region_end (new_rgn),region_end (min_node)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} +/* Test case wrappers for NUMA tests */ static int alloc_try_nid_numa_simple_check (void ) {test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_simple_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_simple_check ();return 0 ; }
@@ -1833,6 +2399,8 @@ static int alloc_try_nid_numa_small_node_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_small_node_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_small_node_check ();return 0 ; }
@@ -1842,6 +2410,8 @@ static int alloc_try_nid_numa_node_reserved_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_node_reserved_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_node_reserved_check ();return 0 ; }
@@ -1851,6 +2421,8 @@ static int alloc_try_nid_numa_part_reserved_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_part_reserved_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_part_reserved_check ();return 0 ; }
@@ -1860,6 +2432,8 @@ static int alloc_try_nid_numa_part_reserved_fallback_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_part_reserved_fallback_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_part_reserved_fallback_check ();return 0 ; }
@@ -1869,6 +2443,8 @@ static int alloc_try_nid_numa_split_range_low_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_split_range_low_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_split_range_low_check ();return 0 ; }
@@ -1878,6 +2454,8 @@ static int alloc_try_nid_numa_split_range_high_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_split_range_high_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_split_range_high_check ();return 0 ; }
@@ -1887,6 +2465,8 @@ static int alloc_try_nid_numa_no_overlap_split_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_top_down_numa_no_overlap_split_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_no_overlap_split_check ();return 0 ; }
@@ -1896,6 +2476,8 @@ static int alloc_try_nid_numa_no_overlap_low_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_numa_top_down_no_overlap_low_check (); +memblock_set_bottom_up (true); +alloc_try_nid_numa_bottom_up_no_overlap_low_check ();return 0 ; }
@@ -1905,6 +2487,8 @@ static int alloc_try_nid_numa_no_overlap_high_check(void)test_print ("\tRunning %s...\n" , __func__);memblock_set_bottom_up (false);alloc_try_nid_numa_top_down_no_overlap_high_check (); +memblock_set_bottom_up (true); +alloc_try_nid_numa_bottom_up_no_overlap_high_check ();return 0 ; }
Signature · 1 line
2.25.1
PATCH v2 4/4 memblock tests: add generic NUMA tests for memblock_alloc_try_nid*
In reply to Rebecca MckeeverAdd tests for memblock_alloc_try_nid() and memblock_alloc_try_nid_raw() where the simulated physical memory is set up with multiple NUMA nodes. Additionally, two of these tests set nid != NUMA_NO_NODE. All tests are run for both top-down and bottom-up allocation directions.
The tested scenarios are:
Range unrestricted:
- region cannot be allocated:
+ none of the nodes have enough memory to allocate the region
Range restricted:
- region can be allocated in the specific node requested without dropping min_addr:
+ the range fully overlaps with the node, and there are adjacent reserved regions
- region cannot be allocated:
+ nid is set to NUMA_NO_NODE and the total range can fit the region, but the range is split between two nodes and everything else is reserved
--- tools/testing/memblock/tests/alloc_nid_api.c | 203 +++++++++++++++++++ 1 file changed, 203 insertions(+)
tools/testing/memblock/tests/alloc_nid_api.c +203 -0
@@ -2382,6 +2382,179 @@ static int alloc_try_nid_numa_bottom_up_no_overlap_high_check(void)return 0 ; } +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* does not have enough memory to allocate a region of the requested size. +* Additionally, none of the nodes have enough memory to allocate the region: +* +* +-----------------------------------+ +* | new | +* +-----------------------------------+ +* |-------+-------+-------+-------+-------+-------+-------+-------| +* | node0 | node1 | node2 | node3 | node4 | node5 | node6 | node7 | +* +-------+-------+-------+-------+-------+-------+-------+-------+ +* +* Expect no allocation to happen. +*/ +static int alloc_try_nid_generic_numa_large_region_check (void ) +{ +int nid_req =3 ; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_8K *MEM_FACTOR ; +phys_addr_t min_addr; +phys_addr_t max_addr; + +setup_numa_memblock (); + + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); +ASSERT_EQ (allocated_ptr,NULL ); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_addr range when +* there are two reserved regions at the borders. The requested node starts at +* min_addr and ends at max_addr and is the same size as the region to be +* allocated: +* +* min_addr +* | max_addr +* | | +* v v +* | +-----------+-----------------------+-----------------------| +* | | node5 | requested | node7 | +* +------+-----------+-----------------------+-----------------------+ +* + + +* | +----+-----------------------+----+ | +* | | r2 | new | r1 | | +* +-------------+----+-----------------------+----+------------------+ +* +* Expect to merge all of the regions into one. The region counter and total +* size fields get updated. +*/ +static int alloc_try_nid_numa_reserved_full_merge_generic_check (void ) +{ +int nid_req =6 ; +int nid_next = nid_req +1 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *next_node = &memblock.memory.regions[nid_next]; +void *allocated_ptr =NULL ; +struct region r1, r2; + +PREFIX_PUSH (); + +phys_addr_t size = req_node->size; +phys_addr_t total_size; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + r1.base = next_node->base; + r1.size =SZ_128 ; + + r2.size =SZ_128 ; + r2.base = r1.base - (size + r2.size); + + total_size = r1.size + r2.size + size; + min_addr = r2.base + r2.size; + max_addr = r1.base; + +memblock_reserve (r1.base, r1.size); +memblock_reserve (r2.base, r2.size); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, total_size); +ASSERT_EQ (new_rgn->base, r2.base); + +ASSERT_LE (new_rgn->base, req_node->base); +ASSERT_LE (region_end (req_node),region_end (new_rgn)); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, total_size); + +test_pass_pop (); + +return 0 ; +} + +/* +* A test that tries to allocate memory within min_addr and max_add range, +* where the total range can fit the region, but it is split between two nodes +* and everything else is reserved. Additionally, nid is set to NUMA_NO_NODE +* instead of requesting a specific node: +* +* +-----------+ +* | new | +* +-----------+ +* | +---------------------+-----------| +* | | prev node | next node | +* +------+---------------------+-----------+ +* + + +* |----------------------+ +-----| +* | r1 | | r2 | +* +----------------------+-----------+-----+ +* ^ ^ +* | | +* | max_addr +* | +* min_addr +* +* Expect no allocation to happen. +*/ +static int alloc_try_nid_numa_split_all_reserved_generic_check (void ) +{ +void *allocated_ptr =NULL ; +struct memblock_region *next_node = &memblock.memory.regions[7 ]; +struct region r1, r2; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_256 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +setup_numa_memblock (); + + r2.base = next_node->base +SZ_128 ; + r2.size =memblock_end_of_DRAM () - r2.base; + + r1.size =MEM_SIZE - (r2.size + size); + r1.base =memblock_start_of_DRAM (); + + min_addr = r1.base + r1.size; + max_addr = r2.base; + +memblock_reserve (r1.base, r1.size); +memblock_reserve (r2.base, r2.size); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, +NUMA_NO_NODE ); + +ASSERT_EQ (allocated_ptr,NULL ); + +test_pass_pop (); + +return 0 ; +} +/* Test case wrappers for NUMA tests */ static int alloc_try_nid_numa_simple_check (void ) {
@@ -2493,6 +2666,33 @@ static int alloc_try_nid_numa_no_overlap_high_check(void)return 0 ; } +static int alloc_try_nid_numa_large_region_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +run_top_down (alloc_try_nid_generic_numa_large_region_check); +run_bottom_up (alloc_try_nid_generic_numa_large_region_check); + +return 0 ; +} + +static int alloc_try_nid_numa_reserved_full_merge_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +run_top_down (alloc_try_nid_numa_reserved_full_merge_generic_check); +run_bottom_up (alloc_try_nid_numa_reserved_full_merge_generic_check); + +return 0 ; +} + +static int alloc_try_nid_numa_split_all_reserved_check (void ) +{ +test_print ("\tRunning %s...\n" , __func__); +run_top_down (alloc_try_nid_numa_split_all_reserved_generic_check); +run_bottom_up (alloc_try_nid_numa_split_all_reserved_generic_check); + +return 0 ; +} +int __memblock_alloc_nid_numa_checks (void ) { test_print("Running %s NUMA tests...\n",
@@ -2509,6 +2709,9 @@ int __memblock_alloc_nid_numa_checks(void)alloc_try_nid_numa_no_overlap_split_check ();alloc_try_nid_numa_no_overlap_low_check ();alloc_try_nid_numa_no_overlap_high_check (); +alloc_try_nid_numa_large_region_check (); +alloc_try_nid_numa_reserved_full_merge_check (); +alloc_try_nid_numa_split_all_reserved_check ();return 0 ; }
Signature · 1 line
2.25.1
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to Rebecca MckeeverQuoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];
I'm a bit lost why we need the factor if we already provide sizes in the array.
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Signature · 3 lines
Thanks, David / dhildenb
Re: [PATCH v2 2/4] memblock tests: add top-down NUMA tests for memblock_alloc_try_nid*
In reply to Rebecca MckeeverQuoted 91 lines · Rebecca Mckeever
Add tests for
memblock_alloc_try_nid()andmemblock_alloc_try_nid_raw()where the simulated physical memory is set up with multiple NUMA nodes. Additionally, all of these tests set nid !=NUMA_NO_NODE. These tests are run with a top-down allocation direction.The tested scenarios are:
Range unrestricted:
- region can be allocated in the specific node requested:
+ there are no previously reserved regions
+ the requested node is partially reserved but has enough space
- the specific node requested cannot accommodate the request, but the region can be allocated in a different node:
+ there are no previously reserved regions, but node is too small
+ the requested node is fully reserved
+ the requested node is partially reserved and does not have enough spaceRange restricted:
- region can be allocated in the specific node requested after droppingmin_addr:
+ range partially overlaps with two different nodes, where the first node is the requested node
+ range partially overlaps with two different nodes, where the requested node ends beforemin_addr
- region cannot be allocated in the specific node requested, but it can be allocated in the requested range:
+ range overlaps with multiple nodes along node boundaries, and the requested node ends beforemin_addr
+ range overlaps with multiple nodes along node boundaries, and the requested node starts aftermax_addr
- region cannot be allocated in the specific node requested, but it can be allocated after droppingmin_addr:
+ range partially overlaps with two different nodes, where the second node is the requested nodeSigned-off-by Rebecca Mckeever <[email protected]>--- tools/testing/memblock/tests/alloc_nid_api.c | 702 ++++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.h | 18 + 3 files changed, 725 insertions(+), 11 deletions(-)tools/testing/memblock/tests/alloc_nid_api.c +14
-11@@ -1102,7 +1102,7 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)return 0 ; } -/* Test case wrappers */ +/* Test case wrappers for range tests */ static int alloc_try_nid_simple_check (void ) {test_print ("\tRunning %s...\n" , __func__);@@ -1234,17 +1234,10 @@ static int alloc_try_nid_low_max_check(void)return 0 ; } -static int memblock_alloc_nid_checks_internal (int flags) +static int memblock_alloc_nid_range_checks (void ) { -const char *func =get_func_testing (flags); - - alloc_nid_test_flags = flags; -prefix_reset (); -prefix_push (func); -test_print ("Running %s tests...\n" , func); - -reset_memblock_attributes (); -dummy_physical_memory_init (); +test_print ("Running %s range tests...\n" , +get_func_testing (alloc_nid_test_flags));alloc_try_nid_simple_check ();alloc_try_nid_misaligned_check ();@@ -1261,6 +1254,693 @@ static int memblock_alloc_nid_checks_internal(int flags)alloc_try_nid_reserved_all_check ();alloc_try_nid_low_max_check (); +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* has enough memory to allocate a region of the requested size. +* Expect to allocate an aligned region at the end of the requested node. +*/ +static int alloc_try_nid_top_down_numa_simple_check (void ) +{
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1276
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +10
-0+int nid_req =3 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr;
Usually we define variables in a single block. So, before the PREFIX_PUSH(). Same applies to the other functions.
Quoted 26 lines
tools/testing/memblock/tests/alloc_nid_api.c +26
-0+ +setup_numa_memblock (); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_4 ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (req_node) - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} +
[...]
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +10
-0+ +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the first +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1548
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +10
-0+* | +-----------------------+-----------+ | +* | | requested | node3 | | +* +-----------+-----------------------+-----------+--------------+ +* + + +* | +-----------+ | +* | | rgn | | +* +-----------------------+-----------+--------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that +* ends at the end of the requested node.
Interesting, allocating out-of-range is expected behavior? At least to me that wasn't immediately clear :)
[...]
Quoted 9 lines
tools/testing/memblock/tests/alloc_nid_api.c +9
-0+ +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the second +* node is the requested node: +* +* min_addr +* | max_addr +* | |
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1605
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +10
-0+* v v +* | +--------------------------+---------+ | +* | | expected |requested| | +* +------+--------------------------+---------+----------------+ +* + + +* | +---------+ | +* | | rgn | | +* +-----------------------+---------+--------------------------+ +* +* Expect to drop the lower limit and allocate a cleared memory region that
Does the "cleared memory region" part still apply? Or would we also end up calling the raw variant from run_memblock_alloc_try_nid() ?
Quoted 40 lines
+ * ends at the end of the first node that overlaps with the range.
+ */tools/testing/memblock/tests/alloc_nid_api.c +38
-0+static int alloc_try_nid_top_down_numa_split_range_high_check (void ) +{ +int nid_req =3 ; +int nid_exp = nid_req -1 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +setup_numa_memblock (); + + exp_node_end =region_end (exp_node); + min_addr = exp_node_end -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node_end - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +}
[...]
Quoted 13 lines
tools/testing/memblock/tests/alloc_nid_api.c +13
-0+int __memblock_alloc_nid_numa_checks (void ) +{ +test_print ("Running %s NUMA tests...\n" , +get_func_testing (alloc_nid_test_flags)); + +alloc_try_nid_numa_simple_check (); +alloc_try_nid_numa_small_node_check (); +alloc_try_nid_numa_node_reserved_check (); +alloc_try_nid_numa_part_reserved_check (); +alloc_try_nid_numa_part_reserved_fallback_check (); +alloc_try_nid_numa_split_range_low_check (); +alloc_try_nid_numa_split_range_high_check (); +
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1934
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +10
-0+alloc_try_nid_numa_no_overlap_split_check (); +alloc_try_nid_numa_no_overlap_low_check (); +alloc_try_nid_numa_no_overlap_high_check (); + +return 0 ; +} + +static int memblock_alloc_nid_checks_internal (int flags) +{ + alloc_nid_test_flags = flags;
Empty line missing
Quoted 12 lines
tools/testing/memblock/tests/alloc_nid_api.c +9
-0+prefix_reset (); +prefix_push (get_func_testing (flags)); + +reset_memblock_attributes (); +dummy_physical_memory_init (); + +memblock_alloc_nid_range_checks (); +memblock_alloc_nid_numa_checks (); +dummy_physical_memory_cleanup ();prefix_pop ();
Signature · 3 lines
Thanks, David / dhildenb
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to David HildenbrandQuoted 85 lines · David Hildenbrand
Quoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];I'm a bit lost why we need the factor if we already provide sizes in the array.
Quoted 4 lines
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Without the factor, some of the tests will break if we increase MEM_SIZE in the future (which we may need to do). I could rewrite them so that the factor is not needed, but I thought the code would be over-complicated if I did.
Quoted 5 lines
Signature · 3 lines
Thanks, David / dhildenb
Thanks,
Rebecca
Mike Rapoport
maintainerRe: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
Quoted 86 lines · Rebecca Mckeever
Quoted 85 lines · David Hildenbrand
Quoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];I'm a bit lost why we need the factor if we already provide sizes in the array.
Quoted 8 lines
Quoted 4 lines
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Without the factor, some of the tests will break if we increase
MEM_SIZEin the future (which we may need to do). I could rewrite them so that the factor is not needed, but I thought the code would be over-complicated if I did.
What if we make nodes[] to represent the fraction of the memory rather than a node size? Then the factor won't be required.
Quoted 2 lines
Thanks,
Rebecca
Signature · 2 lines
Sincerely yours, Mike.
Mike Rapoport
maintainerRe: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to Rebecca MckeeverQuoted 25 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)
...
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 90
Quoted 12 lines
tools/testing/memblock/tests/common.c +12
-0+/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)
I only had time for a quick look and it seems this function is never used on its own.
Let's fold it into setup_numa_memblock() for now.
Quoted 22 lines
tools/testing/memblock/tests/common.c +22
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i]; + +memblock_add_node (base, size, i, flags); + base += size; + } +fill_memblock (); +} + +void setup_numa_memblock (void ) +{ +setup_numa_memblock_generic (node_sizes,NUMA_NODES ,MEM_FACTOR ); +} +
Signature · 2 lines
Sincerely yours, Mike.
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to Rebecca MckeeverQuoted 86 lines · Rebecca Mckeever
Quoted 85 lines · David Hildenbrand
Quoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];I'm a bit lost why we need the factor if we already provide sizes in the array.
Quoted 8 lines
Quoted 4 lines
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Without the factor, some of the tests will break if we increase
MEM_SIZEin the future (which we may need to do). I could rewrite them so that the factor is not needed, but I thought the code would be over-complicated if I did.
Independent of the suggestion from Mike, I wonder if we should really care about (eventual) MEM_SIZE changes for now if not caring simplifies the current code.
Signature · 3 lines
Thanks, David / dhildenb
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to Mike RapoportQuoted 91 lines · Mike Rapoport
Quoted 90 lines · Rebecca Mckeever
Quoted 89 lines · David Hildenbrand
Quoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];I'm a bit lost why we need the factor if we already provide sizes in the array.
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Quoted 8 lines
Quoted 4 lines
Without the factor, some of the tests will break if we increase
MEM_SIZEin the future (which we may need to do). I could rewrite them so that the factor is not needed, but I thought the code would be over-complicated if I did.What if we make nodes[] to represent the fraction of the memory rather than a node size? Then the factor won't be required.
I think that will work. I'll try it.
Quoted 6 lines
Quoted 2 lines
Thanks,
RebeccaSignature · 2 lines
Sincerely yours, Mike.
Thanks,
Rebecca
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to David HildenbrandQuoted 91 lines · David Hildenbrand
Quoted 90 lines · Rebecca Mckeever
Quoted 89 lines · David Hildenbrand
Quoted 70 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)tools/testing/memblock/scripts/Makefile.include +1
-1@@ -3,7 +3,7 @@ # Simulate CONFIG_NUMA=y ifeq ($(NUMA), 1) - CFLAGS += -D CONFIG_NUMA + CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4 endif # Use 32 bit physical addresses.tools/testing/memblock/tests/common.c +16
-0@@ -34,6 +34,10 @@ static const char * const help_opts[] = {static int verbose; +static const phys_addr_t node_sizes[] = { +SZ_4K ,SZ_1K ,SZ_2K ,SZ_2K ,SZ_1K ,SZ_1K ,SZ_4K ,SZ_1K +}; +/* sets global variable returned by movable_node_is_enabled() stub */ bool movable_node_enabled;@@ -72,6 +76,40 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)tools/testing/memblock/tests/common.c void setup_memblock(void) · line 100
Quoted 10 lines
tools/testing/memblock/tests/common.c +10
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i];I'm a bit lost why we need the factor if we already provide sizes in the array.
Can you enlighten me? :)
Why can't we just stick to the sizes in the array?
Quoted 9 lines
Quoted 4 lines
Without the factor, some of the tests will break if we increase
MEM_SIZEin the future (which we may need to do). I could rewrite them so that the factor is not needed, but I thought the code would be over-complicated if I did.Independent of the suggestion from Mike, I wonder if we should really care about (eventual)
MEM_SIZEchanges for now if not caring simplifies the current code.
Maybe not. I'm going to try Mike's suggestion, but I will keep this in mind if the code seems too complicated.
Quoted 5 lines
Signature · 3 lines
Thanks, David / dhildenb
Thanks,
Rebecca
Re: [PATCH v2 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
In reply to Mike RapoportQuoted 29 lines · Mike Rapoport
Quoted 25 lines · Rebecca Mckeever
Add functions
setup_numa_memblock_generic()andsetup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. These functions can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock_generic():
- allows for setting up a custom memory layout by specifying the amount of memory in each node, the number of nodes, and a factor that will be used to scale the memory in each node
setup_numa_memblock():
- allows for setting up a default memory layoutIntroduce constant
MEM_FACTOR, which is used to scale the default memory layout based onMEM_SIZE.Set
CONFIG_NODES_SHIFTto 4 when building with NUMA=1 to allow for up to 16 NUMA nodes.Signed-off-by Rebecca Mckeever <[email protected]>--- .../testing/memblock/scripts/Makefile.include | 2 +- tools/testing/memblock/tests/common.c | 38 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 9 ++++- 3 files changed, 47 insertions(+), 2 deletions(-)...
Quoted 17 lines
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 90
Quoted 12 lines
tools/testing/memblock/tests/common.c +12
-0+/** +* setup_numa_memblock_generic: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the amount of memory in each node +* @node_cnt: the size of @nodes +* @factor: a factor that will be used to scale the memory in each node +* +* The nids will be set to 0 through node_cnt - 1. +*/ +void setup_numa_memblock_generic (const phys_addr_t nodes[], +int node_cnt,int factor)I only had time for a quick look and it seems this function is never used on its own.
Let's fold it intosetup_numa_memblock()for now.
Okay, will do.
Quoted 14 lines
Quoted 14 lines
tools/testing/memblock/tests/common.c +14
-0+{ +phys_addr_t base; +int flags; + +reset_memblock_regions (); + base = (phys_addr_t )memory_block.base; + flags = (movable_node_is_enabled ()) ?MEMBLOCK_NONE :MEMBLOCK_HOTPLUG ; + +for (int i =0 ; i < node_cnt; i++) { +phys_addr_t size = factor * nodes[i]; + +memblock_add_node (base, size, i, flags); + base += size; + }
Quoted 12 lines
Quoted 8 lines
tools/testing/memblock/tests/common.c +8
-0+fill_memblock (); +} + +void setup_numa_memblock (void ) +{ +setup_numa_memblock_generic (node_sizes,NUMA_NODES ,MEM_FACTOR ); +} +Signature · 2 lines
Sincerely yours, Mike.
Thanks,
Rebecca
Re: [PATCH v2 2/4] memblock tests: add top-down NUMA tests for memblock_alloc_try_nid*
In reply to David HildenbrandQuoted 97 lines · David Hildenbrand
Quoted 96 lines · Rebecca Mckeever
Add tests for
memblock_alloc_try_nid()andmemblock_alloc_try_nid_raw()where the simulated physical memory is set up with multiple NUMA nodes. Additionally, all of these tests set nid !=NUMA_NO_NODE. These tests are run with a top-down allocation direction.The tested scenarios are:
Range unrestricted:
- region can be allocated in the specific node requested:
+ there are no previously reserved regions
+ the requested node is partially reserved but has enough space
- the specific node requested cannot accommodate the request, but the region can be allocated in a different node:
+ there are no previously reserved regions, but node is too small
+ the requested node is fully reserved
+ the requested node is partially reserved and does not have enough spaceRange restricted:
- region can be allocated in the specific node requested after droppingmin_addr:
+ range partially overlaps with two different nodes, where the first node is the requested node
+ range partially overlaps with two different nodes, where the requested node ends beforemin_addr
- region cannot be allocated in the specific node requested, but it can be allocated in the requested range:
+ range overlaps with multiple nodes along node boundaries, and the requested node ends beforemin_addr
+ range overlaps with multiple nodes along node boundaries, and the requested node starts aftermax_addr
- region cannot be allocated in the specific node requested, but it can be allocated after droppingmin_addr:
+ range partially overlaps with two different nodes, where the second node is the requested nodeSigned-off-by Rebecca Mckeever <[email protected]>--- tools/testing/memblock/tests/alloc_nid_api.c | 702 ++++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.h | 18 + 3 files changed, 725 insertions(+), 11 deletions(-)tools/testing/memblock/tests/alloc_nid_api.c +19
-11@@ -1102,7 +1102,7 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)return 0 ; } -/* Test case wrappers */ +/* Test case wrappers for range tests */ static int alloc_try_nid_simple_check (void ) {test_print ("\tRunning %s...\n" , __func__);@@ -1234,17 +1234,10 @@ static int alloc_try_nid_low_max_check(void)return 0 ; } -static int memblock_alloc_nid_checks_internal (int flags) +static int memblock_alloc_nid_range_checks (void ) { -const char *func =get_func_testing (flags); - - alloc_nid_test_flags = flags; -prefix_reset (); -prefix_push (func); -test_print ("Running %s tests...\n" , func); - -reset_memblock_attributes (); -dummy_physical_memory_init (); +test_print ("Running %s range tests...\n" , +get_func_testing (alloc_nid_test_flags));alloc_try_nid_simple_check ();alloc_try_nid_misaligned_check ();@@ -1261,6 +1254,693 @@ static int memblock_alloc_nid_checks_internal(int flags)alloc_try_nid_reserved_all_check ();alloc_try_nid_low_max_check (); +return 0 ; +} + +/* +* A test that tries to allocate a memory region in a specific NUMA node that +* has enough memory to allocate a region of the requested size. +* Expect to allocate an aligned region at the end of the requested node. +*/ +static int alloc_try_nid_top_down_numa_simple_check (void ) +{ +int nid_req =3 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +void *allocated_ptr =NULL ; +
Quoted 9 lines
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1276
Quoted 5 lines
tools/testing/memblock/tests/alloc_nid_api.c +5
-0+PREFIX_PUSH (); + +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr;Usually we define variables in a single block. So, before the
PREFIX_PUSH(). Same applies to the other functions.
Got it.
Quoted 44 lines
Quoted 26 lines
tools/testing/memblock/tests/alloc_nid_api.c +26
-0+ +setup_numa_memblock (); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_4 ; + min_addr =memblock_start_of_DRAM (); + max_addr =memblock_end_of_DRAM (); + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base,region_end (req_node) - size); +ASSERT_LE (req_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +} +[...]
Quoted 15 lines
tools/testing/memblock/tests/alloc_nid_api.c +15
-0+ +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the first +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* | +-----------------------+-----------+ | +* | | requested | node3 | | +* +-----------+-----------------------+-----------+--------------+ +* + + +* | +-----------+ |
Quoted 9 lines
Quoted 5 lines
+ * | | rgn | |
+ * +-----------------------+-----------+--------------------------+
+ *
+ * Expect to drop the lower limit and allocate a cleared memory region that
+ * ends at the end of the requested node.Interesting, allocating out-of-range is expected behavior? At least to me that wasn't immediately clear :)
Yeah, it seems that memblock avoids allocations that would overlap with more than one node. Do you think I should explain that in the comment?
Quoted 16 lines
[...]
Quoted 14 lines
tools/testing/memblock/tests/alloc_nid_api.c +14
-0+ +/* +* A test that tries to allocate a memory region that spans over the min_addr +* and max_addr range and overlaps with two different nodes, where the second +* node is the requested node: +* +* min_addr +* | max_addr +* | | +* v v +* | +--------------------------+---------+ | +* | | expected |requested| | +* +------+--------------------------+---------+----------------+ +* + +
Quoted 9 lines
Quoted 5 lines
+ * | +---------+ | + * | | rgn | | + * +-----------------------+---------+--------------------------++ *
+ * Expect to drop the lower limit and allocate a cleared memory region thatDoes the "cleared memory region" part still apply? Or would we also end up calling the raw variant from
run_memblock_alloc_try_nid()?
No, it doesn't apply. Thanks for catching this. I should probably add another patch to update the wording in the pre-existing tests too.
Quoted 61 lines
Quoted 40 lines
+ * ends at the end of the first node that overlaps with the range.
+ */tools/testing/memblock/tests/alloc_nid_api.c +38
-0+static int alloc_try_nid_top_down_numa_split_range_high_check (void ) +{ +int nid_req =3 ; +int nid_exp = nid_req -1 ; +struct memblock_region *new_rgn = &memblock.reserved.regions[0 ]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; + +PREFIX_PUSH (); + +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +setup_numa_memblock (); + + exp_node_end =region_end (exp_node); + min_addr = exp_node_end -SZ_256 ; + max_addr = min_addr + size; + + allocated_ptr =run_memblock_alloc_try_nid (size,SMP_CACHE_BYTES , + min_addr, max_addr, nid_req); + +ASSERT_NE (allocated_ptr,NULL ); +verify_mem_content (allocated_ptr, size, alloc_nid_test_flags); + +ASSERT_EQ (new_rgn->size, size); +ASSERT_EQ (new_rgn->base, exp_node_end - size); +ASSERT_LE (exp_node->base, new_rgn->base); + +ASSERT_EQ (memblock.reserved.cnt,1 ); +ASSERT_EQ (memblock.reserved.total_size, size); + +test_pass_pop (); + +return 0 ; +}[...]
Quoted 17 lines
tools/testing/memblock/tests/alloc_nid_api.c +17
-0+int __memblock_alloc_nid_numa_checks (void ) +{ +test_print ("Running %s NUMA tests...\n" , +get_func_testing (alloc_nid_test_flags)); + +alloc_try_nid_numa_simple_check (); +alloc_try_nid_numa_small_node_check (); +alloc_try_nid_numa_node_reserved_check (); +alloc_try_nid_numa_part_reserved_check (); +alloc_try_nid_numa_part_reserved_fallback_check (); +alloc_try_nid_numa_split_range_low_check (); +alloc_try_nid_numa_split_range_high_check (); + +alloc_try_nid_numa_no_overlap_split_check (); +alloc_try_nid_numa_no_overlap_low_check (); +alloc_try_nid_numa_no_overlap_high_check (); +
Quoted 9 lines
tools/testing/memblock/tests/alloc_nid_api.c static int memblock_alloc_nid_checks_internal(int flags) · line 1934
Quoted 6 lines
tools/testing/memblock/tests/alloc_nid_api.c +6
-0+return 0 ; +} + +static int memblock_alloc_nid_checks_internal (int flags) +{ + alloc_nid_test_flags = flags;Empty line missing
Got it.
Quoted 11 lines
Quoted 11 lines
tools/testing/memblock/tests/alloc_nid_api.c +9
-0+prefix_reset (); +prefix_push (get_func_testing (flags)); + +reset_memblock_attributes (); +dummy_physical_memory_init (); + +memblock_alloc_nid_range_checks (); +memblock_alloc_nid_numa_checks (); +dummy_physical_memory_cleanup ();
Quoted 9 lines
Quoted 1 line
prefix_pop();Signature · 3 lines
Thanks, David / dhildenb
Thanks,
Rebecca