Skip to contentSkip to conversation

trace memory objects

RFC PATCH In review Wu Fengguang 2 participants 17 messages Aug 29, 2011 – Aug 30, 2011 1 message not in the archive

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

cover trace memory objects

Andrew, Ingo,

I'd like to introduce three memory object interfaces

/debug/tracing/objects/mm/pages/dump-pfn
/debug/tracing/objects/mm/pages/dump-file
/debug/tracing/objects/mm/pages/dump-fs

for dumping

- a range of PFNs
- the cached inodes (icache)
- the cached inode pages (page cache)

The "dump-pfn" interface is a superset of the existing /proc/kpageflags and /proc/kpagecount interfaces. Example output:

# echo 10000 +10 > /debug/tracing/objects/mm/pages/dump-pfn
# cat /debug/tracing/trace
# tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh-3128  [000]  1393.460292: dump_page_frame: pfn=10001 page=ffffea000009c400 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460296: dump_page_frame: pfn=10002 page=ffffea000009c440 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460298: dump_page_frame: pfn=10003 page=ffffea000009c480 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460299: dump_page_frame: pfn=10004 page=ffffea000009c4c0 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460300: dump_page_frame: pfn=10005 page=ffffea000009c500 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460301: dump_page_frame: pfn=10006 page=ffffea000009c540 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460301: dump_page_frame: pfn=10007 page=ffffea000009c580 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460302: dump_page_frame: pfn=10008 page=ffffea000009c5c0 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460303: dump_page_frame: pfn=10009 page=ffffea000009c600 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved
             zsh-3128  [000]  1393.460304: dump_page_frame: pfn=10010 page=ffffea000009c640 count=1 mapcount=0 memcg=0 private=0 mapping=0 index=0 flags=reserved

The "dump-file", "dump-fs" interfaces could be pretty useful for examining the page cache status. Example output:

# echo > /debug/tracing/trace
# echo / > /debug/tracing/objects/mm/pages/dump-fs
# head -50 /debug/tracing/trace
# tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh-3128  [000]  1482.623149: dump_inode_cache: ino=1507329 size=4096 cached=4096 dirtied_when=4294676467 age=1482 state=____ type=DIR name=/
             zsh-3128  [000]  1482.623157: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623340: dump_inode_cache: ino=1786836 size=12288 cached=12288 dirtied_when=4294676472 age=1482 state=____ type=DIR name=/sbin
             zsh-3128  [000]  1482.623355: dump_page_cache: index=0 len=3 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623393: dump_inode_cache: ino=1786946 size=37312 cached=40960 dirtied_when=4294676473 age=1482 state=____ type=REG name=/sbin/init
             zsh-3128  [000]  1482.623404: dump_page_cache: index=0 len=6 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]  1482.623405: dump_page_cache: index=6 len=1 flags=M__A_U_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]  1482.623406: dump_page_cache: index=7 len=1 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]  1482.623408: dump_page_cache: index=8 len=2 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623422: dump_inode_cache: ino=1507464 size=4 cached=4096 dirtied_when=4294676477 age=1482 state=____ type=LNK name=/lib64
             zsh-3128  [000]  1482.623427: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623441: dump_inode_cache: ino=1590173 size=12288 cached=0 dirtied_when=4294676477 age=1482 state=____ type=DIR name=/lib
             zsh-3128  [000]  1482.623458: dump_inode_cache: ino=1590265 size=27 cached=4096 dirtied_when=4294676478 age=1482 state=____ type=LNK name=/lib/ld-linux-x86-64.so.2
             zsh-3128  [000]  1482.623462: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623478: dump_inode_cache: ino=1663440 size=4096 cached=0 dirtied_when=4294676479 age=1482 state=____ type=DIR name=/lib/x86_64-linux-gnu
             zsh-3128  [000]  1482.623495: dump_inode_cache: ino=3293287 size=136936 cached=139264 dirtied_when=4294676480 age=1482 state=____ type=REG name=/lib/x86_64-linux-gnu/ld-2.13.so
             zsh-3128  [000]  1482.623499: dump_page_cache: index=0 len=1 flags=M__ARU_____ count=28 mapcount=27 memcg=1
             zsh-3128  [000]  1482.623501: dump_page_cache: index=1 len=3 flags=M__ARU_____ count=23 mapcount=22 memcg=1
             zsh-3128  [000]  1482.623503: dump_page_cache: index=4 len=4 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623504: dump_page_cache: index=8 len=2 flags=M__ARU_____ count=34 mapcount=33 memcg=1
             zsh-3128  [000]  1482.623506: dump_page_cache: index=10 len=3 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623508: dump_page_cache: index=13 len=1 flags=M__ARU_____ count=34 mapcount=33 memcg=1
             zsh-3128  [000]  1482.623509: dump_page_cache: index=14 len=1 flags=M__ARU_____ count=33 mapcount=32 memcg=1
             zsh-3128  [000]  1482.623510: dump_page_cache: index=15 len=1 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623511: dump_page_cache: index=16 len=1 flags=M__ARU_____ count=25 mapcount=24 memcg=1
             zsh-3128  [000]  1482.623512: dump_page_cache: index=17 len=1 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623513: dump_page_cache: index=18 len=1 flags=M__ARU_____ count=10 mapcount=9 memcg=1
             zsh-3128  [000]  1482.623514: dump_page_cache: index=19 len=1 flags=M__ARU_____ count=34 mapcount=33 memcg=1
             zsh-3128  [000]  1482.623515: dump_page_cache: index=20 len=1 flags=M__ARU_____ count=23 mapcount=22 memcg=1
             zsh-3128  [000]  1482.623516: dump_page_cache: index=21 len=1 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623517: dump_page_cache: index=22 len=1 flags=M__ARU_____ count=34 mapcount=33 memcg=1
             zsh-3128  [000]  1482.623518: dump_page_cache: index=23 len=2 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623519: dump_page_cache: index=25 len=1 flags=M__ARU_____ count=33 mapcount=32 memcg=1
             zsh-3128  [000]  1482.623520: dump_page_cache: index=26 len=1 flags=M__ARU_____ count=10 mapcount=9 memcg=1
             zsh-3128  [000]  1482.623522: dump_page_cache: index=27 len=1 flags=M__ARU_____ count=4 mapcount=3 memcg=1
             zsh-3128  [000]  1482.623523: dump_page_cache: index=28 len=1 flags=M__ARU_____ count=26 mapcount=25 memcg=1
             zsh-3128  [000]  1482.623525: dump_page_cache: index=29 len=5 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623540: dump_inode_cache: ino=1525477 size=12288 cached=0 dirtied_when=4294676489 age=1482 state=____ type=DIR name=/etc
             zsh-3128  [000]  1482.623556: dump_inode_cache: ino=1526474 size=69589 cached=69632 dirtied_when=4294676491 age=1482 state=____ type=REG name=/etc/ld.so.cache
             zsh-3128  [000]  1482.623561: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623562: dump_page_cache: index=1 len=1 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623569: dump_page_cache: index=2 len=15 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623585: dump_inode_cache: ino=1590258 size=241632 cached=241664 dirtied_when=4294676493 age=1482 state=____ type=REG name=/lib/libsepol.so.1
             zsh-3128  [000]  1482.623591: dump_page_cache: index=0 len=5 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]  1482.623609: dump_page_cache: index=5 len=42 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]  1482.623610: dump_page_cache: index=47 len=1 flags=M__ARU_____ count=2 mapcount=1 memcg=1

patches:

dump-pfn interface
(it looks more clean and easier for review to fold patches 1-5 into one, but let's keep the changelog for the initial post)

[RFC][PATCH 1/7] tracing/mm: add page frame snapshot trace [RFC][PATCH 2/7] tracing/mm: rename trigger file to dump-pfn [RFC][PATCH 3/7] tracing/mm: create trace_objects.c [RFC][PATCH 4/7] tracing/mm: dump more page frame information [RFC][PATCH 5/7] tracing/mm: accept echo-able input format for pfn range

dump-file and dump-fs interfaces

[RFC][PATCH 6/7] tracing/mm: add dump-file and dump-fs interfaces

add memcg support

[RFC][PATCH 7/7] tracing/mm: add memcg field

diffstat:

 fs/inode.c                   |    8 
 fs/internal.h                |    5 
 include/linux/fs.h           |    1 
 include/linux/memcontrol.h   |    6 
 include/linux/page-flags.h   |    1 
 include/trace/events/mm.h    |  170 ++++++++++++++
 kernel/trace/Makefile        |    2 
 kernel/trace/trace.h         |    1 
 kernel/trace/trace_mm.c      |  378 +++++++++++++++++++++++++++++++++
 kernel/trace/trace_objects.c |   26 ++
 mm/memcontrol.c              |   18 +
 mm/page_alloc.c              |    4 
 12 files changed, 612 insertions(+), 8 deletions(-)

Thanks,
Fengguang

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw

RFC PATCH 1/7 tracing/mm: add page frame snapshot trace

From: Steven Rostedt <[email protected]>

This is a prototype to dump out a snapshot of the page tables to the tracing buffer. Currently it is very primitive, and just writes out the events. There is no synchronization to not loose the events, so /debug/tracing/buffer_size_kb has to be large enough for all events to fit.

We will do something about synchronization later. That is, have a way to read the buffer through the tracing/object/mm/page/X file and have the two in sync.

But this is just a prototype to get the ball rolling.

---
 include/trace/events/mm.h |   48 ++++++++++
 kernel/trace/Makefile     |    1 
 kernel/trace/trace_mm.c   |  172 ++++++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+)
 create mode 100644 include/trace/events/mm.h
 create mode 100644 kernel/trace/trace_mm.c
