1================================================== 2page owner: Tracking about who allocated each page 3================================================== 4 5Introduction 6============ 7 8page owner is for the tracking about who allocated each page. 9It can be used to debug memory leak or to find a memory hogger. 10When allocation happens, information about allocation such as call stack 11and order of pages is stored into certain storage for each page. 12When we need to know about status of all pages, we can get and analyze 13this information. 14 15Although we already have tracepoint for tracing page allocation/free, 16using it for analyzing who allocate each page is rather complex. We need 17to enlarge the trace buffer for preventing overlapping until userspace 18program launched. And, launched program continually dump out the trace 19buffer for later analysis and it would change system behaviour with more 20possibility rather than just keeping it in memory, so bad for debugging. 21 22page owner can also be used for various purposes. For example, accurate 23fragmentation statistics can be obtained through gfp flag information of 24each page. It is already implemented and activated if page owner is 25enabled. Other usages are more than welcome. 26 27It can also be used to show all the stacks and their current number of 28allocated base pages, which gives us a quick overview of where the memory 29is going without the need to screen through all the pages and match the 30allocation and free operation. It's also possible to show only a numeric 31identifier of all the stacks (without stack traces) and their number of 32allocated base pages (faster to read and parse, eg, for monitoring) that 33can be matched with stacks later (show_handles and show_stacks_handles). 34 35page owner is disabled by default. So, if you'd like to use it, you need 36to add "page_owner=on" to your boot cmdline. If the kernel is built 37with page owner and page owner is disabled in runtime due to not enabling 38boot option, runtime overhead is marginal. If disabled in runtime, it 39doesn't require memory to store owner information, so there is no runtime 40memory overhead. And, page owner inserts just two unlikely branches into 41the page allocator hotpath and if not enabled, then allocation is done 42like as the kernel without page owner. These two unlikely branches should 43not affect to allocation performance, especially if the static keys jump 44label patching functionality is available. Following is the kernel's code 45size change due to this facility. 46 47Although enabling page owner increases kernel size by several kilobytes, 48most of this code is outside page allocator and its hot path. Building 49the kernel with page owner and turning it on if needed would be great 50option to debug kernel memory problem. 51 52There is one notice that is caused by implementation detail. page owner 53stores information into the memory from struct page extension. This memory 54is initialized some time later than that page allocator starts in sparse 55memory system, so, until initialization, many pages can be allocated and 56they would have no owner information. To fix it up, these early allocated 57pages are investigated and marked as allocated in initialization phase. 58Although it doesn't mean that they have the right owner information, 59at least, we can tell whether the page is allocated or not, 60more accurately. On 2GB memory x86-64 VM box, 13343 early allocated pages 61are caught and marked, although they are mostly allocated from struct 62page extension feature. Anyway, after that, no page is left in 63un-tracking state. 64 65Usage 66===== 67 681) Build user-space helpers: 69:: 70 71 To filter page_owner output: 72 73 cd tools/mm 74 make page_owner_filter 75 76 To sort and analyze page_owner output: 77 78 cd tools/mm 79 make page_owner_sort 80 812) Enable page owner: add "page_owner=on" to boot cmdline. 82 833) Do the job that you want to debug. 84 854) (Optional) Filter page_owner output:: 86 87 ./page_owner_filter -m handle -n 0,1,2 > filtered_page_owner.txt 88 895) Analyze information from page owner:: 90 91 cat /sys/kernel/debug/page_owner_stacks/show_stacks > stacks.txt 92 cat stacks.txt 93 post_alloc_hook+0x177/0x1a0 94 get_page_from_freelist+0xd01/0xd80 95 __alloc_pages+0x39e/0x7e0 96 allocate_slab+0xbc/0x3f0 97 ___slab_alloc+0x528/0x8a0 98 kmem_cache_alloc+0x224/0x3b0 99 sk_prot_alloc+0x58/0x1a0 100 sk_alloc+0x32/0x4f0 101 inet_create+0x427/0xb50 102 __sock_create+0x2e4/0x650 103 inet_ctl_sock_create+0x30/0x180 104 igmp_net_init+0xc1/0x130 105 ops_init+0x167/0x410 106 setup_net+0x304/0xa60 107 copy_net_ns+0x29b/0x4a0 108 create_new_namespaces+0x4a1/0x820 109 nr_base_pages: 16 110 ... 111 ... 112 echo 7000 > /sys/kernel/debug/page_owner_stacks/count_threshold 113 cat /sys/kernel/debug/page_owner_stacks/show_stacks> stacks_7000.txt 114 cat stacks_7000.txt 115 post_alloc_hook+0x177/0x1a0 116 get_page_from_freelist+0xd01/0xd80 117 __alloc_pages+0x39e/0x7e0 118 alloc_pages_mpol+0x22e/0x490 119 folio_alloc+0xd5/0x110 120 filemap_alloc_folio+0x78/0x230 121 page_cache_ra_order+0x287/0x6f0 122 filemap_get_pages+0x517/0x1160 123 filemap_read+0x304/0x9f0 124 xfs_file_buffered_read+0xe6/0x1d0 [xfs] 125 xfs_file_read_iter+0x1f0/0x380 [xfs] 126 __kernel_read+0x3b9/0x730 127 kernel_read_file+0x309/0x4d0 128 __do_sys_finit_module+0x381/0x730 129 do_syscall_64+0x8d/0x150 130 entry_SYSCALL_64_after_hwframe+0x62/0x6a 131 nr_base_pages: 20824 132 ... 133 134 cat /sys/kernel/debug/page_owner_stacks/show_handles > handles_7000.txt 135 cat handles_7000.txt 136 handle: 42 137 nr_base_pages: 20824 138 ... 139 140 cat /sys/kernel/debug/page_owner_stacks/show_stacks_handles > stacks_handles.txt 141 cat stacks_handles.txt 142 post_alloc_hook+0x177/0x1a0 143 get_page_from_freelist+0xd01/0xd80 144 __alloc_pages+0x39e/0x7e0 145 alloc_pages_mpol+0x22e/0x490 146 folio_alloc+0xd5/0x110 147 filemap_alloc_folio+0x78/0x230 148 page_cache_ra_order+0x287/0x6f0 149 filemap_get_pages+0x517/0x1160 150 filemap_read+0x304/0x9f0 151 xfs_file_buffered_read+0xe6/0x1d0 [xfs] 152 xfs_file_read_iter+0x1f0/0x380 [xfs] 153 __kernel_read+0x3b9/0x730 154 kernel_read_file+0x309/0x4d0 155 __do_sys_finit_module+0x381/0x730 156 do_syscall_64+0x8d/0x150 157 entry_SYSCALL_64_after_hwframe+0x62/0x6a 158 handle: 42 159 ... 160 161 cat /sys/kernel/debug/page_owner > page_owner_full.txt 162 ./page_owner_sort page_owner_full.txt sorted_page_owner.txt 163 164 The general output of ``page_owner_full.txt`` is as follows:: 165 166 Page allocated via order XXX, ... 167 PFN XXX ... 168 // Detailed stack 169 170 Page allocated via order XXX, ... 171 PFN XXX ... 172 // Detailed stack 173 By default, it will do full pfn dump, to start with a given pfn, 174 page_owner supports fseek. 175 176 FILE *fp = fopen("/sys/kernel/debug/page_owner", "r"); 177 fseek(fp, pfn_start, SEEK_SET); 178 179 The ``page_owner_sort`` tool ignores ``PFN`` rows, puts the remaining rows 180 in buf, uses regexp to extract the page order value, counts the times 181 and pages of buf, and finally sorts them according to the parameter(s). 182 183 See the result about who allocated each page 184 in the ``sorted_page_owner.txt``. General output:: 185 186 XXX times, XXX pages: 187 Page allocated via order XXX, ... 188 // Detailed stack 189 190 By default, ``page_owner_sort`` is sorted according to the times of buf. 191 If you want to sort by the page nums of buf, use the ``-m`` parameter. 192 The detailed parameters are: 193 194 fundamental function:: 195 196 Sort: 197 -a Sort by memory allocation time. 198 -m Sort by total memory. 199 -p Sort by pid. 200 -P Sort by tgid. 201 -n Sort by task command name. 202 -r Sort by memory release time. 203 -s Sort by stack trace. 204 -t Sort by times (default). 205 --sort <order> Specify sorting order. Sorting syntax is [+|-]key[,[+|-]key[,...]]. 206 Choose a key from the **STANDARD FORMAT SPECIFIERS** section. The "+" is 207 optional since default direction is increasing numerical or lexicographic 208 order. Mixed use of abbreviated and complete-form of keys is allowed. 209 210 Examples: 211 ./page_owner_sort <input> <output> --sort=n,+pid,-tgid 212 ./page_owner_sort <input> <output> --sort=at 213 214 additional function:: 215 216 Cull: 217 --cull <rules> 218 Specify culling rules.Culling syntax is key[,key[,...]].Choose a 219 multi-letter key from the **STANDARD FORMAT SPECIFIERS** section. 220 221 <rules> is a single argument in the form of a comma-separated list, 222 which offers a way to specify individual culling rules. The recognized 223 keywords are described in the **STANDARD FORMAT SPECIFIERS** section below. 224 <rules> can be specified by the sequence of keys k1,k2, ..., as described in 225 the STANDARD SORT KEYS section below. Mixed use of abbreviated and 226 complete-form of keys is allowed. 227 228 Examples: 229 ./page_owner_sort <input> <output> --cull=stacktrace 230 ./page_owner_sort <input> <output> --cull=st,pid,name 231 ./page_owner_sort <input> <output> --cull=n,f 232 233 Filter: 234 -f Filter out the information of blocks whose memory has been released. 235 236 Select: 237 --pid <pidlist> Select by pid. This selects the blocks whose process ID 238 numbers appear in <pidlist>. 239 --tgid <tgidlist> Select by tgid. This selects the blocks whose thread 240 group ID numbers appear in <tgidlist>. 241 --name <cmdlist> Select by task command name. This selects the blocks whose 242 task command name appear in <cmdlist>. 243 244 <pidlist>, <tgidlist>, <cmdlist> are single arguments in the form of a comma-separated list, 245 which offers a way to specify individual selecting rules. 246 247 248 Examples: 249 ./page_owner_sort <input> <output> --pid=1 250 ./page_owner_sort <input> <output> --tgid=1,2,3 251 ./page_owner_sort <input> <output> --name name1,name2 252 253STANDARD FORMAT SPECIFIERS 254========================== 255:: 256 257 For --sort option: 258 259 KEY LONG DESCRIPTION 260 p pid process ID 261 tg tgid thread group ID 262 n name task command name 263 st stacktrace stack trace of the page allocation 264 T txt full text of block 265 ft free_ts timestamp of the page when it was released 266 at alloc_ts timestamp of the page when it was allocated 267 ator allocator memory allocator for pages 268 269 For --cull option: 270 271 KEY LONG DESCRIPTION 272 p pid process ID 273 tg tgid thread group ID 274 n name task command name 275 f free whether the page has been released or not 276 st stacktrace stack trace of the page allocation 277 ator allocator memory allocator for pages 278 279Filtering page_owner output 280============================ 281 282page_owner supports filtering output at the kernel level before reading, 283which reduces the amount of data that needs to be processed in userspace. 284 285The page_owner_filter tool provides a convenient interface for this filtering 286capability. It supports two types of filters: 287 2881. **print_mode filter**: Control what information is printed for each page 289 - ``stack``: Print full stack traces (default, compatible with existing usage) 290 - ``handle``: Print only stack handle numbers (much faster, smaller output) 291 - ``stack_handle``: Print both stack traces and handle numbers 292 293 The ``handle`` mode uses numeric identifiers instead of full stack traces. 294 The mapping from handles to actual stack traces can be obtained via the 295 show_stacks_handles interface. 296 2972. **NUMA node filter**: Filter pages by NUMA node ID 298 - Supports single node: ``-n 0`` 299 - Multiple nodes: ``-n 0,1,2`` 300 - Ranges: ``-n 0-3`` 301 - Mixed format: ``-n 0,2-3,5`` 302 303Usage examples:: 304 305 # Filter by print mode 306 ./page_owner_filter -m handle 307 ./page_owner_filter -m stack_handle 308 309 # Filter by NUMA node 310 ./page_owner_filter -n 0 311 ./page_owner_filter -n 0-3 312 313 # Combined filters 314 ./page_owner_filter -m stack -n 0,1,2 315 ./page_owner_filter -m handle -n 0,2-3 316 317 # Save to file 318 ./page_owner_filter -m handle -o filtered_output.txt 319 320The handle mode is particularly useful for monitoring and performance-critical 321scenarios as it dramatically reduces output size. Testing shows handle mode can 322reduce output size by ~66% (84MB vs 244MB) and improve read performance by ~4.4x 323compared to full stack output. 324 325The NUMA node filter is useful for NUMA-aware memory allocation analysis and debugging. 326 327Behind the scenes, page_owner_filter opens /sys/kernel/debug/page_owner and 328writes filter commands before reading the filtered output. The filtering uses 329per-file-descriptor state, allowing each open() to have independent filter settings. 330 331Each file descriptor maintains its own filter state, so you can have multiple 332independent filtering operations running concurrently. For example, in different 333terminals you can run different filters simultaneously:: 334 335 # Terminal 1: Filter node 0 336 ./page_owner_filter -n 0 > node0_output.txt 337 338 # Terminal 2: Filter node 1 (runs concurrently) 339 ./page_owner_filter -n 1 > node1_output.txt 340