Linux进程调度响应时间测试方法
目录Linux进程调度响应时间测试方法Linux进程调度响应时间测试方法环境:虚拟机Ubuntu18.04内核版本:5.6.19参考:linux内核添加模块
·
Linux进程调度响应时间测试方法
最好准备两个不同的内核版本,我们对目标版本操作时,可以先重启进入另一个版本,以免出现问题。
- 环境:虚拟机Ubuntu18.04
- 目标内核版本:5.6.19
- 参考:
1 修改内核代码
测试原理是计算进程就绪后加入到就绪队列(enqueue_task()函数),到该进程开始运行的时间差。
- 打开
include/linux/sched.h
,在task_struct结构体定义中,添加以下代码:
u64 enqueue_time;
enqueue_time记录进入就绪队列的时刻。
注意,不能添加到定义的最前和最后面,我加在了stime定义的后面。
- 打开
kernel/sched/core.c
,添加以下两行头文件:
#include <linux/time.h>
#include <linux/timekeeping.h>
- 同一文件内再找到enqueue_task()函数定义,插入以下代码(插入位置我觉得都可以,我放在了倒数第二有效行):
p->enqueue_time = (u64)ktime_get();
- 重新编译安装:
sudo make -j8
sudo make modules_install
sudo make install
- 重启进入目标内核版本。
2 动态添加内核模块
- 在内核代码目录
/home/linux/linux-5.6.19/drivers/
中创建linux_test
文件夹。 - 在
linux_test
文件夹中创建test.c
文件:
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/pid.h>
#include <linux/time.h>
#include <linux/timekeeping.h>
MODULE_LICENSE("GPL");
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
static struct task_struct *task = NULL;
int my_kernel_thread(void *arg)
{
struct sched_param param;
u64 etime,use_time;
u64 count=0,sum=0,max_time=0;
//struct pid * kpid=find_get_pid(current->pid);//获取当前进程的描述符信息
//struct task_struct * task=pid_task(kpid, PIDTYPE_PID); //获取进程的任务描述符信息
param.sched_priority = 99; //设置字段sched_priority的值
sched_setscheduler(task, SCHED_RR, ¶m); //调用函数改变进程的调度策略
while(1){
if(kthread_should_stop())break;
etime = task->enqueue_time;
if(etime && count<1000){
use_time = (u64)ktime_get() - etime;
//printk("use_time is:%llu\n", now_time - etime);
task->enqueue_time = 0;
++count;
sum += use_time;
if(max_time < use_time){
max_time = use_time;
}
}
ssleep(0.01);
}
printk("count is:%llu\n", count);
printk("avg_use_time is:%llu\n", sum/count);
printk("max_use_time is:%llu\n", max_time);
return 0;
}
static int __init test_init(void)
{
printk("into test_init.\n");
task = kthread_run(my_kernel_thread,NULL,"test task"); //创建新进程
//struct pid * kpid=find_get_pid(result/*current->pid*/); //获取当前进程的描述符信息
//struct task_struct * task=pid_task(kpid, PIDTYPE_PID); //获取进程的任务描述符信息
//printk("the state of the task is:%d\n", task->state); //显示任务当前所处的状态
//printk("the pid of the task is:%d\n", task->pid); //显示任务的进程号
//printk("the tgid of the task is:%d\n", task->tgid); //显示任务的线程组号
//printk("the pid of current thread is:%d\n", current->pid); //显示当前进程的进程号
printk("out test_init.\n");
return 0;
}
static void __exit test_exit(void)
{
if(task){
kthread_stop(task);
task = NULL;
}
printk("test exit!\n");
}
module_init(test_init);
module_exit(test_exit);
- 新创建的线程中,每次循环开始都会先判定task->enqueue_time的值:若为0,则表示距离上一次循环,线程一直在运行没有挂起,不计入响应时间;若不为0,则表示距离上一次循环,线程有挂起过,可以计入响应时间,且要将enqueue_time置0。
- 循环体每执行一次都会挂起0.01秒,有效循环共1000次,也就是计算1000次响应时间的平均值和最大值。
- 同目录创建
Makefile
:
obj-m := test.o
- 同目录执行以下命令编译:
make -C /home/linux/linux-5.6.19 M=/home/linux/linux-5.6.19/drivers/linux_test/ modules
- 同目录执行以下命令安装插入模块:
sudo insmod test.ko
- 等待大约10秒,同目录执行以下命令删除模块:
sudo rmmod test.ko
- 同目录执行以下命令查看输出:
sudo dmesg
(或 sudo dmesg | tail -10)
- 结果如下,时间单位纳秒ns:
$ sudo dmesg | tail -10
[ 2877.339786] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[ 2877.340443] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
[ 4072.016473] test: loading out-of-tree module taints kernel.
[ 4072.016566] test: module verification failed: signature and/or required key missing - tainting kernel
[ 4072.017088] into test_init.
[ 4072.019076] out test_init.
[ 4091.297209] count is:1000
[ 4091.297210] avg_use_time is:15679
[ 4091.297210] max_use_time is:275061
[ 4091.297224] test exit!
注意,若修改模块,再次插入需要先删除原模块。
更多推荐
已为社区贡献10条内容
所有评论(0)