[PATCH v2 6/8] mm: Count requests to free & nr freed per shrinker

Kent Overstreet
2022-04-21T23:50:45Z

The next step in this patch series for improving debugging of shrinker
related issues: keep counts of number of objects we request to free vs.
actually freed, and prints them in shrinker_to_text().

Shrinkers won't necessarily free all objects requested for a variety of
reasons, but if the two counts are wildly different something is likely
amiss.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
---
include/linux/shrinker.h | 3 +++
mm/vmscan.c | 16 +++++++++++++---
2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index b5f411768b..12967748f9 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -79,6 +79,9 @@ struct shrinker {
#endif
/* objs pending delete, per node */
atomic_long_t *nr_deferred;
+
+ atomic_long_t objects_requested_to_free;
+ atomic_long_t objects_freed;
};
#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 905bc23800..12562546a7 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -711,16 +711,22 @@ void shrinker_to_text(struct printbuf *out, struct shrinker *shrinker)
pr_buf(out, "%s", shrinker->name);
else
pr_buf(out, "%ps:", shrinker->scan_objects);
+ pr_newline(out);
+ pr_indent_push(out, 2);

- pr_buf(out, " objects: %lu", shrinker->count_objects(shrinker, &sc));
+ pr_buf(out, "objects: %lu", shrinker->count_objects(shrinker, &sc));
+ pr_newline(out);
+ pr_buf(out, "requested to free: %lu", atomic_long_read(&shrinker->objects_requested_to_free));
+ pr_newline(out);
+ pr_buf(out, "objects freed: %lu", atomic_long_read(&shrinker->objects_freed));
pr_newline(out);

if (shrinker->to_text) {
- pr_indent_push(out, 2);
shrinker->to_text(out, shrinker);
- pr_indent_pop(out, 2);
pr_newline(out);
}
+
+ pr_indent_pop(out, 2);
}

/**
@@ -846,12 +852,16 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
unsigned long ret;
unsigned long nr_to_scan = min(batch_size, total_scan);

+ atomic_long_add(nr_to_scan, &shrinker->objects_requested_to_free);
+
shrinkctl->nr_to_scan = nr_to_scan;
shrinkctl->nr_scanned = nr_to_scan;
ret = shrinker->scan_objects(shrinker, shrinkctl);
if (ret == SHRINK_STOP)
break;
+
freed += ret;
+ atomic_long_add(ret, &shrinker->objects_freed);

count_vm_events(SLABS_SCANNED, shrinkctl->nr_scanned);
total_scan -= shrinkctl->nr_scanned;
--
2.35.2