From: Ridong Chen <[email protected]>

The number of pages of a given type in a generation is computed by
summing lrugen->nr_pages[gen][type][] over all zones and clamping each
per-zone counter to >= 0, since the counters are updated locklessly and
can transiently go negative. This loop is open-coded in
lruvec_evictable_size() and in the debugfs lru_gen output.

Add lruvec_gen_size() to compute it from a seq, and convert both users.
Put it in mm/vmscan.h so that the vmscan tracepoints, which include that
header, can use it as well.
An upcoming tracepoint and the MGLRU swappiness rework will also use it.

No functional change.

Suggested-by: Barry Song <[email protected]>
Signed-off-by: Ridong Chen <[email protected]>
---
 mm/vmscan.c | 18 ++++++------------
 mm/vmscan.h | 16 ++++++++++++++++
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 3054175717ab..1581b73aec56 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4207,18 +4207,15 @@ static void set_initial_priority(struct pglist_data 
*pgdat, struct scan_control
 
 static unsigned long lruvec_evictable_size(struct lruvec *lruvec, int 
swappiness)
 {
-       int gen, type, zone;
+       int type;
        unsigned long seq, total = 0;
        struct lru_gen_folio *lrugen = &lruvec->lrugen;
        DEFINE_MAX_SEQ(lruvec);
        DEFINE_MIN_SEQ(lruvec);
 
        for_each_evictable_type(type, swappiness) {
-               for (seq = min_seq[type]; seq <= max_seq; seq++) {
-                       gen = lru_gen_from_seq(seq);
-                       for (zone = 0; zone < MAX_NR_ZONES; zone++)
-                               total += 
max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L);
-               }
+               for (seq = min_seq[type]; seq <= max_seq; seq++)
+                       total += lruvec_gen_size(lrugen, type, seq);
        }
 
        return total;
@@ -5723,20 +5720,17 @@ static int lru_gen_seq_show(struct seq_file *m, void *v)
                seq = 0;
 
        for (; seq <= max_seq; seq++) {
-               int type, zone;
+               int type;
                int gen = lru_gen_from_seq(seq);
                unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]);
 
                seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - 
birth));
 
                for (type = 0; type < ANON_AND_FILE; type++) {
-                       unsigned long size = 0;
                        char mark = full && seq < min_seq[type] ? 'x' : ' ';
 
-                       for (zone = 0; zone < MAX_NR_ZONES; zone++)
-                               size += 
max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L);
-
-                       seq_printf(m, " %10lu%c", size, mark);
+                       seq_printf(m, " %10lu%c",
+                                  lruvec_gen_size(lrugen, type, seq), mark);
                }
 
                seq_putc(m, '\n');
diff --git a/mm/vmscan.h b/mm/vmscan.h
index adb22e80d760..c6b583fc7493 100644
--- a/mm/vmscan.h
+++ b/mm/vmscan.h
@@ -3,6 +3,7 @@
 #define _MM_VMSCAN_H
 
 #include <linux/gfp_types.h>
+#include <linux/mm_inline.h>
 #include <linux/nodemask.h>
 #include <linux/swap.h>
 #include <linux/types.h>
@@ -115,4 +116,19 @@ struct scan_control {
        struct reclaim_state reclaim_state;
 };
 
+#ifdef CONFIG_LRU_GEN
+/* The number of pages of @type in the generation @seq, summed over all zones 
*/
+static inline unsigned long lruvec_gen_size(struct lru_gen_folio *lrugen,
+                                           int type, unsigned long seq)
+{
+       int gen = lru_gen_from_seq(seq);
+       unsigned long size = 0;
+
+       for (int zone = 0; zone < MAX_NR_ZONES; zone++)
+               size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L);
+
+       return size;
+}
+#endif /* CONFIG_LRU_GEN */
+
 #endif /* _MM_VMSCAN_H */
-- 
2.34.1


Reply via email to