include/trace/events/mm.h new file +48 -0
@@ -0,0 +1,48 @@
+#if !defined(_TRACE_MM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MM_H
+
+#include <linux/tracepoint.h>
+#include <linux/mm.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mm
+
+/**
+ * dump_pages - called by the trace page dump trigger
+ * @pfn: page frame number
+ * @page: pointer to the page frame
+ *
+ * This is a helper trace point into the dumping of the page frames.
+ * It will record various infromation about a page frame.
+ */
+TRACE_EVENT(dump_pages,
+
+	TP_PROTO(unsigned long pfn, struct page *page),
+
+	TP_ARGS(pfn, page),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	pfn		)
+		__field(	unsigned long,	flags		)
+		__field(	unsigned long,	index		)
+		__field(	unsigned int,	count		)
+		__field(	unsigned int,	mapcount	)
+	),
+
+	TP_fast_assign(
+		__entry->pfn		= pfn;
+		__entry->flags		= page->flags;
+		__entry->count		= atomic_read(&page->_count);
+		__entry->mapcount	= page_mapcount(page);
+		__entry->index		= page->index;
+	),
+
+	TP_printk("pfn=%lu flags=%lx count=%u mapcount=%u index=%lu",
+		  __entry->pfn, __entry->flags, __entry->count,
+		  __entry->mapcount, __entry->index)
+);
+
+#endif /*  _TRACE_MM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
kernel/trace/Makefile +1 -0
@@ -53,6 +53,7 @@ endif
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
 obj-$(CONFIG_TRACEPOINTS) += power-traces.o
+obj-$(CONFIG_EVENT_TRACING) += trace_mm.o
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
kernel/trace/trace_mm.c new file +172 -0

172 lines not on this page · raw message

#2 lore raw

RFC PATCH 1/7 tracing/mm: add page frame snapshot trace

In reply to Wu Fengguang

From: Steven Rostedt <[email protected]>

This is a prototype to dump out a snapshot of the page tables to the tracing buffer. Currently it is very primitive, and just writes out the events. There is no synchronization to not loose the events, so /debug/tracing/buffer_size_kb has to be large enough for all events to fit.

We will do something about synchronization later. That is, have a way to read the buffer through the tracing/object/mm/page/X file and have the two in sync.

But this is just a prototype to get the ball rolling.

---
 include/trace/events/mm.h |   48 ++++++++++
 kernel/trace/Makefile     |    1 
 kernel/trace/trace_mm.c   |  172 ++++++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+)
 create mode 100644 include/trace/events/mm.h
 create mode 100644 kernel/trace/trace_mm.c
include/trace/events/mm.h new file +48 -0
@@ -0,0 +1,48 @@
+#if !defined(_TRACE_MM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MM_H
+
+#include <linux/tracepoint.h>
+#include <linux/mm.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mm
+
+/**
+ * dump_pages - called by the trace page dump trigger
+ * @pfn: page frame number
+ * @page: pointer to the page frame
+ *
+ * This is a helper trace point into the dumping of the page frames.
+ * It will record various infromation about a page frame.
+ */
+TRACE_EVENT(dump_pages,
+
+	TP_PROTO(unsigned long pfn, struct page *page),
+
+	TP_ARGS(pfn, page),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	pfn		)
+		__field(	unsigned long,	flags		)
+		__field(	unsigned long,	index		)
+		__field(	unsigned int,	count		)
+		__field(	unsigned int,	mapcount	)
+	),
+
+	TP_fast_assign(
+		__entry->pfn		= pfn;
+		__entry->flags		= page->flags;
+		__entry->count		= atomic_read(&page->_count);
+		__entry->mapcount	= page_mapcount(page);
+		__entry->index		= page->index;
+	),
+
+	TP_printk("pfn=%lu flags=%lx count=%u mapcount=%u index=%lu",
+		  __entry->pfn, __entry->flags, __entry->count,
+		  __entry->mapcount, __entry->index)
+);
+
+#endif /*  _TRACE_MM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
kernel/trace/Makefile +1 -0
@@ -53,6 +53,7 @@ endif
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
 obj-$(CONFIG_TRACEPOINTS) += power-traces.o
+obj-$(CONFIG_EVENT_TRACING) += trace_mm.o
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
kernel/trace/trace_mm.c new file +172 -0

172 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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#4 lore raw

PATCH 1/1 kernel.h/checkpatch: Mark strict_strto<foo> and simple_strto<foo> as obsolete

Mark obsolete/deprecated strict_strto<foo> and simple_strto<foo> functions and macros as obsolete.

Update checkpatch to warn about their use.

---

 include/linux/kernel.h |    4 ++++
 scripts/checkpatch.pl  |    6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)
include/linux/kernel.h +4 -0
index 46ac9a5..1f9bc02 100644
@@ -287,6 +287,8 @@ static inline int __must_check kstrtos32_from_user(const char __user *s, size_t
 	return kstrtoint_from_user(s, count, base, res);
 }
 
+/* Obsolete, do not use.  Use kstrto<foo> instead */
+
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
@@ -296,6 +298,8 @@ extern long long simple_strtoll(const char *,char **,unsigned int);
 #define strict_strtoull	kstrtoull
 #define strict_strtoll	kstrtoll
 
+/* lib/printf utilities */
+
 extern int sprintf(char * buf, const char * fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
 extern int vsprintf(char *buf, const char *, va_list)
scripts/checkpatch.pl +3 -3
index 9d761c9..bf1734a 100755
@@ -3150,10 +3150,10 @@ sub process {
 			     "consider using a completion\n" . $herecurr);
 
 		}
