diff --git a/LICENSE b/LICENSE
index fc48fd28904f6680c1da24e70d27c7ffb7a31c16..97c58d4662c37e15a56f149eedfb98c00e604414 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,5 +2,6 @@
./newip/
./xpm/
./qos_auth/
+ ./ucollection/
As for the specific use of the licenses, please refer to the relevant description in the documents.
diff --git a/OAT.xml b/OAT.xml
index 9de7aacb31ad265d296ee9139b08fe3783166732..55a93aaac5d9767f9e9f8ec15add42c0fa350918 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -60,9 +60,11 @@ Note:If the text contains special characters, please escape them according to th
+
+
@@ -81,6 +83,7 @@ Note:If the text contains special characters, please escape them according to th
+
diff --git a/ucollection/Kconfig b/ucollection/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..d60e708a1d6a863f59a97ebb4939953e409c2b4b
--- /dev/null
+++ b/ucollection/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+config UNIFIED_COLLECTION
+ def_bool $(success,$(srctree)/scripts/ohos-check-dir.sh $(srctree)/drivers/staging/ucollection)
+ tristate "Enable unified collection"
+ help
+ unified collection
\ No newline at end of file
diff --git a/ucollection/Makefile b/ucollection/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5d1b45ebc9fd3a1ed5b9ca39a1136acd718b5b30
--- /dev/null
+++ b/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/ucollection/README_zh.md b/ucollection/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..3b94e8e0c81b8bba1374928e72fce54666dce584
--- /dev/null
+++ b/ucollection/README_zh.md
@@ -0,0 +1,32 @@
+## 背景
+当前系统需要获取进程的CPU维测数据,支持开发者性能问题分析,通过遍例所有进程的结点虽然可以获取所有进程的CPU使用率,但是该方法性能相对较差,为了提升获取效率,因此开僻了内核的设备结点,通过结点可能快速获取CPU的数据。
+
+## ucollection(unified collection)模块
+通过ioctl的方式向设备结点/dev/uncollection发送命令,内核根据不同的命令做不同的处理,返回相应的维测数据。
+
+
+## 目录
+统一采集设备的主要代码目录结构如下:
+
+```
+# 代码路径 /kernel/linux/common_modules/xpm
+├── apply_ucollection.sh # XPM 头文件
+├── figures # ReadMe 内嵌图例
+├── Konfig
+├── Makefile
+├── README_zh.md
+├── ucollection_process_cpu.c # 获取进程CPU数据
+├── ucollection_process_cpu.h
+├── unified_collection_data.h
+├── unified_collection_driver.c # 注册/dev/ucollection设备
+```
+
+## 相关仓
+
+[内核子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%86%85%E6%A0%B8%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
+
+[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10)
+
+[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config)
+
+[kernel_linux_build](https://gitee.com/openharmony/kernel_linux_build)
diff --git a/ucollection/apply_ucollection.sh b/ucollection/apply_ucollection.sh
new file mode 100755
index 0000000000000000000000000000000000000000..96af21c461d6d560c0c56c9b498c14cfae4db09e
--- /dev/null
+++ b/ucollection/apply_ucollection.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+#
+# Description: Create a symbolic link for Unified Collection Driver in Linux 5.10
+#
+
+set -e
+
+OHOS_SOURCE_ROOT=$1
+KERNEL_BUILD_ROOT=$2
+PRODUCT_NAME=$3
+KERNEL_VERSION=$4
+UNIFIED_COLLECTION_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/ucollection
+
+function main()
+{
+ pushd .
+
+ echo "create link $KERNEL_BUILD_ROOT/drivers/staging/ucollection/"
+ if [ ! -d "$KERNEL_BUILD_ROOT/drivers/staging/ucollection" ]; then
+ mkdir $KERNEL_BUILD_ROOT/drivers/staging/ucollection
+ fi
+
+ cd $KERNEL_BUILD_ROOT/drivers/staging/ucollection/
+ ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/drivers/staging/ucollection/ $UNIFIED_COLLECTION_SOURCE_ROOT)/* ./
+
+ popd
+}
+
+main
diff --git a/ucollection/figures/collector_framework.png b/ucollection/figures/collector_framework.png
new file mode 100644
index 0000000000000000000000000000000000000000..b56e1ac3d383eaca42505e38f48e7bbe01215ad9
Binary files /dev/null and b/ucollection/figures/collector_framework.png differ
diff --git a/ucollection/ucollection_process_cpu.c b/ucollection/ucollection_process_cpu.c
new file mode 100644
index 0000000000000000000000000000000000000000..bba8422b4e5a3ea8119dcbebf9dea2352a265b43
--- /dev/null
+++ b/ucollection/ucollection_process_cpu.c
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ */
+#include "ucollection_process_cpu.h"
+
+#include
+#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[],
+ 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;
+
+ thread_group_cputime_adjusted(task, &utime, &stime);
+ utime = utime + task->signal->cutime;
+ stime = stime + task->signal->cstime;
+ do_div(utime, NS_TO_MS);
+ do_div(stime, NS_TO_MS);
+ *ut = utime;
+ *st = stime;
+}
+
+static void 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);
+ (void)copy_to_user(&entry->datas[cur_count], &proc_cpu_entry, sizeof(struct ucollection_process_cpu_item));
+}
+
+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));
+ (void)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 bool is_pid_alive(int pid)
+{
+ struct task_struct *task = NULL;
+ task = pid_task(find_vpid(pid), PIDTYPE_PID);
+ if (task == NULL)
+ return false;
+
+ return pid_alive(task);
+}
+
+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));
+ (void)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();
+ if (!is_pid_alive(kentry.filter.pid)) {
+ pr_err("pid=%d is not alive", kentry.filter.pid);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ 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));
+ (void)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/ucollection/ucollection_process_cpu.h b/ucollection/ucollection_process_cpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..09076aa3eea7b4512ccfec2a7f964a1c0fb62e26
--- /dev/null
+++ b/ucollection/ucollection_process_cpu.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ */
+#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/ucollection/unified_collection_data.h b/ucollection/unified_collection_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..ddd2050d3a979e5660b3357d5d25aef493b24684
--- /dev/null
+++ b/ucollection/unified_collection_data.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ */
+#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/ucollection/unified_collection_driver.c b/ucollection/unified_collection_driver.c
new file mode 100644
index 0000000000000000000000000000000000000000..be70a171aaf3de1b46f0793ec75566b1fc70ffc8
--- /dev/null
+++ b/ucollection/unified_collection_driver.c
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ */
+#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