xref: /openbmc/linux/Documentation/translations/zh_CN/mm/page_owner.rst (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1ee65728eSMike Rapoport:Original: Documentation/mm/page_owner.rst
2ee65728eSMike Rapoport
3ee65728eSMike Rapoport:翻译:
4ee65728eSMike Rapoport
5ee65728eSMike Rapoport 司延腾 Yanteng Si <siyanteng@loongson.cn>
6ee65728eSMike Rapoport
7ee65728eSMike Rapoport:校译:
8ee65728eSMike Rapoport
9ee65728eSMike Rapoport
10ee65728eSMike Rapoport================================
11ee65728eSMike Rapoportpage owner: 跟踪谁分配的每个页面
12ee65728eSMike Rapoport================================
13ee65728eSMike Rapoport
14ee65728eSMike Rapoport概述
15ee65728eSMike Rapoport====
16ee65728eSMike Rapoport
17ee65728eSMike Rapoportpage owner是用来追踪谁分配的每一个页面。它可以用来调试内存泄漏或找到内存占用者。
18ee65728eSMike Rapoport当分配发生时,有关分配的信息,如调用堆栈和页面的顺序被存储到每个页面的特定存储中。
19ee65728eSMike Rapoport当我们需要了解所有页面的状态时,我们可以获得并分析这些信息。
20ee65728eSMike Rapoport
21ee65728eSMike Rapoport尽管我们已经有了追踪页面分配/释放的tracepoint,但用它来分析谁分配的每个页面是
22ee65728eSMike Rapoport相当复杂的。我们需要扩大跟踪缓冲区,以防止在用户空间程序启动前出现重叠。而且,启
23ee65728eSMike Rapoport动的程序会不断地将跟踪缓冲区转出,供以后分析,这将会改变系统的行为,会产生更多的
24ee65728eSMike Rapoport可能性,而不是仅仅保留在内存中,所以不利于调试。
25ee65728eSMike Rapoport
26ee65728eSMike Rapoport页面所有者也可以用于各种目的。例如,可以通过每个页面的gfp标志信息获得精确的碎片
27ee65728eSMike Rapoport统计。如果启用了page owner,它就已经实现并激活了。我们非常欢迎其他用途。
28ee65728eSMike Rapoport
29ee65728eSMike Rapoportpage owner在默认情况下是禁用的。所以,如果你想使用它,你需要在你的启动cmdline
30ee65728eSMike Rapoport中加入"page_owner=on"。如果内核是用page owner构建的,并且由于没有启用启动
31ee65728eSMike Rapoport选项而在运行时禁用page owner,那么运行时的开销是很小的。如果在运行时禁用,它不
32ee65728eSMike Rapoport需要内存来存储所有者信息,所以没有运行时内存开销。而且,页面所有者在页面分配器的
33ee65728eSMike Rapoport热路径中只插入了两个不可能的分支,如果不启用,那么分配就会像没有页面所有者的内核
34ee65728eSMike Rapoport一样进行。这两个不可能的分支应该不会影响到分配的性能,特别是在静态键跳转标签修补
35ee65728eSMike Rapoport功能可用的情况下。以下是由于这个功能而导致的内核代码大小的变化。
36ee65728eSMike Rapoport
37c363059cSYanteng Si尽管启用page owner会使内核的大小增加几千字节,但这些代码大部分都在页面分配器和
38c363059cSYanteng Si热路径之外。构建带有page owner的内核,并在需要时打开它,将是调试内核内存问题的
39c363059cSYanteng Si最佳选择。
40ee65728eSMike Rapoport
41ee65728eSMike Rapoport有一个问题是由实现细节引起的。页所有者将信息存储到struct page扩展的内存中。这
42ee65728eSMike Rapoport个内存的初始化时间比稀疏内存系统中的页面分配器启动的时间要晚一些,所以,在初始化
43ee65728eSMike Rapoport之前,许多页面可以被分配,但它们没有所有者信息。为了解决这个问题,这些早期分配的
44ee65728eSMike Rapoport页面在初始化阶段被调查并标记为分配。虽然这并不意味着它们有正确的所有者信息,但至
45ee65728eSMike Rapoport少,我们可以更准确地判断该页是否被分配。在2GB内存的x86-64虚拟机上,有13343
46ee65728eSMike Rapoport个早期分配的页面被捕捉和标记,尽管它们大部分是由结构页扩展功能分配的。总之,在这
47ee65728eSMike Rapoport之后,没有任何页面处于未追踪状态。
48ee65728eSMike Rapoport
49ee65728eSMike Rapoport使用方法
50ee65728eSMike Rapoport========
51ee65728eSMike Rapoport
52ee65728eSMike Rapoport1) 构建用户空间的帮助::
53ee65728eSMike Rapoport
54*799fb82aSSeongJae Park	cd tools/mm
55ee65728eSMike Rapoport	make page_owner_sort
56ee65728eSMike Rapoport
57ee65728eSMike Rapoport2) 启用page owner: 添加 "page_owner=on" 到 boot cmdline.
58ee65728eSMike Rapoport
59ee65728eSMike Rapoport3) 做你想调试的工作。
60ee65728eSMike Rapoport
61ee65728eSMike Rapoport4) 分析来自页面所有者的信息::
62ee65728eSMike Rapoport
63ee65728eSMike Rapoport	cat /sys/kernel/debug/page_owner > page_owner_full.txt
64ee65728eSMike Rapoport	./page_owner_sort page_owner_full.txt sorted_page_owner.txt
65ee65728eSMike Rapoport
664e3ce6d0SYanteng Si   ``page_owner_full.txt`` 的一般输出情况如下::
67ee65728eSMike Rapoport
68ee65728eSMike Rapoport	Page allocated via order XXX, ...
69ee65728eSMike Rapoport	PFN XXX ...
704e3ce6d0SYanteng Si	// 栈详情
71ee65728eSMike Rapoport
72ee65728eSMike Rapoport	Page allocated via order XXX, ...
73ee65728eSMike Rapoport	PFN XXX ...
744e3ce6d0SYanteng Si	// 栈详情
754e3ce6d0SYanteng Si    默认情况下,它将以一个给定的pfn开始,做完整的pfn转储,且page_owner支持fseek。
764e3ce6d0SYanteng Si
774e3ce6d0SYanteng Si    FILE *fp = fopen("/sys/kernel/debug/page_owner", "r");
784e3ce6d0SYanteng Si    fseek(fp, pfn_start, SEEK_SET);
79ee65728eSMike Rapoport
80ee65728eSMike Rapoport   ``page_owner_sort`` 工具忽略了 ``PFN`` 行,将剩余的行放在buf中,使用regexp提
81ee65728eSMike Rapoport   取页序值,计算buf的次数和页数,最后根据参数进行排序。
82ee65728eSMike Rapoport
83ee65728eSMike Rapoport   在 ``sorted_page_owner.txt`` 中可以看到关于谁分配了每个页面的结果。一般输出::
84ee65728eSMike Rapoport
85ee65728eSMike Rapoport	XXX times, XXX pages:
86ee65728eSMike Rapoport	Page allocated via order XXX, ...
87ee65728eSMike Rapoport	// Detailed stack
88ee65728eSMike Rapoport
89ee65728eSMike Rapoport   默认情况下, ``page_owner_sort`` 是根据buf的时间来排序的。如果你想
90ee65728eSMike Rapoport   按buf的页数排序,请使用-m参数。详细的参数是:
91ee65728eSMike Rapoport
926614a3c3SLinus Torvalds   基本函数::
93ee65728eSMike Rapoport
946614a3c3SLinus Torvalds	排序:
95ee65728eSMike Rapoport		-a		按内存分配时间排序
96ee65728eSMike Rapoport		-m		按总内存排序
97ee65728eSMike Rapoport		-p		按pid排序。
98ee65728eSMike Rapoport		-P		按tgid排序。
996614a3c3SLinus Torvalds		-n		按任务命令名称排序。
100ee65728eSMike Rapoport		-r		按内存释放时间排序。
101ee65728eSMike Rapoport		-s		按堆栈跟踪排序。
102ee65728eSMike Rapoport		-t		按时间排序(默认)。
1036614a3c3SLinus Torvalds       --sort <order> 指定排序顺序。排序的语法是[+|-]key[,[+|-]key[,...]]。从
1046614a3c3SLinus Torvalds       **标准格式指定器**那一节选择一个键。"+"是可选的,因为默认的方向是数字或
1056614a3c3SLinus Torvalds       词法的增加。允许混合使用缩写和完整格式的键。
106ee65728eSMike Rapoport
1076614a3c3SLinus Torvalds        例子:
1086614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --sort=n,+pid,-tgid
1096614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --sort=at
110ee65728eSMike Rapoport
1116614a3c3SLinus Torvalds    其它函数::
112ee65728eSMike Rapoport
1136614a3c3SLinus Torvalds	剔除:
1146614a3c3SLinus Torvalds		--cull <rules>
1156614a3c3SLinus Torvalds		        指定剔除规则。剔除的语法是key[,key[,...]]。从**标准格式指定器**
1166614a3c3SLinus Torvalds				部分选择一个多字母键。
1176614a3c3SLinus Torvalds		<rules>是一个以逗号分隔的列表形式的单一参数,它提供了一种指定单个剔除规则的
1186614a3c3SLinus Torvalds		方法。 识别的关键字在下面的**标准格式指定器**部分有描述。<规则>可以通过键的
1196614a3c3SLinus Torvalds		序列k1,k2,...来指定,在下面的标准排序键部分有描述。允许混合使用简写和完整形
1206614a3c3SLinus Torvalds		式的键。
1216614a3c3SLinus Torvalds
1226614a3c3SLinus Torvalds		Examples:
1236614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --cull=stacktrace
1246614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --cull=st,pid,name
1256614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --cull=n,f
1266614a3c3SLinus Torvalds
1276614a3c3SLinus Torvalds	过滤:
128ee65728eSMike Rapoport		-f		过滤掉内存已被释放的块的信息。
1296614a3c3SLinus Torvalds
1306614a3c3SLinus Torvalds	选择:
1316614a3c3SLinus Torvalds		--pid <pidlist>		按pid选择。这将选择进程ID号出现在<pidlist>中的块。
1326614a3c3SLinus Torvalds		--tgid <tgidlist>	按tgid选择。这将选择其线程组ID号出现在<tgidlist>
1336614a3c3SLinus Torvalds		                    中的块。
1346614a3c3SLinus Torvalds		--name <cmdlist>	按任务命令名称选择。这将选择其任务命令名称出现在
1356614a3c3SLinus Torvalds		                    <cmdlist>中的区块。
1366614a3c3SLinus Torvalds
1376614a3c3SLinus Torvalds		<pidlist>, <tgidlist>, <cmdlist>是以逗号分隔的列表形式的单个参数,
1386614a3c3SLinus Torvalds		它提供了一种指定单个选择规则的方法。
1396614a3c3SLinus Torvalds
1406614a3c3SLinus Torvalds
1416614a3c3SLinus Torvalds		例子:
1426614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --pid=1
1436614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --tgid=1,2,3
1446614a3c3SLinus Torvalds				./page_owner_sort <input> <output> --name name1,name2
1456614a3c3SLinus Torvalds
1466614a3c3SLinus Torvalds标准格式指定器
1476614a3c3SLinus Torvalds==============
1486614a3c3SLinus Torvalds::
1496614a3c3SLinus Torvalds
1506614a3c3SLinus Torvalds  --sort的选项:
1516614a3c3SLinus Torvalds
1526614a3c3SLinus Torvalds	短键		长键		描述
1536614a3c3SLinus Torvalds	p		pid		进程ID
1546614a3c3SLinus Torvalds	tg		tgid		线程组ID
1556614a3c3SLinus Torvalds	n		name		任务命令名称
1566614a3c3SLinus Torvalds	st		stacktrace	页面分配的堆栈跟踪
1576614a3c3SLinus Torvalds	T		txt		块的全文
1586614a3c3SLinus Torvalds	ft		free_ts		页面释放时的时间戳
1596614a3c3SLinus Torvalds	at		alloc_ts	页面被分配时的时间戳
1606614a3c3SLinus Torvalds	ator		allocator	页面的内存分配器
1616614a3c3SLinus Torvalds
1626614a3c3SLinus Torvalds  --curl的选项:
1636614a3c3SLinus Torvalds
1646614a3c3SLinus Torvalds	短键		长键		描述
1656614a3c3SLinus Torvalds	p		pid		进程ID
1666614a3c3SLinus Torvalds	tg		tgid		线程组ID
1676614a3c3SLinus Torvalds	n		name		任务命令名称
1686614a3c3SLinus Torvalds	f		free		该页是否已经释放
1696614a3c3SLinus Torvalds	st		stacktrace	页面分配的堆栈跟踪
1706614a3c3SLinus Torvalds	ator		allocator	页面的内存分配器
171