[PATCH] mm: optimize memblock_add_range() for improved performance

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



- Streamlined memory insertion logic to minimize redundant iterations.
- Improved handling of memory insufficiency to avoid excessive
  reallocations.

Signed-off-by: stephen.eta.zhou <stephen.eta.zhou@xxxxxxxxxxx>
---
 mm/memblock.c | 106 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 70 insertions(+), 36 deletions(-)

diff --git a/mm/memblock.c b/mm/memblock.c
index 95af35fd1389..75c76b39a364 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -585,16 +585,16 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??phys_addr_t base, phys_addr_t size,
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??int nid, enum memblock_flags flags)
 {
-â??â??â??â??â??bool insert = false;
 â??â??â??â??â??phys_addr_t obase = base;
 â??â??â??â??â??phys_addr_t end = base + memblock_cap_size(base, &size);
-â??â??â??â??â??int idx, nr_new, start_rgn = -1, end_rgn;
+â??â??â??â??â??phys_addr_t rbase, rend;
+â??â??â??â??â??int idx, nr_new, start_rgn, end_rgn;
 â??â??â??â??â??struct memblock_region *rgn;
 
 â??â??â??â??â??if (!size)
 â??â??â??â??â??â??â??â??â??â??â??return 0;
 
-â??â??â??â??â??/* special case for empty array */
+â??â??â??â??â??/* Special case for empty array */
 â??â??â??â??â??if (type->regions[0].size == 0) {
 â??â??â??â??â??â??â??â??â??â??â??WARN_ON(type->cnt != 0 || type->total_size);
 â??â??â??â??â??â??â??â??â??â??â??type->regions[0].base = base;
@@ -606,80 +606,114 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
 â??â??â??â??â??â??â??â??â??â??â??return 0;
 â??â??â??â??â??}
 
+    /* Delayed assignment, which is not necessary when the array is empty. */
+â??â??â??â??â??start_rgn = -1;
 â??â??â??â??â??/*
-â??â??â??â??â?? * The worst case is when new range overlaps all existing regions,
-â??â??â??â??â?? * then we'll need type->cnt + 1 empty regions in @type. So if
-â??â??â??â??â?? * type->cnt * 2 + 1 is less than or equal to type->max, we know
-â??â??â??â??â?? * that there is enough empty regions in @type, and we can insert
-â??â??â??â??â?? * regions directly.
+â??â??â??â??â?? * Originally, `end_rgn` didn't need to be assigned a value,
+â??â??â??â??â?? * but due to the use of nested conditional expressions,
+â??â??â??â??â?? * the compiler reports a warning that `end_rgn` is uninitialized.
+â??â??â??â??â?? * Therefore, it has been given an initial value here
+â??â??â??â??â?? * to eliminate the warning.
 â??â??â??â??â?? */
-â??â??â??â??â??if (type->cnt * 2 + 1 <= type->max)
-â??â??â??â??â??â??â??â??â??â??â??insert = true;
+â??â??â??â??â??end_rgn   = -1;
 
 repeat:
 â??â??â??â??â??/*
-â??â??â??â??â?? * The following is executed twice.  Once with %false @insert and
-â??â??â??â??â?? * then with %true.  The first counts the number of regions needed
-â??â??â??â??â?? * to accommodate the new area.  The second actually inserts them.
+â??â??â??â??â?? * It is assumed that insertion is always possible under normal circumstances.
+â??â??â??â??â?? * If memory is insufficient during insertion, the operation will record the need,
+â??â??â??â??â?? * allocate memory, and then re-execute the insertion for the remaining portion.
 â??â??â??â??â?? */
 â??â??â??â??â??base = obase;
 â??â??â??â??â??nr_new = 0;
 
 â??â??â??â??â??for_each_memblock_type(idx, type, rgn) {
-â??â??â??â??â??â??â??â??â??â??â??phys_addr_t rbase = rgn->base;
-â??â??â??â??â??â??â??â??â??â??â??phys_addr_t rend = rbase + rgn->size;
+â??â??â??â??â??â??â??â??â??â??â??rbase = rgn->base;
+â??â??â??â??â??â??â??â??â??â??â??rend = rbase + rgn->size;
 
 â??â??â??â??â??â??â??â??â??â??â??if (rbase >= end)
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??break;
 â??â??â??â??â??â??â??â??â??â??â??if (rend <= base)
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??continue;
+
 â??â??â??â??â??â??â??â??â??â??â??/*
-â??â??â??â??â??â??â??â??â??â??â?? * @rgn overlaps.  If it separates the lower part of new
-â??â??â??â??â??â??â??â??â??â??â?? * area, insert that portion.
+â??â??â??â??â??â??â??â??â??â??â?? * @rgn overlaps. If it separates the lower part of new area, insert that portion.
 â??â??â??â??â??â??â??â??â??â??â?? */
 â??â??â??â??â??â??â??â??â??â??â??if (rbase > base) {
 #ifdef CONFIG_NUMA
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??WARN_ON(nid != memblock_get_region_node(rgn));
 #endif
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??WARN_ON(flags != rgn->flags);
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++;
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (insert) {
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/*
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If memory is insufficient, the space required will be recorded.
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If memory is sufficient, the insertion will proceed.
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (type->cnt >= type->max) {
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/*
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * Record obase as the address where the
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * overlapping part has not been resolved,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * so that when repeat restarts,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * redundant operations of resolving the
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * overlapping addresses are avoided.
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (nr_new == 0)
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??obase = base;
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++;
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??} else {
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (start_rgn == -1)
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??start_rgn = idx;
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??end_rgn = idx + 1;
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx++, base,
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??       rbase - base, nid,
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??       flags);
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx++, base, rbase - base, nid, flags);
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??}
 â??â??â??â??â??â??â??â??â??â??â??}
-â??â??â??â??â??â??â??â??â??â??â??/* area below @rend is dealt with, forget about it */
+â??â??â??â??â??â??â??â??â??â??â??/* Area below @rend is dealt with, forget about it */
 â??â??â??â??â??â??â??â??â??â??â??base = min(rend, end);
 â??â??â??â??â??}
 
-â??â??â??â??â??/* insert the remaining portion */
+â??â??â??â??â??/* Insert the remaining portion */
 â??â??â??â??â??if (base < end) {
-â??â??â??â??â??â??â??â??â??â??â??nr_new++;
-â??â??â??â??â??â??â??â??â??â??â??if (insert) {
+â??â??â??â??â??â??â??â??â??â??â??/*
+â??â??â??â??â??â??â??â??â??â??â?? * Similarly, after handling the overlapping part,
+â??â??â??â??â??â??â??â??â??â??â?? * it is still possible that memory is
+â??â??â??â??â??â??â??â??â??â??â?? * insufficient. In that case, the space will be recorded once again.
+â??â??â??â??â??â??â??â??â??â??â?? */
+â??â??â??â??â??â??â??â??â??â??â??if (type->cnt >= type->max) {
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/*
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * The address of obase needs to be recorded here as well. The purpose is to
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * handle the situation where,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * after resolving the overlap, there is still a remaining space to
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * insert but memory is insufficient (i.e.,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * no memory shortage occurred while resolving the overlap).
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * This means that space for
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * N (overlapping parts) + 1 (non-overlapping part) is required.
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If obase is not recorded, after memory expansion,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * base might revert to the original address to be
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * inserted (which could be overlapping).
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * This could lead to for_each_memblock_type attempting
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * to resolve the overlap again, causing multiple unnecessary iterations,
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * even if it's just a simple check.
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (nr_new == 0)
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??obase = base;
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++;
+â??â??â??â??â??â??â??â??â??â??â??} else {
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (start_rgn == -1)
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??start_rgn = idx;
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??end_rgn = idx + 1;
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx, base, end - base,
-â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??       nid, flags);
+â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx, base, end - base, nid, flags);
 â??â??â??â??â??â??â??â??â??â??â??}
 â??â??â??â??â??}
 
-â??â??â??â??â??if (!nr_new)
-â??â??â??â??â??â??â??â??â??â??â??return 0;
-
 â??â??â??â??â??/*
-â??â??â??â??â?? * If this was the first round, resize array and repeat for actual
-â??â??â??â??â?? * insertions; otherwise, merge and return.
+â??â??â??â??â?? * Finally, check if memory insufficiency occurred during insertion.
+â??â??â??â??â?? * If so, the memory will be expanded to an appropriate size,
+â??â??â??â??â?? * and the remaining portion will be inserted again.
+â??â??â??â??â?? * If not, it means memory is sufficient, and the regions will be merged directly.
 â??â??â??â??â?? */
-â??â??â??â??â??if (!insert) {
-â??â??â??â??â??â??â??â??â??â??â??while (type->cnt + nr_new > type->max)
+â??â??â??â??â??if (nr_new > 0) {
+â??â??â??â??â??â??â??â??â??â??â??while (type->cnt + nr_new > type->max) {
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (memblock_double_array(type, obase, size) < 0)
 â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??return -ENOMEM;
-â??â??â??â??â??â??â??â??â??â??â??insert = true;
+â??â??â??â??â??â??â??â??â??â??â??}
 â??â??â??â??â??â??â??â??â??â??â??goto repeat;
 â??â??â??â??â??} else {
 â??â??â??â??â??â??â??â??â??â??â??memblock_merge_regions(type, start_rgn, end_rgn);
-- 
2.25.1





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux