mirror of
https://github.com/openharmony/kernel_linux_common_modules.git
synced 2026-08-27 01:31:36 -04:00
add unified collection driver
Signed-off-by: zhouhaifeng <kutcher.zhou@huawei.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -60,9 +60,11 @@ Note:If the text contains special characters, please escape them according to th
|
||||
<policyitem type="compatibility" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="compatibility" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="compatibility" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="compatibility" name="GPL" path="ucollection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="license" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="license" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="license" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
<policyitem type="license" name="GPL" path="ucollection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
</policy>
|
||||
</policylist>
|
||||
<filefilterlist>
|
||||
@@ -81,6 +83,7 @@ Note:If the text contains special characters, please escape them according to th
|
||||
<filteritem type="filepath" name="newip/figures/.*"/>
|
||||
<filteritem type="filepath" name="xpm/figures/.*"/>
|
||||
<filteritem type="filepath" name="qos_auth/figures/.*"/>
|
||||
<filteritem type="filepath" name="ucollection/figures/.*"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
Executable
+31
@@ -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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,194 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include "ucollection_process_cpu.h"
|
||||
|
||||
#include <asm/div64.h>
|
||||
#ifdef CONFIG_CPU_FREQ_TIMES
|
||||
#include <linux/cpufreq_times.h>
|
||||
#endif // CONFIG_CPU_FREQ_TIMES
|
||||
#include <linux/sched/stat.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/uaccess.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/cputime.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#endif // LINUX_VERSION_CODE
|
||||
#ifdef CONFIG_SMT_MODE_GOV
|
||||
#include <platform_include/cee/linux/time_in_state.h>
|
||||
#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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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 <linux/ioctl.h>
|
||||
|
||||
// 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__
|
||||
@@ -0,0 +1,90 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <linux/compat.h>
|
||||
#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");
|
||||
Reference in New Issue
Block a user