!45 [新需求]:【master】增加采集所有进程的CPU使用率设备结点(统一采集设备驱动)

Merge pull request !45 from 周海锋/master
This commit is contained in:
openharmony_ci
2023-09-22 14:16:42 +00:00
committed by Gitee
11 changed files with 416 additions and 0 deletions
+1
View File
@@ -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.
+3
View File
@@ -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>
+6
View File
@@ -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
+3
View File
@@ -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
+32
View File
@@ -0,0 +1,32 @@
## 背景
当前系统需要获取进程的CPU维测数据,支持开发者性能问题分析,通过遍例所有进程的结点虽然可以获取所有进程的CPU使用率,但是该方法性能相对较差,为了提升获取效率,因此开僻了内核的设备结点,通过结点可能快速获取CPU的数据。
## ucollection(unified collection)模块
通过ioctl的方式向设备结点/dev/uncollection发送命令,内核根据不同的命令做不同的处理,返回相应的维测数据。
![framework](figures/collector_framework.png)
## 目录
统一采集设备的主要代码目录结构如下:
```
# 代码路径 /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)
+31
View File
@@ -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

+194
View File
@@ -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;
}
+9
View File
@@ -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__
+47
View File
@@ -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__
+90
View File
@@ -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");