瀹屽杽浜哛EADME.md...

This commit is contained in:
gatieme
2016-08-04 16:28:45 +08:00
parent 7e7e4c9109
commit bee0a2ff16
@@ -698,7 +698,7 @@ enum zone_stat_item
##4.5 等待队列
##4.5 Zone等待队列表(zone wait queue table)
-------
@@ -717,9 +717,30 @@ struct zone
|:-----:|:-----:|
| wait_table | 待一个page释放的等待队列哈希表。它会被wait_on_page()unlock_page()函数使用. 用哈希表,而不用一个等待队列的原因,防止进程长期等待资源 |
| wait_table_hash_nr_entries | 哈希表中的等待队列的数量 |
| wait_table_bits | 等待队列散列表数组大小 |
| wait_table_bits | 等待队列散列表数组大小, wait_table_size == (1 << wait_table_bits) |
当对一个page做I/O操作的时候,I/O操作需要被锁住,防止不正确的数据被访问。进程在访问page前,wait_on_page_locked函数,使进程加入一个等待队列
访问完成后,UnlockPage函数解锁其他进程对page的访问。其他正在等待队列中的进程被唤醒。每个page都可以有一个等待队列,但是太多的分离的等待队列使得花费太多的内存访问周期。替代的解决方法,就是将所有的队列放在struct zone数据结构中
也可以有一种可能,就是struct zone中只有一个队列,但是这就意味着,当一个page unlock的时候,访问这个zone里内存page的所有休眠的进程将都被唤醒,这样就会出现拥堵(thundering herd)的问题。建立一个哈希表管理多个等待队列,能解决这个问题,zone->wait_table就是这个哈希表。哈希表的方法可能还是会造成一些进程不必要的唤醒。但是这种事情发生的机率不是很频繁的。下面这个图就是进程及等待队列的运行关系:
等待队列的哈希表的分配和建立在free_area_init_core()函数中进行。哈希表的表项的数量在wait_table_size() 函数中计算,并且保持在zone->wait_table_size成员中。最大4096个等待队列。最小是NoPages / PAGES_PER_WAITQUEUE的2次方,NoPages是zone管理的page的数量,PAGES_PER_WAITQUEUE被定义256。(原文:For smaller tables the size of the table is the minimum power of 2 required to store NoPages / PAGES PER WAITQUEUE number of queues where NoPages is the number of pages in the zone and PAGE PER WAITQUEUE is defined to be 256.
下面这个公式可以用于计算这个值:
zone->wait_table_bits用于计算:根据page 地址得到需要使用的等待队列在哈希表中的索引的算法因子。page_waitqueue()函数负责返回zone中page所对应等待队列。它用一个基于struct page虚拟地址的简单的乘法哈希算法来确定等待队列的。
page_waitqueue()函数用GOLDEN_RATIO_PRIME的地址和“右移zone→wait_table_bits一个索引值”的一个乘积来确定等待队列在哈希表中的索引的。
Zone的初始化
在kernel page table通过paging_init()函数完全建立起z来以后,zone被初始化。下面章节将描述这个。当然不同的体系结构这个过程肯定也是不一样的,但它们的目的却是相同的:确定什么参数需要传递给free_area_init()函数(对于UMA体系结构)或者free_area_init_node()函数(对于NUMA体系结构)。这里省略掉NUMA体系结构的说明。
free_area_init()函数的参数:
unsigned long *zones_sizes: 系统中每个zone所管理的page的数量的数组。这个时候,还没能确定zone中那些page是可以分配使用的(free)。这个信息知道boot memory allocator完成之前还无法知道。
来源: http://www.uml.org.cn/embeded/201208071.asp
##4.6 冷热页
-------
@@ -736,17 +757,5 @@ struct zone
PFN是物理内存以Page为单位的偏移量。系统可用的第一个PFN是min_low_pfn变量,开始与_end标号的后面,也就是kernel结束的地方。在文件mm/bootmem.c中对这个变量作初始化。系统可用的最后一个PFN是max_pfn变量,这个变量的初始化完全依赖与硬件的体系结构。x86的系统中,find_max_pfn()函数通过读取e820表获得最高的page frame的数值。同样在文件mm/bootmem.c中对这个变量作初始化。e820表是由BIOS创建的。
x86中,max_low_pfn变量是由find_max_low_pfn()函数计算并且初始化的,它被初始化成ZONE_NORMAL的最后一个page的位置。这个位置是kernel直接访问的物理内存,也是关系到kernel/userspace通过“PAGE_OFFSET宏”把线性地址内存空间分开的内存地址位置。(原文:This is the physical memory directly accessible by the kernel and is related to the kernel/userspace split in the linear address space marked by PAGE OFFSET.)我理解为这段地址kernel可以直接访问,可以通过PAGE_OFFSET宏直接将kernel所用的虚拟地址转换成物理地址的区段。在文件mm/bootmem.c中对这个变量作初始化。在内存比较小的系统中max_pfn和max_low_pfn的值相同
min_low_pfn max_pfn和max_low_pfn这3个值,也要用于对高端内存(high memory)的起止位置的计算。在arch/i386/mm/init.c文件中会对类似的highstart_pfn和highend_pfn变量作初始化。这些变量用于对高端内存页面的分配。后面将描述。
Zone等待队列表(zone wait queue table)
当对一个page做I/O操作的时候,I/O操作需要被锁住,防止不正确的数据被访问。进程在访问page前,调用wait_on_page()函数,使进程加入一个等待队列。访问完成后,UnlockPage()函数解锁其他进程对page的访问。其他正在等待队列中的进程被唤醒。每个page都可以有一个等待队列,但是太多的分离的等待队列使得花费太多的内存访问周期。替代的解决方法,就是将所有的队列放在struct zone数据结构中。
也可以有一种可能,就是struct zone中只有一个队列,但是这就意味着,当一个page unlock的时候,访问这个zone里内存page的所有休眠的进程将都被唤醒,这样就会出现拥堵(thundering herd)的问题。建立一个哈希表管理多个等待队列,能解决这个问题,zone->wait_table就是这个哈希表。哈希表的方法可能还是会造成一些进程不必要的唤醒。但是这种事情发生的机率不是很频繁的。下面这个图就是进程及等待队列的运行关系:
等待队列的哈希表的分配和建立在free_area_init_core()函数中进行。哈希表的表项的数量在wait_table_size() 函数中计算,并且保持在zone->wait_table_size成员中。最大4096个等待队列。最小是NoPages / PAGES_PER_WAITQUEUE的2次方,NoPages是zone管理的page的数量,PAGES_PER_WAITQUEUE被定义256。(原文:For smaller tables the size of the table is the minimum power of 2 required to store NoPages / PAGES PER WAITQUEUE number of queues where NoPages is the number of pages in the zone and PAGE PER WAITQUEUE is defined to be 256.
下面这个公式可以用于计算这个值:
zone->wait_table_bits用于计算:根据page 地址得到需要使用的等待队列在哈希表中的索引的算法因子。page_waitqueue()函数负责返回zone中page所对应等待队列。它用一个基于struct page虚拟地址的简单的乘法哈希算法来确定等待队列的。
page_waitqueue()函数用GOLDEN_RATIO_PRIME的地址和“右移zone→wait_table_bits一个索引值”的一个乘积来确定等待队列在哈希表中的索引的。
Zone的初始化
在kernel page table通过paging_init()函数完全建立起z来以后,zone被初始化。下面章节将描述这个。当然不同的体系结构这个过程肯定也是不一样的,但它们的目的却是相同的:确定什么参数需要传递给free_area_init()函数(对于UMA体系结构)或者free_area_init_node()函数(对于NUMA体系结构)。这里省略掉NUMA体系结构的说明。
free_area_init()函数的参数:
unsigned long *zones_sizes: 系统中每个zone所管理的page的数量的数组。这个时候,还没能确定zone中那些page是可以分配使用的(free)。这个信息知道boot memory allocator完成之前还无法知道。
来源: http://www.uml.org.cn/embeded/201208071.asp