defer_init,内核中的延迟满足
在上一节的内容中page结构体,我要如何安放你的灵魂中我们看到了为了应对海量内存,内核是如何安放page结构体的。然而到了这里,事情还没有结束。紧接着应对海量内存,内核遇到了另一个棘手的问题―初始化。
Page结构体需要初始化后才能加入到buddy分配器供内核中各个模块使用,可想而知,随着内存容量的增加,需要初始化的page结构体也会增加。如果没有记错的话,当内存达到T级别,page结构体初始化的时间将达到分钟级。
那有什么办法解决这个问题呢?有的,那就是
延迟满足
其实思想很简单,在系统启动时只初始化部分的page结构体,然后使用内核线程来初始化剩下的page结构体。从而达到尽量减少page结构体初始化对系统启动的影响。
多说无益,我们还是直接来看代码吧。
正常情况
为了有一个对比,我们先来看看没有defer_init的情况。
start_kernel()
setup_arch()
x86_init.paging.pagetable_init() -> paging_init()
sparse_init()
sparse_init_nid()
map = __populate_section_memmap() (1)
sparse_init_one_section(sec, map)
zone_sizes_init()
free_area_init() -> free_area_init_node()
free_area_init_core()
memmap_init() -> memmap_init_zone()
__init_single_page() (2)
mm_core_init() -> mem_init()
memblock_free_all()
free_low_memory_core_early()
__free_memory_core() -> __free_pages_memory()
memblock_free_pages()
__free_pages_core() (3)
Page结构体要经历三个过程,被分配,被初始化,添加到buddy。
在上述代码片段中,分别标出了这三个步骤在正常情况下发生的时机。而defer_init要解决的就是2,3在初始化时占用的时间过多,导致系统启动时间过长。
既然是在2,3的地方占用了太多时间,那么就把这部分的工作延后执行把。
延迟满足
现在我们来看看内核代码是如何把这部分的工作延后执行的。
start_kernel()
setup_arch()
x86_init.paging.pagetable_init() -> paging_init()
sparse_init()
sparse_init_nid()
map = __populate_section_memmap()
sparse_init_one_section(sec, map)
zone_sizes_init()
free_area_init() -> free_area_init_node()
free_area_init_core()
memmap_init() -> memmap_init_zone()
defer_init() (1)
__init_single_page()
mm_core_init() -> mem_init()
memblock_free_all()
free_low_memory_core_early()
__free_memory_core() -> __free_pages_memory()
memblock_free_pages()
early_page_uninitialised() (2)
__free_pages_core()
rest_init()
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
kernel_init_freeable() -> page_alloc_init_late()
deferred_init_memmap() (3)
在上面的代码片段中可以看到,在1,2的地方分别增加了判断,是否要跳过这部分的初始化。
接着在3的位置启用了一个内核线程来初始化剩下的page结构体,并将page释放到buddy system。
好了,这件事情就是这么简单~
Last updated