memblock tests: add NUMA tests for memblock_alloc_try_nid*
v4 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(). This function uses a previously allocated dummy physical memory. It 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.
---
Changelog
v3 -> v4
Based on feedback from David Hildenbrand:
PATCH 1:
- tests/common.h:
+ Remove #define MEM_FACTOR
PATCH 2:
- tests/alloc_nid_api.c:
+ Add missing blank line after alloc_nid_test_flags = flags;
PATCH 2, PATCH 3, PATCH 4:
- tests/alloc_nid_api.c:
+ Define variables in new tests in a single block
+ Change "cleared memory region" to "memory region" in comment blocks for new tests
Based on feedback from Mike Rapoport:
PATCH 1:
- tests/common.c:
+ Remove node_sizes[] array
- tests/common.c, tests/common.h:
+ Combine setup_numa_memblock_generic() and setup_numa_memblock():
* Remove setup_numa_memblock(void)
* Change setup_numa_memblock_generic() to setup_numa_memblock() and remove the factor and node_cnt parameters
* Change nodes[] parameter to an array containing the denominators of the fractions of MEM_SIZE contained in each node e.g., if nodes[0] = SZ_8, node 0 will contain 1/8th of MEM_SIZE
PATCH 2:
- tests/alloc_nid_api.c:
+ Add node_fractions[] array:
* Based on values from node_sizes[] array previously in PATCH 1
* Update to fit the new nodes[] parameter of setup_numa_memblock()
v2 -> v3
PATCH 2, PATCH 3, PATCH 4:
- tests/alloc_nid_api.c:
+ Edits for consistency between tests and test naming styles:
* Change "numa_top_down" to "top_down_numa"
* Change "numa_bottom_up" to "bottom_up_numa"
* Move "generic" to immediately before "check"
* alloc_try_nid_bottom_up_numa_small_node_check() and alloc_try_nid_bottom_up_numa_node_reserved_check():
- Separate size definition from its declaration
Updates based on changes to the dependent patch set noted above:
PATCH 2, PATCH 3, PATCH 4:
- tests/alloc_nid_api.c:
+ get_func_testing():
* Rename to get_memblock_alloc_try_nid_name().
+ Update calls to verify_mem_content() to assert_mem_content().
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 | 1459 ++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.c | 29 + tools/testing/memblock/tests/common.h | 22 +- 5 files changed, 1515 insertions(+), 13 deletions(-)
Signature · 1 line
2.25.1
PATCH v4 1/4 memblock tests: add simulation of physical memory with multiple NUMA nodes
Add function setup_numa_memblock() for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. This function can be used in place of setup_memblock() in tests that need to simulate a NUMA system.
setup_numa_memblock():
- allows for setting up a memory layout by specifying the fraction of MEM_SIZE in each node
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 | 29 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 4 ++- 3 files changed, 33 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 +29 -0
@@ -72,6 +72,35 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the denominators of the fractions of MEM_SIZE +* contained in each node (e.g., if nodes[0] = SZ_8, node 0 will +* contain 1/8th of MEM_SIZE) +* +* The nids will be set to 0 through NUMA_NODES - 1. +*/ +void setup_numa_memblock (const phys_addr_t nodes[]) +{ +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 <NUMA_NODES ; i++) { +assert (nodes[i] <=MEM_SIZE && nodes[i] >0 ); +phys_addr_t size =MEM_SIZE / nodes[i]; + +memblock_add_node (base, size, i, flags); + base += size; + } +fill_memblock (); +} +void dummy_physical_memory_init (void ) { memory_block.base =malloc (MEM_SIZE );
tools/testing/memblock/tests/common.h +3 -1
@@ -10,7 +10,8 @@#include <linux/printk.h> #include <../selftests/kselftest.h> -#define MEM_SIZE SZ_16K +#define MEM_SIZE SZ_16K +#define NUMA_NODES 8enum test_flags {/* No special request. */
@@ -102,6 +103,7 @@ struct region {void reset_memblock_regions (void );void reset_memblock_attributes (void );void setup_memblock (void ); +void setup_numa_memblock (const phys_addr_t nodes[]);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
Re: [PATCH v4 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
Quoted 51 lines · Rebecca Mckeever
Add function
setup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. This function can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock():
- allows for setting up a memory layout by specifying the fraction ofMEM_SIZEin each nodeSet
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 | 29 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 4 ++- 3 files changed, 33 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 +11
-0@@ -72,6 +72,35 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the denominators of the fractions of MEM_SIZE +* contained in each node (e.g., if nodes[0] = SZ_8, node 0 will +* contain 1/8th of MEM_SIZE) +* +* The nids will be set to 0 through NUMA_NODES - 1. +*/ +void setup_numa_memblock (const phys_addr_t nodes[])
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 95
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 <NUMA_NODES ; i++) { +assert (nodes[i] <=MEM_SIZE && nodes[i] >0 );
I think it would be even easier to get if this would just be a fraction. E.g., instead of "1/8 * MEM_SIZE" just "1/8". All values have to add up to 1.
... but then we'd have to mess with floats eventually, so I guess this makes it easier to handle these fractions.
We could use "int" and simply specify the fraction in percent, like
nodes[0] = 50;
nodes[1] = 25;
nodes[2] = 25;
and everything has to add up to 100.
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 96
Quoted 1 line
tools/testing/memblock/tests/common.c +1
-0+phys_addr_t size =MEM_SIZE / nodes[i];
Hmmm, assuming a single node with "MEM_SIZE", we would get size=1.
Shouldn't this be "size = nodes[i]"
?
Signature · 3 lines
Thanks, David / dhildenb
Re: [PATCH v4 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
Quoted 68 lines · David Hildenbrand
Quoted 48 lines · Rebecca Mckeever
Add function
setup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. This function can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock():
- allows for setting up a memory layout by specifying the fraction ofMEM_SIZEin each nodeSet
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 | 29 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 4 ++- 3 files changed, 33 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 +11
-0@@ -72,6 +72,35 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the denominators of the fractions of MEM_SIZE +* contained in each node (e.g., if nodes[0] = SZ_8, node 0 will +* contain 1/8th of MEM_SIZE) +* +* The nids will be set to 0 through NUMA_NODES - 1. +*/ +void setup_numa_memblock (const phys_addr_t nodes[])tools/testing/memblock/tests/common.c void setup_memblock(void) · line 94
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 <NUMA_NODES ; i++) { +assert (nodes[i] <=MEM_SIZE && nodes[i] >0 );I think it would be even easier to get if this would just be a fraction. E.g., instead of "1/8 *
MEM_SIZE" just "1/8". All values have to add up to 1.... but then we'd have to mess with floats eventually, so I guess this makes it easier to handle these fractions.
Quoted 8 lines
We could use "int" and simply specify the fraction in percent, like
nodes[0] = 50;
nodes[1] = 25;
nodes[2] = 25;and everything has to add up to 100.
This would still be a float for 1/8th (12.5) and 1/16th (6.25). What if it was the "percent" of 256 (i.e., 0x100)?
Quoted 6 lines
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 96
Quoted 2 lines
tools/testing/memblock/tests/common.c +1
-0+phys_addr_t size =MEM_SIZE / nodes[i];Hmmm, assuming a single node with "
MEM_SIZE", we would get size=1.
For a single node of MEM_SIZE, nodes[0] would be 1.
Quoted 3 lines
Shouldn't this be "size = nodes[i]"
?
No, not with the current implementation. The nodes array stores the denominator of the fraction that will be multiplied by MEM_SIZE to determine the size of that node (the numerator is always 1). So if the size of the node should be 1/8 * MEM_SIZE, the nodes array just stores the 8. I think the name of the array is misleading. Do you have any suggestions for a better name?
Quoted 6 lines
Signature · 4 lines
-- Thanks, David / dhildenb
Thanks,
Rebecca
Re: [PATCH v4 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
Quoted 71 lines · Rebecca Mckeever
Quoted 70 lines · David Hildenbrand
Quoted 48 lines · Rebecca Mckeever
Add function
setup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. This function can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock():
- allows for setting up a memory layout by specifying the fraction ofMEM_SIZEin each nodeSet
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 | 29 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 4 ++- 3 files changed, 33 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 +11
-0@@ -72,6 +72,35 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the denominators of the fractions of MEM_SIZE +* contained in each node (e.g., if nodes[0] = SZ_8, node 0 will +* contain 1/8th of MEM_SIZE) +* +* The nids will be set to 0 through NUMA_NODES - 1. +*/ +void setup_numa_memblock (const phys_addr_t nodes[])tools/testing/memblock/tests/common.c void setup_memblock(void) · line 94
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 <NUMA_NODES ; i++) { +assert (nodes[i] <=MEM_SIZE && nodes[i] >0 );I think it would be even easier to get if this would just be a fraction. E.g., instead of "1/8 *
MEM_SIZE" just "1/8". All values have to add up to 1.... but then we'd have to mess with floats eventually, so I guess this makes it easier to handle these fractions.
We could use "int" and simply specify the fraction in percent, like
Quoted 8 lines
Quoted 6 lines
nodes[0] = 50;
nodes[1] = 25;
nodes[2] = 25;and everything has to add up to 100.
This would still be a float for 1/8th (12.5) and 1/16th (6.25). What if it was the "percent" of 256 (i.e.,
0x100)?
Right, or in something "smaller" like 1/32 th. I don't think we go below that?
If we don't need more digits, why not in "basis points" (per ten thousand) -> https://en.wikipedia.org/wiki/Basis_point
nodes[0] = 5000; /* 1/2 */
nodes[1] = 2500; /* 1/4 */
nodes[2] = 1250; /* 1/8 */
nodes[4] = 0625; /* 1/32 */
nodes[5] = 0625;
Quoted 10 lines
Quoted 6 lines
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 96
Quoted 2 lines
tools/testing/memblock/tests/common.c +1
-0+phys_addr_t size =MEM_SIZE / nodes[i];Hmmm, assuming a single node with "
MEM_SIZE", we would get size=1.For a single node of
MEM_SIZE, nodes[0] would be 1.Quoted 2 lines
Shouldn't this be "size = nodes[i]"
Quoted 7 lines
Quoted 1 line
?
No, not with the current implementation. The nodes array stores the denominator of the fraction that will be multiplied by
MEM_SIZEto determine the size of that node (the numerator is always 1). So if the size of the node should be 1/8 *MEM_SIZE, the nodes array just stores the 8. I think the name of the array is misleading. Do you have any suggestions for a better name?
Then I am confused about the
assert(nodes[i] <= MEM_SIZE && nodes[i] > 0);
assertion :)
I think it would really be best to just store the actual fraction somehow. But maybe just I am confused :)
Signature · 3 lines
Thanks, David / dhildenb
Re: [PATCH v4 1/4] memblock tests: add simulation of physical memory with multiple NUMA nodes
Quoted 78 lines · David Hildenbrand
Quoted 77 lines · Rebecca Mckeever
Quoted 76 lines · David Hildenbrand
Quoted 48 lines · Rebecca Mckeever
Add function
setup_numa_memblock()for setting up a memory layout with multiple NUMA nodes in a previously allocated dummy physical memory. This function can be used in place ofsetup_memblock()in tests that need to simulate a NUMA system.
setup_numa_memblock():
- allows for setting up a memory layout by specifying the fraction ofMEM_SIZEin each nodeSet
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 | 29 +++++++++++++++++++ tools/testing/memblock/tests/common.h | 4 ++- 3 files changed, 33 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 +11
-0@@ -72,6 +72,35 @@ void setup_memblock(void)fill_memblock (); } +/** +* setup_numa_memblock: +* Set up a memory layout with multiple NUMA nodes in a previously allocated +* dummy physical memory. +* @nodes: an array containing the denominators of the fractions of MEM_SIZE +* contained in each node (e.g., if nodes[0] = SZ_8, node 0 will +* contain 1/8th of MEM_SIZE) +* +* The nids will be set to 0 through NUMA_NODES - 1. +*/ +void setup_numa_memblock (const phys_addr_t nodes[])tools/testing/memblock/tests/common.c void setup_memblock(void) · line 94
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 <NUMA_NODES ; i++) { +assert (nodes[i] <=MEM_SIZE && nodes[i] >0 );I think it would be even easier to get if this would just be a fraction. E.g., instead of "1/8 *
MEM_SIZE" just "1/8". All values have to add up to 1.... but then we'd have to mess with floats eventually, so I guess this makes it easier to handle these fractions.
We could use "int" and simply specify the fraction in percent, like
nodes[0] = 50;
nodes[1] = 25;
nodes[2] = 25;and everything has to add up to 100.
Quoted 9 lines
Quoted 2 lines
This would still be a float for 1/8th (12.5) and 1/16th (6.25). What if it was the "percent" of 256 (i.e.,
0x100)?Right, or in something "smaller" like 1/32 th. I don't think we go below that?
If we don't need more digits, why not in "basis points" (per ten thousand) -> https://en.wikipedia.org/wiki/Basis_point
Basis points should work.
Quoted 25 lines
nodes[0] = 5000; /* 1/2 */
nodes[1] = 2500; /* 1/4 */
nodes[2] = 1250; /* 1/8 */
nodes[4] = 0625; /* 1/32 */
nodes[5] = 0625;Quoted 10 lines
Quoted 6 lines
tools/testing/memblock/tests/common.c void setup_memblock(void) · line 96
Quoted 2 lines
tools/testing/memblock/tests/common.c +1
-0+phys_addr_t size =MEM_SIZE / nodes[i];Hmmm, assuming a single node with "
MEM_SIZE", we would get size=1.For a single node of
MEM_SIZE, nodes[0] would be 1.Quoted 2 lines
Shouldn't this be "size = nodes[i]"
Quoted 7 lines
Quoted 1 line
?
No, not with the current implementation. The nodes array stores the denominator of the fraction that will be multiplied by
MEM_SIZEto determine the size of that node (the numerator is always 1). So if the size of the node should be 1/8 *MEM_SIZE, the nodes array just stores the 8. I think the name of the array is misleading. Do you have any suggestions for a better name?
Quoted 5 lines
Then I am confused about the
assert(nodes[i] <= MEM_SIZE && nodes[i] > 0);assertion :)
The first part of the assert ensures that size doesn't become less than 1, and the second part prevents a divide by 0. I see how this is confusing now.
Quoted 8 lines
I think it would really be best to just store the actual fraction somehow. But maybe just I am confused :)
Signature · 3 lines
Thanks, David / dhildenb
Thanks,
Rebecca
PATCH v4 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 | 694 ++++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.h | 18 + 3 files changed, 717 insertions(+), 11 deletions(-)
tools/testing/memblock/tests/alloc_nid_api.c +683 -11
@@ -3,6 +3,14 @@static int alloc_nid_test_flags =TEST_F_NONE ; +/* +* contains the denominators of the fractions of MEM_SIZE contained in each node +* (e.g., if node_fractions[0] = SZ_8, node 0 will contain 1/8th of MEM_SIZE) +*/ +static const phys_addr_t node_fractions[] = { +SZ_4 ,SZ_16 ,SZ_8 ,SZ_8 ,SZ_16 ,SZ_16 ,SZ_4 ,SZ_16 +}; +static inline const char *const get_memblock_alloc_try_nid_name (int flags) {if (flags &TEST_F_RAW )
@@ -1094,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__);
@@ -1226,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_memblock_alloc_try_nid_name (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_memblock_alloc_try_nid_name (alloc_nid_test_flags));alloc_try_nid_simple_check ();alloc_try_nid_misaligned_check ();
@@ -1253,6 +1254,677 @@ 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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +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 ); +assert_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 *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + size =SZ_2 * req_node->size; + 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 ); +assert_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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + size = req_node->size; + 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 ); +assert_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; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +ASSERT_LE (SZ_8 , req_node->size); + r1.base = req_node->base; + r1.size = req_node->size /SZ_2 ; + size = r1.size /SZ_4 ; + 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 ); +assert_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; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_2 ; + r1.base = req_node->base + (size /SZ_2 ); + 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 ); +assert_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 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 ; +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t req_node_end; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 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 ; +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 memory region at the end of the final node in +* the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_top_down_numa_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 ; +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 memory region at the end of the final node in +* the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_top_down_numa_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 ; +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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_top_down_numa_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_top_down_numa_no_overlap_high_check (); + +return 0 ; +} + +int __memblock_alloc_nid_numa_checks (void ) +{ +test_print ("Running %s NUMA tests...\n" , +get_memblock_alloc_try_nid_name (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_memblock_alloc_try_nid_name (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
@@ -59,6 +59,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.
@@ -100,6 +113,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
Re: [PATCH v4 2/4] memblock tests: add top-down NUMA tests for memblock_alloc_try_nid*
Quoted 49 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 | 694 ++++++++++++++++++- tools/testing/memblock/tests/alloc_nid_api.h | 16 + tools/testing/memblock/tests/common.h | 18 + 3 files changed, 717 insertions(+), 11 deletions(-)tools/testing/memblock/tests/alloc_nid_api.c +0
-0@@ -3,6 +3,14 @@
tools/testing/memblock/tests/alloc_nid_api.c line 13
Quoted 10 lines
tools/testing/memblock/tests/alloc_nid_api.c +8
-0static int alloc_nid_test_flags =TEST_F_NONE ; +/* +* contains the denominators of the fractions of MEM_SIZE contained in each node +* (e.g., if node_fractions[0] = SZ_8, node 0 will contain 1/8th of MEM_SIZE) +*/ +static const phys_addr_t node_fractions[] = { +SZ_4 ,SZ_16 ,SZ_8 ,SZ_8 ,SZ_16 ,SZ_16 ,SZ_4 ,SZ_16 +}; +
Besides that part, that I consider confusing :)
Signature · 3 lines
Thanks, David / dhildenb
PATCH v4 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 | 568 +++++++++++++++++++ 1 file changed, 568 insertions(+)
tools/testing/memblock/tests/alloc_nid_api.c +568 -0
@@ -1801,12 +1801,562 @@ static int alloc_try_nid_top_down_numa_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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +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 ); +assert_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 *req_node = &memblock.memory.regions[nid_req]; +struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +void *allocated_ptr =NULL ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + size =SZ_2 * req_node->size; + 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 ); +assert_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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + size = req_node->size; + 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 ); +assert_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; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t total_size; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +ASSERT_LE (SZ_8 , req_node->size); + r1.base = req_node->base; + r1.size = req_node->size /SZ_2 ; + size = r1.size /SZ_4 ; + 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 ); +assert_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; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + +ASSERT_LE (SZ_4 , req_node->size); + size = req_node->size /SZ_2 ; + r1.base = req_node->base + (size /SZ_2 ); + 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 ); +assert_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 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 ; +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t req_node_end; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 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 ; +phys_addr_t size =SZ_512 ; +phys_addr_t min_addr; +phys_addr_t max_addr; +phys_addr_t exp_node_end; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 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 ; +phys_addr_t size; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 memory region at the beginning of the first node +* in the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_bottom_up_numa_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 ; +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 memory region at the beginning of the first node +* in the range after falling back to NUMA_NO_NODE. +*/ +static int alloc_try_nid_bottom_up_numa_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 ; +phys_addr_t size =SZ_64 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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 ; }
@@ -1816,6 +2366,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 ; }
@@ -1825,6 +2377,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 ; }
@@ -1834,6 +2388,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 ; }
@@ -1843,6 +2399,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 ; }
@@ -1852,6 +2410,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 ; }
@@ -1861,6 +2421,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 ; }
@@ -1870,6 +2432,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 ; }
@@ -1879,6 +2443,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_top_down_numa_no_overlap_low_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_no_overlap_low_check ();return 0 ; }
@@ -1888,6 +2454,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_top_down_numa_no_overlap_high_check (); +memblock_set_bottom_up (true); +alloc_try_nid_bottom_up_numa_no_overlap_high_check ();return 0 ; }
Signature · 1 line
2.25.1
Re: [PATCH v4 3/4] memblock tests: add bottom-up NUMA tests for memblock_alloc_try_nid*
Quoted 36 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 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 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 node
Quoted 4 lines
Signed-off-by Rebecca Mckeever <[email protected]>--- tools/testing/memblock/tests/alloc_nid_api.c | 568 +++++++++++++++++++ 1 file changed, 568 insertions(+)
Signature · 3 lines
Thanks, David / dhildenb
PATCH v4 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 | 197 +++++++++++++++++++ 1 file changed, 197 insertions(+)
tools/testing/memblock/tests/alloc_nid_api.c +197 -0
@@ -2349,6 +2349,173 @@ static int alloc_try_nid_bottom_up_numa_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_numa_large_region_generic_check (void ) +{ +int nid_req =3 ; +void *allocated_ptr =NULL ; +phys_addr_t size =MEM_SIZE /SZ_2 ; +phys_addr_t min_addr; +phys_addr_t max_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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; +phys_addr_t size = req_node->size; +phys_addr_t total_size; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ); +assert_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; +phys_addr_t size =SZ_256 ; +phys_addr_t max_addr; +phys_addr_t min_addr; + +PREFIX_PUSH (); +setup_numa_memblock (node_fractions); + + 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 ) {
@@ -2460,6 +2627,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_numa_large_region_generic_check); +run_bottom_up (alloc_try_nid_numa_large_region_generic_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",
@@ -2476,6 +2670,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 v4 4/4] memblock tests: add generic NUMA tests for memblock_alloc_try_nid*
Quoted 21 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, 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 regionRange restricted:
- region can be allocated in the specific node requested without droppingmin_addr:
+ the range fully overlaps with the node, and there are adjacent reserved regions
- region cannot be allocated:
+ nid is set toNUMA_NO_NODEand the total range can fit the region, but the range is split between two nodes and everything else is reserved
Quoted 5 lines
Signed-off-by Rebecca Mckeever <[email protected]>--- tools/testing/memblock/tests/alloc_nid_api.c | 197 +++++++++++++++++++ 1 file changed, 197 insertions(+)
Signature · 3 lines
Thanks, David / dhildenb