diff options
| author | Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> | 2013-11-12 18:07:50 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 22:09:07 -0500 |
| commit | 46c77e2bb07eba3b38edfec76873f12942c49dd3 (patch) | |
| tree | 2e6dd491627079f3e377e948f23137dd0c4cab40 /tools | |
| parent | ec8e41aec13005fed0dbee002fb8c99b4e001d50 (diff) | |
tools/vm/page-types.c: support KPF_SOFTDIRTY bit
Soft dirty bit allows us to track which pages are written since the last
clear_ref (by "echo 4 > /proc/pid/clear_refs".) This is useful for
userspace applications to know their memory footprints.
Note that the kernel exposes this flag via bit[55] of /proc/pid/pagemap,
and the semantics is not a default one (scheduled to be the default in the
near future.) However, it shifts to the new semantics at the first
clear_ref, and the users of soft dirty bit always do it before utilizing
the bit, so that's not a big deal. Users must avoid relying on the bit in
page-types before the first clear_ref.
Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/vm/page-types.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 71c9c2511ee7..d5e9d6d185c8 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c | |||
| @@ -59,12 +59,14 @@ | |||
| 59 | #define PM_PSHIFT_BITS 6 | 59 | #define PM_PSHIFT_BITS 6 |
| 60 | #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) | 60 | #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) |
| 61 | #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) | 61 | #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) |
| 62 | #define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) | 62 | #define __PM_PSHIFT(x) (((uint64_t) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) |
| 63 | #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) | 63 | #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) |
| 64 | #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) | 64 | #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) |
| 65 | 65 | ||
| 66 | #define __PM_SOFT_DIRTY (1LL) | ||
| 66 | #define PM_PRESENT PM_STATUS(4LL) | 67 | #define PM_PRESENT PM_STATUS(4LL) |
| 67 | #define PM_SWAP PM_STATUS(2LL) | 68 | #define PM_SWAP PM_STATUS(2LL) |
| 69 | #define PM_SOFT_DIRTY __PM_PSHIFT(__PM_SOFT_DIRTY) | ||
| 68 | 70 | ||
| 69 | 71 | ||
| 70 | /* | 72 | /* |
| @@ -83,6 +85,7 @@ | |||
| 83 | #define KPF_OWNER_PRIVATE 37 | 85 | #define KPF_OWNER_PRIVATE 37 |
| 84 | #define KPF_ARCH 38 | 86 | #define KPF_ARCH 38 |
| 85 | #define KPF_UNCACHED 39 | 87 | #define KPF_UNCACHED 39 |
| 88 | #define KPF_SOFTDIRTY 40 | ||
| 86 | 89 | ||
| 87 | /* [48-] take some arbitrary free slots for expanding overloaded flags | 90 | /* [48-] take some arbitrary free slots for expanding overloaded flags |
| 88 | * not part of kernel API | 91 | * not part of kernel API |
| @@ -132,6 +135,7 @@ static const char * const page_flag_names[] = { | |||
| 132 | [KPF_OWNER_PRIVATE] = "O:owner_private", | 135 | [KPF_OWNER_PRIVATE] = "O:owner_private", |
| 133 | [KPF_ARCH] = "h:arch", | 136 | [KPF_ARCH] = "h:arch", |
| 134 | [KPF_UNCACHED] = "c:uncached", | 137 | [KPF_UNCACHED] = "c:uncached", |
| 138 | [KPF_SOFTDIRTY] = "f:softdirty", | ||
| 135 | 139 | ||
| 136 | [KPF_READAHEAD] = "I:readahead", | 140 | [KPF_READAHEAD] = "I:readahead", |
| 137 | [KPF_SLOB_FREE] = "P:slob_free", | 141 | [KPF_SLOB_FREE] = "P:slob_free", |
| @@ -417,7 +421,7 @@ static int bit_mask_ok(uint64_t flags) | |||
| 417 | return 1; | 421 | return 1; |
| 418 | } | 422 | } |
| 419 | 423 | ||
| 420 | static uint64_t expand_overloaded_flags(uint64_t flags) | 424 | static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme) |
| 421 | { | 425 | { |
| 422 | /* SLOB/SLUB overload several page flags */ | 426 | /* SLOB/SLUB overload several page flags */ |
| 423 | if (flags & BIT(SLAB)) { | 427 | if (flags & BIT(SLAB)) { |
| @@ -433,6 +437,9 @@ static uint64_t expand_overloaded_flags(uint64_t flags) | |||
| 433 | if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) | 437 | if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) |
| 434 | flags ^= BIT(RECLAIM) | BIT(READAHEAD); | 438 | flags ^= BIT(RECLAIM) | BIT(READAHEAD); |
| 435 | 439 | ||
| 440 | if (pme & PM_SOFT_DIRTY) | ||
| 441 | flags |= BIT(SOFTDIRTY); | ||
| 442 | |||
| 436 | return flags; | 443 | return flags; |
| 437 | } | 444 | } |
| 438 | 445 | ||
| @@ -448,11 +455,11 @@ static uint64_t well_known_flags(uint64_t flags) | |||
| 448 | return flags; | 455 | return flags; |
| 449 | } | 456 | } |
| 450 | 457 | ||
| 451 | static uint64_t kpageflags_flags(uint64_t flags) | 458 | static uint64_t kpageflags_flags(uint64_t flags, uint64_t pme) |
| 452 | { | 459 | { |
| 453 | flags = expand_overloaded_flags(flags); | 460 | if (opt_raw) |
| 454 | 461 | flags = expand_overloaded_flags(flags, pme); | |
| 455 | if (!opt_raw) | 462 | else |
| 456 | flags = well_known_flags(flags); | 463 | flags = well_known_flags(flags); |
| 457 | 464 | ||
| 458 | return flags; | 465 | return flags; |
| @@ -545,9 +552,9 @@ static size_t hash_slot(uint64_t flags) | |||
| 545 | } | 552 | } |
| 546 | 553 | ||
| 547 | static void add_page(unsigned long voffset, | 554 | static void add_page(unsigned long voffset, |
| 548 | unsigned long offset, uint64_t flags) | 555 | unsigned long offset, uint64_t flags, uint64_t pme) |
| 549 | { | 556 | { |
| 550 | flags = kpageflags_flags(flags); | 557 | flags = kpageflags_flags(flags, pme); |
| 551 | 558 | ||
| 552 | if (!bit_mask_ok(flags)) | 559 | if (!bit_mask_ok(flags)) |
| 553 | return; | 560 | return; |
| @@ -569,7 +576,8 @@ static void add_page(unsigned long voffset, | |||
| 569 | #define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ | 576 | #define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ |
| 570 | static void walk_pfn(unsigned long voffset, | 577 | static void walk_pfn(unsigned long voffset, |
| 571 | unsigned long index, | 578 | unsigned long index, |
| 572 | unsigned long count) | 579 | unsigned long count, |
| 580 | uint64_t pme) | ||
| 573 | { | 581 | { |
| 574 | uint64_t buf[KPAGEFLAGS_BATCH]; | 582 | uint64_t buf[KPAGEFLAGS_BATCH]; |
| 575 | unsigned long batch; | 583 | unsigned long batch; |
| @@ -583,7 +591,7 @@ static void walk_pfn(unsigned long voffset, | |||
| 583 | break; | 591 | break; |
| 584 | 592 | ||
| 585 | for (i = 0; i < pages; i++) | 593 | for (i = 0; i < pages; i++) |
| 586 | add_page(voffset + i, index + i, buf[i]); | 594 | add_page(voffset + i, index + i, buf[i], pme); |
| 587 | 595 | ||
| 588 | index += pages; | 596 | index += pages; |
| 589 | count -= pages; | 597 | count -= pages; |
| @@ -608,7 +616,7 @@ static void walk_vma(unsigned long index, unsigned long count) | |||
| 608 | for (i = 0; i < pages; i++) { | 616 | for (i = 0; i < pages; i++) { |
| 609 | pfn = pagemap_pfn(buf[i]); | 617 | pfn = pagemap_pfn(buf[i]); |
| 610 | if (pfn) | 618 | if (pfn) |
| 611 | walk_pfn(index + i, pfn, 1); | 619 | walk_pfn(index + i, pfn, 1, buf[i]); |
| 612 | } | 620 | } |
| 613 | 621 | ||
| 614 | index += pages; | 622 | index += pages; |
| @@ -659,7 +667,7 @@ static void walk_addr_ranges(void) | |||
| 659 | 667 | ||
| 660 | for (i = 0; i < nr_addr_ranges; i++) | 668 | for (i = 0; i < nr_addr_ranges; i++) |
| 661 | if (!opt_pid) | 669 | if (!opt_pid) |
| 662 | walk_pfn(0, opt_offset[i], opt_size[i]); | 670 | walk_pfn(0, opt_offset[i], opt_size[i], 0); |
| 663 | else | 671 | else |
| 664 | walk_task(opt_offset[i], opt_size[i]); | 672 | walk_task(opt_offset[i], opt_size[i]); |
| 665 | 673 | ||
