Commit 59ae96ff authored by Christian Hansen's avatar Christian Hansen Committed by Linus Torvalds

tools/vm/page-types.c: add support for idle page tracking

Add a flag which causes page-types to use the kernels's idle page
tracking to mark pages idle.  As the tool already prints the idle flag
if set, subsequent runs will show which pages have been accessed since
last run.

[akpm@linux-foundation.org: simplify mark_page_idle()]
[chansen3@cisco.com: reorganize mark_page_idle() logic, add docs]
  Link: http://lkml.kernel.org/r/20180706172237.21691-1-chansen3@cisco.com
Link: http://lkml.kernel.org/r/20180612153223.13174-1-chansen3@cisco.comSigned-off-by: default avatarChristian Hansen <chansen3@cisco.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7f1d23e6
...@@ -65,6 +65,11 @@ workload one should: ...@@ -65,6 +65,11 @@ workload one should:
are not reclaimable, he or she can filter them out using are not reclaimable, he or she can filter them out using
``/proc/kpageflags``. ``/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 See :ref:`Documentation/admin-guide/mm/pagemap.rst <pagemap>` for more
information about ``/proc/pid/pagemap``, ``/proc/kpageflags``, and information about ``/proc/pid/pagemap``, ``/proc/kpageflags``, and
``/proc/kpagecgroup``. ``/proc/kpagecgroup``.
......
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
#define PROC_KPAGECOUNT "/proc/kpagecount" #define PROC_KPAGECOUNT "/proc/kpagecount"
#define PROC_KPAGECGROUP "/proc/kpagecgroup" #define PROC_KPAGECGROUP "/proc/kpagecgroup"
#define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap"
/* [32-] kernel hacking assistances */ /* [32-] kernel hacking assistances */
#define KPF_RESERVED 32 #define KPF_RESERVED 32
#define KPF_MLOCKED 33 #define KPF_MLOCKED 33
...@@ -169,6 +171,7 @@ static const char * const debugfs_known_mountpoints[] = { ...@@ -169,6 +171,7 @@ static const char * const debugfs_known_mountpoints[] = {
static int opt_raw; /* for kernel developers */ static int opt_raw; /* for kernel developers */
static int opt_list; /* list pages (in ranges) */ 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 int opt_no_summary; /* don't show summary */
static pid_t opt_pid; /* process to walk */ static pid_t opt_pid; /* process to walk */
const char *opt_file; /* file or directory path */ const char *opt_file; /* file or directory path */
...@@ -198,6 +201,7 @@ static int pagemap_fd; ...@@ -198,6 +201,7 @@ static int pagemap_fd;
static int kpageflags_fd; static int kpageflags_fd;
static int kpagecount_fd = -1; static int kpagecount_fd = -1;
static int kpagecgroup_fd = -1; static int kpagecgroup_fd = -1;
static int page_idle_fd = -1;
static int opt_hwpoison; static int opt_hwpoison;
static int opt_unpoison; static int opt_unpoison;
...@@ -587,6 +591,30 @@ static int unpoison_page(unsigned long offset) ...@@ -587,6 +591,30 @@ static int unpoison_page(unsigned long offset)
return 0; 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 * page frame walker
*/ */
...@@ -635,6 +663,9 @@ static void add_page(unsigned long voffset, unsigned long offset, ...@@ -635,6 +663,9 @@ static void add_page(unsigned long voffset, unsigned long offset,
if (opt_unpoison) if (opt_unpoison)
unpoison_page(offset); unpoison_page(offset);
if (opt_mark_idle)
mark_page_idle(offset);
if (opt_list == 1) if (opt_list == 1)
show_page_range(voffset, offset, 1, flags, cgroup, mapcnt); show_page_range(voffset, offset, 1, flags, cgroup, mapcnt);
else if (opt_list == 2) else if (opt_list == 2)
...@@ -783,6 +814,9 @@ static void walk_addr_ranges(void) ...@@ -783,6 +814,9 @@ static void walk_addr_ranges(void)
else else
walk_task(opt_offset[i], opt_size[i]); walk_task(opt_offset[i], opt_size[i]);
if (opt_mark_idle)
mark_page_idle(0);
close(kpageflags_fd); close(kpageflags_fd);
} }
...@@ -813,6 +847,7 @@ static void usage(void) ...@@ -813,6 +847,7 @@ static void usage(void)
" -c|--cgroup path|@inode Walk pages within memory cgroup\n" " -c|--cgroup path|@inode Walk pages within memory cgroup\n"
" -p|--pid pid Walk process address space\n" " -p|--pid pid Walk process address space\n"
" -f|--file filename Walk file 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 Show page details in ranges\n"
" -L|--list-each Show page details one by one\n" " -L|--list-each Show page details one by one\n"
" -C|--list-cgroup Show cgroup inode for pages\n" " -C|--list-cgroup Show cgroup inode for pages\n"
...@@ -1221,6 +1256,7 @@ static const struct option opts[] = { ...@@ -1221,6 +1256,7 @@ static const struct option opts[] = {
{ "bits" , 1, NULL, 'b' }, { "bits" , 1, NULL, 'b' },
{ "cgroup" , 1, NULL, 'c' }, { "cgroup" , 1, NULL, 'c' },
{ "describe" , 1, NULL, 'd' }, { "describe" , 1, NULL, 'd' },
{ "mark-idle" , 0, NULL, 'i' },
{ "list" , 0, NULL, 'l' }, { "list" , 0, NULL, 'l' },
{ "list-each" , 0, NULL, 'L' }, { "list-each" , 0, NULL, 'L' },
{ "list-cgroup", 0, NULL, 'C' }, { "list-cgroup", 0, NULL, 'C' },
...@@ -1240,7 +1276,7 @@ int main(int argc, char *argv[]) ...@@ -1240,7 +1276,7 @@ int main(int argc, char *argv[])
page_size = getpagesize(); page_size = getpagesize();
while ((c = getopt_long(argc, argv, 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) { opts, NULL)) != -1) {
switch (c) { switch (c) {
case 'r': case 'r':
...@@ -1267,6 +1303,9 @@ int main(int argc, char *argv[]) ...@@ -1267,6 +1303,9 @@ int main(int argc, char *argv[])
case 'd': case 'd':
describe_flags(optarg); describe_flags(optarg);
exit(0); exit(0);
case 'i':
opt_mark_idle = 1;
break;
case 'l': case 'l':
opt_list = 1; opt_list = 1;
break; break;
...@@ -1308,6 +1347,9 @@ int main(int argc, char *argv[]) ...@@ -1308,6 +1347,9 @@ int main(int argc, char *argv[])
if (opt_list && opt_list_mapcnt) if (opt_list && opt_list_mapcnt)
kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY); 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) if (opt_list && opt_pid)
printf("voffset\t"); printf("voffset\t");
if (opt_list && opt_file) if (opt_list && opt_file)
...@@ -1341,5 +1383,8 @@ int main(int argc, char *argv[]) ...@@ -1341,5 +1383,8 @@ int main(int argc, char *argv[])
if (opt_list_mapcnt) if (opt_list_mapcnt)
close(kpagecount_fd); close(kpagecount_fd);
if (page_idle_fd >= 0)
close(page_idle_fd);
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment