From: Joonsoo Kim <[email protected]>

To prepare the workingset detection for anon LRU, this patch splits
workingset event counters for refault, activate and restore into anon
and file variants, as well as the refaults counter in struct lruvec.

Acked-by: Johannes Weiner <[email protected]>
Acked-by: Vlastimil Babka <[email protected]>
Signed-off-by: Joonsoo Kim <[email protected]>
---
 include/linux/mmzone.h | 16 +++++++++++-----
 mm/memcontrol.c        | 16 +++++++++++-----
 mm/vmscan.c            | 15 ++++++++++-----
 mm/vmstat.c            |  9 ++++++---
 mm/workingset.c        |  8 +++++---
 5 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 635a96c..efbd95d 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -173,9 +173,15 @@ enum node_stat_item {
        NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
        NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
        WORKINGSET_NODES,
-       WORKINGSET_REFAULT,
-       WORKINGSET_ACTIVATE,
-       WORKINGSET_RESTORE,
+       WORKINGSET_REFAULT_BASE,
+       WORKINGSET_REFAULT_ANON = WORKINGSET_REFAULT_BASE,
+       WORKINGSET_REFAULT_FILE,
+       WORKINGSET_ACTIVATE_BASE,
+       WORKINGSET_ACTIVATE_ANON = WORKINGSET_ACTIVATE_BASE,
+       WORKINGSET_ACTIVATE_FILE,
+       WORKINGSET_RESTORE_BASE,
+       WORKINGSET_RESTORE_ANON = WORKINGSET_RESTORE_BASE,
+       WORKINGSET_RESTORE_FILE,
        WORKINGSET_NODERECLAIM,
        NR_ANON_MAPPED, /* Mapped anonymous pages */
        NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
@@ -277,8 +283,8 @@ struct lruvec {
        unsigned long                   file_cost;
        /* Non-resident age, driven by LRU movement */
        atomic_long_t                   nonresident_age;
-       /* Refaults at the time of last reclaim cycle */
-       unsigned long                   refaults;
+       /* Refaults at the time of last reclaim cycle, anon=0, file=1 */
+       unsigned long                   refaults[2];
        /* Various lruvec state flags (enum lruvec_flags) */
        unsigned long                   flags;
 #ifdef CONFIG_MEMCG
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 14dd98d..e84c2b5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1530,12 +1530,18 @@ static char *memory_stat_format(struct mem_cgroup 
*memcg)
        seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGMAJFAULT),
                       memcg_events(memcg, PGMAJFAULT));
 
-       seq_buf_printf(&s, "workingset_refault %lu\n",
-                      memcg_page_state(memcg, WORKINGSET_REFAULT));
-       seq_buf_printf(&s, "workingset_activate %lu\n",
-                      memcg_page_state(memcg, WORKINGSET_ACTIVATE));
+       seq_buf_printf(&s, "workingset_refault_anon %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_REFAULT_ANON));
+       seq_buf_printf(&s, "workingset_refault_file %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_REFAULT_FILE));
+       seq_buf_printf(&s, "workingset_activate_anon %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_ACTIVATE_ANON));
+       seq_buf_printf(&s, "workingset_activate_file %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_ACTIVATE_FILE));
        seq_buf_printf(&s, "workingset_restore %lu\n",
-                      memcg_page_state(memcg, WORKINGSET_RESTORE));
+                      memcg_page_state(memcg, WORKINGSET_RESTORE_ANON));
+       seq_buf_printf(&s, "workingset_restore %lu\n",
+                      memcg_page_state(memcg, WORKINGSET_RESTORE_FILE));
        seq_buf_printf(&s, "workingset_nodereclaim %lu\n",
                       memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
 
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9406948..6dda5b2 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2683,7 +2683,10 @@ static void shrink_node(pg_data_t *pgdat, struct 
scan_control *sc)
        if (!sc->force_deactivate) {
                unsigned long refaults;
 
-               if (inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
+               refaults = lruvec_page_state(target_lruvec,
+                               WORKINGSET_ACTIVATE_ANON);
+               if (refaults != target_lruvec->refaults[0] ||
+                       inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
                        sc->may_deactivate |= DEACTIVATE_ANON;
                else
                        sc->may_deactivate &= ~DEACTIVATE_ANON;
@@ -2694,8 +2697,8 @@ static void shrink_node(pg_data_t *pgdat, struct 
scan_control *sc)
                 * rid of any stale active pages quickly.
                 */
                refaults = lruvec_page_state(target_lruvec,
-                                            WORKINGSET_ACTIVATE);
-               if (refaults != target_lruvec->refaults ||
+                               WORKINGSET_ACTIVATE_FILE);
+               if (refaults != target_lruvec->refaults[1] ||
                    inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
                        sc->may_deactivate |= DEACTIVATE_FILE;
                else
@@ -2972,8 +2975,10 @@ static void snapshot_refaults(struct mem_cgroup 
*target_memcg, pg_data_t *pgdat)
        unsigned long refaults;
 
        target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat);
-       refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE);
-       target_lruvec->refaults = refaults;
+       refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON);
+       target_lruvec->refaults[0] = refaults;
+       refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_FILE);
+       target_lruvec->refaults[1] = refaults;
 }
 
 /*
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 5b35c0e..6eecfcb 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1190,9 +1190,12 @@ const char * const vmstat_text[] = {
        "nr_isolated_anon",
        "nr_isolated_file",
        "workingset_nodes",
-       "workingset_refault",
-       "workingset_activate",
-       "workingset_restore",
+       "workingset_refault_anon",
+       "workingset_refault_file",
+       "workingset_activate_anon",
+       "workingset_activate_file",
+       "workingset_restore_anon",
+       "workingset_restore_file",
        "workingset_nodereclaim",
        "nr_anon_pages",
        "nr_mapped",
diff --git a/mm/workingset.c b/mm/workingset.c
index 21b2986..2d77e4d 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
 #include <linux/writeback.h>
 #include <linux/shmem_fs.h>
 #include <linux/pagemap.h>
@@ -280,6 +281,7 @@ void *workingset_eviction(struct page *page, struct 
mem_cgroup *target_memcg)
  */
 void workingset_refault(struct page *page, void *shadow)
 {
+       bool file = page_is_file_lru(page);
        struct mem_cgroup *eviction_memcg;
        struct lruvec *eviction_lruvec;
        unsigned long refault_distance;
@@ -346,7 +348,7 @@ void workingset_refault(struct page *page, void *shadow)
        memcg = page_memcg(page);
        lruvec = mem_cgroup_lruvec(memcg, pgdat);
 
-       inc_lruvec_state(lruvec, WORKINGSET_REFAULT);
+       inc_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + file);
 
        /*
         * Compare the distance to the existing workingset size. We
@@ -366,7 +368,7 @@ void workingset_refault(struct page *page, void *shadow)
 
        SetPageActive(page);
        workingset_age_nonresident(lruvec, thp_nr_pages(page));
-       inc_lruvec_state(lruvec, WORKINGSET_ACTIVATE);
+       inc_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + file);
 
        /* Page was active prior to eviction */
        if (workingset) {
@@ -375,7 +377,7 @@ void workingset_refault(struct page *page, void *shadow)
                spin_lock_irq(&page_pgdat(page)->lru_lock);
                lru_note_cost_page(page);
                spin_unlock_irq(&page_pgdat(page)->lru_lock);
-               inc_lruvec_state(lruvec, WORKINGSET_RESTORE);
+               inc_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + file);
        }
 out:
        rcu_read_unlock();
-- 
2.7.4

Reply via email to