Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 494c0daf authored by Johannes Weiner's avatar Johannes Weiner Committed by Patrick Daly
Browse files

mm: workingset: tell cache transitions from workingset thrashing

Refaults happen during transitions between workingsets as well as in-place
thrashing.  Knowing the difference between the two has a range of
applications, including measuring the impact of memory shortage on the
system performance, as well as the ability to smarter balance pressure
between the filesystem cache and the swap-backed workingset.

During workingset transitions, inactive cache refaults and pushes out
established active cache.  When that active cache isn't stale, however,
and also ends up refaulting, that's bonafide thrashing.

Introduce a new page flag that tells on eviction whether the page has been
active or not in its lifetime.  This bit is then stored in the shadow
entry, to classify refaults as transitioning or thrashing.

How many page->flags does this leave us with on 32-bit?

	20 bits are always page flags

	21 if you have an MMU

	23 with the zone bits for DMA, Normal, HighMem, Movable

	29 with the sparsemem section bits

	30 if PAE is enabled

	31 with this patch.

So on 32-bit PAE, that leaves 1 bit for distinguishing two NUMA nodes.  If
that's not enough, the system can switch to discontigmem and re-gain the 6
or 7 sparsemem section bits.

Link: http://lkml.kernel.org/r/20180828172258.3185-3-hannes@cmpxchg.org


Signed-off-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: default avatarDaniel Drake <drake@endlessm.com>
Tested-by: default avatarSuren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Change-Id: I6134c51987d401584f513f8b5a7826962009997c
Git-commit: 1899ad18c6072d689896badafb81267b0a1092a4
Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.19


Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 8730af68
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -165,6 +165,7 @@ enum node_stat_item {
	NR_ISOLATED_FILE,	/* Temporary isolated pages from file lru */
	NR_ISOLATED_FILE,	/* Temporary isolated pages from file lru */
	WORKINGSET_REFAULT,
	WORKINGSET_REFAULT,
	WORKINGSET_ACTIVATE,
	WORKINGSET_ACTIVATE,
	WORKINGSET_RESTORE,
	WORKINGSET_NODERECLAIM,
	WORKINGSET_NODERECLAIM,
	NR_ANON_MAPPED,	/* Mapped anonymous pages */
	NR_ANON_MAPPED,	/* Mapped anonymous pages */
	NR_FILE_MAPPED,	/* pagecache pages mapped into pagetables.
	NR_FILE_MAPPED,	/* pagecache pages mapped into pagetables.
+4 −1
Original line number Original line Diff line number Diff line
@@ -69,13 +69,14 @@
 */
 */
enum pageflags {
enum pageflags {
	PG_locked,		/* Page is locked. Don't touch. */
	PG_locked,		/* Page is locked. Don't touch. */
	PG_error,
	PG_referenced,
	PG_referenced,
	PG_uptodate,
	PG_uptodate,
	PG_dirty,
	PG_dirty,
	PG_lru,
	PG_lru,
	PG_active,
	PG_active,
	PG_workingset,
	PG_waiters,		/* Page has waiters, check its waitqueue. Must be bit #7 and in the same byte as "PG_locked" */
	PG_waiters,		/* Page has waiters, check its waitqueue. Must be bit #7 and in the same byte as "PG_locked" */
	PG_error,
	PG_slab,
	PG_slab,
	PG_owner_priv_1,	/* Owner use. If pagecache, fs may use*/
	PG_owner_priv_1,	/* Owner use. If pagecache, fs may use*/
	PG_arch_1,
	PG_arch_1,
@@ -280,6 +281,8 @@ PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD)
PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD)
PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD)
PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD)
PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD)
	TESTCLEARFLAG(Active, active, PF_HEAD)
	TESTCLEARFLAG(Active, active, PF_HEAD)
PAGEFLAG(Workingset, workingset, PF_HEAD)
	TESTCLEARFLAG(Workingset, workingset, PF_HEAD)
__PAGEFLAG(Slab, slab, PF_NO_TAIL)
__PAGEFLAG(Slab, slab, PF_NO_TAIL)
__PAGEFLAG(SlobFree, slob_free, PF_NO_TAIL)
__PAGEFLAG(SlobFree, slob_free, PF_NO_TAIL)
PAGEFLAG(Checked, checked, PF_NO_COMPOUND)	   /* Used by some filesystems */
PAGEFLAG(Checked, checked, PF_NO_COMPOUND)	   /* Used by some filesystems */
+1 −1
Original line number Original line Diff line number Diff line
@@ -308,7 +308,7 @@ struct vma_swap_readahead {


/* linux/mm/workingset.c */
/* linux/mm/workingset.c */
void *workingset_eviction(struct address_space *mapping, struct page *page);
void *workingset_eviction(struct address_space *mapping, struct page *page);
bool workingset_refault(void *shadow);
void workingset_refault(struct page *page, void *shadow);
void workingset_activation(struct page *page);
void workingset_activation(struct page *page);


/* Do not use directly, use workingset_lookup_update */
/* Do not use directly, use workingset_lookup_update */
+1 −0
Original line number Original line Diff line number Diff line
@@ -88,6 +88,7 @@
	{1UL << PG_dirty,		"dirty"		},		\
	{1UL << PG_dirty,		"dirty"		},		\
	{1UL << PG_lru,			"lru"		},		\
	{1UL << PG_lru,			"lru"		},		\
	{1UL << PG_active,		"active"	},		\
	{1UL << PG_active,		"active"	},		\
	{1UL << PG_workingset,		"workingset"	},		\
	{1UL << PG_slab,		"slab"		},		\
	{1UL << PG_slab,		"slab"		},		\
	{1UL << PG_owner_priv_1,	"owner_priv_1"	},		\
	{1UL << PG_owner_priv_1,	"owner_priv_1"	},		\
	{1UL << PG_arch_1,		"arch_1"	},		\
	{1UL << PG_arch_1,		"arch_1"	},		\
+3 −6
Original line number Original line Diff line number Diff line
@@ -919,12 +919,9 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
		 * data from the working set, only to cache data that will
		 * data from the working set, only to cache data that will
		 * get overwritten with something else, is a waste of memory.
		 * get overwritten with something else, is a waste of memory.
		 */
		 */
		if (!(gfp_mask & __GFP_WRITE) &&
		WARN_ON_ONCE(PageActive(page));
		    shadow && workingset_refault(shadow)) {
		if (!(gfp_mask & __GFP_WRITE) && shadow)
			SetPageActive(page);
			workingset_refault(page, shadow);
			workingset_activation(page);
		} else
			ClearPageActive(page);
		lru_cache_add(page);
		lru_cache_add(page);
	}
	}
	return ret;
	return ret;
Loading