-# recommend kstrto* over simple_strto*
-		if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+# recommend kstrto* over simple_strto* and strict_strto*
+		if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
 			WARN("CONSIDER_KSTRTO",
-			     "consider using kstrto* in preference to simple_$1\n" . $herecurr);
+			     "$1 is obsolete, use k$3 instead\n" . $herecurr);
 		}
 # check for __initcall(), use device_initcall() explicitly please
 		if ($line =~ /^.\s*__initcall\s*\(/) {
#5 lore raw

RFC PATCH 2/7 tracing/mm: rename trigger file to dump-pfn

In reply to Wu Fengguang

From: Ingo Molnar <[email protected]>

Wu Fengguang noted that /debug/tracing/objects/mm/pages/trigger was not very intuitively named - rename it to 'dump-pfn', which covers its functionality better.

[ Impact: rename /debug/tracing file ]

---
 include/trace/events/mm.h |    4 ++--
 kernel/trace/trace_mm.c   |   26 +++++++++++++-------------
 2 files changed, 15 insertions(+), 15 deletions(-)
kernel/trace/trace_mm.c +13 -13
@@ -15,8 +15,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/mm.h>
 
-void trace_read_page_frames(unsigned long start, unsigned long end,
-			    void (*trace)(unsigned long pfn, struct page *page))
+void trace_mm_page_frames(unsigned long start, unsigned long end,
+			  void (*trace)(unsigned long pfn, struct page *page))
 {
 	unsigned long pfn = start;
 	struct page *page;
@@ -37,22 +37,22 @@ void trace_read_page_frames(unsigned lon
 	}
 }
 
-static void trace_do_dump_pages(unsigned long pfn, struct page *page)
+static void trace_mm_page_frame(unsigned long pfn, struct page *page)
 {
-	trace_dump_pages(pfn, page);
+	trace_dump_page_frame(pfn, page);
 }
 
 static ssize_t
-trace_mm_trigger_read(struct file *filp, char __user *ubuf, size_t cnt,
-		 loff_t *ppos)
+trace_mm_pfn_range_read(struct file *filp, char __user *ubuf, size_t cnt,
+			loff_t *ppos)
 {
 	return simple_read_from_buffer(ubuf, cnt, ppos, "0\n", 2);
 }
 
 
 static ssize_t
-trace_mm_trigger_write(struct file *filp, const char __user *ubuf, size_t cnt,
-		       loff_t *ppos)
+trace_mm_pfn_range_write(struct file *filp, const char __user *ubuf, size_t cnt,
+			 loff_t *ppos)
 {
 	unsigned long val, start, end;
 	char buf[64];
@@ -67,7 +67,7 @@ trace_mm_trigger_write(struct file *filp
 	if (tracing_update_buffers() < 0)
 		return -ENOMEM;
 
-	if (trace_set_clr_event("mm", "dump_pages", 1))
+	if (trace_set_clr_event("mm", "dump_page_frame", 1))
 		return -EINVAL;
 
 	buf[cnt] = 0;
@@ -82,7 +82,7 @@ trace_mm_trigger_write(struct file *filp
 	else
 		end = start + val;
 
-	trace_read_page_frames(start, end, trace_do_dump_pages);
+	trace_mm_page_frames(start, end, trace_mm_page_frame);
 
 	*ppos += cnt;
 
@@ -91,8 +91,8 @@ trace_mm_trigger_write(struct file *filp
 
 static const struct file_operations trace_mm_fops = {
 	.open		= tracing_open_generic,
-	.read		= trace_mm_trigger_read,
-	.write		= trace_mm_trigger_write,
+	.read		= trace_mm_pfn_range_read,
+	.write		= trace_mm_pfn_range_write,
 };
 
 /* move this into trace_objects.c when that file is created */
@@ -164,7 +164,7 @@ static __init int trace_objects_mm_init(
 	if (!d_pages)
 		return 0;
 
-	trace_create_file("trigger", 0600, d_pages, NULL,
+	trace_create_file("dump-pfn", 0600, d_pages, NULL,
 			  &trace_mm_fops);
 
 	return 0;
include/trace/events/mm.h +2 -2
@@ -8,14 +8,14 @@
 #define TRACE_SYSTEM mm
 
 /**
- * dump_pages - called by the trace page dump trigger
+ * dump_page_frame - called by the trace page dump trigger
  * @pfn: page frame number
  * @page: pointer to the page frame
  *
  * This is a helper trace point into the dumping of the page frames.
  * It will record various infromation about a page frame.
  */
-TRACE_EVENT(dump_pages,
+TRACE_EVENT(dump_page_frame,
 
 	TP_PROTO(unsigned long pfn, struct page *page),
 
#6 lore raw

RFC PATCH 2/7 tracing/mm: rename trigger file to dump-pfn

In reply to Wu Fengguang

From: Ingo Molnar <[email protected]>

Wu Fengguang noted that /debug/tracing/objects/mm/pages/trigger was not very intuitively named - rename it to 'dump-pfn', which covers its functionality better.

[ Impact: rename /debug/tracing file ]

---
 include/trace/events/mm.h |    4 ++--
 kernel/trace/trace_mm.c   |   26 +++++++++++++-------------
 2 files changed, 15 insertions(+), 15 deletions(-)
kernel/trace/trace_mm.c +13 -13
@@ -15,8 +15,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/mm.h>
 
-void trace_read_page_frames(unsigned long start, unsigned long end,
-			    void (*trace)(unsigned long pfn, struct page *page))
+void trace_mm_page_frames(unsigned long start, unsigned long end,
+			  void (*trace)(unsigned long pfn, struct page *page))
 {
 	unsigned long pfn = start;
 	struct page *page;
@@ -37,22 +37,22 @@ void trace_read_page_frames(unsigned lon
 	}
 }
 
-static void trace_do_dump_pages(unsigned long pfn, struct page *page)
+static void trace_mm_page_frame(unsigned long pfn, struct page *page)
 {
-	trace_dump_pages(pfn, page);
+	trace_dump_page_frame(pfn, page);
 }
 
 static ssize_t
-trace_mm_trigger_read(struct file *filp, char __user *ubuf, size_t cnt,
-		 loff_t *ppos)
+trace_mm_pfn_range_read(struct file *filp, char __user *ubuf, size_t cnt,
+			loff_t *ppos)
 {
 	return simple_read_from_buffer(ubuf, cnt, ppos, "0\n", 2);
 }
 
 
 static ssize_t
-trace_mm_trigger_write(struct file *filp, const char __user *ubuf, size_t cnt,
-		       loff_t *ppos)
+trace_mm_pfn_range_write(struct file *filp, const char __user *ubuf, size_t cnt,
+			 loff_t *ppos)
 {
 	unsigned long val, start, end;
 	char buf[64];
@@ -67,7 +67,7 @@ trace_mm_trigger_write(struct file *filp
 	if (tracing_update_buffers() < 0)
 		return -ENOMEM;
 
-	if (trace_set_clr_event("mm", "dump_pages", 1))
+	if (trace_set_clr_event("mm", "dump_page_frame", 1))
 		return -EINVAL;
 
 	buf[cnt] = 0;
@@ -82,7 +82,7 @@ trace_mm_trigger_write(struct file *filp
 	else
 		end = start + val;
 
-	trace_read_page_frames(start, end, trace_do_dump_pages);
+	trace_mm_page_frames(start, end, trace_mm_page_frame);
 
 	*ppos += cnt;
 
@@ -91,8 +91,8 @@ trace_mm_trigger_write(struct file *filp
 
 static const struct file_operations trace_mm_fops = {
 	.open		= tracing_open_generic,
-	.read		= trace_mm_trigger_read,
-	.write		= trace_mm_trigger_write,
+	.read		= trace_mm_pfn_range_read,
+	.write		= trace_mm_pfn_range_write,
 };
 
 /* move this into trace_objects.c when that file is created */
@@ -164,7 +164,7 @@ static __init int trace_objects_mm_init(
 	if (!d_pages)
 		return 0;
 
-	trace_create_file("trigger", 0600, d_pages, NULL,
+	trace_create_file("dump-pfn", 0600, d_pages, NULL,
 			  &trace_mm_fops);
 
 	return 0;
include/trace/events/mm.h +2 -2
@@ -8,14 +8,14 @@
 #define TRACE_SYSTEM mm
 
 /**
- * dump_pages - called by the trace page dump trigger
+ * dump_page_frame - called by the trace page dump trigger
  * @pfn: page frame number
  * @page: pointer to the page frame
  *
  * This is a helper trace point into the dumping of the page frames.
  * It will record various infromation about a page frame.
  */
-TRACE_EVENT(dump_pages,
+TRACE_EVENT(dump_page_frame,
 
 	TP_PROTO(unsigned long pfn, struct page *page),
 

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#7 lore raw

RFC PATCH 3/7 tracing/mm: create trace_objects.c

In reply to Wu Fengguang

Code refactor: create trace_objects.c and move relevant code from trace_mm.c

CC Steven Rostedt <[email protected]>
---
 kernel/trace/Makefile        |    1 +
 kernel/trace/trace.h         |    1 +
 kernel/trace/trace_mm.c      |   22 ----------------------
 kernel/trace/trace_objects.c |   26 ++++++++++++++++++++++++++
 4 files changed, 28 insertions(+), 22 deletions(-)
kernel/trace/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_RING_BUFFER) += ring_buffer
 obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o
 
 obj-$(CONFIG_TRACING) += trace.o
+obj-$(CONFIG_TRACING) += trace_objects.o
 obj-$(CONFIG_TRACING) += trace_output.o
 obj-$(CONFIG_TRACING) += trace_stat.o
 obj-$(CONFIG_TRACING) += trace_printk.o
kernel/trace/trace.h +1 -0
@@ -318,6 +318,7 @@ struct dentry *trace_create_file(const c
 				 const struct file_operations *fops);
 
 struct dentry *tracing_init_dentry(void);
+struct dentry *trace_objects_dir(void);
 
 struct ring_buffer_event;
 
kernel/trace/trace_objects.c new file +26 -0
@@ -0,0 +1,26 @@
+#include <linux/debugfs.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+struct dentry *trace_objects_dir(void)
+{
+	static struct dentry *d_objects;
+	struct dentry *d_tracer;
+
+	if (d_objects)
+		return d_objects;
+
+	d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return NULL;
+
+	d_objects = debugfs_create_dir("objects", d_tracer);
+	if (!d_objects)
+		pr_warning("Could not create debugfs "
+			   "'objects' directory\n");
+
+	return d_objects;
+}
+
+
kernel/trace/trace_mm.c +0 -22
@@ -95,28 +95,6 @@ static const struct file_operations trac
 	.write		= trace_mm_pfn_range_write,
 };
 
-/* move this into trace_objects.c when that file is created */
-static struct dentry *trace_objects_dir(void)
-{
-	static struct dentry *d_objects;
-	struct dentry *d_tracer;
-
-	if (d_objects)
-		return d_objects;
-
-	d_tracer = tracing_init_dentry();
-	if (!d_tracer)
-		return NULL;
-
-	d_objects = debugfs_create_dir("objects", d_tracer);
-	if (!d_objects)
-		pr_warning("Could not create debugfs "
-			   "'objects' directory\n");
-
-	return d_objects;
-}
-
-
 static struct dentry *trace_objects_mm_dir(void)
 {
 	static struct dentry *d_mm;
#8 lore raw

RFC PATCH 3/7 tracing/mm: create trace_objects.c

In reply to Wu Fengguang

Code refactor: create trace_objects.c and move relevant code from trace_mm.c

CC Steven Rostedt <[email protected]>
---
 kernel/trace/Makefile        |    1 +
 kernel/trace/trace.h         |    1 +
 kernel/trace/trace_mm.c      |   22 ----------------------
 kernel/trace/trace_objects.c |   26 ++++++++++++++++++++++++++
 4 files changed, 28 insertions(+), 22 deletions(-)
kernel/trace/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_RING_BUFFER) += ring_buffer
 obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o
 
 obj-$(CONFIG_TRACING) += trace.o
+obj-$(CONFIG_TRACING) += trace_objects.o
 obj-$(CONFIG_TRACING) += trace_output.o
 obj-$(CONFIG_TRACING) += trace_stat.o
 obj-$(CONFIG_TRACING) += trace_printk.o
kernel/trace/trace.h +1 -0
@@ -318,6 +318,7 @@ struct dentry *trace_create_file(const c
 				 const struct file_operations *fops);
 
 struct dentry *tracing_init_dentry(void);
+struct dentry *trace_objects_dir(void);
 
 struct ring_buffer_event;
 
kernel/trace/trace_objects.c new file +26 -0
@@ -0,0 +1,26 @@
+#include <linux/debugfs.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+struct dentry *trace_objects_dir(void)
+{
+	static struct dentry *d_objects;
+	struct dentry *d_tracer;
+
+	if (d_objects)
+		return d_objects;
+
+	d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return NULL;
+
+	d_objects = debugfs_create_dir("objects", d_tracer);
+	if (!d_objects)
+		pr_warning("Could not create debugfs "
+			   "'objects' directory\n");
+
+	return d_objects;
+}
+
+
kernel/trace/trace_mm.c +0 -22
@@ -95,28 +95,6 @@ static const struct file_operations trac
 	.write		= trace_mm_pfn_range_write,
 };
 
-/* move this into trace_objects.c when that file is created */
-static struct dentry *trace_objects_dir(void)
-{
-	static struct dentry *d_objects;
-	struct dentry *d_tracer;
-
-	if (d_objects)
-		return d_objects;
-
-	d_tracer = tracing_init_dentry();
-	if (!d_tracer)
-		return NULL;
-
-	d_objects = debugfs_create_dir("objects", d_tracer);
-	if (!d_objects)
-		pr_warning("Could not create debugfs "
-			   "'objects' directory\n");
-
-	return d_objects;
-}
-
-
 static struct dentry *trace_objects_mm_dir(void)
 {
 	static struct dentry *d_mm;

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

RFC PATCH 4/7 tracing/mm: dump more page frame information

In reply to Wu Fengguang

Add 4 more fields to dump_page_frame trace event.

1) stable page flags in addition to the raw page flags

User space should only make use the stable page flags. The raw page flags is stored mainly to take advantage of ftrace_print_flags_seq() for showing symbolic flag names.

2) struct page address
3) page->private
4) page->mapping

The above 3 fields are mainly targeted for VM debug aids.

---
 include/linux/page-flags.h |    1 +
 include/trace/events/mm.h  |   29 +++++++++++++++++++++++++----
 mm/page_alloc.c            |    4 ++--
 3 files changed, 28 insertions(+), 6 deletions(-)
mm/page_alloc.c +2 -2
@@ -5743,7 +5743,7 @@ bool is_free_buddy_page(struct page *pag
 }
 #endif
 
-static struct trace_print_flags pageflag_names[] = {
+struct trace_print_flags pageflag_names[] = {
 	{1UL << PG_locked,		"locked"	},
 	{1UL << PG_error,		"error"		},
 	{1UL << PG_referenced,		"referenced"	},
@@ -5790,7 +5790,7 @@ static void dump_page_flags(unsigned lon
 	printk(KERN_ALERT "page flags: %#lx(", flags);
 
 	/* remove zone id */
-	flags &= (1UL << NR_PAGEFLAGS) - 1;
+	flags &= PAGE_FLAGS_MASK;
 
 	for (i = 0; pageflag_names[i].name && flags; i++) {
 
include/linux/page-flags.h +1 -0
@@ -462,6 +462,7 @@ static inline int PageTransCompound(stru
  * there has been a kernel bug or struct page corruption.
  */
 #define PAGE_FLAGS_CHECK_AT_PREP	((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_MASK			((1 << NR_PAGEFLAGS) - 1)
 
 #define PAGE_FLAGS_PRIVATE				\
 	(1 << PG_private | 1 << PG_private_2)
include/trace/events/mm.h +25 -4
@@ -2,11 +2,14 @@
 #define _TRACE_MM_H
 
 #include <linux/tracepoint.h>
+#include <linux/page-flags.h>
 #include <linux/mm.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mm
 
+extern struct trace_print_flags pageflag_names[];
+
 /**
  * dump_page_frame - called by the trace page dump trigger
  * @pfn: page frame number
@@ -23,23 +26,41 @@ TRACE_EVENT(dump_page_frame,
 
 	TP_STRUCT__entry(
 		__field(	unsigned long,	pfn		)
+		__field(	struct page *,	page		)
+		__field(	u64,		stable_flags	)
 		__field(	unsigned long,	flags		)
-		__field(	unsigned long,	index		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned long,	private		)
+		__field(	unsigned long,	mapping		)
+		__field(	unsigned long,	index		)
 	),
 
 	TP_fast_assign(
 		__entry->pfn		= pfn;
+		__entry->page		= page;
+		__entry->stable_flags	= stable_page_flags(page);
 		__entry->flags		= page->flags;
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->private	= page->private;
+		__entry->mapping	= (unsigned long)page->mapping;
 		__entry->index		= page->index;
 	),
 
-	TP_printk("pfn=%lu flags=%lx count=%u mapcount=%u index=%lu",
-		  __entry->pfn, __entry->flags, __entry->count,
-		  __entry->mapcount, __entry->index)
+	TP_printk("pfn=%lu page=%p count=%u mapcount=%u "
+		  "private=%lx mapping=%lx index=%lx flags=%s",
+		  __entry->pfn,
+		  __entry->page,
+		  __entry->count,
+		  __entry->mapcount,
+		  __entry->private,
+		  __entry->mapping,
+		  __entry->index,
+		  ftrace_print_flags_seq(p, "|",
+					 __entry->flags & PAGE_FLAGS_MASK,
+					 pageflag_names)
+	)
 );
 
 #endif /*  _TRACE_MM_H */
#10 lore raw

RFC PATCH 4/7 tracing/mm: dump more page frame information

In reply to Wu Fengguang

Add 4 more fields to dump_page_frame trace event.

1) stable page flags in addition to the raw page flags

User space should only make use the stable page flags. The raw page flags is stored mainly to take advantage of ftrace_print_flags_seq() for showing symbolic flag names.

2) struct page address
3) page->private
4) page->mapping

The above 3 fields are mainly targeted for VM debug aids.

---
 include/linux/page-flags.h |    1 +
 include/trace/events/mm.h  |   29 +++++++++++++++++++++++++----
 mm/page_alloc.c            |    4 ++--
 3 files changed, 28 insertions(+), 6 deletions(-)
mm/page_alloc.c +2 -2
@@ -5743,7 +5743,7 @@ bool is_free_buddy_page(struct page *pag
 }
 #endif
 
-static struct trace_print_flags pageflag_names[] = {
+struct trace_print_flags pageflag_names[] = {
 	{1UL << PG_locked,		"locked"	},
 	{1UL << PG_error,		"error"		},
 	{1UL << PG_referenced,		"referenced"	},
@@ -5790,7 +5790,7 @@ static void dump_page_flags(unsigned lon
 	printk(KERN_ALERT "page flags: %#lx(", flags);
 
 	/* remove zone id */
-	flags &= (1UL << NR_PAGEFLAGS) - 1;
+	flags &= PAGE_FLAGS_MASK;
 
 	for (i = 0; pageflag_names[i].name && flags; i++) {
 
include/linux/page-flags.h +1 -0
@@ -462,6 +462,7 @@ static inline int PageTransCompound(stru
  * there has been a kernel bug or struct page corruption.
  */
 #define PAGE_FLAGS_CHECK_AT_PREP	((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_MASK			((1 << NR_PAGEFLAGS) - 1)
 
 #define PAGE_FLAGS_PRIVATE				\
 	(1 << PG_private | 1 << PG_private_2)
include/trace/events/mm.h +25 -4
@@ -2,11 +2,14 @@
 #define _TRACE_MM_H
 
 #include <linux/tracepoint.h>
+#include <linux/page-flags.h>
 #include <linux/mm.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mm
 
+extern struct trace_print_flags pageflag_names[];
+
 /**
  * dump_page_frame - called by the trace page dump trigger
  * @pfn: page frame number
@@ -23,23 +26,41 @@ TRACE_EVENT(dump_page_frame,
 
 	TP_STRUCT__entry(
 		__field(	unsigned long,	pfn		)
+		__field(	struct page *,	page		)
+		__field(	u64,		stable_flags	)
 		__field(	unsigned long,	flags		)
-		__field(	unsigned long,	index		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned long,	private		)
+		__field(	unsigned long,	mapping		)
+		__field(	unsigned long,	index		)
 	),
 
 	TP_fast_assign(
 		__entry->pfn		= pfn;
+		__entry->page		= page;
+		__entry->stable_flags	= stable_page_flags(page);
 		__entry->flags		= page->flags;
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->private	= page->private;
+		__entry->mapping	= (unsigned long)page->mapping;
 		__entry->index		= page->index;
 	),
 
-	TP_printk("pfn=%lu flags=%lx count=%u mapcount=%u index=%lu",
-		  __entry->pfn, __entry->flags, __entry->count,
-		  __entry->mapcount, __entry->index)
+	TP_printk("pfn=%lu page=%p count=%u mapcount=%u "
+		  "private=%lx mapping=%lx index=%lx flags=%s",
+		  __entry->pfn,
+		  __entry->page,
+		  __entry->count,
+		  __entry->mapcount,
+		  __entry->private,
+		  __entry->mapping,
+		  __entry->index,
+		  ftrace_print_flags_seq(p, "|",
+					 __entry->flags & PAGE_FLAGS_MASK,
+					 pageflag_names)
+	)
 );
 
 #endif /*  _TRACE_MM_H */

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

RFC PATCH 5/7 tracing/mm: accept echo-able input format for pfn range

In reply to Wu Fengguang

The seek+write style input for specifying pfn range is not scriptable. Change it to more user friendly echo-able format.

Before patch:

	fd = open("/debug/tracing/object/mm/page/dump-pfn");
	seek(fd, start);
	write(fd, "size");

After patch:

echo start +size > /debug/tracing/object/mm/page/dump-pfn
or
echo start end > /debug/tracing/object/mm/page/dump-pfn

---
 kernel/trace/trace_mm.c |   39 +++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)
kernel/trace/trace_mm.c +24 -15
@@ -9,6 +9,7 @@
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
+#include <linux/ctype.h>
 
 #include "trace_output.h"
 
@@ -24,8 +25,8 @@ void trace_mm_page_frames(unsigned long 
 	if (start > max_pfn - 1)
 		return;
 
-	if (end > max_pfn - 1)
-		end = max_pfn - 1;
+	if (end > max_pfn)
+		end = max_pfn;
 
 	while (pfn < end) {
 		page = NULL;
@@ -50,13 +51,20 @@ trace_mm_pfn_range_read(struct file *fil
 }
 
 
+/*
+ * recognized formats:
+ * 		"M N"	start=M, end=N
+ * 		"M"	start=M, end=M+1
+ * 		"M +N"	start=M, end=M+N-1
+ */
 static ssize_t
 trace_mm_pfn_range_write(struct file *filp, const char __user *ubuf, size_t cnt,
 			 loff_t *ppos)
 {
-	unsigned long val, start, end;
+	unsigned long start;
+	unsigned long end = 0;
 	char buf[64];
-	int ret;
+	char *ptr;
 
 	if (cnt >= sizeof(buf))
 		return -EINVAL;
@@ -72,19 +80,20 @@ trace_mm_pfn_range_write(struct file *fi
 
 	buf[cnt] = 0;
 
-	ret = strict_strtol(buf, 10, &val);
-	if (ret < 0)
-		return ret;
-
-	start = *ppos;
-	if (val < 0)
-		end = max_pfn - 1;
-	else
-		end = start + val;
+	start = simple_strtoul(buf, &ptr, 0);
 
-	trace_mm_page_frames(start, end, trace_mm_page_frame);
+	for (; *ptr; ptr++) {
+		if (isdigit(*ptr)) {
+			if (*(ptr - 1) == '+')
+				end = start;
+			end += simple_strtoul(ptr, NULL, 0);
+			break;
+		}
+	}
+	if (!*ptr)
+		end = start + 1;
 
-	*ppos += cnt;
+	trace_mm_page_frames(start, end, trace_mm_page_frame);
 
 	return cnt;
 }
#12 lore raw

RFC PATCH 5/7 tracing/mm: accept echo-able input format for pfn range

In reply to Wu Fengguang

The seek+write style input for specifying pfn range is not scriptable. Change it to more user friendly echo-able format.

Before patch:

	fd = open("/debug/tracing/object/mm/page/dump-pfn");
	seek(fd, start);
	write(fd, "size");

After patch:

echo start +size > /debug/tracing/object/mm/page/dump-pfn
or
echo start end > /debug/tracing/object/mm/page/dump-pfn

---
 kernel/trace/trace_mm.c |   39 +++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)
kernel/trace/trace_mm.c +24 -15
@@ -9,6 +9,7 @@
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
+#include <linux/ctype.h>
 
 #include "trace_output.h"
 
@@ -24,8 +25,8 @@ void trace_mm_page_frames(unsigned long 
 	if (start > max_pfn - 1)
 		return;
 
-	if (end > max_pfn - 1)
-		end = max_pfn - 1;
+	if (end > max_pfn)
+		end = max_pfn;
 
 	while (pfn < end) {
 		page = NULL;
@@ -50,13 +51,20 @@ trace_mm_pfn_range_read(struct file *fil
 }
 
 
+/*
+ * recognized formats:
+ * 		"M N"	start=M, end=N
+ * 		"M"	start=M, end=M+1
+ * 		"M +N"	start=M, end=M+N-1
+ */
 static ssize_t
 trace_mm_pfn_range_write(struct file *filp, const char __user *ubuf, size_t cnt,
 			 loff_t *ppos)
 {
-	unsigned long val, start, end;
+	unsigned long start;
+	unsigned long end = 0;
 	char buf[64];
-	int ret;
+	char *ptr;
 
 	if (cnt >= sizeof(buf))
 		return -EINVAL;
@@ -72,19 +80,20 @@ trace_mm_pfn_range_write(struct file *fi
 
 	buf[cnt] = 0;
 
-	ret = strict_strtol(buf, 10, &val);
-	if (ret < 0)
-		return ret;
-
-	start = *ppos;
-	if (val < 0)
-		end = max_pfn - 1;
-	else
-		end = start + val;
+	start = simple_strtoul(buf, &ptr, 0);
 
-	trace_mm_page_frames(start, end, trace_mm_page_frame);
+	for (; *ptr; ptr++) {
+		if (isdigit(*ptr)) {
+			if (*(ptr - 1) == '+')
+				end = start;
+			end += simple_strtoul(ptr, NULL, 0);
+			break;
+		}
+	}
+	if (!*ptr)
+		end = start + 1;
 
-	*ppos += cnt;
+	trace_mm_page_frames(start, end, trace_mm_page_frame);
 
 	return cnt;
 }

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#13 lore raw

RFC PATCH 6/7 tracing/mm: add dump-file and dump-fs interfaces

In reply to Wu Fengguang

This dumps
- all cached files of a mounted fs (the inode-cache)
- all cached pages of a cached file (the page-cache)

Usage and Sample output:

# echo / > /debug/tracing/objects/mm/pages/dump-fs
# head -20 /debug/tracing/trace
# tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh-3128  [000]   432.050943: dump_inode_cache: ino=1507329 size=4096 cached=4096 dirtied_when=4294676467 age=444 state=____ type=DIR name=/
             zsh-3128  [000]   432.050949: dump_page_cache: index=0 len=1 flags=____RU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050962: dump_inode_cache: ino=1786836 size=12288 cached=12288 dirtied_when=4294676472 age=444 state=____ type=DIR name=/sbin
             zsh-3128  [000]   432.050966: dump_page_cache: index=0 len=3 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050973: dump_inode_cache: ino=1786946 size=37312 cached=40960 dirtied_when=4294676473 age=444 state=____ type=REG name=/sbin/init
             zsh-3128  [000]   432.050977: dump_page_cache: index=0 len=6 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050978: dump_page_cache: index=6 len=1 flags=M__A_U_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050978: dump_page_cache: index=7 len=1 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050979: dump_page_cache: index=8 len=2 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050986: dump_inode_cache: ino=1507464 size=4 cached=4096 dirtied_when=4294676477 age=444 state=____ type=LNK name=/lib64
             zsh-3128  [000]   432.050989: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050995: dump_inode_cache: ino=1590173 size=12288 cached=0 dirtied_when=4294676477 age=444 state=____ type=DIR name=/lib
             zsh-3128  [000]   432.051003: dump_inode_cache: ino=1590265 size=27 cached=4096 dirtied_when=4294676478 age=444 state=____ type=LNK name=/lib/ld-linux-x86-64.so.2
             zsh-3128  [000]   432.051006: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.051013: dump_inode_cache: ino=1663440 size=4096 cached=0 dirtied_when=4294676479 age=444 state=____ type=DIR name=/lib/x86_64-linux-gnu
             zsh-3128  [000]   432.051022: dump_inode_cache: ino=3293287 size=136936 cached=139264 dirtied_when=4294676480 age=444 state=____ type=REG name=/lib/x86_64-linux-gnu/ld-2.13.so

Here "age" is the number of seconds from either inode create time, or last dirty time for dirtied inodes. "memcg" is the memory controller group id to be added by next patch.

CC Ingo Molnar <[email protected]>
CC Chris Frost <[email protected]>
CC Steven Rostedt <[email protected]>
CC Peter Zijlstra <[email protected]>
CC Frederic Weisbecker <[email protected]>
---
 fs/inode.c                |    8 +
 fs/internal.h             |    5 
 include/linux/fs.h        |    1 
 include/trace/events/mm.h |   95 ++++++++++++++++
 kernel/trace/trace_mm.c   |  213 ++++++++++++++++++++++++++++++++++++
 5 files changed, 316 insertions(+), 6 deletions(-)
include/trace/events/mm.h +95 -0
@@ -3,7 +3,10 @@
 
 #include <linux/tracepoint.h>
 #include <linux/page-flags.h>
+#include <linux/memcontrol.h>
+#include <linux/pagemap.h>
 #include <linux/mm.h>
+#include <linux/kernel-page-flags.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mm
@@ -63,6 +66,98 @@ TRACE_EVENT(dump_page_frame,
 	)
 );
 
+TRACE_EVENT(dump_page_cache,
+
+	TP_PROTO(struct page *page, unsigned long len),
+
+	TP_ARGS(page, len),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	index		)
+		__field(	unsigned long,	len		)
+		__field(	u64,		flags		)
+		__field(	unsigned int,	count		)
+		__field(	unsigned int,	mapcount	)
+	),
+
+	TP_fast_assign(
+		__entry->index		= page->index;
+		__entry->len		= len;
+		__entry->flags		= stable_page_flags(page);
+		__entry->count		= atomic_read(&page->_count);
+		__entry->mapcount	= page_mapcount(page);
+	),
+
+	TP_printk("index=%lu len=%lu flags=%c%c%c%c%c%c%c%c%c%c%c "
+		  "count=%u mapcount=%u",
+		  __entry->index,
+		  __entry->len,
+		  __entry->flags & (1ULL << KPF_MMAP)		? 'M' : '_',
+		  __entry->flags & (1ULL << KPF_MLOCKED)	? 'm' : '_',
+		  __entry->flags & (1ULL << KPF_UNEVICTABLE)	? 'u' : '_',
+		  __entry->flags & (1ULL << KPF_ACTIVE)		? 'A' : '_',
+		  __entry->flags & (1ULL << KPF_REFERENCED)	? 'R' : '_',
+		  __entry->flags & (1ULL << KPF_UPTODATE)	? 'U' : '_',
+		  __entry->flags & (1ULL << KPF_DIRTY)		? 'D' : '_',
+		  __entry->flags & (1ULL << KPF_WRITEBACK)	? 'W' : '_',
+		  __entry->flags & (1ULL << KPF_RECLAIM)	? 'I' : '_',
+		  __entry->flags & (1ULL << KPF_MAPPEDTODISK)	? 'd' : '_',
+		  __entry->flags & (1ULL << KPF_PRIVATE)	? 'P' : '_',
+		  __entry->count,
+		  __entry->mapcount)
+);
+
+
+#define show_inode_type(val)	__print_symbolic(val, 	   \
+				{ S_IFREG,	"REG"	}, \
+				{ S_IFDIR,	"DIR"	}, \
+				{ S_IFLNK,	"LNK"	}, \
+				{ S_IFBLK,	"BLK"	}, \
+				{ S_IFCHR,	"CHR"	}, \
+				{ S_IFIFO,	"FIFO"	}, \
+				{ S_IFSOCK,	"SOCK"	})
+
+TRACE_EVENT(dump_inode_cache,
+
+	TP_PROTO(struct inode *inode, char *name, int len),
+
+	TP_ARGS(inode, name, len),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	ino		)
+		__field(	loff_t,		size		) /* bytes */
+		__field(	loff_t,		cached		) /* bytes */
+		__field(	unsigned long,	dirtied_when	)
+		__field(	unsigned long,	state		)
+		__field(	umode_t,	mode		)
+		__dynamic_array(char,		file,	len	)
+	),
+
+	TP_fast_assign(
+		__entry->ino	= inode->i_ino;
+		__entry->size	= i_size_read(inode);
+		__entry->cached	= inode->i_mapping->nrpages << PAGE_CACHE_SHIFT;
+		__entry->dirtied_when	= inode->dirtied_when;
+		__entry->state	= inode->i_state;
+		__entry->mode	= inode->i_mode;
+		memcpy(__get_str(file), name, len);
+	),
+
+	TP_printk("ino=%lu size=%llu cached=%llu dirtied_when=%lu age=%lu "
+		  "state=%c%c%c%c type=%s name=%s",
+		  __entry->ino,
+		  __entry->size,
+		  __entry->cached,
+		  __entry->dirtied_when,
+		  (jiffies - __entry->dirtied_when) / HZ,
+		  __entry->state & I_DIRTY_PAGES	? 'D' : '_',
+		  __entry->state & I_DIRTY_DATASYNC	? 'd' : '_',
+		  __entry->state & I_DIRTY_SYNC		? 'm' : '_',
+		  __entry->state & I_SYNC		? 'S' : '_',
+		  show_inode_type(__entry->mode & S_IFMT),
+		  __get_str(file))
+);
+
 #endif /*  _TRACE_MM_H */
 
 /* This part must be outside protection */
kernel/trace/trace_mm.c +213 -0

237 lines not on this page · raw message

fs/inode.c +7 -1
@@ -158,7 +158,13 @@ int inode_init_always(struct super_block
 	inode->i_bdev = NULL;
 	inode->i_cdev = NULL;
 	inode->i_rdev = 0;
-	inode->dirtied_when = 0;
+
+	/*
+	 * This records inode load time. It will be invalidated once inode is
+	 * dirtied, or jiffies wraps around. Despite the pitfalls it still
+	 * provides useful information for some use cases like fastboot.
+	 */
+	inode->dirtied_when = jiffies;
 
 	if (security_inode_alloc(inode))
 		goto out;
fs/internal.h +0 -5
@@ -124,11 +124,6 @@ extern long do_handle_open(int mountdirf
 			   struct file_handle __user *ufh, int open_flag);
 
 /*
- * inode.c
- */
-extern spinlock_t inode_sb_list_lock;
-
-/*
  * fs-writeback.c
  */
 extern void inode_wb_list_del(struct inode *inode);
include/linux/fs.h +1 -0
@@ -1378,6 +1378,7 @@ extern int send_sigurg(struct fown_struc
 
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
+extern spinlock_t inode_sb_list_lock;
 
 struct super_block {
 	struct list_head	s_list;		/* Keep this first */
#14 lore raw

RFC PATCH 6/7 tracing/mm: add dump-file and dump-fs interfaces

In reply to Wu Fengguang

This dumps
- all cached files of a mounted fs (the inode-cache)
- all cached pages of a cached file (the page-cache)

Usage and Sample output:

# echo / > /debug/tracing/objects/mm/pages/dump-fs
# head -20 /debug/tracing/trace
# tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh-3128  [000]   432.050943: dump_inode_cache: ino=1507329 size=4096 cached=4096 dirtied_when=4294676467 age=444 state=____ type=DIR name=/
             zsh-3128  [000]   432.050949: dump_page_cache: index=0 len=1 flags=____RU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050962: dump_inode_cache: ino=1786836 size=12288 cached=12288 dirtied_when=4294676472 age=444 state=____ type=DIR name=/sbin
             zsh-3128  [000]   432.050966: dump_page_cache: index=0 len=3 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050973: dump_inode_cache: ino=1786946 size=37312 cached=40960 dirtied_when=4294676473 age=444 state=____ type=REG name=/sbin/init
             zsh-3128  [000]   432.050977: dump_page_cache: index=0 len=6 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050978: dump_page_cache: index=6 len=1 flags=M__A_U_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050978: dump_page_cache: index=7 len=1 flags=M__ARU_____ count=2 mapcount=1 memcg=1
             zsh-3128  [000]   432.050979: dump_page_cache: index=8 len=2 flags=_____U_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050986: dump_inode_cache: ino=1507464 size=4 cached=4096 dirtied_when=4294676477 age=444 state=____ type=LNK name=/lib64
             zsh-3128  [000]   432.050989: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.050995: dump_inode_cache: ino=1590173 size=12288 cached=0 dirtied_when=4294676477 age=444 state=____ type=DIR name=/lib
             zsh-3128  [000]   432.051003: dump_inode_cache: ino=1590265 size=27 cached=4096 dirtied_when=4294676478 age=444 state=____ type=LNK name=/lib/ld-linux-x86-64.so.2
             zsh-3128  [000]   432.051006: dump_page_cache: index=0 len=1 flags=___ARU_____ count=1 mapcount=0 memcg=1
             zsh-3128  [000]   432.051013: dump_inode_cache: ino=1663440 size=4096 cached=0 dirtied_when=4294676479 age=444 state=____ type=DIR name=/lib/x86_64-linux-gnu
             zsh-3128  [000]   432.051022: dump_inode_cache: ino=3293287 size=136936 cached=139264 dirtied_when=4294676480 age=444 state=____ type=REG name=/lib/x86_64-linux-gnu/ld-2.13.so

Here "age" is the number of seconds from either inode create time, or last dirty time for dirtied inodes. "memcg" is the memory controller group id to be added by next patch.

CC Ingo Molnar <[email protected]>
CC Chris Frost <[email protected]>
CC Steven Rostedt <[email protected]>
CC Peter Zijlstra <[email protected]>
CC Frederic Weisbecker <[email protected]>
---
 fs/inode.c                |    8 +
 fs/internal.h             |    5 
 include/linux/fs.h        |    1 
 include/trace/events/mm.h |   95 ++++++++++++++++
 kernel/trace/trace_mm.c   |  213 ++++++++++++++++++++++++++++++++++++
 5 files changed, 316 insertions(+), 6 deletions(-)
include/trace/events/mm.h +95 -0
@@ -3,7 +3,10 @@
 
 #include <linux/tracepoint.h>
 #include <linux/page-flags.h>
+#include <linux/memcontrol.h>
+#include <linux/pagemap.h>
 #include <linux/mm.h>
+#include <linux/kernel-page-flags.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mm
@@ -63,6 +66,98 @@ TRACE_EVENT(dump_page_frame,
 	)
 );
 
+TRACE_EVENT(dump_page_cache,
+
+	TP_PROTO(struct page *page, unsigned long len),
+
+	TP_ARGS(page, len),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	index		)
+		__field(	unsigned long,	len		)
+		__field(	u64,		flags		)
+		__field(	unsigned int,	count		)
+		__field(	unsigned int,	mapcount	)
+	),
+
+	TP_fast_assign(
+		__entry->index		= page->index;
+		__entry->len		= len;
+		__entry->flags		= stable_page_flags(page);
+		__entry->count		= atomic_read(&page->_count);
+		__entry->mapcount	= page_mapcount(page);
+	),
+
+	TP_printk("index=%lu len=%lu flags=%c%c%c%c%c%c%c%c%c%c%c "
+		  "count=%u mapcount=%u",
+		  __entry->index,
+		  __entry->len,
+		  __entry->flags & (1ULL << KPF_MMAP)		? 'M' : '_',
+		  __entry->flags & (1ULL << KPF_MLOCKED)	? 'm' : '_',
+		  __entry->flags & (1ULL << KPF_UNEVICTABLE)	? 'u' : '_',
+		  __entry->flags & (1ULL << KPF_ACTIVE)		? 'A' : '_',
+		  __entry->flags & (1ULL << KPF_REFERENCED)	? 'R' : '_',
+		  __entry->flags & (1ULL << KPF_UPTODATE)	? 'U' : '_',
+		  __entry->flags & (1ULL << KPF_DIRTY)		? 'D' : '_',
+		  __entry->flags & (1ULL << KPF_WRITEBACK)	? 'W' : '_',
+		  __entry->flags & (1ULL << KPF_RECLAIM)	? 'I' : '_',
+		  __entry->flags & (1ULL << KPF_MAPPEDTODISK)	? 'd' : '_',
+		  __entry->flags & (1ULL << KPF_PRIVATE)	? 'P' : '_',
+		  __entry->count,
+		  __entry->mapcount)
+);
+
+
+#define show_inode_type(val)	__print_symbolic(val, 	   \
+				{ S_IFREG,	"REG"	}, \
+				{ S_IFDIR,	"DIR"	}, \
+				{ S_IFLNK,	"LNK"	}, \
+				{ S_IFBLK,	"BLK"	}, \
+				{ S_IFCHR,	"CHR"	}, \
+				{ S_IFIFO,	"FIFO"	}, \
+				{ S_IFSOCK,	"SOCK"	})
+
+TRACE_EVENT(dump_inode_cache,
+
+	TP_PROTO(struct inode *inode, char *name, int len),
+
+	TP_ARGS(inode, name, len),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	ino		)
+		__field(	loff_t,		size		) /* bytes */
+		__field(	loff_t,		cached		) /* bytes */
+		__field(	unsigned long,	dirtied_when	)
+		__field(	unsigned long,	state		)
+		__field(	umode_t,	mode		)
+		__dynamic_array(char,		file,	len	)
+	),
+
+	TP_fast_assign(
+		__entry->ino	= inode->i_ino;
+		__entry->size	= i_size_read(inode);
+		__entry->cached	= inode->i_mapping->nrpages << PAGE_CACHE_SHIFT;
+		__entry->dirtied_when	= inode->dirtied_when;
+		__entry->state	= inode->i_state;
+		__entry->mode	= inode->i_mode;
+		memcpy(__get_str(file), name, len);
+	),
+
+	TP_printk("ino=%lu size=%llu cached=%llu dirtied_when=%lu age=%lu "
+		  "state=%c%c%c%c type=%s name=%s",
+		  __entry->ino,
+		  __entry->size,
+		  __entry->cached,
+		  __entry->dirtied_when,
+		  (jiffies - __entry->dirtied_when) / HZ,
+		  __entry->state & I_DIRTY_PAGES	? 'D' : '_',
+		  __entry->state & I_DIRTY_DATASYNC	? 'd' : '_',
+		  __entry->state & I_DIRTY_SYNC		? 'm' : '_',
+		  __entry->state & I_SYNC		? 'S' : '_',
+		  show_inode_type(__entry->mode & S_IFMT),
+		  __get_str(file))
+);
+
 #endif /*  _TRACE_MM_H */
 
 /* This part must be outside protection */
kernel/trace/trace_mm.c +213 -0

237 lines not on this page · raw message

fs/inode.c +7 -1
@@ -158,7 +158,13 @@ int inode_init_always(struct super_block
 	inode->i_bdev = NULL;
 	inode->i_cdev = NULL;
 	inode->i_rdev = 0;
-	inode->dirtied_when = 0;
+
+	/*
+	 * This records inode load time. It will be invalidated once inode is
+	 * dirtied, or jiffies wraps around. Despite the pitfalls it still
+	 * provides useful information for some use cases like fastboot.
+	 */
+	inode->dirtied_when = jiffies;
 
 	if (security_inode_alloc(inode))
 		goto out;
fs/internal.h +0 -5
@@ -124,11 +124,6 @@ extern long do_handle_open(int mountdirf
 			   struct file_handle __user *ufh, int open_flag);
 
 /*
- * inode.c
- */
-extern spinlock_t inode_sb_list_lock;
-
-/*
  * fs-writeback.c
  */
 extern void inode_wb_list_del(struct inode *inode);
include/linux/fs.h +1 -0
@@ -1378,6 +1378,7 @@ extern int send_sigurg(struct fown_struc
 
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
+extern spinlock_t inode_sb_list_lock;
 
 struct super_block {
 	struct list_head	s_list;		/* Keep this first */

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#15 lore raw

RFC PATCH 7/7 tracing/mm: add memcg field

In reply to Wu Fengguang

Dump the memcg id associated with a pagecache page.

The downside is, the page_memcg_id() is a pretty heavy weight function that needs to lock/unlock the page..

CC Balbir Singh <[email protected]>
CC Daisuke Nishimura <[email protected]>
CC KAMEZAWA Hiroyuki <[email protected]>
---
 include/linux/memcontrol.h |    6 ++++++
 include/trace/events/mm.h  |   16 +++++++++++-----
 kernel/trace/trace_mm.c    |   12 +++++++++---
 mm/memcontrol.c            |   18 ++++++++++++++++++
 4 files changed, 44 insertions(+), 8 deletions(-)
include/linux/memcontrol.h +6 -0
@@ -91,6 +91,7 @@ extern void mem_cgroup_uncharge_cache_pa
 extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
 
+extern unsigned short page_memcg_id(struct page *page);
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
 extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
 extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
@@ -199,6 +200,11 @@ static inline int mem_cgroup_try_charge_
 	return 0;
 }
 
+static inline unsigned short page_memcg_id(struct page *page)
+{
+	return 0;
+}
+
 static inline void mem_cgroup_commit_charge_swapin(struct page *page,
 					  struct mem_cgroup *ptr)
 {
mm/memcontrol.c +18 -0
@@ -591,6 +591,24 @@ mem_cgroup_largest_soft_limit_node(struc
 	return mz;
 }
 
+unsigned short page_memcg_id(struct page *page)
+{
+	struct mem_cgroup *memcg;
+	struct cgroup_subsys_state *css;
+	unsigned short id = 0;
+
+	lock_page(page);
+	memcg = try_get_mem_cgroup_from_page(page);
+	if (memcg) {
+		css = mem_cgroup_css(memcg);
+		id = css_id(css);
+		css_put(css);
+	}
+	unlock_page(page);
+
+	return id;
+}
+
 /*
  * Implementation Note: reading percpu statistics for memcg.
  *
include/trace/events/mm.h +11 -5
@@ -34,6 +34,7 @@ TRACE_EVENT(dump_page_frame,
 		__field(	unsigned long,	flags		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned int,	memcg		)
 		__field(	unsigned long,	private		)
 		__field(	unsigned long,	mapping		)
 		__field(	unsigned long,	index		)
@@ -46,17 +47,19 @@ TRACE_EVENT(dump_page_frame,
 		__entry->flags		= page->flags;
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->memcg		= page_memcg_id(page);
 		__entry->private	= page->private;
 		__entry->mapping	= (unsigned long)page->mapping;
 		__entry->index		= page->index;
 	),
 
 	TP_printk("pfn=%lu page=%p count=%u mapcount=%u "
-		  "private=%lx mapping=%lx index=%lx flags=%s",
+		  "memcg=%u private=%lx mapping=%lx index=%lx flags=%s",
 		  __entry->pfn,
 		  __entry->page,
 		  __entry->count,
 		  __entry->mapcount,
+		  __entry->memcg,
 		  __entry->private,
 		  __entry->mapping,
 		  __entry->index,
@@ -68,9 +71,9 @@ TRACE_EVENT(dump_page_frame,
 
 TRACE_EVENT(dump_page_cache,
 
-	TP_PROTO(struct page *page, unsigned long len),
+	TP_PROTO(struct page *page, unsigned long len, unsigned int memcg),
 
-	TP_ARGS(page, len),
+	TP_ARGS(page, len, memcg),
 
 	TP_STRUCT__entry(
 		__field(	unsigned long,	index		)
@@ -78,6 +81,7 @@ TRACE_EVENT(dump_page_cache,
 		__field(	u64,		flags		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned int,	memcg		)
 	),
 
 	TP_fast_assign(
@@ -86,10 +90,11 @@ TRACE_EVENT(dump_page_cache,
 		__entry->flags		= stable_page_flags(page);
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->memcg		= memcg;
 	),
 
 	TP_printk("index=%lu len=%lu flags=%c%c%c%c%c%c%c%c%c%c%c "
-		  "count=%u mapcount=%u",
+		  "count=%u mapcount=%u memcg=%u",
 		  __entry->index,
 		  __entry->len,
 		  __entry->flags & (1ULL << KPF_MMAP)		? 'M' : '_',
@@ -104,7 +109,8 @@ TRACE_EVENT(dump_page_cache,
 		  __entry->flags & (1ULL << KPF_MAPPEDTODISK)	? 'd' : '_',
 		  __entry->flags & (1ULL << KPF_PRIVATE)	? 'P' : '_',
 		  __entry->count,
-		  __entry->mapcount)
+		  __entry->mapcount,
+		  __entry->memcg)
 );
 
 
kernel/trace/trace_mm.c +9 -3
@@ -155,6 +155,8 @@ static void dump_pagecache(struct addres
 	struct page *page;
 	unsigned long start = 0;
 	unsigned long len = 0;
+	unsigned int memcg0;
+	unsigned int memcg;
 	int i;
 
 	for (;;) {
@@ -165,23 +167,27 @@ static void dump_pagecache(struct addres
 
 		if (nr_pages == 0) {
 			if (len)
-				trace_dump_page_cache(page0, len);
+				trace_dump_page_cache(page0, len, memcg0);
 			return;
 		}
 
 		for (i = 0; i < nr_pages; i++) {
 			page = pages[i];
+			memcg = page_memcg_id(page);
 
 			if (len &&
 			    page->index == start + len &&
-			    pages_similar(page0, page))
+			    pages_similar(page0, page) &&
+			    memcg0 == memcg)
 				len++;
 			else {
 				if (len)
-					trace_dump_page_cache(page0, len);
+					trace_dump_page_cache(page0, len,
+							      memcg0);
 				page0 = page;
 				start = page->index;
 				len = 1;
+				memcg0 = memcg;
 			}
 		}
 		cond_resched();
#16 lore raw

RFC PATCH 7/7 tracing/mm: add memcg field

In reply to Wu Fengguang

Dump the memcg id associated with a pagecache page.

The downside is, the page_memcg_id() is a pretty heavy weight function that needs to lock/unlock the page..

CC Balbir Singh <[email protected]>
CC Daisuke Nishimura <[email protected]>
CC KAMEZAWA Hiroyuki <[email protected]>
---
 include/linux/memcontrol.h |    6 ++++++
 include/trace/events/mm.h  |   16 +++++++++++-----
 kernel/trace/trace_mm.c    |   12 +++++++++---
 mm/memcontrol.c            |   18 ++++++++++++++++++
 4 files changed, 44 insertions(+), 8 deletions(-)
include/linux/memcontrol.h +6 -0
@@ -91,6 +91,7 @@ extern void mem_cgroup_uncharge_cache_pa
 extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
 
+extern unsigned short page_memcg_id(struct page *page);
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
 extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
 extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
@@ -199,6 +200,11 @@ static inline int mem_cgroup_try_charge_
 	return 0;
 }
 
+static inline unsigned short page_memcg_id(struct page *page)
+{
+	return 0;
+}
+
 static inline void mem_cgroup_commit_charge_swapin(struct page *page,
 					  struct mem_cgroup *ptr)
 {
mm/memcontrol.c +18 -0
@@ -591,6 +591,24 @@ mem_cgroup_largest_soft_limit_node(struc
 	return mz;
 }
 
+unsigned short page_memcg_id(struct page *page)
+{
+	struct mem_cgroup *memcg;
+	struct cgroup_subsys_state *css;
+	unsigned short id = 0;
+
+	lock_page(page);
+	memcg = try_get_mem_cgroup_from_page(page);
+	if (memcg) {
+		css = mem_cgroup_css(memcg);
+		id = css_id(css);
+		css_put(css);
+	}
+	unlock_page(page);
+
+	return id;
+}
+
 /*
  * Implementation Note: reading percpu statistics for memcg.
  *
include/trace/events/mm.h +11 -5
@@ -34,6 +34,7 @@ TRACE_EVENT(dump_page_frame,
 		__field(	unsigned long,	flags		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned int,	memcg		)
 		__field(	unsigned long,	private		)
 		__field(	unsigned long,	mapping		)
 		__field(	unsigned long,	index		)
@@ -46,17 +47,19 @@ TRACE_EVENT(dump_page_frame,
 		__entry->flags		= page->flags;
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->memcg		= page_memcg_id(page);
 		__entry->private	= page->private;
 		__entry->mapping	= (unsigned long)page->mapping;
 		__entry->index		= page->index;
 	),
 
 	TP_printk("pfn=%lu page=%p count=%u mapcount=%u "
-		  "private=%lx mapping=%lx index=%lx flags=%s",
+		  "memcg=%u private=%lx mapping=%lx index=%lx flags=%s",
 		  __entry->pfn,
 		  __entry->page,
 		  __entry->count,
 		  __entry->mapcount,
+		  __entry->memcg,
 		  __entry->private,
 		  __entry->mapping,
 		  __entry->index,
@@ -68,9 +71,9 @@ TRACE_EVENT(dump_page_frame,
 
 TRACE_EVENT(dump_page_cache,
 
-	TP_PROTO(struct page *page, unsigned long len),
+	TP_PROTO(struct page *page, unsigned long len, unsigned int memcg),
 
-	TP_ARGS(page, len),
+	TP_ARGS(page, len, memcg),
 
 	TP_STRUCT__entry(
 		__field(	unsigned long,	index		)
@@ -78,6 +81,7 @@ TRACE_EVENT(dump_page_cache,
 		__field(	u64,		flags		)
 		__field(	unsigned int,	count		)
 		__field(	unsigned int,	mapcount	)
+		__field(	unsigned int,	memcg		)
 	),
 
 	TP_fast_assign(
@@ -86,10 +90,11 @@ TRACE_EVENT(dump_page_cache,
 		__entry->flags		= stable_page_flags(page);
 		__entry->count		= atomic_read(&page->_count);
 		__entry->mapcount	= page_mapcount(page);
+		__entry->memcg		= memcg;
 	),
 
 	TP_printk("index=%lu len=%lu flags=%c%c%c%c%c%c%c%c%c%c%c "
-		  "count=%u mapcount=%u",
+		  "count=%u mapcount=%u memcg=%u",
 		  __entry->index,
 		  __entry->len,
 		  __entry->flags & (1ULL << KPF_MMAP)		? 'M' : '_',
@@ -104,7 +109,8 @@ TRACE_EVENT(dump_page_cache,
 		  __entry->flags & (1ULL << KPF_MAPPEDTODISK)	? 'd' : '_',
 		  __entry->flags & (1ULL << KPF_PRIVATE)	? 'P' : '_',
 		  __entry->count,
-		  __entry->mapcount)
+		  __entry->mapcount,
+		  __entry->memcg)
 );
 
 
kernel/trace/trace_mm.c +9 -3
@@ -155,6 +155,8 @@ static void dump_pagecache(struct addres
 	struct page *page;
 	unsigned long start = 0;
 	unsigned long len = 0;
+	unsigned int memcg0;
+	unsigned int memcg;
 	int i;
 
 	for (;;) {
@@ -165,23 +167,27 @@ static void dump_pagecache(struct addres
 
 		if (nr_pages == 0) {
 			if (len)
-				trace_dump_page_cache(page0, len);
+				trace_dump_page_cache(page0, len, memcg0);
 			return;
 		}
 
 		for (i = 0; i < nr_pages; i++) {
 			page = pages[i];
+			memcg = page_memcg_id(page);
 
 			if (len &&
 			    page->index == start + len &&
-			    pages_similar(page0, page))
+			    pages_similar(page0, page) &&
+			    memcg0 == memcg)
 				len++;
 			else {
 				if (len)
-					trace_dump_page_cache(page0, len);
+					trace_dump_page_cache(page0, len,
+							      memcg0);
 				page0 = page;
 				start = page->index;
 				len = 1;
+				memcg0 = memcg;
 			}
 		}
 		cond_resched();

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw
In reply to Wu Fengguang
Quoted 9 lines

dump-pfn interface
(it looks more clean and easier for review to fold patches 1-5 into one, but let's keep the changelog for the initial post)

[RFC][PATCH 1/7] tracing/mm: add page frame snapshot trace [RFC][PATCH 2/7] tracing/mm: rename trigger file to dump-pfn [RFC][PATCH 3/7] tracing/mm: create trace_objects.c [RFC][PATCH 4/7] tracing/mm: dump more page frame information [RFC][PATCH 5/7] tracing/mm: accept echo-able input format for pfn range

For your convenience, here is the combined diff for the above 5 incremental ones.

include/trace/events/mm.h new file +69 -0
@@ -0,0 +1,69 @@
+#if !defined(_TRACE_MM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MM_H
+
+#include <linux/tracepoint.h>
+#include <linux/page-flags.h>
+#include <linux/mm.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mm
+
+extern struct trace_print_flags pageflag_names[];
+
+/**
+ * dump_page_frame - called by the trace page dump trigger
+ * @pfn: page frame number
+ * @page: pointer to the page frame
+ *
+ * This is a helper trace point into the dumping of the page frames.
+ * It will record various infromation about a page frame.
+ */
+TRACE_EVENT(dump_page_frame,
+
+	TP_PROTO(unsigned long pfn, struct page *page),
+
+	TP_ARGS(pfn, page),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	pfn		)
+		__field(	struct page *,	page		)
+		__field(	u64,		stable_flags	)
+		__field(	unsigned long,	flags		)
+		__field(	unsigned int,	count		)
+		__field(	unsigned int,	mapcount	)
+		__field(	unsigned long,	private		)
+		__field(	unsigned long,	mapping		)
+		__field(	unsigned long,	index		)
+	),
+
+	TP_fast_assign(
+		__entry->pfn		= pfn;
+		__entry->page		= page;
+		__entry->stable_flags	= stable_page_flags(page);
+		__entry->flags		= page->flags;
+		__entry->count		= atomic_read(&page->_count);
+		__entry->mapcount	= page_mapcount(page);
+		__entry->private	= page->private;
+		__entry->mapping	= (unsigned long)page->mapping;
+		__entry->index		= page->index;
+	),
+
+	TP_printk("pfn=%lu page=%p count=%u mapcount=%u "
+		  "private=%lx mapping=%lx index=%lx flags=%s",
+		  __entry->pfn,
+		  __entry->page,
+		  __entry->count,
+		  __entry->mapcount,
+		  __entry->private,
+		  __entry->mapping,
+		  __entry->index,
+		  ftrace_print_flags_seq(p, "|",
+					 __entry->flags & PAGE_FLAGS_MASK,
+					 pageflag_names)
+	)
+);
+
+#endif /*  _TRACE_MM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
kernel/trace/Makefile +2 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_RING_BUFFER) += ring_buffer
 obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o
 
 obj-$(CONFIG_TRACING) += trace.o
+obj-$(CONFIG_TRACING) += trace_objects.o
 obj-$(CONFIG_TRACING) += trace_output.o
 obj-$(CONFIG_TRACING) += trace_stat.o
 obj-$(CONFIG_TRACING) += trace_printk.o
@@ -53,6 +54,7 @@ endif
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
 obj-$(CONFIG_TRACEPOINTS) += power-traces.o
+obj-$(CONFIG_EVENT_TRACING) += trace_mm.o
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
kernel/trace/trace_mm.c new file +150 -0

150 lines not on this page · raw message

kernel/trace/trace.h +1 -0
@@ -318,6 +318,7 @@ struct dentry *trace_create_file(const c
 				 const struct file_operations *fops);
 
 struct dentry *tracing_init_dentry(void);
+struct dentry *trace_objects_dir(void);
 
 struct ring_buffer_event;
 
kernel/trace/trace_objects.c new file +26 -0
@@ -0,0 +1,26 @@
+#include <linux/debugfs.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+struct dentry *trace_objects_dir(void)
+{
+	static struct dentry *d_objects;
+	struct dentry *d_tracer;
+
+	if (d_objects)
+		return d_objects;
+
+	d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return NULL;
+
+	d_objects = debugfs_create_dir("objects", d_tracer);
+	if (!d_objects)
+		pr_warning("Could not create debugfs "
+			   "'objects' directory\n");
+
+	return d_objects;
+}
+
+
mm/page_alloc.c +2 -2
@@ -5743,7 +5743,7 @@ bool is_free_buddy_page(struct page *pag
 }
 #endif
 
-static struct trace_print_flags pageflag_names[] = {
+struct trace_print_flags pageflag_names[] = {
 	{1UL << PG_locked,		"locked"	},
 	{1UL << PG_error,		"error"		},
 	{1UL << PG_referenced,		"referenced"	},
@@ -5790,7 +5790,7 @@ static void dump_page_flags(unsigned lon
 	printk(KERN_ALERT "page flags: %#lx(", flags);
 
 	/* remove zone id */
-	flags &= (1UL << NR_PAGEFLAGS) - 1;
+	flags &= PAGE_FLAGS_MASK;
 
 	for (i = 0; pageflag_names[i].name && flags; i++) {
 
include/linux/page-flags.h +1 -0
@@ -462,6 +462,7 @@ static inline int PageTransCompound(stru
  * there has been a kernel bug or struct page corruption.
  */
 #define PAGE_FLAGS_CHECK_AT_PREP	((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_MASK			((1 << NR_PAGEFLAGS) - 1)
 
 #define PAGE_FLAGS_PRIVATE				\
 	(1 << PG_private | 1 << PG_private_2)

--
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/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>