From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4EUVI CVE: NA
-------------------------------------------------
/proc/sys/vm/sharepool_perf_alloc allows us to track the time consuming of sp_alloc.
Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Zhou Guanghui zhouguanghui1@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- include/linux/share_pool.h | 1 + kernel/sysctl.c | 9 +++++++ mm/share_pool.c | 48 +++++++++++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/include/linux/share_pool.h b/include/linux/share_pool.h index fc9f411f7a33c..e118ac1cf15ca 100644 --- a/include/linux/share_pool.h +++ b/include/linux/share_pool.h @@ -45,6 +45,7 @@ extern int sysctl_share_pool_map_lock_enable; extern int sysctl_sp_compact_enable; extern unsigned long sysctl_sp_compact_interval; extern unsigned long sysctl_sp_compact_interval_max; +extern int sysctl_sp_perf_alloc;
#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC extern bool vmap_allow_huge; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c5d4395efd430..165d5ccd384f7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1807,6 +1807,15 @@ static struct ctl_table vm_table[] = { .extra1 = &zero_ul, .extra2 = &sysctl_sp_compact_interval_max, }, + { + .procname = "sharepool_perf_alloc", + .data = &sysctl_sp_perf_alloc, + .maxlen = sizeof(sysctl_sp_perf_alloc), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &ten_thousand, + }, #endif { } }; diff --git a/mm/share_pool.c b/mm/share_pool.c index 9aa65349168cd..716b3ea7c960d 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -48,6 +48,8 @@ #include <linux/preempt.h> #include <linux/swapops.h> #include <linux/mmzone.h> +#include <linux/timekeeping.h> +#include <linux/time64.h>
/* access control mode macros */ #define AC_NONE 0 @@ -68,6 +70,9 @@
#define GROUP_NONE 0
+#define SEC2US(sec) ((sec) * 1000000) +#define NS2US(ns) ((ns) / 1000) + #define PF_DOMAIN_CORE 0x10000000 /* AOS CORE processes in sched.h */
/* mdc scene hack */ @@ -84,6 +89,8 @@ int sysctl_sp_debug_mode;
int sysctl_share_pool_map_lock_enable;
+int sysctl_sp_perf_alloc; + static int share_pool_group_mode = SINGLE_GROUP_MODE;
static int system_group_count; @@ -1955,8 +1962,38 @@ struct sp_alloc_context { unsigned long populate; int state; bool need_fallocate; + struct timespec64 start; + struct timespec64 end; };
+static void trace_sp_alloc_begin(struct sp_alloc_context *ac) +{ + if (!sysctl_sp_perf_alloc) + return; + + ktime_get_ts64(&ac->start); +} + +static void trace_sp_alloc_finish(struct sp_alloc_context *ac, unsigned long va) +{ + unsigned long cost; + bool is_pass_through = ac->spg == spg_none ? true : false; + + if (!sysctl_sp_perf_alloc) + return; + + ktime_get_ts64(&ac->end); + + cost = SEC2US(ac->end.tv_sec - ac->start.tv_sec) + + NS2US(ac->end.tv_nsec - ac->start.tv_nsec); + if (cost >= (unsigned long)sysctl_sp_perf_alloc) { + pr_err("Task %s(%d/%d) sp_alloc returns 0x%lx consumes %luus, size is %luKB, " + "size_aligned is %luKB, sp_flags is %lx, pass through is %d\n", + current->comm, current->tgid, current->pid, + va, cost, byte2kb(ac->size), byte2kb(ac->size_aligned), ac->sp_flags, is_pass_through); + } +} + static int sp_alloc_prepare(unsigned long size, unsigned long sp_flags, int spg_id, struct sp_alloc_context *ac) { @@ -1964,6 +2001,8 @@ static int sp_alloc_prepare(unsigned long size, unsigned long sp_flags,
check_interrupt_context();
+ trace_sp_alloc_begin(ac); + /* mdc scene hack */ if (enable_mdc_default_group) spg_id = mdc_default_group_id; @@ -2210,9 +2249,11 @@ static int sp_alloc_mmap_populate(struct sp_area *spa, return ret; }
-/* spa maybe an error pointer, so introduce param spg */ -static void sp_alloc_finish(int result, struct sp_area *spa, struct sp_group *spg) +/* spa maybe an error pointer, so introduce variable spg */ +static void sp_alloc_finish(int result, struct sp_area *spa, + struct sp_alloc_context *ac) { + struct sp_group *spg = ac->spg; bool is_pass_through = spg == spg_none ? true : false;
/* match sp_alloc_check_prepare */ @@ -2229,6 +2270,7 @@ static void sp_alloc_finish(int result, struct sp_area *spa, struct sp_group *sp if (!is_pass_through) sp_group_drop(spg);
+ trace_sp_alloc_finish(ac, spa->va_start); sp_dump_stack(); sp_try_to_compact(); } @@ -2270,7 +2312,7 @@ void *sp_alloc(unsigned long size, unsigned long sp_flags, int spg_id) goto try_again;
out: - sp_alloc_finish(ret, spa, ac.spg); + sp_alloc_finish(ret, spa, &ac); if (ret) return ERR_PTR(ret); else