Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b666a7e4 authored by Elliot Berman's avatar Elliot Berman
Browse files

time: Add rq_stats snapshot



Add snapshot of runqueue stats module as of commit <e56fe938419e>
(Merge "uapi: Introduce V4L2_FLAG_CVPMETADATA_SKIP flag").

Added #ifdefery to allow rq_stats to actually be optional.

Change-Id: I3352a472c5b0ad61cc04317a1d6f26549bfcdc04
Signed-off-by: default avatarElliot Berman <eberman@codeaurora.org>
parent 5b1b65d0
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -282,6 +282,14 @@ config QCOM_RPMHPD
	  value to RPMh which then translates it into corresponding voltage
	  for the voltage rail.

config QCOM_RUN_QUEUE_STATS
       bool "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_RPMPD
	bool "Qualcomm RPM Power domain driver"
	depends on QCOM_SMD_RPM=y
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o
obj-$(CONFIG_QCOM_SOCINFO)	+= socinfo.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_IPCC) += qcom_ipcc.o
obj-$(CONFIG_QCOM_RUN_QUEUE_STATS) += rq_stats.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
obj-$(CONFIG_QCOM_LAHAINA_LLCC) += llcc-lahaina.o
+108 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2010-2015, 2017, 2019, The Linux Foundation. All rights reserved.
 */

#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/rq_stats.h>

#define MAX_LONG_SIZE 24
#define DEFAULT_DEF_TIMER_JIFFIES 5

struct rq_data rq_info;
struct workqueue_struct *rq_wq;
spinlock_t rq_lock;

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 snprintf(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 */
	rq_info.init = 0;
	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();

	rq_info.init = 1;

	return ret;
}
late_initcall(msm_rq_stats_init);
+22 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2011,2013-2014,2019, The Linux Foundation. All rights reserved.
 */

#ifdef CONFIG_QCOM_RUN_QUEUE_STATS

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;
	int init;
};

extern struct rq_data rq_info;
extern struct workqueue_struct *rq_wq;
extern spinlock_t rq_lock;

#endif
+24 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/irq_work.h>
#include <linux/posix-timers.h>
#include <linux/rq_stats.h>
#include <linux/timer.h>
#include <linux/context_tracking.h>
#include <linux/mm.h>
@@ -1284,6 +1285,18 @@ void tick_irq_enter(void)
 * High resolution timer specific code
 */
#ifdef CONFIG_HIGH_RES_TIMERS
#ifdef CONFIG_QCOM_RUN_QUEUE_STATS
static void wakeup_user(void)
{
	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);
	}
}
#endif
/*
 * We rearm the timer until we get disabled by the idle code.
 * Called with interrupts disabled.
@@ -1301,8 +1314,18 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
	 * Do not call, when we are not in irq context and have
	 * no valid regs pointer
	 */
	if (regs)
	if (regs) {
		tick_sched_handle(ts, regs);
#ifdef CONFIG_QCOM_RUN_QUEUE_STATS
		if (rq_info.init == 1 &&
				tick_do_timer_cpu == smp_processor_id()) {
			/*
			 * wakeup user if needed
			 */
			wakeup_user();
		}
#endif
	}
	else
		ts->next_tick = 0;