summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/admin-guide/mm/idle_page_tracking.rst5
-rw-r--r--tools/vm/page-types.c47
2 files changed, 51 insertions, 1 deletions
diff --git a/Documentation/admin-guide/mm/idle_page_tracking.rst b/Documentation/admin-guide/mm/idle_page_tracking.rst
index 6f7b7ca1add3..df9394fb39c2 100644
--- a/Documentation/admin-guide/mm/idle_page_tracking.rst
+++ b/Documentation/admin-guide/mm/idle_page_tracking.rst
@@ -65,6 +65,11 @@ workload one should:
are not reclaimable, he or she can filter them out using
``/proc/kpageflags``.
+The page-types tool in the tools/vm directory can be used to assist in this.
+If the tool is run initially with the appropriate option, it will mark all the
+queried pages as idle. Subsequent runs of the tool can then show which pages have
+their idle flag cleared in the interim.
+
See :ref:`Documentation/admin-guide/mm/pagemap.rst <pagemap>` for more
information about ``/proc/pid/pagemap``, ``/proc/kpageflags``, and
``/proc/kpagecgroup``.
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index 14ebd1695223..30cb0a0713ff 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -78,6 +78,8 @@
#define PROC_KPAGECOUNT "/proc/kpagecount"
#define PROC_KPAGECGROUP "/proc/kpagecgroup"
+#define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap"
+
/* [32-] kernel hacking assistances */
#define KPF_RESERVED 32
#define KPF_MLOCKED 33
@@ -169,6 +171,7 @@ static const char * const debugfs_known_mountpoints[] = {
static int opt_raw; /* for kernel developers */
static int opt_list; /* list pages (in ranges) */
+static int opt_mark_idle; /* set accessed bit */
static int opt_no_summary; /* don't show summary */
static pid_t opt_pid; /* process to walk */
const char *opt_file; /* file or directory path */
@@ -198,6 +201,7 @@ static int pagemap_fd;
static int kpageflags_fd;
static int kpagecount_fd = -1;
static int kpagecgroup_fd = -1;
+static int page_idle_fd = -1;
static int opt_hwpoison;
static int opt_unpoison;
@@ -587,6 +591,30 @@ static int unpoison_page(unsigned long offset)
return 0;
}
+static int mark_page_idle(unsigned long offset)
+{
+ static unsigned long off;
+ static uint64_t buf;
+ int len;
+
+ if ((offset / 64 == off / 64) || buf == 0) {
+ buf |= 1UL << (offset % 64);
+ off = offset;
+ return 0;
+ }
+
+ len = pwrite(page_idle_fd, &buf, 8, 8 * (off / 64));
+ if (len < 0) {
+ perror("mark page idle");
+ return len;
+ }
+
+ buf = 1UL << (offset % 64);
+ off = offset;
+
+ return 0;
+}
+
/*
* page frame walker
*/
@@ -635,6 +663,9 @@ static void add_page(unsigned long voffset, unsigned long offset,
if (opt_unpoison)
unpoison_page(offset);
+ if (opt_mark_idle)
+ mark_page_idle(offset);
+
if (opt_list == 1)
show_page_range(voffset, offset, 1, flags, cgroup, mapcnt);
else if (opt_list == 2)
@@ -783,6 +814,9 @@ static void walk_addr_ranges(void)
else
walk_task(opt_offset[i], opt_size[i]);
+ if (opt_mark_idle)
+ mark_page_idle(0);
+
close(kpageflags_fd);
}
@@ -813,6 +847,7 @@ static void usage(void)
" -c|--cgroup path|@inode Walk pages within memory cgroup\n"
" -p|--pid pid Walk process address space\n"
" -f|--file filename Walk file address space\n"
+" -i|--mark-idle Mark pages idle\n"
" -l|--list Show page details in ranges\n"
" -L|--list-each Show page details one by one\n"
" -C|--list-cgroup Show cgroup inode for pages\n"
@@ -1221,6 +1256,7 @@ static const struct option opts[] = {
{ "bits" , 1, NULL, 'b' },
{ "cgroup" , 1, NULL, 'c' },
{ "describe" , 1, NULL, 'd' },
+ { "mark-idle" , 0, NULL, 'i' },
{ "list" , 0, NULL, 'l' },
{ "list-each" , 0, NULL, 'L' },
{ "list-cgroup", 0, NULL, 'C' },
@@ -1240,7 +1276,7 @@ int main(int argc, char *argv[])
page_size = getpagesize();
while ((c = getopt_long(argc, argv,
- "rp:f:a:b:d:c:ClLMNXxF:h",
+ "rp:f:a:b:d:c:CilLMNXxF:h",
opts, NULL)) != -1) {
switch (c) {
case 'r':
@@ -1267,6 +1303,9 @@ int main(int argc, char *argv[])
case 'd':
describe_flags(optarg);
exit(0);
+ case 'i':
+ opt_mark_idle = 1;
+ break;
case 'l':
opt_list = 1;
break;
@@ -1308,6 +1347,9 @@ int main(int argc, char *argv[])
if (opt_list && opt_list_mapcnt)
kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
+ if (opt_mark_idle && opt_file)
+ page_idle_fd = checked_open(SYS_KERNEL_MM_PAGE_IDLE, O_RDWR);
+
if (opt_list && opt_pid)
printf("voffset\t");
if (opt_list && opt_file)
@@ -1341,5 +1383,8 @@ int main(int argc, char *argv[])
if (opt_list_mapcnt)
close(kpagecount_fd);
+ if (page_idle_fd >= 0)
+ close(page_idle_fd);
+
return 0;
}