2022-10-02 23:45:14

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 0/5] memblock tests: add tests for memblock_alloc_exact_nid_raw

These patches add tests for memblock_alloc_exact_nid_raw(). There are two
sets of tests: range tests and NUMA tests. The range tests use a normal
(i.e., UMA) simulated physical memory and set the nid to NUMA_NO_NODE. The
NUMA tests use a simulated physical memory that is set up with multiple
NUMA nodes. Additionally, most of these tests set nid != NUMA_NO_NODE.

The range tests are very similar to the range tests for
memblock_alloc_try_nid_raw(). The NUMA tests have the same setup as the
corresponding test for memblock_alloc_try_nid_raw(), but several of the
memblock_alloc_exact_nid_raw() tests fail to allocate memory in setups
where the memblock_alloc_try_nid_raw() test would allocate memory. Also,
some memblock_alloc_exact_nid_raw() tests drop the lower limit of the
requested range in order to allocate within the requested node, but the
same setup in a memblock_alloc_try_nid_raw() test allocates within the
requested range.

---
Changelog

v1 -> v2
PATCH 0:
- Add missing memblock_alloc_exact_nid_raw to subject line
---

Rebecca Mckeever (5):
memblock tests: add range tests for memblock_alloc_exact_nid_raw
memblock tests: add top-down NUMA tests for
memblock_alloc_exact_nid_raw
memblock tests: add bottom-up NUMA tests for
memblock_alloc_exact_nid_raw
memblock tests: add generic NUMA tests for
memblock_alloc_exact_nid_raw
memblock tests: remove completed TODO item

tools/testing/memblock/Makefile | 2 +-
tools/testing/memblock/TODO | 7 +-
tools/testing/memblock/main.c | 2 +
.../memblock/tests/alloc_exact_nid_api.c | 2299 +++++++++++++++++
.../memblock/tests/alloc_exact_nid_api.h | 25 +
5 files changed, 2328 insertions(+), 7 deletions(-)
create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.c
create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.h

--
2.25.1


2022-10-02 23:45:19

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 1/5] memblock tests: add range tests for memblock_alloc_exact_nid_raw

Add tests for memblock_alloc_exact_nid_raw() that are very similar to
the range tests for memblock_alloc_try_nid_raw().

Signed-off-by: Rebecca Mckeever <[email protected]>
---
tools/testing/memblock/Makefile | 2 +-
tools/testing/memblock/main.c | 2 +
.../memblock/tests/alloc_exact_nid_api.c | 1208 +++++++++++++++++
.../memblock/tests/alloc_exact_nid_api.h | 9 +
4 files changed, 1220 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.c
create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.h

diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile
index 246f7ac8489b..2310ac4d080e 100644
--- a/tools/testing/memblock/Makefile
+++ b/tools/testing/memblock/Makefile
@@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
LDFLAGS += -fsanitize=address -fsanitize=undefined
TARGETS = main
TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
- tests/basic_api.o tests/common.o
+ tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o
OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
EXTR_SRC = ../../../mm/memblock.c
diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c
index 4ca1024342b1..278f9dec5008 100644
--- a/tools/testing/memblock/main.c
+++ b/tools/testing/memblock/main.c
@@ -3,6 +3,7 @@
#include "tests/alloc_api.h"
#include "tests/alloc_helpers_api.h"
#include "tests/alloc_nid_api.h"
+#include "tests/alloc_exact_nid_api.h"
#include "tests/common.h"

int main(int argc, char **argv)
@@ -12,6 +13,7 @@ int main(int argc, char **argv)
memblock_alloc_checks();
memblock_alloc_helpers_checks();
memblock_alloc_nid_checks();
+ memblock_alloc_exact_nid_checks();

