RE: free bootmem feedback patch

Luck, Tony
2004-07-15T19:11:07Z

[-- Attachment #1: Type: text/plain, Size: 2188 bytes --]

William Irwin wrote:
>I'd even go so far as to suggest scanning the bitmap until the
>maximally sized higher-order page to free at the cursor (determined
>by cursor alignment and the first bit indicating a reserved page or
>otherwise MAX_ORDER bits out from the cursor) is found.

Attached is my version that just frees pages in O(log2(BITS_PER_LONG))
pieces ... because I'm too lazy to figure out all the boundary
conditions to implement wli's excellent suggestion.

On my 2G machine, this reduced the time to free all the bootmem
from 41ms to 18.1ms ... so it should shave some minutes off the
monster SGI box that started this thread, but perhaps not enough
to avoid the "looks like the system is hung" problem as you will
still be looking at a couple of minutes :-( Since I only got a
55% reduction, rather than a factor of 64 I expect that modifying
to look an larger order pages may have diminishing returns.

Notes and Caveats:
1) Is there a define someplace for log2(BITS_PER_LONG)? I couldn't
find one, which is why I calculate the "order" in this patch.

2) On ia64 it looks like the pages and the bitmap are nicely aligned
so that a longword in node_bootmem_map[] corresponds to an order 6
page with the right physical alignment. This may not be true on other
architectures, and mm/bootmem.c is generic code. Before this patch
can go into the base, someone would have to check all the other
architectures (some of which might not care to change ... if they
only support 4G or less, then the benefits of saving a few milliseconds
during boot may not inspire them to mess with the boot code). For
this reason I'm not adding a "Signed-off-by" to this patch because
I don't want the flack for breaking other architectures ... but by
all means take this patch and try it out.

I did also play with adding a "prefetchw(page + N)" to the original
loop. With N>=6 the saving is about 5% for me. SGI might need a
bigger N, and might see more savings, since most of the accesses
here are to remote nodes. I didn't try this in my modified patch
(the gains may be smaller as we don't do as much work in between
touching each page).

-Tony

[-- Attachment #2: bootmem.patch --]
[-- Type: application/octet-stream, Size: 1110 bytes --]

diff -ru linux-2.6.8-rc1-orig/mm/bootmem.c linux-2.6.8-rc1/mm/bootmem.c
--- linux-2.6.8-rc1-orig/mm/bootmem.c 2004-07-11 10:34:19.000000000 -0700
+++ linux-2.6.8-rc1/mm/bootmem.c 2004-07-15 11:22:33.464794109 -0700
@@ -259,9 +259,12 @@
unsigned long i, count, total = 0;
unsigned long idx;
unsigned long *map;
+ int order;

BUG_ON(!bdata->node_bootmem_map);

+ for (order = 0; (1 << order) < BITS_PER_LONG; order++)
+ ;
count = 0;
/* first extant page of the node */
page = virt_to_page(phys_to_virt(bdata->node_boot_start));
@@ -269,7 +272,20 @@
map = bdata->node_bootmem_map;
for (i = 0; i < idx; ) {
unsigned long v = ~map[i / BITS_PER_LONG];
- if (v) {
+ if (v == ~0UL) {
+ int j;
+
+ count += BITS_PER_LONG;
+ ClearPageReserved(page);
+ set_page_count(page, 1);
+ for (j = 1; j < BITS_PER_LONG; j++) {
+ ClearPageReserved(page + j);
+ set_page_count(page + j, 0);
+ }
+ __free_pages(page, order);
+ i += BITS_PER_LONG;
+ page += BITS_PER_LONG;
+ } else if (v) {
unsigned long m;
for (m = 1; m && i < idx; m<<=1, page++, i++) {
if (v & m) {