Skip to content

Commit 7f1d23e

Browse files
chansen3torvalds
authored andcommitted
tools/vm/page-types.c: include shared map counts
Add a new flag that will read kpagecount for each PFN and print out the number of times the page is mapped along with the flags in the listing view. This information is useful in understanding and optimizing memory usage. Identifying pages which are not shared allows us to focus on adjusting the memory layout or access patterns for the sole owning process. Knowing the number of processes that share a page tells us how many other times we must make the same adjustments or how many processes to potentially disable. Truncated sample output: voffset map-cnt offset len flags 561a3591e 1 15fe8 1 ___U_lA____Ma_b___________________________ 561a3591f 1 2b103 1 ___U_lA____Ma_b___________________________ 561a36ca4 1 2cc78 1 ___U_lA____Ma_b___________________________ 7f588bb4e 14 2273c 1 __RU_lA____M______________________________ [[email protected]: coding-style fixes] [[email protected]: add documentation, tweak whitespace] Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Christian Hansen <[email protected]> Reviewed-by: Andrew Morton <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fadae29 commit 7f1d23e

File tree

2 files changed

+62
-14
lines changed

2 files changed

+62
-14
lines changed

Documentation/admin-guide/mm/pagemap.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ There are four components to pagemap:
4444
* ``/proc/kpagecount``. This file contains a 64-bit count of the number of
4545
times each page is mapped, indexed by PFN.
4646

47+
The page-types tool in the tools/vm directory can be used to query the
48+
number of times a page is mapped.
49+
4750
* ``/proc/kpageflags``. This file contains a 64-bit set of flags for each
4851
page, indexed by PFN.
4952

tools/vm/page-types.c

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575

7676
#define KPF_BYTES 8
7777
#define PROC_KPAGEFLAGS "/proc/kpageflags"
78+
#define PROC_KPAGECOUNT "/proc/kpagecount"
7879
#define PROC_KPAGECGROUP "/proc/kpagecgroup"
7980

8081
/* [32-] kernel hacking assistances */
@@ -173,6 +174,7 @@ static pid_t opt_pid; /* process to walk */
173174
const char *opt_file; /* file or directory path */
174175
static uint64_t opt_cgroup; /* cgroup inode */
175176
static int opt_list_cgroup;/* list page cgroup */
177+
static int opt_list_mapcnt;/* list page map count */
176178
static const char *opt_kpageflags;/* kpageflags file to parse */
177179

178180
#define MAX_ADDR_RANGES 1024
@@ -194,6 +196,7 @@ static int page_size;
194196

195197
static int pagemap_fd;
196198
static int kpageflags_fd;
199+
static int kpagecount_fd = -1;
197200
static int kpagecgroup_fd = -1;
198201

199202
static int opt_hwpoison;
@@ -298,6 +301,15 @@ static unsigned long kpagecgroup_read(uint64_t *buf,
298301
return do_u64_read(kpagecgroup_fd, opt_kpageflags, buf, index, pages);
299302
}
300303

304+
static unsigned long kpagecount_read(uint64_t *buf,
305+
unsigned long index,
306+
unsigned long pages)
307+
{
308+
return kpagecount_fd < 0 ? pages :
309+
do_u64_read(kpagecount_fd, PROC_KPAGECOUNT,
310+
buf, index, pages);
311+
}
312+
301313
static unsigned long pagemap_read(uint64_t *buf,
302314
unsigned long index,
303315
unsigned long pages)
@@ -370,16 +382,18 @@ static char *page_flag_longname(uint64_t flags)
370382
*/
371383