return 0;
}
diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.c b/tools/testing/memblock/tests/alloc_exact_nid_api.c
new file mode 100644
index 000000000000..452aba1f19db
--- /dev/null
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.c
@@ -0,0 +1,1208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "alloc_exact_nid_api.h"
+
+#define FUNC_NAME "memblock_alloc_exact_nid_raw"
+
+/*
+ * A simple test that tries to allocate a memory region within min_addr and
+ * max_addr range:
+ *
+ * + +
+ * | + +-----------+ |
+ * | | | rgn | |
+ * +----+-------+-----------+------+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to allocate a region that ends at max_addr.
+ */
+static int alloc_exact_nid_top_down_simple_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_128;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t rgn_end;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;
+ max_addr = min_addr + SZ_512;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+ rgn_end = rgn->base + rgn->size;
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size);
+ ASSERT_EQ(rgn_end, max_addr);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A simple test that tries to allocate a memory region within min_addr and
+ * max_addr range, where the end address is misaligned:
+ *
+ * + + +
+ * | + +---------+ + |
+ * | | | rgn | | |
+ * +------+-------+---------+--+----+
+ * ^ ^ ^
+ * | | |
+ * min_add | max_addr
+ * |
+ * Aligned address
+ * boundary
+ *
+ * Expect to allocate an aligned region that ends before max_addr.
+ */
+static int alloc_exact_nid_top_down_end_misaligned_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_128;
+ phys_addr_t misalign = SZ_2;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t rgn_end;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;
+ max_addr = min_addr + SZ_512 + misalign;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+ rgn_end = rgn->base + rgn->size;
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size - misalign);
+ ASSERT_LT(rgn_end, max_addr);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A simple test that tries to allocate a memory region, which spans over the
+ * min_addr and max_addr range:
+ *
+ * + +
+ * | +---------------+ |
+ * | | rgn | |
+ * +------+---------------+-------+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to allocate a region that starts at min_addr and ends at
+ * max_addr, given that min_addr is aligned.
+ */
+static int alloc_exact_nid_exact_address_generic_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_1K;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t rgn_end;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES;
+ max_addr = min_addr + size;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+ rgn_end = rgn->base + rgn->size;
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
+ ASSERT_EQ(rgn_end, max_addr);
+
+ 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, which can't fit into
+ * min_addr and max_addr range:
+ *
+ * + + +
+ * | +----------+-----+ |
+ * | | rgn + | |
+ * +--------+----------+-----+----+
+ * ^ ^ ^
+ * | | |
+ * Aligned | max_addr
+ * address |
+ * boundary min_add
+ *
+ * Expect to drop the lower limit and allocate a memory region which
+ * ends at max_addr (if the address is aligned).
+ */
+static int alloc_exact_nid_top_down_narrow_range_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_256;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SZ_512;
+ max_addr = min_addr + SMP_CACHE_BYTES;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size);
+
+ 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, which can't fit into
+ * min_addr and max_addr range, with the latter being too close to the beginning
+ * of the available memory:
+ *
+ * +-------------+
+ * | new |
+ * +-------------+
+ * + +
+ * | + |
+ * | | |
+ * +-------+--------------+
+ * ^ ^
+ * | |
+ * | max_addr
+ * |
+ * min_addr
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_low_max_generic_check(void)
+{
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_1K;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM();
+ max_addr = min_addr + SMP_CACHE_BYTES;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A test that tries to allocate a memory region within min_addr min_addr range,
+ * with min_addr being so close that it's next to an allocated region:
+ *
+ * + +
+ * | +--------+---------------|
+ * | | r1 | rgn |
+ * +-------+--------+---------------+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect a merge of both regions. Only the region size gets updated.
+ */
+static int alloc_exact_nid_min_reserved_generic_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t r1_size = SZ_128;
+ phys_addr_t r2_size = SZ_64;
+ phys_addr_t total_size = r1_size + r2_size;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t reserved_base;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ max_addr = memblock_end_of_DRAM();
+ min_addr = max_addr - r2_size;
+ reserved_base = min_addr - r1_size;
+
+ memblock_reserve(reserved_base, r1_size);
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(r2_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r2_size);
+
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, reserved_base);
+
+ 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 within min_addr and max_addr,
+ * with max_addr being so close that it's next to an allocated region:
+ *
+ * + +
+ * | +-------------+--------|
+ * | | rgn | r1 |
+ * +----------+-------------+--------+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect a merge of regions. Only the region size gets updated.
+ */
+static int alloc_exact_nid_max_reserved_generic_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t r1_size = SZ_64;
+ phys_addr_t r2_size = SZ_128;
+ phys_addr_t total_size = r1_size + r2_size;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ max_addr = memblock_end_of_DRAM() - r1_size;
+ min_addr = max_addr - r2_size;
+
+ memblock_reserve(max_addr, r1_size);
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(r2_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r2_size);
+
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, min_addr);
+
+ 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, when
+ * there are two reserved regions at the borders, with a gap big enough to fit
+ * a new region:
+ *
+ * + +
+ * | +--------+ +-------+------+ |
+ * | | r2 | | rgn | r1 | |
+ * +----+--------+---+-------+------+--+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to merge the new region with r1. The second region does not get
+ * updated. The total size field gets updated.
+ */
+
+static int alloc_exact_nid_top_down_reserved_with_space_check(void)
+{
+ struct memblock_region *rgn1 = &memblock.reserved.regions[1];
+ struct memblock_region *rgn2 = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_64;
+ phys_addr_t gap_size = SMP_CACHE_BYTES;
+ phys_addr_t total_size;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = SZ_128;
+ r2.base = r1.base - (r3_size + gap_size + r2.size);
+
+ total_size = r1.size + r2.size + r3_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 = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r3_size);
+
+ ASSERT_EQ(rgn1->size, r1.size + r3_size);
+ ASSERT_EQ(rgn1->base, max_addr - r3_size);
+
+ ASSERT_EQ(rgn2->size, r2.size);
+ ASSERT_EQ(rgn2->base, r2.base);
+
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ 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, when
+ * there are two reserved regions at the borders, with a gap of a size equal to
+ * the size of the new region:
+ *
+ * + +
+ * | +--------+--------+--------+ |
+ * | | r2 | r3 | r1 | |
+ * +-----+--------+--------+--------+-----+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to merge all of the regions into one. The region counter and total
+ * size fields get updated.
+ */
+static int alloc_exact_nid_reserved_full_merge_generic_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_64;
+ phys_addr_t total_size;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = SZ_128;
+ r2.base = r1.base - (r3_size + r2.size);
+
+ total_size = r1.size + r2.size + r3_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 = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r3_size);
+
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, r2.base);
+
+ 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, when
+ * there are two reserved regions at the borders, with a gap that can't fit
+ * a new region:
+ *
+ * + +
+ * | +----------+------+ +------+ |
+ * | | r3 | r2 | | r1 | |
+ * +--+----------+------+----+------+---+
+ * ^ ^
+ * | |
+ * | max_addr
+ * |
+ * min_addr
+ *
+ * Expect to merge the new region with r2. The second region does not get
+ * updated. The total size counter gets updated.
+ */
+static int alloc_exact_nid_top_down_reserved_no_space_check(void)
+{
+ struct memblock_region *rgn1 = &memblock.reserved.regions[1];
+ struct memblock_region *rgn2 = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_256;
+ phys_addr_t gap_size = SMP_CACHE_BYTES;
+ phys_addr_t total_size;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = SZ_128;
+ r2.base = r1.base - (r2.size + gap_size);
+
+ total_size = r1.size + r2.size + r3_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 = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r3_size);
+
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
+
+ ASSERT_EQ(rgn2->size, r2.size + r3_size);
+ ASSERT_EQ(rgn2->base, r2.base - r3_size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ 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, but
+ * it's too narrow and everything else is reserved:
+ *
+ * +-----------+
+ * | new |
+ * +-----------+
+ * + +
+ * |--------------+ +----------|
+ * | r2 | | r1 |
+ * +--------------+------+----------+
+ * ^ ^
+ * | |
+ * | max_addr
+ * |
+ * min_addr
+ *
+ * Expect no allocation to happen.
+ */
+
+static int alloc_exact_nid_reserved_all_generic_check(void)
+{
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_256;
+ phys_addr_t gap_size = SMP_CACHE_BYTES;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = MEM_SIZE - (r1.size + gap_size);
+ r2.base = memblock_start_of_DRAM();
+
+ min_addr = r2.base + r2.size;
+ max_addr = r1.base;
+
+ memblock_reserve(r1.base, r1.size);
+ memblock_reserve(r2.base, r2.size);
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A test that tries to allocate a memory region, where max_addr is
+ * bigger than the end address of the available memory. Expect to allocate
+ * a region that ends before the end of the memory.
+ */
+static int alloc_exact_nid_top_down_cap_max_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_256;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_end_of_DRAM() - SZ_1K;
+ max_addr = memblock_end_of_DRAM() + SZ_256;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
+
+ 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, where min_addr is
+ * smaller than the start address of the available memory. Expect to allocate
+ * a region that ends before the end of the memory.
+ */
+static int alloc_exact_nid_top_down_cap_min_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_1K;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() - SZ_256;
+ max_addr = memblock_end_of_DRAM();
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A simple test that tries to allocate a memory region within min_addr and
+ * max_addr range:
+ *
+ * + +
+ * | +-----------+ | |
+ * | | rgn | | |
+ * +----+-----------+-----------+------+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to allocate a region that ends before max_addr.
+ */
+static int alloc_exact_nid_bottom_up_simple_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_128;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t rgn_end;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;
+ max_addr = min_addr + SZ_512;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+ rgn_end = rgn->base + rgn->size;
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
+ ASSERT_LT(rgn_end, max_addr);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A simple test that tries to allocate a memory region within min_addr and
+ * max_addr range, where the start address is misaligned:
+ *
+ * + +
+ * | + +-----------+ + |
+ * | | | rgn | | |
+ * +-----+---+-----------+-----+-----+
+ * ^ ^----. ^
+ * | | |
+ * min_add | max_addr
+ * |
+ * Aligned address
+ * boundary
+ *
+ * Expect to allocate an aligned region that ends before max_addr.
+ */
+static int alloc_exact_nid_bottom_up_start_misaligned_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_128;
+ phys_addr_t misalign = SZ_2;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+ phys_addr_t rgn_end;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + misalign;
+ max_addr = min_addr + SZ_512;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+ rgn_end = rgn->base + rgn->size;
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr + (SMP_CACHE_BYTES - misalign));
+ ASSERT_LT(rgn_end, max_addr);
+
+ 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, which can't fit into min_addr
+ * and max_addr range:
+ *
+ * + +
+ * |---------+ + + |
+ * | rgn | | | |
+ * +---------+---------+----+------+
+ * ^ ^
+ * | |
+ * | max_addr
+ * |
+ * min_add
+ *
+ * Expect to drop the lower limit and allocate a memory region which
+ * starts at the beginning of the available memory.
+ */
+static int alloc_exact_nid_bottom_up_narrow_range_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_256;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SZ_512;
+ max_addr = min_addr + SMP_CACHE_BYTES;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+ 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
+ * there are two reserved regions at the borders, with a gap big enough to fit
+ * a new region:
+ *
+ * + +
+ * | +--------+-------+ +------+ |
+ * | | r2 | rgn | | r1 | |
+ * +----+--------+-------+---+------+--+
+ * ^ ^
+ * | |
+ * min_addr max_addr
+ *
+ * Expect to merge the new region with r2. The second region does not get
+ * updated. The total size field gets updated.
+ */
+
+static int alloc_exact_nid_bottom_up_reserved_with_space_check(void)
+{
+ struct memblock_region *rgn1 = &memblock.reserved.regions[1];
+ struct memblock_region *rgn2 = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_64;
+ phys_addr_t gap_size = SMP_CACHE_BYTES;
+ phys_addr_t total_size;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = SZ_128;
+ r2.base = r1.base - (r3_size + gap_size + r2.size);
+
+ total_size = r1.size + r2.size + r3_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 = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r3_size);
+
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, max_addr);
+
+ ASSERT_EQ(rgn2->size, r2.size + r3_size);
+ ASSERT_EQ(rgn2->base, r2.base);
+
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ 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, when
+ * there are two reserved regions at the borders, with a gap of a size equal to
+ * the size of the new region:
+ *
+ * + +
+ * |----------+ +------+ +----+ |
+ * | r3 | | r2 | | r1 | |
+ * +----------+----+------+---+----+--+
+ * ^ ^
+ * | |
+ * | max_addr
+ * |
+ * min_addr
+ *
+ * Expect to drop the lower limit and allocate memory at the beginning of the
+ * available memory. The region counter and total size fields get updated.
+ * Other regions are not modified.
+ */
+
+static int alloc_exact_nid_bottom_up_reserved_no_space_check(void)
+{
+ struct memblock_region *rgn1 = &memblock.reserved.regions[2];
+ struct memblock_region *rgn2 = &memblock.reserved.regions[1];
+ struct memblock_region *rgn3 = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ struct region r1, r2;
+ phys_addr_t r3_size = SZ_256;
+ phys_addr_t gap_size = SMP_CACHE_BYTES;
+ phys_addr_t total_size;
+ phys_addr_t max_addr;
+ phys_addr_t min_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
+ r1.size = SMP_CACHE_BYTES;
+
+ r2.size = SZ_128;
+ r2.base = r1.base - (r2.size + gap_size);
+
+ total_size = r1.size + r2.size + r3_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 = memblock_alloc_exact_nid_raw(r3_size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, r3_size);
+
+ ASSERT_EQ(rgn3->size, r3_size);
+ ASSERT_EQ(rgn3->base, memblock_start_of_DRAM());
+
+ ASSERT_EQ(rgn2->size, r2.size);
+ ASSERT_EQ(rgn2->base, r2.base);
+
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
+
+ ASSERT_EQ(memblock.reserved.cnt, 3);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/*
+ * A test that tries to allocate a memory region, where max_addr is
+ * bigger than the end address of the available memory. Expect to allocate
+ * a region that starts at the min_addr.
+ */
+static int alloc_exact_nid_bottom_up_cap_max_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_256;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM() + SZ_1K;
+ max_addr = memblock_end_of_DRAM() + SZ_256;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
+
+ 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, where min_addr is
+ * smaller than the start address of the available memory. Expect to allocate
+ * a region at the beginning of the available memory.
+ */
+static int alloc_exact_nid_bottom_up_cap_min_check(void)
+{
+ struct memblock_region *rgn = &memblock.reserved.regions[0];
+ void *allocated_ptr = NULL;
+ phys_addr_t size = SZ_1K;
+ phys_addr_t min_addr;
+ phys_addr_t max_addr;
+
+ PREFIX_PUSH();
+ setup_memblock();
+
+ min_addr = memblock_start_of_DRAM();
+ max_addr = memblock_end_of_DRAM() - SZ_256;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ NUMA_NO_NODE);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
+
+ return 0;
+}
+
+/* Test case wrappers for range tests */
+static int alloc_exact_nid_simple_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_simple_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_simple_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_misaligned_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_end_misaligned_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_start_misaligned_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_narrow_range_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_narrow_range_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_narrow_range_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_reserved_with_space_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_reserved_with_space_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_reserved_with_space_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_reserved_no_space_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_reserved_no_space_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_reserved_no_space_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_cap_max_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_cap_max_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_cap_max_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_cap_min_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_cap_min_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_cap_min_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_min_reserved_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_min_reserved_generic_check);
+ run_bottom_up(alloc_exact_nid_min_reserved_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_max_reserved_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_max_reserved_generic_check);
+ run_bottom_up(alloc_exact_nid_max_reserved_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_exact_address_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_exact_address_generic_check);
+ run_bottom_up(alloc_exact_nid_exact_address_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_reserved_full_merge_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_reserved_full_merge_generic_check);
+ run_bottom_up(alloc_exact_nid_reserved_full_merge_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_reserved_all_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_reserved_all_generic_check);
+ run_bottom_up(alloc_exact_nid_reserved_all_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_low_max_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_low_max_generic_check);
+ run_bottom_up(alloc_exact_nid_low_max_generic_check);
+
+ return 0;
+}
+
+static int memblock_alloc_exact_nid_range_checks(void)
+{
+ test_print("Running %s range tests...\n", FUNC_NAME);
+
+ alloc_exact_nid_simple_check();
+ alloc_exact_nid_misaligned_check();
+ alloc_exact_nid_narrow_range_check();
+ alloc_exact_nid_reserved_with_space_check();
+ alloc_exact_nid_reserved_no_space_check();
+ alloc_exact_nid_cap_max_check();
+ alloc_exact_nid_cap_min_check();
+
+ alloc_exact_nid_min_reserved_check();
+ alloc_exact_nid_max_reserved_check();
+ alloc_exact_nid_exact_address_check();
+ alloc_exact_nid_reserved_full_merge_check();
+ alloc_exact_nid_reserved_all_check();
+ alloc_exact_nid_low_max_check();
+
+ return 0;
+}
+
+int memblock_alloc_exact_nid_checks(void)
+{
+ prefix_reset();
+ prefix_push(FUNC_NAME);
+
+ reset_memblock_attributes();
+ dummy_physical_memory_init();
+
+ memblock_alloc_exact_nid_range_checks();
+
+ dummy_physical_memory_cleanup();
+
+ prefix_pop();
+
+ return 0;
+}
diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.h b/tools/testing/memblock/tests/alloc_exact_nid_api.h
new file mode 100644
index 000000000000..4408719de3b9
--- /dev/null
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _MEMBLOCK_ALLOC_EXACT_NID_H
+#define _MEMBLOCK_ALLOC_EXACT_NID_H
+
+#include "common.h"
+
+int memblock_alloc_exact_nid_checks(void);
+
+#endif
--
2.25.1

