memblock: Avoid useless checks in memblock_merge_regions().
authorPeng Zhang <zhangpeng.00@bytedance.com>
Sun, 29 Jan 2023 09:00:34 +0000 (17:00 +0800)
committerMike Rapoport (IBM) <rppt@kernel.org>
Tue, 31 Jan 2023 13:51:56 +0000 (15:51 +0200)
memblock_merge_regions() is called after regions have been modified to
merge the neighboring compatible regions. That will check all regions
but most checks are useless.

Most of the time we only insert one or a few new regions, or modify one or
a few regions. At this time, we don't need to check all the regions. We
only need to check the changed regions, because other not related regions
cannot be merged.

Add two parameters to memblock_merge_regions() to indicate the lower and
upper boundary to scan.

Debug code that counts the number of total iterations in
memblock_merge_regions(), like for instance

void memblock_merge_regions(struct memblock_type *type)
{
static int iteration_count = 0;
static int max_nr_regions = 0;

max_nr_regions = max(max_nr_regions, (int)type->cnt);
...
while () {
iteration_count++;
...
}
pr_info("iteration_count: %d max_nr_regions %d", iteration_count,
max_nr_regions);
}

Produces the following numbers on a physical machine with 1T of memory:

before: [2.472243] iteration_count: 45410 max_nr_regions 178
after:  [2.470869] iteration_count: 923 max_nr_regions 176

The actual startup speed seems to change little, but it does reduce the
scan overhead.

Signed-off-by: Peng Zhang <zhangpeng.00@bytedance.com>
Link: https://lore.kernel.org/r/20230129090034.12310-3-zhangpeng.00@bytedance.com
[rppt: massaged the changelog]
Signed-off-by: Mike Rapoport (IBM) <rppt@kernel.org>
mm/memblock.c

index 836eb71ea3eabdb71bafc07432af6ff373cd8a51..22e48b0f57ad769218caad221f22ad3a99370e08 100644 (file)
@@ -500,15 +500,19 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 /**
  * memblock_merge_regions - merge neighboring compatible regions
  * @type: memblock type to scan
- *
- * Scan @type and merge neighboring compatible regions.
+ * @start_rgn: start scanning from (@start_rgn - 1)
+ * @end_rgn: end scanning at (@end_rgn - 1)
+ * Scan @type and merge neighboring compatible regions in [@start_rgn - 1, @end_rgn)
  */
-static void __init_memblock memblock_merge_regions(struct memblock_type *type)
+static void __init_memblock memblock_merge_regions(struct memblock_type *type,
+                                                  unsigned long start_rgn,
+                                                  unsigned long end_rgn)
 {
        int i = 0;
-
-       /* cnt never goes below 1 */
-       while (i < type->cnt - 1) {
+       if (start_rgn)
+               i = start_rgn - 1;
+       end_rgn = min(end_rgn, type->cnt - 1);
+       while (i < end_rgn) {
                struct memblock_region *this = &type->regions[i];
                struct memblock_region *next = &type->regions[i + 1];
 
@@ -525,6 +529,7 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
                /* move forward from next + 1, index of which is i + 2 */
                memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
                type->cnt--;
+               end_rgn--;
        }
 }
 
@@ -581,7 +586,7 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
        bool insert = false;
        phys_addr_t obase = base;
        phys_addr_t end = base + memblock_cap_size(base, &size);
-       int idx, nr_new;
+       int idx, nr_new, start_rgn = -1, end_rgn;
        struct memblock_region *rgn;
 
        if (!size)
@@ -635,10 +640,14 @@ repeat:
 #endif
                        WARN_ON(flags != rgn->flags);
                        nr_new++;
-                       if (insert)
+                       if (insert) {
+                               if (start_rgn == -1)
+                                       start_rgn = idx;
+                               end_rgn = idx + 1;
                                memblock_insert_region(type, idx++, base,
                                                       rbase - base, nid,
                                                       flags);
+                       }
                }
                /* area below @rend is dealt with, forget about it */
                base = min(rend, end);
@@ -647,9 +656,13 @@ repeat:
        /* insert the remaining portion */
        if (base < end) {
                nr_new++;
-               if (insert)
+               if (insert) {
+                       if (start_rgn == -1)
+                               start_rgn = idx;
+                       end_rgn = idx + 1;
                        memblock_insert_region(type, idx, base, end - base,
                                               nid, flags);
+               }
        }
 
        if (!nr_new)
@@ -666,7 +679,7 @@ repeat:
                insert = true;
                goto repeat;
        } else {
-               memblock_merge_regions(type);
+               memblock_merge_regions(type, start_rgn, end_rgn);
                return 0;
        }
 }
@@ -902,7 +915,7 @@ static int __init_memblock memblock_setclr_flag(phys_addr_t base,
                        r->flags &= ~flag;
        }
 
-       memblock_merge_regions(type);
+       memblock_merge_regions(type, start_rgn, end_rgn);
        return 0;
 }
 
@@ -1275,7 +1288,7 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
        for (i = start_rgn; i < end_rgn; i++)
                memblock_set_region_node(&type->regions[i], nid);
 
-       memblock_merge_regions(type);
+       memblock_merge_regions(type, start_rgn, end_rgn);
 #endif
        return 0;
 }