结束了对内核进程的剖析,接下来将要开始对内核资源(从os角度)的剖析。OS为了更好地管理资源,会对真实的资源进行虚拟化,例如针对内存有虚拟内存(虚拟线性地址空间),针对与文件系统有虚拟文件系统(VFS层);为了更好的使用该资源会首先对资源进行抽象(即定义资源的数据结构)然后基于此在定义操作(函数)。因此,我们读内核,要遵从“虚实结合,一动一静”的原则,虚与实的结合往往便是掌握内核的关键,动与静可以从两个角度出发:一是描述该资源的数据结构,二是操作该资源的函数。
虚实结合
http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory这个博客讲的不错,自己的感悟后面在慢慢补充吧。
动静结合
内存管理的数据结构有三个,这三个是包含的意思,从高层到底层,粒度越来越细,struct pg_data_t是最上层的结构体,在UMA机上只有一个;下一层是struct zone,一个struct pg_data_t中包含很多个struct zone;最底层的是struct page。这三者的结构如下图所示,其中zone中的struct free_area free_area[MAX_ORDER]就是管理空闲page的buddy方法。
遍历系统中所有zone
针对于我们的pc机,只有一个pg_data_t结构体,系统中所有的zone并不是采用链表的形式串联在一起的,而是在pa_data_t中使用数组来表示的(如上图所示),所以找到系统中那个唯一的pa_data_t结构体的地址,便可以遍历系统中的所有zonele。
我们打印的内容有zone的名字,zone的起始物理页框号,每个zone包含的page数量,以及可用page数量(内存空洞不可使用)。代码如下:
1 //scan the zones
2
3 %{
4 #include <linux/mmzone.h>
5 #include <linux/mm.h>
6
7 structpglist_data *(*first_online_pgdat_own)(void)=(struct pglist_data*(*)(void))0xffffffff81125cd0;
8 struct zone *(*next_zone_own)(structzone *)=(struct zone *(*)(struct zone *))0xffffffff81125d60;
9
10 void print_each_zone(void)
11 {
12 struct zone *zone;
13 struct pglist_data *pg_data;
14
15 pg_data =first_online_pgdat_own();
16 _stp_printf("node_id:%d\tnr_zones:%d\n",pg_data->node_id,pg_data->nr_zones);
17 _stp_printf("node_start_pfn:%ld \tnode_present_pages:%ld\tnode_spanned_pages:%ld\n\n",\
18 pg_data->node_start_pfn,pg_data->node_present_pages,pg_data->node_spanned_pages);
19 for(zone=pg_data->node_zones;zone;zone = next_zone_own(zone))
20 {
21 _stp_printf("zonename:%s\n",zone->name);
22 _stp_printf("zone_start_pfn:%ld\n",zone->zone_start_pfn);
23 _stp_printf("spanned_pages:%ld\tpresent_pages:%ld\n\n",zone->spanned_pages,zone->present_pages);
24 }
25 }
26 %}
27
28 function print_each_zone_bridge()
29 %{
30 print_each_zone();
31 %}
32 probe begin
33 {
34 print_each_zone_bridge();
35 exit();
36 }
结果如下:
node_id:0 nr_zones:3