2022-10-03 00:01:06

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 4/5] memblock tests: add generic NUMA tests for memblock_alloc_exact_nid_raw

Add tests for memblock_alloc_exact_nid_raw() where the simulated physical
memory is set up with multiple NUMA nodes. Additionally, all but one 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:
+ there are no previously reserved regions, but requested node is
too small
+ the requested node is fully reserved
+ the requested node is partially reserved and does not have
enough space
+ 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:
+ range partially overlaps with two different nodes, where the
second node is the requested node
+ range overlaps with multiple nodes along node boundaries, and
the requested node starts after max_addr
+ 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

Signed-off-by: Rebecca Mckeever <[email protected]>
---
.../memblock/tests/alloc_exact_nid_api.c | 465 ++++++++++++++++++
1 file changed, 465 insertions(+)

diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.c b/tools/testing/memblock/tests/alloc_exact_nid_api.c
index 63279d1e35b1..0f9a84867207 100644
--- a/tools/testing/memblock/tests/alloc_exact_nid_api.c
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.c
@@ -1746,6 +1746,390 @@ static int alloc_exact_nid_bottom_up_numa_no_overlap_low_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:
+ *
+ * | +-----+ |
+ * | | req | |
+ * +---+-----+----------------------------+
+ *
+ * +---------+
+ * | rgn |
+ * +---------+
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_numa_small_node_generic_check(void)
+{
+ int nid_req = 1;
+ 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);
+
+ size = SZ_2 * req_node->size;
+ min_addr = memblock_start_of_DRAM();
+ max_addr = memblock_end_of_DRAM();
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(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 a memory region in a specific NUMA node that
+ * is fully reserved:
+ *
+ * | +---------+ |
+ * | |requested| |
+ * +--------------+---------+-------------+
+ *
+ * | +---------+ |
+ * | | reserved| |
+ * +--------------+---------+-------------+
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_numa_node_reserved_generic_check(void)
+{
+ int nid_req = 2;
+ 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);
+
+ 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 = memblock_alloc_exact_nid_raw(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 a memory region in a specific NUMA node that
+ * is partially reserved and does not have enough contiguous memory for the
+ * allocated region:
+ *
+ * | +-----------------------+ |
+ * | | requested | |
+ * +-----------+-----------------------+----+
+ *
+ * | +----------+ |
+ * | | reserved | |
+ * +-----------------+----------+-----------+
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_numa_part_reserved_fail_generic_check(void)
+{
+ int nid_req = 4;
+ 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_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 = memblock_alloc_exact_nid_raw(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 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
+ * | +--------------------------+---------+ |
+ * | | first node |requested| |
+ * +------+--------------------------+---------+----------------+
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_numa_split_range_high_generic_check(void)
+{
+ int nid_req = 3;
+ 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;
+
+ PREFIX_PUSH();
+ setup_numa_memblock(node_fractions);
+
+ min_addr = req_node->base - SZ_256;
+ max_addr = min_addr + size;
+
+ allocated_ptr = memblock_alloc_exact_nid_raw(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_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 | |
+ * +-----+----------+----...----+----------+--------+-----------+---+
+ *
+ * Expect no allocation to happen.
+ */
+static int alloc_exact_nid_numa_no_overlap_high_generic_check(void)
+{
+ int nid_req = 7;
+ 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 = memblock_alloc_exact_nid_raw(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 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_exact_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 = memblock_alloc_exact_nid_raw(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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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_exact_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 = memblock_alloc_exact_nid_raw(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_exact_nid_numa_simple_check(void)
{
@@ -1802,6 +2186,78 @@ static int alloc_exact_nid_numa_no_overlap_low_check(void)
return 0;
}

+static int alloc_exact_nid_numa_small_node_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_small_node_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_small_node_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_node_reserved_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_node_reserved_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_node_reserved_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_part_reserved_fail_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_part_reserved_fail_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_part_reserved_fail_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_split_range_high_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_split_range_high_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_split_range_high_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_no_overlap_high_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_no_overlap_high_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_no_overlap_high_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_large_region_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_large_region_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_large_region_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_reserved_full_merge_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_reserved_full_merge_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_reserved_full_merge_generic_check);
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_split_all_reserved_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ run_top_down(alloc_exact_nid_numa_split_all_reserved_generic_check);
+ run_bottom_up(alloc_exact_nid_numa_split_all_reserved_generic_check);
+
+ return 0;
+}
+
int __memblock_alloc_exact_nid_numa_checks(void)
{
test_print("Running %s NUMA tests...\n", FUNC_NAME);
@@ -1812,6 +2268,15 @@ int __memblock_alloc_exact_nid_numa_checks(void)
alloc_exact_nid_numa_no_overlap_split_check();
alloc_exact_nid_numa_no_overlap_low_check();

+ alloc_exact_nid_numa_small_node_check();
+ alloc_exact_nid_numa_node_reserved_check();
+ alloc_exact_nid_numa_part_reserved_fail_check();
+ alloc_exact_nid_numa_split_range_high_check();
+ alloc_exact_nid_numa_no_overlap_high_check();
+ alloc_exact_nid_numa_large_region_check();
+ alloc_exact_nid_numa_reserved_full_merge_check();
+ alloc_exact_nid_numa_split_all_reserved_check();
+
return 0;
}

--
2.25.1

2022-10-03 00:03:16

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 2/5] memblock tests: add top-down NUMA tests for memblock_alloc_exact_nid_raw

Add tests for memblock_alloc_exact_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

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
+ range overlaps with multiple nodes along node boundaries, and
the requested node ends before min_addr

Signed-off-by: Rebecca Mckeever <[email protected]>
---
.../memblock/tests/alloc_exact_nid_api.c | 344 ++++++++++++++++++
.../memblock/tests/alloc_exact_nid_api.h | 16 +
2 files changed, 360 insertions(+)

diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.c b/tools/testing/memblock/tests/alloc_exact_nid_api.c
index 452aba1f19db..48c1b97a3f98 100644
--- a/tools/testing/memblock/tests/alloc_exact_nid_api.c
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.c
@@ -3,6 +3,21 @@

#define FUNC_NAME "memblock_alloc_exact_nid_raw"

+/*
+ * contains the fraction of MEM_SIZE contained in each node in basis point
+ * units (one hundredth of 1% or 1/10000)
+ */
+static const unsigned int node_fractions[] = {
+ 2500, /* 1/4 */
+ 625, /* 1/16 */
+ 1250, /* 1/8 */
+ 1250, /* 1/8 */
+ 625, /* 1/16 */
+ 625, /* 1/16 */
+ 2500, /* 1/4 */
+ 625, /* 1/16 */
+};
+
/*
* A simple test that tries to allocate a memory region within min_addr and
* max_addr range:
@@ -1190,6 +1205,334 @@ static int memblock_alloc_exact_nid_range_checks(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 end of the requested node.
+ */
+static int alloc_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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
+ * 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 drop the lower limit and allocate a memory region that ends at
+ * the end of the requested node.
+ */
+static int alloc_exact_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 *req_node = &memblock.memory.regions[nid_req];
+ 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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ ASSERT_EQ(new_rgn->size, size);
+ ASSERT_EQ(new_rgn->base, region_end(req_node) - size);
+
+ 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_exact_nid_numa_simple_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_numa_simple_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_part_reserved_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_numa_part_reserved_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_split_range_low_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_numa_split_range_low_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_no_overlap_split_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_numa_no_overlap_split_check();
+
+ return 0;
+}
+
+static int alloc_exact_nid_numa_no_overlap_low_check(void)
+{
+ test_print("\tRunning %s...\n", __func__);
+ memblock_set_bottom_up(false);
+ alloc_exact_nid_top_down_numa_no_overlap_low_check();
+
+ return 0;
+}
+
+int __memblock_alloc_exact_nid_numa_checks(void)
+{
+ test_print("Running %s NUMA tests...\n", FUNC_NAME);
+
+ alloc_exact_nid_numa_simple_check();
+ alloc_exact_nid_numa_part_reserved_check();
+ alloc_exact_nid_numa_split_range_low_check();
+ alloc_exact_nid_numa_no_overlap_split_check();
+ alloc_exact_nid_numa_no_overlap_low_check();
+
+ return 0;
+}
+
int memblock_alloc_exact_nid_checks(void)
{
prefix_reset();
@@ -1199,6 +1542,7 @@ int memblock_alloc_exact_nid_checks(void)
dummy_physical_memory_init();

memblock_alloc_exact_nid_range_checks();
+ memblock_alloc_exact_nid_numa_checks();

dummy_physical_memory_cleanup();

diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.h b/tools/testing/memblock/tests/alloc_exact_nid_api.h
index 4408719de3b9..cef419d55d2a 100644
--- a/tools/testing/memblock/tests/alloc_exact_nid_api.h
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.h
@@ -5,5 +5,21 @@
#include "common.h"

int memblock_alloc_exact_nid_checks(void);
+int __memblock_alloc_exact_nid_numa_checks(void);
+
+#ifdef CONFIG_NUMA
+static inline int memblock_alloc_exact_nid_numa_checks(void)
+{
+ __memblock_alloc_exact_nid_numa_checks();
+ return 0;
+}
+
+#else
+static inline int memblock_alloc_exact_nid_numa_checks(void)
+{
+ return 0;
+}
+
+#endif /* CONFIG_NUMA */

#endif
--
2.25.1

2022-10-03 01:12:20

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 5/5] memblock tests: remove completed TODO item

Remove completed item from TODO list.

Signed-off-by: Rebecca Mckeever <[email protected]>
---
tools/testing/memblock/TODO | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/tools/testing/memblock/TODO b/tools/testing/memblock/TODO
index 33044c634ea7..cb7fac47a643 100644
--- a/tools/testing/memblock/TODO
+++ b/tools/testing/memblock/TODO
@@ -8,10 +8,5 @@ TODO
likely that the current MEM_SIZE won't be enough for these
test cases. Use realloc to adjust the size accordingly.

-2. Add test cases using this functions (implement them for both directions):
- + memblock_alloc_raw()
- + memblock_alloc_exact_nid_raw()
- + memblock_alloc_try_nid_raw()
-
-3. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
+2. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
for the new region
--
2.25.1

2022-10-03 01:29:02

by Rebecca Mckeever

[permalink] [raw]
Subject: [PATCH v2 3/5] memblock tests: add bottom-up NUMA tests for memblock_alloc_exact_nid_raw

Add tests for memblock_alloc_exact_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

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
+ range overlaps with multiple nodes along node boundaries, and
the requested node ends before min_addr

Signed-off-by: Rebecca Mckeever <[email protected]>
---
.../memblock/tests/alloc_exact_nid_api.c | 282 ++++++++++++++++++
1 file changed, 282 insertions(+)

diff --git a/tools/testing/memblock/tests/alloc_exact_nid_api.c b/tools/testing/memblock/tests/alloc_exact_nid_api.c
index 48c1b97a3f98..63279d1e35b1 100644
--- a/tools/testing/memblock/tests/alloc_exact_nid_api.c
+++ b/tools/testing/memblock/tests/alloc_exact_nid_api.c
@@ -1474,12 +1474,286 @@ static int alloc_exact_nid_top_down_numa_no_overlap_low_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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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
+ * 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 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_exact_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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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 drop the lower limit and allocate a memory region that starts at
+ * the beginning of the requested node.
+ */
+static int alloc_exact_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 *req_node = &memblock.memory.regions[nid_req];
+ 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 = memblock_alloc_exact_nid_raw(size, SMP_CACHE_BYTES,
+ min_addr, max_addr,
+ nid_req);
+
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_MEM_NE(allocated_ptr, 0, size);
+
+ 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;
+}
+
/* Test case wrappers for NUMA tests */
static int alloc_exact_nid_numa_simple_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_exact_nid_top_down_numa_simple_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_numa_simple_check();

return 0;
}
@@ -1489,6 +1763,8 @@ static int alloc_exact_nid_numa_part_reserved_check(void)
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_exact_nid_top_down_numa_part_reserved_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_numa_part_reserved_check();

return 0;
}
@@ -1498,6 +1774,8 @@ static int alloc_exact_nid_numa_split_range_low_check(void)
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_exact_nid_top_down_numa_split_range_low_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_numa_split_range_low_check();

return 0;
}
@@ -1507,6 +1785,8 @@ static int alloc_exact_nid_numa_no_overlap_split_check(void)
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_exact_nid_top_down_numa_no_overlap_split_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_numa_no_overlap_split_check();

return 0;
}
@@ -1516,6 +1796,8 @@ static int alloc_exact_nid_numa_no_overlap_low_check(void)
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_exact_nid_top_down_numa_no_overlap_low_check();
+ memblock_set_bottom_up(true);
+ alloc_exact_nid_bottom_up_numa_no_overlap_low_check();

return 0;
}
--
2.25.1