372384
static void show_page_range(unsigned long voffset, unsigned long offset,
373-
unsigned long size, uint64_t flags, uint64_t cgroup)
385+
unsigned long size, uint64_t flags,
386+
uint64_t cgroup, uint64_t mapcnt)
374387
{
375388
static uint64_t flags0;
376389
static uint64_t cgroup0;
390+
static uint64_t mapcnt0;
377391
static unsigned long voff;
378392
static unsigned long index;
379393
static unsigned long count;
380394

381-
if (flags == flags0 && cgroup == cgroup0 && offset == index + count &&
382-
size && voffset == voff + count) {
395+
if (flags == flags0 && cgroup == cgroup0 && mapcnt == mapcnt0 &&
396+
offset == index + count && size && voffset == voff + count) {
383397
count += size;
384398
return;
385399
}
@@ -391,31 +405,37 @@ static void show_page_range(unsigned long voffset, unsigned long offset,
391405
printf("%lu\t", voff);
392406
if (opt_list_cgroup)
393407
printf("@%llu\t", (unsigned long long)cgroup0);
408+
if (opt_list_mapcnt)
409+
printf("%lu\t", mapcnt0);
394410
printf("%lx\t%lx\t%s\n",
395411
index, count, page_flag_name(flags0));
396412
}
397413

398414
flags0 = flags;
399-
cgroup0= cgroup;
415+
cgroup0 = cgroup;
416+
mapcnt0 = mapcnt;
400417
index = offset;
401418
voff = voffset;
402419
count = size;
403420
}
404421

405422
static void flush_page_range(void)
406423
{
407-
show_page_range(0, 0, 0, 0, 0);
424+
show_page_range(0, 0, 0, 0, 0, 0);
408425
}
409426

410427
static void show_page(unsigned long voffset, unsigned long offset,
411-
uint64_t flags, uint64_t cgroup)
428+
uint64_t flags, uint64_t cgroup, uint64_t mapcnt)
412429
{
413430
if (opt_pid)
414431
printf("%lx\t", voffset);
415432
if (opt_file)
416433
printf("%lu\t", voffset);
417434
if (opt_list_cgroup)
418435
printf("@%llu\t", (unsigned long long)cgroup);
436+
if (opt_list_mapcnt)
437+
printf("%lu\t", mapcnt);
438+
419439
printf("%lx\t%s\n", offset, page_flag_name(flags));
420440
}
421441

@@ -599,7 +619,8 @@ static size_t hash_slot(uint64_t flags)
599619
}
600620

