forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mm/page_ref: add tracepoint to track down page reference manipulation
CMA allocation should be guaranteed to succeed by definition, but, unfortunately, it would be failed sometimes. It is hard to track down the problem, because it is related to page reference manipulation and we don't have any facility to analyze it. This patch adds tracepoints to track down page reference manipulation. With it, we can find exact reason of failure and can fix the problem. Following is an example of tracepoint output. (note: this example is stale version that printing flags as the number. Recent version will print it as human readable string.) <...>-9018 [004] 92.678375: page_ref_set: pfn=0x17ac9 flags=0x0 count=1 mapcount=0 mapping=(nil) mt=4 val=1 <...>-9018 [004] 92.678378: kernel_stack: => get_page_from_freelist (ffffffff81176659) => __alloc_pages_nodemask (ffffffff81176d22) => alloc_pages_vma (ffffffff811bf675) => handle_mm_fault (ffffffff8119e693) => __do_page_fault (ffffffff810631ea) => trace_do_page_fault (ffffffff81063543) => do_async_page_fault (ffffffff8105c40a) => async_page_fault (ffffffff817581d8) [snip] <...>-9018 [004] 92.678379: page_ref_mod: pfn=0x17ac9 flags=0x40048 count=2 mapcount=1 mapping=0xffff880015a78dc1 mt=4 val=1 [snip] ... ... <...>-9131 [001] 93.174468: test_pages_isolated: start_pfn=0x17800 end_pfn=0x17c00 fin_pfn=0x17ac9 ret=fail [snip] <...>-9018 [004] 93.174843: page_ref_mod_and_test: pfn=0x17ac9 flags=0x40068 count=0 mapcount=0 mapping=0xffff880015a78dc1 mt=4 val=-1 ret=1 => release_pages (ffffffff8117c9e4) => free_pages_and_swap_cache (ffffffff811b0697) => tlb_flush_mmu_free (ffffffff81199616) => tlb_finish_mmu (ffffffff8119a62c) => exit_mmap (ffffffff811a53f7) => mmput (ffffffff81073f47) => do_exit (ffffffff810794e9) => do_group_exit (ffffffff81079def) => SyS_exit_group (ffffffff81079e74) => entry_SYSCALL_64_fastpath (ffffffff817560b6) This output shows that problem comes from exit path. In exit path, to improve performance, pages are not freed immediately. They are gathered and processed by batch. During this process, migration cannot be possible and CMA allocation is failed. This problem is hard to find without this page reference tracepoint facility. Enabling this feature bloat kernel text 30 KB in my configuration. text data bss dec hex filename 12127327 2243616 1507328 15878271 f2487f vmlinux_disabled 12157208 2258880 1507328 15923416 f2f8d8 vmlinux_enabled Note that, due to header file dependency problem between mm.h and tracepoint.h, this feature has to open code the static key functions for tracepoints. Proposed by Steven Rostedt in following link. https://lkml.org/lkml/2015/12/9/699 [[email protected]: crypto/async_pq: use __free_page() instead of put_page()] [[email protected]: fix build failure for xtensa] [[email protected]: tweak Kconfig text, per Vlastimil] Signed-off-by: Joonsoo Kim <[email protected]> Acked-by: Michal Nazarewicz <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Mel Gorman <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Cc: Sergey Senozhatsky <[email protected]> Acked-by: Steven Rostedt <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
1 parent
fe896d1
commit 95813b8
Showing
6 changed files
with
296 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#undef TRACE_SYSTEM | ||
#define TRACE_SYSTEM page_ref | ||
|
||
#if !defined(_TRACE_PAGE_REF_H) || defined(TRACE_HEADER_MULTI_READ) | ||
#define _TRACE_PAGE_REF_H | ||
|
||
#include <linux/types.h> | ||
#include <linux/page_ref.h> | ||
#include <linux/tracepoint.h> | ||
#include <trace/events/mmflags.h> | ||
|
||
DECLARE_EVENT_CLASS(page_ref_mod_template, | ||
|
||
TP_PROTO(struct page *page, int v), | ||
|
||
TP_ARGS(page, v), | ||
|
||
TP_STRUCT__entry( | ||
__field(unsigned long, pfn) | ||
__field(unsigned long, flags) | ||
__field(int, count) | ||
__field(int, mapcount) | ||
__field(void *, mapping) | ||
__field(int, mt) | ||
__field(int, val) | ||
), | ||
|
||
TP_fast_assign( | ||
__entry->pfn = page_to_pfn(page); | ||
__entry->flags = page->flags; | ||
__entry->count = page_ref_count(page); | ||
__entry->mapcount = page_mapcount(page); | ||
__entry->mapping = page->mapping; | ||
__entry->mt = get_pageblock_migratetype(page); | ||
__entry->val = v; | ||
), | ||
|
||
TP_printk("pfn=0x%lx flags=%s count=%d mapcount=%d mapping=%p mt=%d val=%d", | ||
__entry->pfn, | ||
show_page_flags(__entry->flags & ((1UL << NR_PAGEFLAGS) - 1)), | ||
__entry->count, | ||
__entry->mapcount, __entry->mapping, __entry->mt, | ||
__entry->val) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_template, page_ref_set, | ||
|
||
TP_PROTO(struct page *page, int v), | ||
|
||
TP_ARGS(page, v) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_template, page_ref_mod, | ||
|
||
TP_PROTO(struct page *page, int v), | ||
|
||
TP_ARGS(page, v) | ||
); | ||
|
||
DECLARE_EVENT_CLASS(page_ref_mod_and_test_template, | ||
|
||
TP_PROTO(struct page *page, int v, int ret), | ||
|
||
TP_ARGS(page, v, ret), | ||
|
||
TP_STRUCT__entry( | ||
__field(unsigned long, pfn) | ||
__field(unsigned long, flags) | ||
__field(int, count) | ||
__field(int, mapcount) | ||
__field(void *, mapping) | ||
__field(int, mt) | ||
__field(int, val) | ||
__field(int, ret) | ||
), | ||
|
||
TP_fast_assign( | ||
__entry->pfn = page_to_pfn(page); | ||
__entry->flags = page->flags; | ||
__entry->count = page_ref_count(page); | ||
__entry->mapcount = page_mapcount(page); | ||
__entry->mapping = page->mapping; | ||
__entry->mt = get_pageblock_migratetype(page); | ||
__entry->val = v; | ||
__entry->ret = ret; | ||
), | ||
|
||
TP_printk("pfn=0x%lx flags=%s count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d", | ||
__entry->pfn, | ||
show_page_flags(__entry->flags & ((1UL << NR_PAGEFLAGS) - 1)), | ||
__entry->count, | ||
__entry->mapcount, __entry->mapping, __entry->mt, | ||
__entry->val, __entry->ret) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_and_test_template, page_ref_mod_and_test, | ||
|
||
TP_PROTO(struct page *page, int v, int ret), | ||
|
||
TP_ARGS(page, v, ret) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_and_test_template, page_ref_mod_and_return, | ||
|
||
TP_PROTO(struct page *page, int v, int ret), | ||
|
||
TP_ARGS(page, v, ret) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_and_test_template, page_ref_mod_unless, | ||
|
||
TP_PROTO(struct page *page, int v, int ret), | ||
|
||
TP_ARGS(page, v, ret) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_and_test_template, page_ref_freeze, | ||
|
||
TP_PROTO(struct page *page, int v, int ret), | ||
|
||
TP_ARGS(page, v, ret) | ||
); | ||
|
||
DEFINE_EVENT(page_ref_mod_template, page_ref_unfreeze, | ||
|
||
TP_PROTO(struct page *page, int v), | ||
|
||
TP_ARGS(page, v) | ||
); | ||
|
||
#endif /* _TRACE_PAGE_COUNT_H */ | ||
|
||
/* This part must be outside protection */ | ||
#include <trace/define_trace.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#include <linux/mm_types.h> | ||
#include <linux/tracepoint.h> | ||
|
||
#define CREATE_TRACE_POINTS | ||
#include <trace/events/page_ref.h> | ||
|
||
void __page_ref_set(struct page *page, int v) | ||
{ | ||
trace_page_ref_set(page, v); | ||
} | ||
EXPORT_SYMBOL(__page_ref_set); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_set); | ||
|
||
void __page_ref_mod(struct page *page, int v) | ||
{ | ||
trace_page_ref_mod(page, v); | ||
} | ||
EXPORT_SYMBOL(__page_ref_mod); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_mod); | ||
|
||
void __page_ref_mod_and_test(struct page *page, int v, int ret) | ||
{ | ||
trace_page_ref_mod_and_test(page, v, ret); | ||
} | ||
EXPORT_SYMBOL(__page_ref_mod_and_test); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_mod_and_test); | ||
|
||
void __page_ref_mod_and_return(struct page *page, int v, int ret) | ||
{ | ||
trace_page_ref_mod_and_return(page, v, ret); | ||
} | ||
EXPORT_SYMBOL(__page_ref_mod_and_return); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_mod_and_return); | ||
|
||
void __page_ref_mod_unless(struct page *page, int v, int u) | ||
{ | ||
trace_page_ref_mod_unless(page, v, u); | ||
} | ||
EXPORT_SYMBOL(__page_ref_mod_unless); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_mod_unless); | ||
|
||
void __page_ref_freeze(struct page *page, int v, int ret) | ||
{ | ||
trace_page_ref_freeze(page, v, ret); | ||
} | ||
EXPORT_SYMBOL(__page_ref_freeze); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_freeze); | ||
|
||
void __page_ref_unfreeze(struct page *page, int v) | ||
{ | ||
trace_page_ref_unfreeze(page, v); | ||
} | ||
EXPORT_SYMBOL(__page_ref_unfreeze); | ||
EXPORT_TRACEPOINT_SYMBOL(page_ref_unfreeze); |