2022-10-10 09:15:54

by David Hildenbrand

[permalink] [raw]
Subject: Re: [PATCH v2 5/5] memblock tests: remove completed TODO item

On 03.10.22 01:41, Rebecca Mckeever wrote:
> Remove completed item from TODO list.
>
> Signed-off-by: Rebecca Mckeever <[email protected]>
> ---

Reviewed-by: David Hildenbrand <[email protected]>

--
Thanks,

David / dhildenb

2022-10-10 11:32:17

by David Hildenbrand

[permalink] [raw]
Subject: Re: [PATCH v2 1/5] memblock tests: add range tests for memblock_alloc_exact_nid_raw

On 03.10.22 01:41, Rebecca Mckeever wrote:
> Add tests for memblock_alloc_exact_nid_raw() that are very similar to
> the range tests for memblock_alloc_try_nid_raw().
>
> Signed-off-by: Rebecca Mckeever <[email protected]>
> ---
> tools/testing/memblock/Makefile | 2 +-
> tools/testing/memblock/main.c | 2 +
> .../memblock/tests/alloc_exact_nid_api.c | 1208 +++++++++++++++++
> .../memblock/tests/alloc_exact_nid_api.h | 9 +
> 4 files changed, 1220 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.c
> create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.h
>
> diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile
> index 246f7ac8489b..2310ac4d080e 100644
> --- a/tools/testing/memblock/Makefile
> +++ b/tools/testing/memblock/Makefile
> @@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
> LDFLAGS += -fsanitize=address -fsanitize=undefined
> TARGETS = main
> TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
> - tests/basic_api.o tests/common.o
> + tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
> DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o
> OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
> EXTR_SRC = ../../../mm/memblock.c
> diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c
> index 4ca1024342b1..278f9dec5008 100644
> --- a/tools/testing/memblock/main.c
> +++ b/tools/testing/memblock/main.c
> @@ -3,6 +3,7 @@
> #include "tests/alloc_api.h"
> #include "tests/alloc_helpers_api.h"
> #include "tests/alloc_nid_api.h"
> +#include "tests/alloc_exact_nid_api.h"
> #include "tests/common.h"
>
> int main(int argc, char **argv)
> @@ -12,6 +13,7 @@ int main(int argc, char **argv)
> memblock_alloc_checks();
> memblock_alloc_helpers_checks();
> memblock_alloc_nid_checks();
> + memblock_alloc_exact_nid_checks();
>
> return 0;
> }


