tegrakernel/kernel/kernel-4.9/drivers/misc/cpuload.c

149 lines
3.4 KiB
C

/*
* drivers/misc/cpuload.c
*
* Copyright (c) 2012-2016, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/tick.h>
#include <asm/cputime.h>
static unsigned int enabled;
/* Consider IO as busy */
static unsigned long io_is_busy_value;
static inline cputime64_t get_cpu_iowait_time(
unsigned int cpu, cputime64_t *wall)
{
u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
if (iowait_time == -1ULL)
return 0;
return iowait_time;
}
static ssize_t show_io_is_busy(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", io_is_busy_value);
}
static ssize_t store_io_is_busy(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int ret;
unsigned long val;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
io_is_busy_value = val;
return count;
}
define_one_global_rw(io_is_busy);
static ssize_t show_cpus_online(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int i, t;
const cpumask_t *cpus = cpu_online_mask;
i = 0;
for_each_cpu(t, cpus)
i++;
return sprintf(buf, "%u\n", i);
}
define_one_global_ro(cpus_online);
static ssize_t show_cpu_usage(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int t, len, total = 0;
const cpumask_t *cpus = cpu_online_mask;
for_each_cpu(t, cpus) {
/* XXX: Remove the hardcoded 0 once readers are updated */
len = sprintf(buf, "%u %u %llu %llu %llu\n",
t, 0,
ktime_to_us(ktime_get()),
get_cpu_idle_time_us(t, NULL),
get_cpu_iowait_time_us(t, NULL));
total += len;
buf = &buf[len];
}
return total;
}
define_one_global_ro(cpu_usage);
static ssize_t show_enable(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", enabled);
}
/* XXX: Remove the now dummy enable variable once readers are updated */
static ssize_t store_enable(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int ret;
unsigned long val;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
enabled = !!val; /* normalize user input */
return count;
}
define_one_global_rw(enable);
static struct attribute *cpuload_attributes[] = {
&io_is_busy.attr,
&cpus_online.attr,
&cpu_usage.attr,
&enable.attr,
NULL,
};
static struct attribute_group cpuload_attr_group = {
.attrs = cpuload_attributes,
.name = "cpuload",
};
static int __init cpuload_monitor_init(void)
{
/* XXX: Move this node into a different syfs path */
return sysfs_create_group(cpufreq_global_kobject,
&cpuload_attr_group);
}
module_init(cpuload_monitor_init);
static void __exit cpuload_monitor_exit(void)
{
sysfs_remove_group(cpufreq_global_kobject,
&cpuload_attr_group);
}
module_exit(cpuload_monitor_exit);
MODULE_AUTHOR("Ilan Aelion <iaelion@nvidia.com>");
MODULE_DESCRIPTION("'cpuload_monitor' - A cpu load monitor");
MODULE_LICENSE("GPL");