From 5b4abda8974da8b4262fa14fa558250cf783116b Mon Sep 17 00:00:00 2001 From: Huang Yiwei Date: Thu, 31 Mar 2022 20:20:21 +0800 Subject: [PATCH] soc: qcom: Add snapshot of rq_stats driver This is a snapshot of the rq_stats driver as of msm-5.15 commit <908a517b050d> ("Merge "sched/walt: remove duplicate definitions of rt_task_arrival_time""). Change-Id: I83cc75fe4dcbb843810628825df7ef0d5516b2bb Signed-off-by: Huang Yiwei --- drivers/soc/qcom/Kconfig | 8 +++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rq_stats.c | 139 ++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/soc/qcom/rq_stats.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b482b32fb4d0..69cf5b7719f5 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -136,6 +136,14 @@ config QCOM_RPMPD value to RPM which then translates it into corresponding voltage for the voltage rail. +config QCOM_RUN_QUEUE_STATS + tristate "Enable collection and exporting of QTI Run Queue stats to userspace" + help + This option enables the driver to periodically collecting the statistics + of kernel run queue information and calculate the load of the system. + This information is exported to usespace via sysfs entries and userspace + algorithms uses info and decide when to turn on/off the cpu cores. + config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dd4c37eafa7f..b30d224b0452 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o +obj-$(CONFIG_QCOM_RUN_QUEUE_STATS) += rq_stats.o diff --git a/drivers/soc/qcom/rq_stats.c b/drivers/soc/qcom/rq_stats.c new file mode 100644 index 000000000000..ffb9b2354669 --- /dev/null +++ b/drivers/soc/qcom/rq_stats.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2010-2015, 2017, 2019-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_LONG_SIZE 24 +#define DEFAULT_DEF_TIMER_JIFFIES 5 + +struct rq_data { + unsigned long def_timer_jiffies; + unsigned long def_timer_last_jiffy; + int64_t def_start_time; + struct attribute_group *attr_group; + struct kobject *kobj; + struct work_struct def_timer_work; +}; + +static struct rq_data rq_info; +static struct workqueue_struct *rq_wq; +spinlock_t rq_lock; + +static void wakeup_user(void *ignore, void *extra) +{ + unsigned long jiffy_gap; + + jiffy_gap = jiffies - rq_info.def_timer_last_jiffy; + + if (jiffy_gap >= rq_info.def_timer_jiffies) { + rq_info.def_timer_last_jiffy = jiffies; + queue_work(rq_wq, &rq_info.def_timer_work); + } +} + +static void def_work_fn(struct work_struct *work) +{ + /* Notify polling threads on change of value */ + sysfs_notify(rq_info.kobj, NULL, "def_timer_ms"); +} + +static ssize_t show_def_timer_ms(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int64_t diff; + unsigned int udiff; + + diff = ktime_to_ns(ktime_get()) - rq_info.def_start_time; + do_div(diff, 1000 * 1000); + udiff = (unsigned int) diff; + + return scnprintf(buf, MAX_LONG_SIZE, "%u\n", udiff); +} + +static ssize_t store_def_timer_ms(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int val = 0; + + if (kstrtouint(buf, 0, &val)) + return -EINVAL; + + rq_info.def_timer_jiffies = msecs_to_jiffies(val); + + rq_info.def_start_time = ktime_to_ns(ktime_get()); + + return count; +} + +static struct kobj_attribute def_timer_ms_attr = + __ATTR(def_timer_ms, 0600, show_def_timer_ms, + store_def_timer_ms); + +static struct attribute *rq_attrs[] = { + &def_timer_ms_attr.attr, + NULL, +}; + +static struct attribute_group rq_attr_group = { + .attrs = rq_attrs, +}; + +static int init_rq_attribs(void) +{ + int err; + + rq_info.attr_group = &rq_attr_group; + + /* Create /sys/devices/system/cpu/cpu0/rq-stats/... */ + rq_info.kobj = kobject_create_and_add("rq-stats", + &get_cpu_device(0)->kobj); + if (!rq_info.kobj) + return -ENOMEM; + + err = sysfs_create_group(rq_info.kobj, rq_info.attr_group); + if (err) + kobject_put(rq_info.kobj); + else + kobject_uevent(rq_info.kobj, KOBJ_ADD); + + return err; +} + +static int __init msm_rq_stats_init(void) +{ + int ret; + +#ifndef CONFIG_SMP + /* Bail out if this is not an SMP Target */ + return -EPERM; +#endif + rq_wq = create_singlethread_workqueue("rq_stats"); + WARN_ON(!rq_wq); + INIT_WORK(&rq_info.def_timer_work, def_work_fn); + spin_lock_init(&rq_lock); + rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES; + rq_info.def_timer_last_jiffy = 0; + ret = init_rq_attribs(); + + register_trace_android_vh_jiffies_update(wakeup_user, NULL); + + return ret; +} +late_initcall(msm_rq_stats_init); + +static __exit void msm_rq_stats_exit(void) +{ + destroy_workqueue(rq_wq); + kobject_del(rq_info.kobj); +} +module_exit(msm_rq_stats_exit); + +MODULE_DESCRIPTION("QCOM Run Queue Stats"); +MODULE_LICENSE("GPL v2");