memblock_alloc_exact_nid_raw(NUMA_NO_NODE) behaves exactly the way
memblock_alloc_try_nid_raw(NUMA_NO_NODE) behaves -- which is essentially
memblock_alloc_raw().

So do we really need a separate set of tests for these?

--
Thanks,

David / dhildenb

2022-10-11 04:40:05

by Rebecca Mckeever

[permalink] [raw]
Subject: Re: [PATCH v2 1/5] memblock tests: add range tests for memblock_alloc_exact_nid_raw

On Mon, Oct 10, 2022 at 01:16:03PM +0200, David Hildenbrand wrote:
> On 03.10.22 01:41, Rebecca Mckeever wrote:
> > Add tests for memblock_alloc_exact_nid_raw() that are very similar to
> > the range tests for memblock_alloc_try_nid_raw().
> >
> > Signed-off-by: Rebecca Mckeever <[email protected]>
> > ---
> > tools/testing/memblock/Makefile | 2 +-
> > tools/testing/memblock/main.c | 2 +
> > .../memblock/tests/alloc_exact_nid_api.c | 1208 +++++++++++++++++
> > .../memblock/tests/alloc_exact_nid_api.h | 9 +
> > 4 files changed, 1220 insertions(+), 1 deletion(-)
> > create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.c
> > create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.h
> >
> > diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile
> > index 246f7ac8489b..2310ac4d080e 100644
> > --- a/tools/testing/memblock/Makefile
> > +++ b/tools/testing/memblock/Makefile
> > @@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
> > LDFLAGS += -fsanitize=address -fsanitize=undefined
> > TARGETS = main
> > TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
> > - tests/basic_api.o tests/common.o
> > + tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
> > DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o
> > OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
> > EXTR_SRC = ../../../mm/memblock.c
> > diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c
> > index 4ca1024342b1..278f9dec5008 100644
> > --- a/tools/testing/memblock/main.c
> > +++ b/tools/testing/memblock/main.c
> > @@ -3,6 +3,7 @@
> > #include "tests/alloc_api.h"
> > #include "tests/alloc_helpers_api.h"
> > #include "tests/alloc_nid_api.h"
> > +#include "tests/alloc_exact_nid_api.h"
> > #include "tests/common.h"
> > int main(int argc, char **argv)
> > @@ -12,6 +13,7 @@ int main(int argc, char **argv)
> > memblock_alloc_checks();
> > memblock_alloc_helpers_checks();
> > memblock_alloc_nid_checks();
> > + memblock_alloc_exact_nid_checks();
> > return 0;
> > }
>
>
> memblock_alloc_exact_nid_raw(NUMA_NO_NODE) behaves exactly the way
> memblock_alloc_try_nid_raw(NUMA_NO_NODE) behaves -- which is essentially
> memblock_alloc_raw().
>
> So do we really need a separate set of tests for these?
>
Instead of a separate set of tests, I could add a flag for
memblock_alloc_exact_nid_raw() to test_flags so that the range tests in
alloc_nid_api.c could be run with that flag. Do you think I should do
that, or omit tests for memblock_alloc_exact_nid_raw(NUMA_NO_NODE)
altogether?

