diff options
author | Christoph Lameter <clameter@engr.sgi.com> | 2005-09-03 18:54:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:05:43 -0400 |
commit | 6e21c8f145f5052c1c2fb4a4b41bee01c848159b (patch) | |
tree | 0b956cfbd67636c19be79fc0cbe0a5ed89fb6b9a /fs/proc/task_mmu.c | |
parent | 839b9685e80592809d6dfdd865986cd1b5ddc2fb (diff) |
[PATCH] /proc/<pid>/numa_maps to show on which nodes pages reside
This patch was recently discussed on linux-mm:
http://marc.theaimsgroup.com/?t=112085728500002&r=1&w=2
I inherited a large code base from Ray for page migration. There was a
small patch in there that I find to be very useful since it allows the
display of the locality of the pages in use by a process. I reworked that
patch and came up with a /proc/<pid>/numa_maps that gives more information
about the vma's of a process. numa_maps is indexes by the start address
found in /proc/<pid>/maps. F.e. with this patch you can see the page use
of the "getty" process:
margin:/proc/12008 # cat maps
00000000-00004000 r--p 00000000 00:00 0
2000000000000000-200000000002c000 r-xp 00000000 08:04 516 /lib/ld-2.3.3.so
2000000000038000-2000000000040000 rw-p 00028000 08:04 516 /lib/ld-2.3.3.so
2000000000040000-2000000000044000 rw-p 2000000000040000 00:00 0
2000000000058000-2000000000260000 r-xp 00000000 08:04 54707842 /lib/tls/libc.so.6.1
2000000000260000-2000000000268000 ---p 00208000 08:04 54707842 /lib/tls/libc.so.6.1
2000000000268000-2000000000274000 rw-p 00200000 08:04 54707842 /lib/tls/libc.so.6.1
2000000000274000-2000000000280000 rw-p 2000000000274000 00:00 0
2000000000280000-20000000002b4000 r--p 00000000 08:04 9126923 /usr/lib/locale/en_US.utf8/LC_CTYPE
2000000000300000-2000000000308000 r--s 00000000 08:04 60071467 /usr/lib/gconv/gconv-modules.cache
2000000000318000-2000000000328000 rw-p 2000000000318000 00:00 0
4000000000000000-4000000000008000 r-xp 00000000 08:04 29576399 /sbin/mingetty
6000000000004000-6000000000008000 rw-p 00004000 08:04 29576399 /sbin/mingetty
6000000000008000-600000000002c000 rw-p 6000000000008000 00:00 0 [heap]
60000fff7fffc000-60000fff80000000 rw-p 60000fff7fffc000 00:00 0
60000ffffff44000-60000ffffff98000 rw-p 60000ffffff44000 00:00 0 [stack]
a000000000000000-a000000000020000 ---p 00000000 00:00 0 [vdso]
cat numa_maps
2000000000000000 default MaxRef=43 Pages=11 Mapped=11 N0=4 N1=3 N2=2 N3=2
2000000000038000 default MaxRef=1 Pages=2 Mapped=2 Anon=2 N0=2
2000000000040000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N0=1
2000000000058000 default MaxRef=43 Pages=61 Mapped=61 N0=14 N1=15 N2=16 N3=16
2000000000268000 default MaxRef=1 Pages=2 Mapped=2 Anon=2 N0=2
2000000000274000 default MaxRef=1 Pages=3 Mapped=3 Anon=3 N0=3
2000000000280000 default MaxRef=8 Pages=3 Mapped=3 N0=3
2000000000300000 default MaxRef=8 Pages=2 Mapped=2 N0=2
2000000000318000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N2=1
4000000000000000 default MaxRef=6 Pages=2 Mapped=2 N1=2
6000000000004000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N0=1
6000000000008000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N0=1
60000fff7fffc000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N0=1
60000ffffff44000 default MaxRef=1 Pages=1 Mapped=1 Anon=1 N0=1
getty uses ld.so. The first vma is the code segment which is used by 43
other processes and the pages are evenly distributed over the 4 nodes.
The second vma is the process specific data portion for ld.so. This is
only one page.
The display format is:
<startaddress> Links to information in /proc/<pid>/map
<memory policy> This can be "default" "interleave={}", "prefer=<node>" or "bind={<zones>}"
MaxRef= <maximum reference to a page in this vma>
Pages= <Nr of pages in use>
Mapped= <Nr of pages with mapcount >
Anon= <nr of anonymous pages>
Nx= <Nr of pages on Node x>
The content of the proc-file is self-evident. If this would be tied into
the sparsemem system then the contents of this file would not be too
useful.
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 28b4a0253a92..64e84cadfa3c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -2,6 +2,8 @@ | |||
2 | #include <linux/hugetlb.h> | 2 | #include <linux/hugetlb.h> |
3 | #include <linux/mount.h> | 3 | #include <linux/mount.h> |
4 | #include <linux/seq_file.h> | 4 | #include <linux/seq_file.h> |
5 | #include <linux/pagemap.h> | ||
6 | #include <linux/mempolicy.h> | ||
5 | #include <asm/elf.h> | 7 | #include <asm/elf.h> |
6 | #include <asm/uaccess.h> | 8 | #include <asm/uaccess.h> |
7 | #include "internal.h" | 9 | #include "internal.h" |
@@ -233,3 +235,133 @@ struct seq_operations proc_pid_maps_op = { | |||
233 | .stop = m_stop, | 235 | .stop = m_stop, |
234 | .show = show_map | 236 | .show = show_map |
235 | }; | 237 | }; |
238 | |||
239 | #ifdef CONFIG_NUMA | ||
240 | |||
241 | struct numa_maps { | ||
242 | unsigned long pages; | ||
243 | unsigned long anon; | ||
244 | unsigned long mapped; | ||
245 | unsigned long mapcount_max; | ||
246 | unsigned long node[MAX_NUMNODES]; | ||
247 | }; | ||
248 | |||
249 | /* | ||
250 | * Calculate numa node maps for a vma | ||
251 | */ | ||
252 | static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | ||
253 | { | ||
254 | struct page *page; | ||
255 | unsigned long vaddr; | ||
256 | struct mm_struct *mm = vma->vm_mm; | ||
257 | int i; | ||
258 | struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); | ||
259 | |||
260 | if (!md) | ||
261 | return NULL; | ||
262 | md->pages = 0; | ||
263 | md->anon = 0; | ||
264 | md->mapped = 0; | ||
265 | md->mapcount_max = 0; | ||
266 | for_each_node(i) | ||
267 | md->node[i] =0; | ||
268 | |||
269 | spin_lock(&mm->page_table_lock); | ||
270 | for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { | ||
271 | page = follow_page(mm, vaddr, 0); | ||
272 | if (page) { | ||
273 | int count = page_mapcount(page); | ||
274 | |||
275 | if (count) | ||
276 | md->mapped++; | ||
277 | if (count > md->mapcount_max) | ||
278 | md->mapcount_max = count; | ||
279 | md->pages++; | ||
280 | if (PageAnon(page)) | ||
281 | md->anon++; | ||
282 | md->node[page_to_nid(page)]++; | ||
283 | } | ||
284 | } | ||
285 | spin_unlock(&mm->page_table_lock); | ||
286 | return md; | ||
287 | } | ||
288 | |||
289 | static int show_numa_map(struct seq_file *m, void *v) | ||
290 | { | ||
291 | struct task_struct *task = m->private; | ||
292 | struct vm_area_struct *vma = v; | ||
293 | struct mempolicy *pol; | ||
294 | struct numa_maps *md; | ||
295 | struct zone **z; | ||
296 | int n; | ||
297 | int first; | ||
298 | |||
299 | if (!vma->vm_mm) | ||
300 | return 0; | ||
301 | |||
302 | md = get_numa_maps(vma); | ||
303 | if (!md) | ||
304 | return 0; | ||
305 | |||
306 | seq_printf(m, "%08lx", vma->vm_start); | ||
307 | pol = get_vma_policy(task, vma, vma->vm_start); | ||
308 | /* Print policy */ | ||
309 | switch (pol->policy) { | ||
310 | case MPOL_PREFERRED: | ||
311 | seq_printf(m, " prefer=%d", pol->v.preferred_node); | ||
312 | break; | ||
313 | case MPOL_BIND: | ||
314 | seq_printf(m, " bind={"); | ||
315 | first = 1; | ||
316 | for (z = pol->v.zonelist->zones; *z; z++) { | ||
317 | |||
318 | if (!first) | ||
319 | seq_putc(m, ','); | ||
320 | else | ||
321 | first = 0; | ||
322 | seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id, | ||
323 | (*z)->name); | ||
324 | } | ||
325 | seq_putc(m, '}'); | ||
326 | break; | ||
327 | case MPOL_INTERLEAVE: | ||
328 | seq_printf(m, " interleave={"); | ||
329 | first = 1; | ||
330 | for_each_node(n) { | ||
331 | if (test_bit(n, pol->v.nodes)) { | ||
332 | if (!first) | ||
333 | seq_putc(m,','); | ||
334 | else | ||
335 | first = 0; | ||
336 | seq_printf(m, "%d",n); | ||
337 | } | ||
338 | } | ||
339 | seq_putc(m, '}'); | ||
340 | break; | ||
341 | default: | ||
342 | seq_printf(m," default"); | ||
343 | break; | ||
344 | } | ||
345 | seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu", | ||
346 | md->mapcount_max, md->pages, md->mapped); | ||
347 | if (md->anon) | ||
348 | seq_printf(m," Anon=%lu",md->anon); | ||
349 | |||
350 | for_each_online_node(n) { | ||
351 | if (md->node[n]) | ||
352 | seq_printf(m, " N%d=%lu", n, md->node[n]); | ||
353 | } | ||
354 | seq_putc(m, '\n'); | ||
355 | kfree(md); | ||
356 | if (m->count < m->size) /* vma is copied successfully */ | ||
357 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | struct seq_operations proc_pid_numa_maps_op = { | ||
362 | .start = m_start, | ||
363 | .next = m_next, | ||
364 | .stop = m_stop, | ||
365 | .show = show_numa_map | ||
366 | }; | ||
367 | #endif | ||