From f162870e9fac3f8161854434b82e181f017baf85 Mon Sep 17 00:00:00 2001 From: Lukasz Luba Date: Fri, 29 Jul 2022 15:02:24 +0100 Subject: [PATCH 1/2] lisa._assets.kmodules.sched_tp: Add EM sysfs tree for latest phones Latest Android removed debugfs dir and config. There is a need to expose Energy Model in some other way. Use the kobject and sysfs infrastructure to do that. Signed-off-by: Lukasz Luba (cherry picked from commit d8a8285744d5ecb2d2a72888357d4c6aa2183b84) --- lisa/_assets/kmodules/sched_tp/Makefile | 2 +- lisa/_assets/kmodules/sched_tp/em_sysfs.c | 228 ++++++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 lisa/_assets/kmodules/sched_tp/em_sysfs.c diff --git a/lisa/_assets/kmodules/sched_tp/Makefile b/lisa/_assets/kmodules/sched_tp/Makefile index f9e86319c..a3e5246c3 100644 --- a/lisa/_assets/kmodules/sched_tp/Makefile +++ b/lisa/_assets/kmodules/sched_tp/Makefile @@ -33,7 +33,7 @@ ifneq ($(KERNELRELEASE),) LISA_KMOD_NAME ?= sched_tp obj-m := $(LISA_KMOD_NAME).o -$(LISA_KMOD_NAME)-y := main.o tp.o wq.o features.o pixel6.o +$(LISA_KMOD_NAME)-y := main.o tp.o wq.o features.o pixel6.o em_sysfs.o ldflags-y += -T $(M)/features.lds clean-files := vmlinux.h diff --git a/lisa/_assets/kmodules/sched_tp/em_sysfs.c b/lisa/_assets/kmodules/sched_tp/em_sysfs.c new file mode 100644 index 000000000..889881047 --- /dev/null +++ b/lisa/_assets/kmodules/sched_tp/em_sysfs.c @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "features.h" +#include "wq.h" +#include "ftrace_events.h" + + +struct em_ps_info { + struct em_perf_state *ps; + struct attribute attr; +}; + +struct em_ps_group { + struct kobject kobj; + struct em_ps_info psi[4]; +}; + +struct em_info { + struct kobject *kobj; + struct em_perf_domain *em; + struct em_ps_group *psg; + int num_psg; +}; + +static ssize_t em_ps_show(struct kobject *kobj, struct attribute *attr, + char *buffer); +static void em_sysfs_kobj_release(struct kobject *kobj); + +static struct kobject *em_main_kobj; +static struct em_info em_info[5]; +static int em_id; +static DEFINE_MUTEX(em_lock); + +static const struct sysfs_ops em_sysfs_ops = { + .show = em_ps_show, +}; + +static struct kobj_type em_sysfs_kobj_type = { + .sysfs_ops = &em_sysfs_ops, + .release = em_sysfs_kobj_release, +}; + +static void em_sysfs_kobj_release(struct kobject *kobj) +{ + /* Nothing to do here, but print for checks */ + pr_info("EM_INFO: kobj put %s\n", kobj->name); +} + +static ssize_t em_ps_show(struct kobject *kobj, struct attribute *attr, char *buffer) +{ + struct em_ps_info *psi = container_of(attr, struct em_ps_info, attr); + struct em_perf_state *ps = psi->ps; + int ret = -EINVAL; + + mutex_lock(&em_lock); + if (!strcmp(attr->name, "frequency")) + ret = snprintf(buffer, PAGE_SIZE, "%lu\n", ps->frequency); + else if (!strcmp(attr->name, "power")) + ret = snprintf(buffer, PAGE_SIZE, "%lu\n", ps->power); + else if (!strcmp(attr->name, "cost")) + ret = snprintf(buffer, PAGE_SIZE, "%lu\n", ps->cost); + else if (!strcmp(attr->name, "flags")) + ret = snprintf(buffer, PAGE_SIZE, "%lu\n", ps->flags); + else + pr_err("EMI_INFO: Invalid attribute"); + + mutex_unlock(&em_lock); + return ret; +} + +static void em_sysfs_create_file(struct kobject *kobj, struct attribute *attr, + char *name) +{ + int ret; + + if (!kobj || !attr || !name) + return; + + attr->name = name; + attr->mode = 0644; + sysfs_attr_init(attr); + + ret = sysfs_create_file(kobj, attr); + if (ret) + pr_warn("EM_INFO: Creating %s/%s failed %d\n", + kobj->name, name, ret); + else + pr_info("EM_INFO: Created %s/%s\n", kobj->name, name); +} + +static int em_create_ps(struct em_ps_group *psg, + struct em_perf_state *ps, struct kobject *kobj) +{ + struct kobject *kobj_ps; + char name[24]; + int ret; + + snprintf(name, sizeof(name), "ps:%lu", ps->frequency); + + kobj_ps = &psg->kobj; + + ret = kobject_init_and_add(kobj_ps, &em_sysfs_kobj_type, + kobj, name); + if (ret) { + pr_warn("EM_INFO: Creating %s/%s failed %d\n", + kobj->name, name, ret); + return ret; + } else { + pr_info("EM_INFO: Created %s/%s\n", kobj->name, kobj_ps->name); + } + + psg->psi[0].ps = ps; + psg->psi[1].ps = ps; + psg->psi[2].ps = ps; + psg->psi[3].ps = ps; + + em_sysfs_create_file(kobj_ps, &psg->psi[0].attr, "frequency"); + em_sysfs_create_file(kobj_ps, &psg->psi[1].attr, "power"); + em_sysfs_create_file(kobj_ps, &psg->psi[2].attr, "cost"); + em_sysfs_create_file(kobj_ps, &psg->psi[3].attr, "flags"); + + return 0; +} + +static int em_create_ps_files(struct em_perf_domain *em, + struct kobject *kobj) +{ + struct em_info *emi; + int i, ret; + + mutex_lock(&em_lock); + + emi = &em_info[em_id++]; + emi->em = em; + emi->num_psg = em->nr_perf_states; + emi->kobj = kobj; + + emi->psg = kcalloc(emi->num_psg, sizeof(*emi->psg), GFP_KERNEL); + if (!emi->psg) { + mutex_unlock(&em_lock); + return -ENOMEM; + } + + for (i = 0; i < em->nr_perf_states; i++) { + ret = em_create_ps(&emi->psg[i], &em->table[i], kobj); + if (ret) { + mutex_unlock(&em_lock); + return ret; + } + } + + mutex_unlock(&em_lock); + + return 0; +} + +static int init_em_sysfs(struct feature *_) +{ + struct em_perf_domain *em; + struct cpumask *cpus; + struct kobject *kobj; + struct device *dev; + int cpu; + + pr_info("EM sysfs init\n"); + + em_main_kobj = kobject_create_and_add("energy_model", kernel_kobj); + if (!em_main_kobj) + return -ENOMEM; + + for_each_possible_cpu(cpu) { + em = em_cpu_get(cpu); + cpus = em_span_cpus(em); + + if (cpumask_first(cpus) != cpu) + continue; + + dev = get_cpu_device(cpu); + kobj = kobject_create_and_add(dev_name(dev), em_main_kobj); + if (!kobj) + return -ENOMEM; + + pr_info("EM_INFO: creating for cpu%d\n", cpu); + em_create_ps_files(em, kobj); + } + + return 0; +} + +static int deinit_em_sysfs(struct feature *_) +{ + struct em_info *emi; + int i, j; + + pr_info("EM sysfs exit\n"); + + mutex_lock(&em_lock); + + for (i = 0; i < em_id; i++) { + emi = &em_info[i]; + + for (j = 0; j < emi->num_psg; j++) { + struct em_ps_group *psg = &emi->psg[j]; + + kobject_put(&psg->kobj); + } + kobject_put(emi->kobj); + } + + kobject_put(em_main_kobj); + + for (i = 0; i < em_id; i++) { + kfree(em_info[i].psg); + } + + mutex_unlock(&em_lock); + return 0; +} + +DEFINE_FEATURE(__em_sysfs, init_em_sysfs, deinit_em_sysfs); -- GitLab From f6452b80bda964253b310adad4da67f480ba01d1 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Thu, 4 Aug 2022 16:55:10 +0100 Subject: [PATCH 2/2] lisa._assets.kmodules.sched_tp: Add cpus to EM sysfs tree Latest Android removed debugfs dir and config. There is a need to expose Energy Model in some other way. Building on Lukasz's commit adding the necessary tree and ps directories, this commit also includes the 'cpus' files that were missing previously. This makes the resulting sysfs hierarchy under /sys/kernel/energy_model conform to what Lisa is expecting and prevents Lisa errors. Signed-off-by: Kajetan Puchalski --- lisa/_assets/kmodules/sched_tp/em_sysfs.c | 49 +++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lisa/_assets/kmodules/sched_tp/em_sysfs.c b/lisa/_assets/kmodules/sched_tp/em_sysfs.c index 889881047..c08f440a0 100644 --- a/lisa/_assets/kmodules/sched_tp/em_sysfs.c +++ b/lisa/_assets/kmodules/sched_tp/em_sysfs.c @@ -6,12 +6,18 @@ #include #include #include +#include +#include #include "main.h" #include "features.h" #include "wq.h" #include "ftrace_events.h" +struct em_cpus_info { + struct cpumask *cpus; + struct kobj_attribute attr; +}; struct em_ps_info { struct em_perf_state *ps; @@ -27,6 +33,7 @@ struct em_info { struct kobject *kobj; struct em_perf_domain *em; struct em_ps_group *psg; + struct em_cpus_info *cpui; int num_psg; }; @@ -96,6 +103,46 @@ static void em_sysfs_create_file(struct kobject *kobj, struct attribute *attr, pr_info("EM_INFO: Created %s/%s\n", kobj->name, name); } +static ssize_t em_cpus_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct em_cpus_info *cpui = container_of(attr, struct em_cpus_info, attr); + + int ret = -EINVAL; + ret = snprintf(buf, PAGE_SIZE, "%*pbl\n", cpumask_pr_args(cpui->cpus)); + return ret; +} + +static int em_create_cpus(struct cpumask *cpus, struct kobject *kobj) { + int ret; + struct em_info *emi; + mutex_lock(&em_lock); + + emi = &em_info[em_id]; + emi->cpui = kmalloc(sizeof(*emi->cpui), GFP_KERNEL); + if (!emi->cpui) { + mutex_unlock(&em_lock); + return -ENOMEM; + } + + emi->cpui->cpus = cpus; + emi->cpui->attr.attr.name = "cpus"; + emi->cpui->attr.attr.mode = 0644; + sysfs_attr_init(emi->cpui->attr.attr); + emi->cpui->attr.show = em_cpus_show; + + ret = sysfs_create_file(kobj, &emi->cpui->attr.attr); + if (ret) + pr_warn("EM_INFO: Creating %s/%s failed %d\n", + kobj->name, "cpus", ret); + else + pr_info("EM_INFO: Created %s/%s\n", kobj->name, "cpus"); + + mutex_unlock(&em_lock); + + return 0; +} + static int em_create_ps(struct em_ps_group *psg, struct em_perf_state *ps, struct kobject *kobj) { @@ -189,6 +236,7 @@ static int init_em_sysfs(struct feature *_) return -ENOMEM; pr_info("EM_INFO: creating for cpu%d\n", cpu); + em_create_cpus(cpus, kobj); em_create_ps_files(em, kobj); } @@ -219,6 +267,7 @@ static int deinit_em_sysfs(struct feature *_) for (i = 0; i < em_id; i++) { kfree(em_info[i].psg); + kfree(em_info[i].cpui); } mutex_unlock(&em_lock); -- GitLab