> --
> Thanks,
>
> David / dhildenb
>
Thanks,
Rebecca

2022-10-11 09:49:04

by David Hildenbrand

[permalink] [raw]
Subject: Re: [PATCH v2 1/5] memblock tests: add range tests for memblock_alloc_exact_nid_raw

On 11.10.22 06:19, Rebecca Mckeever wrote:
> On Mon, Oct 10, 2022 at 01:16:03PM +0200, David Hildenbrand wrote:
>> On 03.10.22 01:41, Rebecca Mckeever wrote:
>>> Add tests for memblock_alloc_exact_nid_raw() that are very similar to
>>> the range tests for memblock_alloc_try_nid_raw().
>>>
>>> Signed-off-by: Rebecca Mckeever <[email protected]>
>>> ---
>>> tools/testing/memblock/Makefile | 2 +-
>>> tools/testing/memblock/main.c | 2 +
>>> .../memblock/tests/alloc_exact_nid_api.c | 1208 +++++++++++++++++
>>> .../memblock/tests/alloc_exact_nid_api.h | 9 +
>>> 4 files changed, 1220 insertions(+), 1 deletion(-)
>>> create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.c
>>> create mode 100644 tools/testing/memblock/tests/alloc_exact_nid_api.h
>>>
>>> diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile
>>> index 246f7ac8489b..2310ac4d080e 100644
>>> --- a/tools/testing/memblock/Makefile
>>> +++ b/tools/testing/memblock/Makefile
>>> @@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
>>> LDFLAGS += -fsanitize=address -fsanitize=undefined
>>> TARGETS = main
>>> TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
>>> - tests/basic_api.o tests/common.o
>>> + tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
>>> DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o
>>> OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
>>> EXTR_SRC = ../../../mm/memblock.c
>>> diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c
>>> index 4ca1024342b1..278f9dec5008 100644
>>> --- a/tools/testing/memblock/main.c
>>> +++ b/tools/testing/memblock/main.c
>>> @@ -3,6 +3,7 @@
>>> #include "tests/alloc_api.h"
>>> #include "tests/alloc_helpers_api.h"
>>> #include "tests/alloc_nid_api.h"
>>> +#include "tests/alloc_exact_nid_api.h"
>>> #include "tests/common.h"
>>> int main(int argc, char **argv)
>>> @@ -12,6 +13,7 @@ int main(int argc, char **argv)
>>> memblock_alloc_checks();
>>> memblock_alloc_helpers_checks();
>>> memblock_alloc_nid_checks();
>>> + memblock_alloc_exact_nid_checks();
>>> return 0;
>>> }
>>
>>
>> memblock_alloc_exact_nid_raw(NUMA_NO_NODE) behaves exactly the way
>> memblock_alloc_try_nid_raw(NUMA_NO_NODE) behaves -- which is essentially
>> memblock_alloc_raw().
>>
>> So do we really need a separate set of tests for these?
>>
> Instead of a separate set of tests, I could add a flag for
> memblock_alloc_exact_nid_raw() to test_flags so that the range tests in
> alloc_nid_api.c could be run with that flag. Do you think I should do
> that, or omit tests for memblock_alloc_exact_nid_raw(NUMA_NO_NODE)
> altogether?

Good question. From an API point of view, it makes sense to test that
API somehow. With implementation in mind, it doesn't make too much sense
to test it twice.

Whatever you prefer :) Just wanted to point out that separate tests
don't make sense -- using a flag would be cleaner.

--
Thanks,

David / dhildenb