From 80a603a57a44eb0c431eece7f869d3c93e6543a9 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 27 Feb 2025 13:01:38 -0800 Subject: [PATCH] ANDROID: mm: add GCMA sysfs stats Add GCMA statistics for stored, loaded, evicted, cached and discarded pages. Bug: 236887352 Bug: 391879760 Change-Id: I7238ad6a0ab357402cda3f2357b1a731c50c597a Signed-off-by: Minchan Kim Signed-off-by: Suren Baghdasaryan --- mm/Kconfig | 7 ++++ mm/Makefile | 1 + mm/gcma.c | 9 +++++ mm/gcma_sysfs.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ mm/gcma_sysfs.h | 25 ++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 mm/gcma_sysfs.c create mode 100644 mm/gcma_sysfs.h diff --git a/mm/Kconfig b/mm/Kconfig index 23c14aaa6e64..5c587081636e 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -998,6 +998,13 @@ config GCMA If unsure, say "n". +config GCMA_SYSFS + bool "GCMA information through sysfs interface" + depends on GCMA && SYSFS + help + This option exposes some sysfs attributes to get information + from GCMA. + config MEM_SOFT_DIRTY bool "Track memory changes" depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY && PROC_FS diff --git a/mm/Makefile b/mm/Makefile index 99fa35ef8c6f..3ceafdeacac3 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_Z3FOLD) += z3fold.o obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o obj-$(CONFIG_CMA) += cma.o obj-$(CONFIG_GCMA) += gcma.o +obj-$(CONFIG_GCMA_SYSFS) += gcma_sysfs.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_NUMA_MEMBLKS) += numa_memblks.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o diff --git a/mm/gcma.c b/mm/gcma.c index 573d18f54fa2..bc81e743f827 100644 --- a/mm/gcma.c +++ b/mm/gcma.c @@ -13,6 +13,7 @@ #include #include #include +#include "gcma_sysfs.h" /* * page->page_type : area id @@ -360,6 +361,7 @@ static struct page *gcma_alloc_page(void) ClearPageGCMAFree(page); set_page_count(page, 1); spin_unlock(&area->free_pages_lock); + gcma_stat_inc(CACHED_PAGE); break; } @@ -380,6 +382,7 @@ static void __gcma_free_page(struct page *page) static void gcma_free_page(struct page *page) { __gcma_free_page(page); + gcma_stat_dec(CACHED_PAGE); } static inline void gcma_get_page(struct page *page) @@ -473,6 +476,7 @@ static void isolate_gcma_page(struct gcma_inode *inode, struct page *page) page_area_lock(page); reset_gcma_page(page); page_area_unlock(page); + gcma_stat_dec(CACHED_PAGE); } /* @@ -584,6 +588,7 @@ again: xa_unlock(&inode->pages); isolate_gcma_page(inode, page); + gcma_stat_inc(DISCARDED_PAGE); put_gcma_inode(inode); } local_irq_enable(); @@ -708,6 +713,8 @@ static void evict_gcma_lru_pages(unsigned long nr_request) } nr_evicted += isolated; } + + gcma_stat_add(EVICTED_PAGE, nr_evicted); } static void evict_gcma_pages(struct work_struct *work) @@ -804,6 +811,7 @@ copy: else rotate_lru_page(g_page); + gcma_stat_inc(STORED_PAGE); out_unlock: /* * If inode was just created but failed to add gcma page, @@ -849,6 +857,7 @@ static int gcma_cc_load_page(int hash_id, struct cleancache_filekey key, xa_unlock_irq(&inode->pages); put_gcma_inode(inode); + gcma_stat_inc(LOADED_PAGE); return 0; } diff --git a/mm/gcma_sysfs.c b/mm/gcma_sysfs.c new file mode 100644 index 000000000000..a2a83c2c2661 --- /dev/null +++ b/mm/gcma_sysfs.c @@ -0,0 +1,92 @@ +#include +#include +#include "gcma_sysfs.h" + +extern struct kobject *vendor_mm_kobj; +static struct kobject gcma_kobj; + +static atomic64_t gcma_stats[NUM_OF_GCMA_STAT]; + +void gcma_stat_inc(enum gcma_stat_type type) +{ + atomic64_inc(&gcma_stats[type]); +} + +void gcma_stat_dec(enum gcma_stat_type type) +{ + atomic64_dec(&gcma_stats[type]); +} + +void gcma_stat_add(enum gcma_stat_type type, unsigned long delta) +{ + atomic64_add(delta, &gcma_stats[type]); +} + +/* + * This all compiles without CONFIG_SYSFS, but is a waste of space. + */ + +#define GCMA_ATTR_RO(_name) \ + static struct kobj_attribute _name##_attr = __ATTR_RO(_name) + +static ssize_t stored_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&gcma_stats[STORED_PAGE])); +} +GCMA_ATTR_RO(stored); + +static ssize_t loaded_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&gcma_stats[LOADED_PAGE])); +} +GCMA_ATTR_RO(loaded); + +static ssize_t evicted_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&gcma_stats[EVICTED_PAGE])); +} +GCMA_ATTR_RO(evicted); + +static ssize_t cached_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&gcma_stats[CACHED_PAGE])); +} +GCMA_ATTR_RO(cached); + +static ssize_t discarded_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&gcma_stats[DISCARDED_PAGE])); +} +GCMA_ATTR_RO(discarded); + +static struct attribute *gcma_attrs[] = { + &stored_attr.attr, + &loaded_attr.attr, + &evicted_attr.attr, + &cached_attr.attr, + &discarded_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(gcma); + +static void gcma_kobj_release(struct kobject *obj) +{ + /* Never released the static objects */ +} + +static struct kobj_type gcma_ktype = { + .release = gcma_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, + .default_groups = gcma_groups, +}; + +static int __init gcma_sysfs_init(void) +{ + return kobject_init_and_add(&gcma_kobj, &gcma_ktype, mm_kobj, "gcma"); +} +subsys_initcall(gcma_sysfs_init); diff --git a/mm/gcma_sysfs.h b/mm/gcma_sysfs.h new file mode 100644 index 000000000000..161baac9341d --- /dev/null +++ b/mm/gcma_sysfs.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __GCMA_SYSFS_H__ +#define __GCMA_SYSFS_H__ + +enum gcma_stat_type { + STORED_PAGE, + LOADED_PAGE, + EVICTED_PAGE, + CACHED_PAGE, + DISCARDED_PAGE, + NUM_OF_GCMA_STAT, +}; + +#ifdef CONFIG_GCMA_SYSFS +void gcma_stat_inc(enum gcma_stat_type type); +void gcma_stat_dec(enum gcma_stat_type type); +void gcma_stat_add(enum gcma_stat_type type, unsigned long delta); +#else /* CONFIG_GCMA_SYSFS */ +static inline void gcma_stat_inc(enum gcma_stat_type type) {} +static inline void gcma_stat_dec(enum gcma_stat_type type) {} +static inline void gcma_stat_add(enum gcma_stat_type type, + unsigned long delta) {} +#endif /* CONFIG_GCMA_SYSFS */ + +#endif