mm: page_alloc: skip over regions of invalid pfns where possible
When using a sparse memory model memmap_init_zone() when invoked with the MEMMAP_EARLY context will skip over pages which aren't valid - ie. which aren't in a populated region of the sparse memory map. However if the memory map is extremely sparse then it can spend a long time linearly checking each PFN in a large non-populated region of the memory map & skipping it in turn. When CONFIG_HAVE_MEMBLOCK_NODE_MAP is enabled, we have sufficient information to quickly discover the next valid PFN given an invalid one by searching through the list of memory regions & skipping forwards to the first PFN covered by the memory region to the right of the non-populated region. Implement this in order to speed up memmap_init_zone() for systems with extremely sparse memory maps. James said "I have tested this patch on a virtual model of a Samurai CPU with a sparse memory map. The kernel boot time drops from 109 to 62 seconds. " Link: http://lkml.kernel.org/r/20161125185518.29885-1-paul.burton@imgtec.com Signed-off-by: Paul Burton <paul.burton@imgtec.com> Tested-by: James Hartley <james.hartley@imgtec.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:

committed by
Linus Torvalds

parent
7f354a548d
commit
b92df1de5d
@@ -1105,6 +1105,31 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid,
|
||||
*out_nid = r->nid;
|
||||
}
|
||||
|
||||
unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn,
|
||||
unsigned long max_pfn)
|
||||
{
|
||||
struct memblock_type *type = &memblock.memory;
|
||||
unsigned int right = type->cnt;
|
||||
unsigned int mid, left = 0;
|
||||
phys_addr_t addr = PFN_PHYS(pfn + 1);
|
||||
|
||||
do {
|
||||
mid = (right + left) / 2;
|
||||
|
||||
if (addr < type->regions[mid].base)
|
||||
right = mid;
|
||||
else if (addr >= (type->regions[mid].base +
|
||||
type->regions[mid].size))
|
||||
left = mid + 1;
|
||||
else {
|
||||
/* addr is within the region, so pfn + 1 is valid */
|
||||
return min(pfn + 1, max_pfn);
|
||||
}
|
||||
} while (left < right);
|
||||
|
||||
return min(PHYS_PFN(type->regions[right].base), max_pfn);
|
||||
}
|
||||
|
||||
/**
|
||||
* memblock_set_node - set node ID on memblock regions
|
||||
* @base: base of area to set node ID for
|
||||
|
Reference in New Issue
Block a user