diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 6efe436abd9bd1b5cbfd4d86a87e942b8a018a42..51fb00602a14358cfcb204dfb400041d9c42ebcb 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -130,4 +130,5 @@ source "drivers/staging/hungtask/Kconfig" source "drivers/staging/blackbox/Kconfig" +source "drivers/staging/ucollection/Kconfig" endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 9dacda71f751d353c3bfa2b969ab44ce14595d9d..a8824bb550b44cd9352fd1da713252525d3b078d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_HISYSEVENT) += hisysevent/ obj-$(CONFIG_DFX_ZEROHUNG) += zerohung/ obj-$(CONFIG_DFX_HUNGTASK) += hungtask/ obj-$(CONFIG_BLACKBOX) += blackbox/ +obj-$(CONFIG_UNIFIED_COLLECTION) += ucollection/ diff --git a/drivers/staging/ucollection/Kconfig b/drivers/staging/ucollection/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..c356bbea11f5152555f18a5137bdaec1357797a6 --- /dev/null +++ b/drivers/staging/ucollection/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +config UNIFIED_COLLECTION + tristate "Enable unified collection" + help + unified collection \ No newline at end of file diff --git a/drivers/staging/ucollection/Makefile b/drivers/staging/ucollection/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d1b45ebc9fd3a1ed5b9ca39a1136acd718b5b30 --- /dev/null +++ b/drivers/staging/ucollection/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_UNIFIED_COLLECTION) += ucollection_process_cpu.o +obj-$(CONFIG_UNIFIED_COLLECTION) += unified_collection_driver.o \ No newline at end of file diff --git a/drivers/staging/ucollection/ucollection_process_cpu.c b/drivers/staging/ucollection/ucollection_process_cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..cf66816ccc90f6b1920c4ba7a894766ceaa52ecf --- /dev/null +++ b/drivers/staging/ucollection/ucollection_process_cpu.c @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Huawei Technologies Co., Ltd. All rights reserved. + */ +#include "ucollection_process_cpu.h" + +#ifdef CONFIG_CPU_FREQ_TIMES +#include +#endif // CONFIG_CPU_FREQ_TIMES +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +#include +#include +#include +#endif // LINUX_VERSION_CODE +#ifdef CONFIG_SMT_MODE_GOV +#include +#endif // CONFIG_SMT_MODE_GOV + +#include "unified_collection_data.h" + +#define NS_TO_MS 1000000 +static char dmips_values[DMIPS_NUM]; + +unsigned long long __attribute__((weak)) +get_proc_cpu_load(struct task_struct *task, char dmips_values[], unsigned int dmips_num) +{ + return 0; +} + +static int get_cpu_num(void) +{ + int core_num = 0; + int i = 0; + for_each_possible_cpu(i) + core_num++; + return core_num; +} + +static unsigned long long get_process_load_cputime(struct task_struct *task) +{ + unsigned long long proc_load_cputime = 0; + proc_load_cputime = get_proc_cpu_load(task, dmips_values, DMIPS_NUM); + return proc_load_cputime; +} + +static void get_process_usage_cputime(struct task_struct *task, unsigned long long *ut, unsigned long long *st) +{ + unsigned long long utime, stime, sum_time; + + thread_group_cputime_adjusted(task, &utime, &stime); + utime = utime + task->signal->cutime; + stime = stime + task->signal->cstime; + *ut = (unsigned long long)(utime / NS_TO_MS); + *st = (unsigned long long)(stime / NS_TO_MS); +} + +static int get_process_load(struct task_struct *task, int cpu_num, int cur_count, struct ucollection_process_cpu_entry __user *entry) +{ + struct ucollection_process_cpu_item proc_cpu_entry; + memset(&proc_cpu_entry, 0, sizeof(struct ucollection_process_cpu_item)); + proc_cpu_entry.pid = task->pid; + proc_cpu_entry.cpu_load_time = get_process_load_cputime(task); + get_process_usage_cputime(task, &proc_cpu_entry.cpu_usage_utime, &proc_cpu_entry.cpu_usage_stime); + copy_to_user(&entry->datas[cur_count], &proc_cpu_entry, sizeof(struct ucollection_process_cpu_item)); + return 0; +} + +static long ioctrl_collect_process_cpu(void __user *argp) +{ + int cpu_num = 0; + struct task_struct *task = NULL; + struct ucollection_process_cpu_entry kentry; + struct ucollection_process_cpu_entry __user *entry = argp; + if (entry == NULL) { + pr_err("cpu entry is null"); + return -EINVAL; + } + + memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); + copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); + + cpu_num = get_cpu_num(); + rcu_read_lock(); + task = &init_task; + for_each_process(task) { + if (task->pid != task->tgid) + continue; + + if (kentry.cur_count >= kentry.total_count) { + pr_err("process over total count"); + break; + } + + get_process_load(task, cpu_num, kentry.cur_count, entry); + kentry.cur_count++; + } + put_user(kentry.cur_count, &entry->cur_count); + rcu_read_unlock(); + return 0; +} + +static long ioctrl_collect_the_process_cpu(void __user *argp) +{ + int cpu_num = 0; + struct task_struct *task = NULL; + struct ucollection_process_cpu_entry kentry; + struct ucollection_process_cpu_entry __user *entry = argp; + if (entry == NULL) { + pr_err("cpu entry is null"); + return -EINVAL; + } + + memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); + copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); + + if (kentry.cur_count >= kentry.total_count) { + pr_err("current count over total count"); + return -EINVAL; + } + + rcu_read_lock(); + task = find_task_by_vpid(kentry.filter.pid); + if (task == NULL) { + pr_err("can not get pid=%d", task->pid); + rcu_read_unlock(); + return -EINVAL; + } + + cpu_num = get_cpu_num(); + get_process_load(task, cpu_num, kentry.cur_count, entry); + kentry.cur_count++; + put_user(kentry.cur_count, &entry->cur_count); + rcu_read_unlock(); + return 0; +} + +static long ioctrl_set_cpu_dmips(void __user *argp) +{ + int i; + struct ucollection_cpu_dmips kentry; + struct ucollection_cpu_dmips __user *entry = argp; + memset(&kentry, 0, sizeof(struct ucollection_cpu_dmips)); + copy_from_user(&kentry, entry, sizeof(struct ucollection_cpu_dmips)); + pr_info("set dimps %d cpus\n", kentry.total_count); + for (i = 0; i < DMIPS_NUM; i++) { + if (i >= kentry.total_count) + break; + get_user(dmips_values[i], &entry->dmips[i]); + pr_info("set dimps cpu[%d]=%d\n", i, dmips_values[i]); + } + return 0; +} + +long unified_collection_collect_process_cpu(unsigned int cmd, void __user *argp) +{ + long ret = 0; + switch(cmd) { + case IOCTRL_COLLECT_ALL_PROC_CPU: + ret = ioctrl_collect_process_cpu(argp); + break; + case IOCTRL_COLLECT_THE_PROC_CPU: + ret = ioctrl_collect_the_process_cpu(argp); + break; + case IOCTRL_SET_CPU_DMIPS: + ret = ioctrl_set_cpu_dmips(argp); + break; + default: + pr_err("handle ioctrl cmd %u, _IOC_TYPE(cmd)=%d", cmd, _IOC_TYPE(cmd)); + ret = 0; + } + return ret; +} \ No newline at end of file diff --git a/drivers/staging/ucollection/ucollection_process_cpu.h b/drivers/staging/ucollection/ucollection_process_cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..69bb25bf3c689a63f3de1384484dbe98309115bf --- /dev/null +++ b/drivers/staging/ucollection/ucollection_process_cpu.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Huawei Technologies Co., Ltd. All rights reserved. + */ +#ifndef __UCOLLECTION_PROCESS_CPU__ +#define __UCOLLECTION_PROCESS_CPU__ + +long unified_collection_collect_process_cpu(unsigned int cmd, void __user *argp); +#endif // __UCOLLECTION_PROCESS_CPU__ diff --git a/drivers/staging/ucollection/unified_collection_data.h b/drivers/staging/ucollection/unified_collection_data.h new file mode 100644 index 0000000000000000000000000000000000000000..c9fe49e75f1bf4be80a323c619df9b8c36355d1a --- /dev/null +++ b/drivers/staging/ucollection/unified_collection_data.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Huawei Technologies Co., Ltd. All rights reserved. + */ +#ifndef __UNIFIED_COLLECTION_DATA__ +#define __UNIFIED_COLLECTION_DATA__ + +#include + +// kernel struct, modify at the same time +struct ucollection_process_cpu_item { + int pid; + unsigned long long cpu_usage_utime; + unsigned long long cpu_usage_stime; + unsigned long long cpu_load_time; +}; + +struct ucollection_process_filter { + int uid; + int pid; + int tid; +}; + +struct ucollection_process_cpu_entry { + int magic; + int total_count; + int cur_count; + struct ucollection_process_filter filter; + struct ucollection_process_cpu_item datas[]; +}; + +struct ucollection_cpu_dmips { + int magic; + int total_count; + char dmips[]; +}; + +#define IOCTRL_COLLECT_ALL_PROC_CPU_MAGIC 1 +#define IOCTRL_COLLECT_THE_PROC_CPU_MAGIC 1 +#define IOCTRL_SET_CPU_DMIPS_MAGIC 1 +#define DMIPS_NUM 128 + +#define IOCTRL_COLLECT_CPU_BASE 0 +#define IOCTRL_COLLECT_ALL_PROC_CPU _IOR(IOCTRL_COLLECT_CPU_BASE, 1, struct ucollection_process_cpu_entry) +#define IOCTRL_COLLECT_THE_PROC_CPU _IOR(IOCTRL_COLLECT_CPU_BASE, 2, struct ucollection_process_cpu_entry) +#define IOCTRL_SET_CPU_DMIPS _IOW(IOCTRL_COLLECT_CPU_BASE, 3, struct ucollection_cpu_dmips) +#endif // __UNIFIED_COLLECTION_DATA__ \ No newline at end of file diff --git a/drivers/staging/ucollection/unified_collection_driver.c b/drivers/staging/ucollection/unified_collection_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..dc084724753c1cd60e242ef6f25f381540cc001d --- /dev/null +++ b/drivers/staging/ucollection/unified_collection_driver.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Huawei Technologies Co., Ltd. All rights reserved. + */ +#include +#include +#include +#include + +#ifdef CONFIG_COMPAT +#include +#endif // CONFIG_COMPAT + +#include "ucollection_process_cpu.h" + +static long (*unified_collection_ioctl_cb[])(unsigned int cmd, void __user *argp) = { + unified_collection_collect_process_cpu /* IOCTRL_COLLECT_CPU */ +}; + +static long unified_collection_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + void __user *argp = u64_to_user_ptr(arg); + const char *comm = NULL; + + if ((_IOC_TYPE(cmd) >= ARRAY_SIZE(unified_collection_ioctl_cb)) || + (unified_collection_ioctl_cb[_IOC_TYPE(cmd)] == NULL)) { + pr_err("invalid ioctrl cmd %u, _IOC_TYPE(cmd)=%d", cmd, _IOC_TYPE(cmd)); + return -EINVAL; + } + + return unified_collection_ioctl_cb[_IOC_TYPE(cmd)](cmd, argp); +} + +#ifdef CONFIG_COMPAT +static long unified_collection_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return unified_collection_ioctl(filp, cmd, (unsigned long) compat_ptr(arg)); +} +#endif // CONFIG_COMPAT + +static int unified_collection_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int unified_collection_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static const struct file_operations unified_collection_device_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = unified_collection_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unified_collection_compat_ioctl, +#endif // CONFIG_COMPAT + .open = unified_collection_open, + .release = unified_collection_release, +}; + +static struct miscdevice unified_collection_device = { + .name = "ucollection", + .fops = &unified_collection_device_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int __init unified_collection_init(void) +{ + int ret = misc_register(&unified_collection_device); + if (ret) { + pr_err("failed to register unified collection device"); + return ret; + } + + pr_info("register unified collection device successful"); + return 0; +} + +static void __exit unified_collection_exit(void) +{ + pr_info("deregister unified collection device successful"); + misc_deregister(&unified_collection_device); +} + +module_init(unified_collection_init); +module_exit(unified_collection_exit); + +MODULE_AUTHOR("OHOS"); +MODULE_DESCRIPTION("Unified Collection Driver"); +MODULE_LICENSE("GPL"); \ No newline at end of file