601621
static void add_page(unsigned long voffset, unsigned long offset,
602-
uint64_t flags, uint64_t cgroup, uint64_t pme)
622+
uint64_t flags, uint64_t cgroup, uint64_t mapcnt,
623+
uint64_t pme)
603624
{
604625
flags = kpageflags_flags(flags, pme);
605626

@@ -615,9 +636,9 @@ static void add_page(unsigned long voffset, unsigned long offset,
615636
unpoison_page(offset);
616637

617638
if (opt_list == 1)
618-
show_page_range(voffset, offset, 1, flags, cgroup);
639+
show_page_range(voffset, offset, 1, flags, cgroup, mapcnt);
619640
else if (opt_list == 2)
620-
show_page(voffset, offset, flags, cgroup);
641+
show_page(voffset, offset, flags, cgroup, mapcnt);
621642

622643
nr_pages[hash_slot(flags)]++;
623644
total_pages++;
@@ -631,6 +652,7 @@ static void walk_pfn(unsigned long voffset,
631652
{
632653
uint64_t buf[KPAGEFLAGS_BATCH];
633654
uint64_t cgi[KPAGEFLAGS_BATCH];
655+
uint64_t cnt[KPAGEFLAGS_BATCH];
634656
unsigned long batch;
635657
unsigned long pages;
636658
unsigned long i;
@@ -654,8 +676,12 @@ static void walk_pfn(unsigned long voffset,
654676
if (kpagecgroup_read(cgi, index, pages) != pages)
655677
fatal("kpagecgroup returned fewer pages than expected");
656678

679+
if (kpagecount_read(cnt, index, batch) != pages)
680+
fatal("kpagecount returned fewer pages than expected");
681+
657682
for (i = 0; i < pages; i++)
658-
add_page(voffset + i, index + i, buf[i], cgi[i], pme);
683+
add_page(voffset + i, index + i,
684+
buf[i], cgi[i], cnt[i], pme);
659685

660686
index += pages;
661687
count -= pages;
@@ -673,9 +699,10 @@ static void walk_swap(unsigned long voffset, uint64_t pme)
673699
return;
674700

675701
if (opt_list == 1)
676-
show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, 0);
702+
show_page_range(voffset, pagemap_swap_offset(pme),
703+
1, flags, 0, 0);
677704
else if (opt_list == 2)
678-
show_page(voffset, pagemap_swap_offset(pme), flags, 0);
705+
show_page(voffset, pagemap_swap_offset(pme), flags, 0, 0);
679706

680707
nr_pages[hash_slot(flags)]++;
681708
total_pages++;
@@ -789,6 +816,7 @@ static void usage(void)
789816
" -l|--list Show page details in ranges\n"
790817
" -L|--list-each Show page details one by one\n"
791818
" -C|--list-cgroup Show cgroup inode for pages\n"
819+
" -M|--list-mapcnt Show page map count\n"
792820
" -N|--no-summary Don't show summary info\n"
793821
" -X|--hwpoison hwpoison pages\n"
794822
" -x|--unpoison unpoison pages\n"
@@ -925,6 +953,7 @@ static void walk_file(const char *name, const struct stat *st)
925953
uint8_t vec[PAGEMAP_BATCH];
926954
uint64_t buf[PAGEMAP_BATCH], flags;
927955
uint64_t cgroup = 0;
956+
uint64_t mapcnt = 0;
928957
unsigned long nr_pages, pfn, i;
929958
off_t off, end = st->st_size;
930959
int fd;
@@ -984,13 +1013,15 @@ static void walk_file(const char *name, const struct stat *st)
9841013
continue;
9851014
if (!kpagecgroup_read(&cgroup, pfn, 1))
9861015
fatal("kpagecgroup_read failed");
1016+
if (!kpagecount_read(&mapcnt, pfn, 1))
1017+
fatal("kpagecount_read failed");
9871018
if (first && opt_list) {
9881019
first = 0;
9891020
flush_page_range();
9901021
show_file(name, st);
9911022
}
9921023
add_page(off / page_size + i, pfn,
993-
flags, cgroup, buf[i]);
1024+
flags, cgroup, mapcnt, buf[i]);
9941025
}
9951026
}
9961027

@@ -1193,6 +1224,7 @@ static const struct option opts[] = {
11931224
{ "list" , 0, NULL, 'l' },
11941225
{ "list-each" , 0, NULL, 'L' },
11951226
{ "list-cgroup", 0, NULL, 'C' },
1227+
{ "list-mapcnt", 0, NULL, 'M' },
11961228
{ "no-summary", 0, NULL, 'N' },
11971229
{ "hwpoison" , 0, NULL, 'X' },
11981230
{ "unpoison" , 0, NULL, 'x' },
@@ -1208,7 +1240,8 @@ int main(int argc, char *argv[])
12081240
page_size = getpagesize();
12091241

12101242
while ((c = getopt_long(argc, argv,
1211-
"rp:f:a:b:d:c:ClLNXxF:h", opts, NULL)) != -1) {
1243+
"rp:f:a:b:d:c:ClLMNXxF:h",
1244+
opts, NULL)) != -1) {
12121245
switch (c) {
12131246
case 'r':
12141247
opt_raw = 1;
@@ -1240,6 +1273,9 @@ int main(int argc, char *argv[])
12401273
case 'L':
12411274
opt_list = 2;
12421275
break;
1276+
case 'M':
1277+
opt_list_mapcnt = 1;
1278+
break;
12431279
case 'N':
12441280
opt_no_summary = 1;
12451281
break;
@@ -1269,12 +1305,18 @@ int main(int argc, char *argv[])
12691305
if (opt_cgroup || opt_list_cgroup)
12701306
kpagecgroup_fd = checked_open(PROC_KPAGECGROUP, O_RDONLY);
12711307

1308+
if (opt_list && opt_list_mapcnt)
1309+
kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
1310+
12721311
if (opt_list && opt_pid)
12731312
printf("voffset\t");
12741313
if (opt_list && opt_file)
12751314
printf("foffset\t");
12761315
if (opt_list && opt_list_cgroup)
12771316
printf("cgroup\t");
1317+
if (opt_list && opt_list_mapcnt)
1318+
printf("map-cnt\t");
1319+
12781320
if (opt_list == 1)
12791321
printf("offset\tlen\tflags\n");
12801322
if (opt_list == 2)
@@ -1296,5 +1338,8 @@ int main(int argc, char *argv[])
12961338

12971339
show_summary();
12981340

1341+
if (opt_list_mapcnt)
1342+
close(kpagecount_fd);
1343+
12991344
return 0;
13001345
}

0 commit comments

Comments
 (0)