Debugging: Keep track of page owners
Subsystems (5)
PATCH 1/1 Debugging: Keep track of page owners
From: [email protected] (Mel Gorman)
PAGE_OWNER tracks free pages by setting page->order to -1. However, it is set during __free_pages() which is not the only free path as __pagevec_free() and free_compound_page() do not go through __free_pages().
This leads to a situation where free pages are visible in page_owner
which is confusing and might be interpreted as a memory leak.
This patch sets page->owner when PageBuddy is set. It also prints a warning to the kernel log if a free page is found that does not appear free to PAGE_OWNER. This should be considered a fix to page-owner-tracking-leak-detector.patch.
This only applies to -mm as PAGE_OWNER is not in mainline.
DESC
Print out PAGE_OWNER statistics in relation to fragmentation avoidance EDESC
From: Mel Gorman <[email protected]>
When PAGE_OWNER is set, more information is available of relevance to fragmentation avoidance. A second line is added to 'page_owner' showing the PFN, the pageblock number, the mobility type of the page based on its allocation flags, whether the allocation is improperly placed and the flags. A sample entry looks like
Page allocated via order 0, mask 0x1280d2
PFN 7355 Block 7 type 3 Fallback Flags LA
[0xc01528c6] __handle_mm_fault+598
[0xc0320427] do_page_fault+279
[0xc031ed9a] error_code+114
This information can be used to identify pages that are improperly placed. As the format of PAGE_OWNER data is now different, the comment at the top of Documentation/page_owner.c is updated with new instructions.
As PAGE_OWNER tracks the GFP flags used to allocate the pages, /proc/pagetypeinfo is enhanced to contain how many mixed blocks exist. The additional output looks like
Number of mixed blocks Unmovable Reclaimable Movable Reserve
Node 0, zone DMA 0 1 2 1 Node 0, zone Normal 2 11 33 0
DESC
Allow PAGE_OWNER to be set on any architecture
EDESC
From: Mel Gorman <[email protected]>
Currently PAGE_OWNER depends on CONFIG_X86. This appears to be due to pfn_to_page() being called in an inappropriate for many memory models and the presense of memory holes. This patch ensures that pfn_valid() and pfn_valid_within() is called at the appropriate places and the offsets correctly updated so that PAGE_OWNER is safe on any architecture.
In situations where CONFIG_HOLES_IN_ZONES is set (IA64 with VIRTUAL_MEM_MAP), there may be cases where pages allocated within a MAX_ORDER_NR_PAGES block of pages may not be displayed in 'page_owner' if the hole is at the start of the block. Addressing this would be quite complex, perform slowly and is of no clear benefit.
Once PAGE_OWNER is allowed on all architectures, the statistics for grouping pages by mobility that declare how many pageblocks contain mixed page types becomes optionally available on all arches.
This patch was tested successfully on x86, x86_64, ppc64 and IA64 machines.
DESC allow-page_owner-to-be-set-on-any-architecture-fix EDESC
From: Andrew Morton <[email protected]>
Cc: Andy Whitcroft <[email protected]>
Cc: Mel Gorman <[email protected]>
DESC allow-page_owner-to-be-set-on-any-architecture-fix fix EDESC
From: [email protected] (Mel Gorman)
Page-owner-tracking stores the a backtrace of an allocation in the struct page. How the stack trace is generated depends on whether CONFIG_FRAME_POINTER is set or not. If CONFIG_FRAME_POINTER is set, the frame pointer must be read using some inline assembler which is not available for all architectures.
This patch uses the frame pointer where it is available but has a fallback where it is not.
---
linux-2.6.git-dave/Documentation/page_owner.c | 141 ++++++++++++++++++++++ linux-2.6.git-dave/include/linux/mm_types.h | 7 + linux-2.6.git-dave/include/linux/stacktrace.h | 3 linux-2.6.git-dave/kernel/stacktrace.c | 23 +++ linux-2.6.git-dave/lib/Kconfig.debug | 12 + linux-2.6.git-dave/mm/Makefile | 1 linux-2.6.git-dave/mm/page_alloc.c | 29 ++++ linux-2.6.git-dave/mm/pageowner.c | 163 ++++++++++++++++++++++++++ linux-2.6.git-dave/mm/vmstat.c | 96 +++++++++++++++ 9 files changed, 475 insertions(+)
Documentation/page_owner.c new file +141 -0
@@ -0,0 +1,141 @@ +/* +* User-space helper to sort the output of /sys/kernel/debug/page_owner +* +* Example use: +* cat /sys/kernel/debug/page_owner > page_owner_full.txt +* grep -v ^PFN page_owner_full.txt > page_owner.txt +* ./sort page_owner.txt sorted_page_owner.txt +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +struct block_list { +char *txt; +int len; +int num; +}; + + +static struct block_list *list; +static int list_size; +static int max_size; + +struct block_list *block_head; + +int read_block (char *buf,FILE *fin) +{ +int ret =0 ; +int hit =0 ; +char *curr = buf; + +for (;;) { + *curr =getc (fin); +if (*curr ==EOF )return -1 ; + + ret++; +if (*curr =='\n' && hit ==1 ) +return ret -1 ; +else if (*curr =='\n' ) + hit =1 ; +else + hit =0 ; + curr++; + } +} + +static int compare_txt (struct block_list *l1,struct block_list *l2) +{ +return strcmp (l1->txt, l2->txt); +} + +static int compare_num (struct block_list *l1,struct block_list *l2) +{ +return l2->num - l1->num; +} + +static void add_list (char *buf,int len) +{ +if (list_size !=0 && + len == list[list_size-1 ].len && +memcmp (buf, list[list_size-1 ].txt, len) ==0 ) { + list[list_size-1 ].num++; +return ; + } +if (list_size == max_size) { +printf ("max_size too small??\n" ); +exit (1 ); + } + list[list_size].txt =malloc (len+1 ); + list[list_size].len = len; + list[list_size].num =1 ; +memcpy (list[list_size].txt, buf, len); + list[list_size].txt[len] =0 ; + list_size++; +if (list_size %1000 ==0 ) { +printf ("loaded %d\r" , list_size); +fflush (stdout); + } +} + +int main (int argc,char **argv) +{ +FILE *fin, *fout; +char buf[1024 ]; +int ret, i, count; +struct block_list *list2; +struct stat st; + + fin =fopen (argv[1 ],"r" ); + fout =fopen (argv[2 ],"w" ); +if (!fin || !fout) { +printf ("Usage: ./program <input> <output>\n" ); +perror ("open: " ); +exit (2 ); + } + +fstat (fileno (fin), &st); + max_size = st.st_size /100 ;/* hack ... */ + + list =malloc (max_size *sizeof (*list)); + +for (;;) { + ret =read_block (buf, fin); +if (ret <0 ) +break ; + + buf[ret] ='\0' ; +add_list (buf, ret); + } + +printf ("loaded %d\n" , list_size); + +printf ("sorting ....\n" ); + +qsort (list, list_size,sizeof (list[0 ]), compare_txt); + + list2 =malloc (sizeof (*list) * list_size); + +printf ("culling\n" ); + +for (i=count=0 ;i<list_size;i++) { +if (count ==0 || +strcmp (list2[count-1 ].txt, list[i].txt) !=0 ) { + list2[count++] = list[i]; + }else { + list2[count-1 ].num += list[i].num; + } + } + +qsort (list2, count,sizeof (list[0 ]), compare_num); + +for (i=0 ;i<count;i++) { +fprintf (fout,"%d times:\n%s\n" , list2[i].num, list2[i].txt); + } +return 0 ; +}
include/linux/mm_types.h renamed from include/linux/mm_types.h~pageowner +7 -0
@@ -12,6 +12,7 @@#include <linux/cpumask.h> #include <linux/page-debug-flags.h> #include <linux/uprobes.h> +#include <linux/stacktrace.h> #include <asm/page.h> #include <asm/mmu.h>
@@ -175,6 +176,12 @@ struct page {*/ void *shadow;#endif +#ifdef CONFIG_PAGE_OWNER +int order; +unsigned int gfp_mask; +struct stack_trace trace; +unsigned long trace_entries[8 ]; +#endif }/* * The struct page can be forced to be double word aligned so that atomic ops
include/linux/stacktrace.h renamed from include/linux/stacktrace.h~pageowner +3 -0
@@ -20,6 +20,8 @@ extern void save_stack_trace_tsk(struct struct stack_trace *trace);extern void print_stack_trace (struct stack_trace *trace,int spaces); +extern int snprint_stack_trace (char *buf,int buf_len, +struct stack_trace *trace,int spaces);#ifdef CONFIG_USER_STACKTRACE_SUPPORT extern void save_stack_trace_user (struct stack_trace *trace);
@@ -32,6 +34,7 @@ extern void save_stack_trace_user(struct# define save_stack_trace_tsk (tsk, trace) do { } while (0)# define save_stack_trace_user (trace) do { } while (0)# define print_stack_trace (trace, spaces) do { } while (0) +# define snprint_stack_trace (buf, len, trace, spaces) do { } while (0)#endif #endif
kernel/stacktrace.c renamed from kernel/stacktrace.c~pageowner +23 -0
@@ -11,6 +11,29 @@#include <linux/kallsyms.h> #include <linux/stacktrace.h> +int snprint_stack_trace (char *buf,int buf_len,struct stack_trace *trace, +int spaces) +{ +int ret =0 ; +int i; + +if (WARN_ON (!trace->entries)) +return 0 ; + +for (i =0 ; i < trace->nr_entries; i++) { +unsigned long ip = trace->entries[i]; +int printed =snprintf (buf, buf_len,"%*c[<%p>] %pS\n" , +1 + spaces,' ' , + (void *) ip, (void *) ip); + buf_len -= printed; + ret += printed; + buf += printed; + } + +return ret; +} +EXPORT_SYMBOL_GPL (snprint_stack_trace); +void print_stack_trace (struct stack_trace *trace,int spaces) {int i;
lib/Kconfig.debug renamed from lib/Kconfig.debug~pageowner +12 -0
@@ -99,6 +99,18 @@ config UNUSED_SYMBOLS you really need it, and what the merge plan to the mainline kernel for your module is. +config PAGE_OWNER + bool "Track page owner" + depends on DEBUG_KERNEL + select DEBUG_FS + select STACKTRACE + help + This keeps track of what call chain is the owner of a page, may + help to find bare alloc_page(s) leaks. Eats a fair amount of memory. + See Documentation/page_owner.c for user-space helper. + + If unsure, say N. + config DEBUG_FS bool "Debug Filesystem" help
mm/Makefile renamed from mm/Makefile~pageowner +1 -0
@@ -57,3 +57,4 @@ obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o obj-$(CONFIG_CLEANCACHE) += cleancache.o obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o +obj-$(CONFIG_PAGE_OWNER) += pageowner.o
mm/page_alloc.c renamed from mm/page_alloc.c~pageowner +29 -0
@@ -437,6 +437,9 @@ static inline void set_page_order(struct {set_page_private (page, order);__SetPageBuddy (page); +#ifdef CONFIG_PAGE_OWNER + page->order =-1 ; +#endif }static inline void rmv_page_order (struct page *page)
@@ -2250,6 +2253,22 @@ __perform_reclaim(gfp_t gfp_mask, unsignreturn progress; } +static void set_page_owner (struct page *page,unsigned int order, +unsigned int gfp_mask) +{ +#ifdef CONFIG_PAGE_OWNER +struct stack_trace *trace = &page->trace; + trace->nr_entries =0 ; + trace->max_entries =ARRAY_SIZE (page->trace_entries); + trace->entries = &page->trace_entries[0 ]; + trace->skip =3 ; +save_stack_trace (&page->trace); + + page->order = (int ) order; + page->gfp_mask = gfp_mask; +#endif /* CONFIG_PAGE_OWNER */ +} +/* The really slow allocator path where we enter direct reclaim */ static inline struct page * __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
@@ -2285,6 +2304,8 @@ retry: goto retry; } +if (page) +set_page_owner (page, order, gfp_mask);return page; }
@@ -2593,6 +2614,8 @@ nopage:warn_alloc_failed (gfp_mask, order,NULL );return page; got_pg: +if (page) +set_page_owner (page, order, gfp_mask);if (kmemcheck_enabled)kmemcheck_pagealloc_alloc (page, order, gfp_mask);
@@ -2665,6 +2688,9 @@ out:if (unlikely (!put_mems_allowed (cpuset_mems_cookie) && !page)) goto retry_cpuset; +if (page) +set_page_owner (page, order, gfp_mask); +return page; }EXPORT_SYMBOL (__alloc_pages_nodemask);
@@ -3869,6 +3895,9 @@ void __meminit memmap_init_zone(unsignedif (!is_highmem_idx (zone))set_page_address (page,__va (pfn <<PAGE_SHIFT ));#endif +#ifdef CONFIG_PAGE_OWNER + page->order =-1 ; +#endif } }
mm/pageowner.c new file +163 -0
163 lines not on this page · raw message
mm/vmstat.c renamed from mm/vmstat.c~pageowner +96 -0
114 lines not on this page · raw message
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerQuoted 1 line · On Fri, 07 Dec 2012 16:24:17 -0500 Dave Hansen <[email protected]> wrote:
It's years since I was called that.
Quoted 1 line
From: [email protected] (Mel Gorman)
And him that.
I have cunningly divined the intention of your update and have queued the below incremental. The change to pagetypeinfo_showmixedcount_print() was a surprise. What's that there for?
From: Dave Hansen <[email protected]>
Subject: debugging-keep-track-of-page-owners-fix
Use linux/stacktrace.h rather than hand-coding the stack tracing
---
include/linux/mm_types.h | 4 +- include/linux/stacktrace.h | 3 + kernel/stacktrace.c | 23 ++++++++++++ lib/Kconfig.debug | 1 mm/page_alloc.c | 65 ++++------------------------------- mm/pageowner.c | 27 ++++---------- mm/vmstat.c | 5 ++ 7 files changed, 51 insertions(+), 77 deletions(-)
include/linux/mm_types.h renamed from include/linux/mm_types.h~debugging-keep-track-of-page-owners-fix +3 -1
@@ -8,6 +8,7 @@#include <linux/spinlock.h> #include <linux/rbtree.h> #include <linux/rwsem.h> +#include <linux/stacktrace.h> #include <linux/completion.h> #include <linux/cpumask.h> #include <linux/page-debug-flags.h>
@@ -180,7 +181,8 @@ struct page {#ifdef CONFIG_PAGE_OWNER int order;unsigned int gfp_mask; -unsigned long trace[8 ]; +struct stack_trace trace; +unsigned long trace_entries[8 ];#endif }/*
include/linux/stacktrace.h renamed from include/linux/stacktrace.h~debugging-keep-track-of-page-owners-fix +3 -0
@@ -20,6 +20,8 @@ extern void save_stack_trace_tsk(struct struct stack_trace *trace);extern void print_stack_trace (struct stack_trace *trace,int spaces); +extern int snprint_stack_trace (char *buf,int buf_len, +struct stack_trace *trace,int spaces);#ifdef CONFIG_USER_STACKTRACE_SUPPORT extern void save_stack_trace_user (struct stack_trace *trace);
@@ -32,6 +34,7 @@ extern void save_stack_trace_user(struct# define save_stack_trace_tsk (tsk, trace) do { } while (0)# define save_stack_trace_user (trace) do { } while (0)# define print_stack_trace (trace, spaces) do { } while (0) +# define snprint_stack_trace (buf, len, trace, spaces) do { } while (0)#endif #endif
kernel/stacktrace.c renamed from kernel/stacktrace.c~debugging-keep-track-of-page-owners-fix +23 -0
@@ -11,6 +11,29 @@#include <linux/kallsyms.h> #include <linux/stacktrace.h> +int snprint_stack_trace (char *buf,int buf_len,struct stack_trace *trace, +int spaces) +{ +int ret =0 ; +int i; + +if (WARN_ON (!trace->entries)) +return 0 ; + +for (i =0 ; i < trace->nr_entries; i++) { +unsigned long ip = trace->entries[i]; +int printed =snprintf (buf, buf_len,"%*c[<%p>] %pS\n" , +1 + spaces,' ' , + (void *) ip, (void *) ip); + buf_len -= printed; + ret += printed; + buf += printed; + } + +return ret; +} +EXPORT_SYMBOL_GPL (snprint_stack_trace); +void print_stack_trace (struct stack_trace *trace,int spaces) {int i;
lib/Kconfig.debug renamed from lib/Kconfig.debug~debugging-keep-track-of-page-owners-fix +1 -0
@@ -103,6 +103,7 @@ config PAGE_OWNER bool "Track page owner" depends on DEBUG_KERNEL select DEBUG_FS + select STACKTRACE help This keeps track of what call chain is the owner of a page, may help to find bare alloc_page(s) leaks. Eats a fair amount of memory.
mm/page_alloc.c renamed from mm/page_alloc.c~debugging-keep-track-of-page-owners-fix +9 -56
101 lines not on this page · raw message
mm/pageowner.c renamed from mm/pageowner.c~debugging-keep-track-of-page-owners-fix +8 -19
@@ -26,12 +26,8 @@ read_page_owner(struct file *file, char {unsigned long pfn;struct page *page; -char *kbuf, *modname; -const char *symname; +char *kbuf;int ret =0 ; -char namebuf[128 ]; -unsigned long offset =0 , symsize; -int i;ssize_t num_written =0 ;int blocktype =0 , pagetype =0 ;
@@ -67,7 +63,7 @@ read_page_owner(struct file *file, char pfn);/* Stop search if page is allocated and has trace info */ -if (page->order >=0 && page->trace[0 ]) { +if (page->order >=0 && page->trace.nr_entries) {//intk("stopped search at pfn: %ld\n", pfn); break ; }
@@ -126,20 +122,13 @@ read_page_owner(struct file *file, char num_written = ret; -for (i =0 ; i <8 ; i++) { -if (!page->trace[i]) -break ; - symname =kallsyms_lookup (page->trace[i], &symsize, &offset, - &modname, namebuf); - ret =snprintf (kbuf + num_written, count - num_written, -"[0x%lx] %s+%lu\n" , - page->trace[i], namebuf, offset); -if (ret >= count - num_written) { - ret = -ENOMEM ; - goto out; - } - num_written += ret; + ret =snprint_stack_trace (kbuf + num_written, count - num_written, + &page->trace,0 ); +if (ret >= count - num_written) { + ret = -ENOMEM ; + goto out; } + num_written += ret; ret =snprintf (kbuf + num_written, count - num_written,"\n" );if (ret >= count - num_written) {
mm/vmstat.c renamed from mm/vmstat.c~debugging-keep-track-of-page-owners-fix +4 -1
@@ -985,7 +985,10 @@ static void pagetypeinfo_showmixedcount_ pagetype =allocflags_to_migratetype (page->gfp_mask);if (pagetype != mtype) { - count[mtype]++; +if (is_migrate_cma (pagetype)) + count[MIGRATE_MOVABLE ]++; +else + count[mtype]++;break ; }
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
On 12/07/2012 02:26 PM, Andrew Morton wrote:\
Quoted 4 lines
I have cunningly divined the intention of your update and have queued the below incremental. The change to
pagetypeinfo_showmixedcount_print()was a surprise. What's that there for?
Do you mean to ask why it's being modified at all here in this patch? It's referenced in the changelog a bit. I believe it came from Mel at some point. I didn't do much to that portion, but I happily drug those hunks along with my forward port. I believe it's virtually all the same as what you posted here:
https://bugzilla.kernel.org/show_bug.cgi?id=50181
Andrew Morton
maintainerQuoted 6 lines · On Fri, 07 Dec 2012 14:37:27 -0800 Dave Hansen <[email protected]> wrote:
On 12/07/2012 02:26 PM, Andrew Morton wrote:\
Quoted 4 lines
I have cunningly divined the intention of your update and have queued the below incremental. The change to
pagetypeinfo_showmixedcount_print()was a surprise. What's that there for?
Quoted 7 lines
Do you mean to ask why it's being modified at all here in this patch? It's referenced in the changelog a bit. I believe it came from Mel at some point. I didn't do much to that portion, but I happily drug those hunks along with my forward port. I believe it's virtually all the same as what you posted here:
https://bugzilla.kernel.org/show_bug.cgi?id=50181
I'm now deeply confused.
Two days ago I merged a version which you sent me. It is presently at
http://ozlabs.org/~akpm/mmotm/broken-out/debugging-keep-track-of-page-owners.patch.
Today you sent a new version. My earlier email showed the difference between these two versions.
AFACIT that difference was undescribed. I can see that the new version uses the stack-tracing infrastructure, but the change to pagetypeinfo_showmixedcount_print() is a mystery.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 3 lines · Andrew Morton
AFACIT that difference was undescribed. I can see that the new version uses the stack-tracing infrastructure, but the change to
pagetypeinfo_showmixedcount_print()is a mystery.
Ahhh, I assume you're talking about this hunk:
Quoted 11 lines
mm/vmstat.c static void pagetypeinfo_showmixedcount_print(struct seq_file *m, · line 981
Quoted 11 lines
mm/vmstat.c renamed from mm/vmstat.c~debugging-keep-track-of-page-owners-fix +1
-4@@ -976,10 +976,7 @@ static void pagetypeinfo_showmixedcount_print(struct seq_file *m, pagetype =allocflags_to_migratetype (page->gfp_mask);if (pagetype != mtype) { -if (is_migrate_cma (pagetype)) - count[MIGRATE_MOVABLE ]++; -else - count[mtype]++; + count[mtype]++;break ; }
That was to fix the comment that Laura Abbott made about it miscounting MIGRATE_CMA pages.
My patch-sending scripts were choking a bit on the text description in your patch. I'm using a long-ago-forked copy of your patch-utils and the DESC/EDESC in the patch I imported is giving them fits when I send via email and stripping large parts of the description. I'm happy to resend via email, too, but here, the raw patch (will the full description):
https://www.sr71.net/~dave/linux/pageowner.patch
The important description that the scripts managed to strip out when emailed was this:
Updated 12/4/2012 - should apply to 3.7 kernels. I did a quick sniff-test to make sure that this boots and produces some sane output, but it's not been exhaustively tested.
* Moved file over to debugfs (no reason to keep polluting /proc)
* Now using generic stack tracking infrastructure
* Added check for MIGRATE_CMA pages to explicitly count them as movable.
The new snprint_stack_trace() probably belongs in its own patch if this were to get merged, but it won't kill anyone as it stands.
-----
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Andrew Morton
Quoted 1 line · On Fri, 07 Dec 2012 16:24:17 -0500 Dave Hansen <[email protected]> wrote:
It's years since I was called that.
"Help me [email protected]. You're my only hope"...
Quoted 5 lines
Quoted 2 lines
From: [email protected] (Mel Gorman)
And him that.
"[email protected] is my father!" - Luke Skynet.ie
-- Steve ;-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · Dave Hansen
diff -puN
/dev/nullDocumentation/page_owner.c
Can we stop putting code into Documentation? We have tools, samples and usr directories. I'm sure this could fit into one of them.
-- Steve
Quoted 134 lines
Documentation/page_owner.c new file +131
-0@@ -0,0 +1,141 @@ +/* +* User-space helper to sort the output of /sys/kernel/debug/page_owner +* +* Example use: +* cat /sys/kernel/debug/page_owner > page_owner_full.txt +* grep -v ^PFN page_owner_full.txt > page_owner.txt +* ./sort page_owner.txt sorted_page_owner.txt +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +struct block_list { +char *txt; +int len; +int num; +}; + + +static struct block_list *list; +static int list_size; +static int max_size; + +struct block_list *block_head; + +int read_block (char *buf,FILE *fin) +{ +int ret =0 ; +int hit =0 ; +char *curr = buf; + +for (;;) { + *curr =getc (fin); +if (*curr ==EOF )return -1 ; + + ret++; +if (*curr =='\n' && hit ==1 ) +return ret -1 ; +else if (*curr =='\n' ) + hit =1 ; +else + hit =0 ; + curr++; + } +} + +static int compare_txt (struct block_list *l1,struct block_list *l2) +{ +return strcmp (l1->txt, l2->txt); +} + +static int compare_num (struct block_list *l1,struct block_list *l2) +{ +return l2->num - l1->num; +} + +static void add_list (char *buf,int len) +{ +if (list_size !=0 && + len == list[list_size-1 ].len && +memcmp (buf, list[list_size-1 ].txt, len) ==0 ) { + list[list_size-1 ].num++; +return ; + } +if (list_size == max_size) { +printf ("max_size too small??\n" ); +exit (1 ); + } + list[list_size].txt =malloc (len+1 ); + list[list_size].len = len; + list[list_size].num =1 ; +memcpy (list[list_size].txt, buf, len); + list[list_size].txt[len] =0 ; + list_size++; +if (list_size %1000 ==0 ) { +printf ("loaded %d\r" , list_size); +fflush (stdout); + } +} + +int main (int argc,char **argv) +{ +FILE *fin, *fout; +char buf[1024 ]; +int ret, i, count; +struct block_list *list2; +struct stat st; + + fin =fopen (argv[1 ],"r" ); + fout =fopen (argv[2 ],"w" ); +if (!fin || !fout) { +printf ("Usage: ./program <input> <output>\n" ); +perror ("open: " ); +exit (2 ); + } + +fstat (fileno (fin), &st); + max_size = st.st_size /100 ;/* hack ... */ + + list =malloc (max_size *sizeof (*list)); + +for (;;) { + ret =read_block (buf, fin); +if (ret <0 ) +break ; + + buf[ret] ='\0' ; +add_list (buf, ret); + } + +printf ("loaded %d\n" , list_size); + +printf ("sorting ....\n" ); + +qsort (list, list_size,sizeof (list[0 ]), compare_txt); + + list2 =malloc (sizeof (*list) * list_size); + +printf ("culling\n" ); + +for (i=count=0 ;i<list_size;i++) { +if (count ==0 || +strcmp (list2[count-1 ].txt, list[i].txt) !=0 ) { + list2[count++] = list[i]; + }else { + list2[count-1 ].num += list[i].num;
Documentation/page_owner.c line 141
Quoted 10 lines
Documentation/page_owner.c new file +10
-0+ } + } + +qsort (list2, count,sizeof (list[0 ]), compare_num); + +for (i=0 ;i<count;i++) { +fprintf (fout,"%d times:\n%s\n" , list2[i].num, list2[i].txt); + } +return 0 ; +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>