使用htimer定时计算一个任务的cpu利用率

  有时候我们想关注某一个任务的cpu利用率,除了使用top还有什么其他方法可行呢?

  实际上cpu利用率的原理就是特定时间内一个任务总的运行时间与时间的比值即可简单的认为是cpu利用率。

  那么就有两个问题:1)就是任务在某个时间周期的运行时间;2) 周期性的计算cpu利用率。

  第一个问题任务在某个时钟周期的运行时间可以通过当前时间任务总的运行时间p->se.sum_exec_runtime减去上一个统计周期任务的运行时间,就可得到此统计周期内任务的运行时间;第二个问题cpu利用率就可用第一步计算的运行除以周期就得到cpu利用率,而这个周期可以通过内核的htimer定时器来实现。

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <asm/io.h>
#include <linux/cpu.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/module.h> 
#include <linux/pid_namespace.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>

#define MAX_INT_STRING_NUM 20


static u64 __read_mostly sample_period = 4 * ((u64)NSEC_PER_SEC);  /* period=4s */
static struct hrtimer watchcat_timer;
static pid_t taskid ;
static struct task_struct *tsk;
u64 last_runtime = 0, difftime = 0;


static struct task_struct *find_task_by_vpid2(pid_t vnr)
{
	return pid_task(find_pid_ns(vnr, task_active_pid_ns(current)), PIDTYPE_PID);
}

static int monitask_read_proc(struct seq_file *m, void *v)
{
	//rcu_read_lock();
	tsk = find_task_by_vpid2(taskid);
	if (tsk) {
		get_task_struct(tsk);
		difftime = tsk->se.sum_exec_runtime - last_runtime;
		last_runtime = tsk->se.sum_exec_runtime;
		seq_printf(m, " cpu rate of %s:%d is %lld.%d \n", tsk->comm, tsk->pid, difftime/(4*1000*1000*10), (int)(difftime%(4*1000*1000*100)));
		put_task_struct(tsk);
		goto out;
	}
	//rcu_read_unlock();

out:
	return 0;
}

static int monitask_open(struct inode *inode, struct file *file)
{
	return single_open(file, monitask_read_proc, NULL);
}

static ssize_t monitask_write_proc(struct file *file, const char __user *buffer,
			    size_t count, loff_t *pos)
{
	char kbuf[MAX_INT_STRING_NUM + 1] = {0};

	if (count <= 0 || count > MAX_INT_STRING_NUM)
		return -EINVAL;
	
	if (copy_from_user(&kbuf, buffer, count))
		return -EFAULT;

	if (kstrtoint(kbuf, 0, &taskid) || taskid < 0)
		return -EINVAL;
	//rcu_read_lock();
	if (taskid) {
		tsk = find_task_by_vpid2(taskid);
		if (!tsk) {
			//rcu_read_unlock();
			return -ESRCH;
		}
	}
	last_runtime = tsk->se.sum_exec_runtime;
	//rcu_read_unlock();
	hrtimer_start(&watchcat_timer, ns_to_ktime(sample_period),
				HRTIMER_MODE_REL_PINNED);
	pr_info(" start timer fun:last_runtime=0x%llx\n", last_runtime);
	return count;
}

static const struct file_operations monitask_fops = {
	.open		= monitask_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release 	= single_release,
	.write		= monitask_write_proc, 
};

static enum hrtimer_restart watchcat_timer_fn(struct hrtimer *hrtimer)
{
	/* 
	 * todo:
	 * smp should protect tsk
	*/
	//rcu_read_lock();
	tsk = find_task_by_vpid2(taskid);
	if (tsk) {
		difftime = tsk->se.sum_exec_runtime - last_runtime;
		last_runtime = tsk->se.sum_exec_runtime;
	}
	//rcu_read_unlock();
	//pr_info(" cpu rate of %s:%d is %lld%\n", tsk->comm, tsk->pid, difftime/(4*1000*1000)/1000);
	hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));
	return HRTIMER_RESTART;
}

static void init_watchcat_func(struct work_struct *dummy)
{
	hrtimer_init(&watchcat_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	watchcat_timer.function = watchcat_timer_fn;
	watchcat_timer.irqsafe = 1;
}


static int __init monitask_init(void)
{
	struct proc_dir_entry *entry;

	entry = proc_create("monitask", S_IWUSR | S_IRUSR, NULL,  &monitask_fops);
	if (entry == NULL)
	{
		printk(KERN_ERR "Failed to register /proc/monitask\n");
		remove_proc_entry("monitask", NULL);
		return -ENOMEM;
	}
	init_watchcat_func(NULL);

	return 0;
}

static void __exit monitask_exit(void)
{
	hrtimer_cancel(&watchcat_timer);
	remove_proc_entry("monitask", NULL);
}

module_init(monitask_init);
module_exit(monitask_exit);
MODULE_LICENSE("GPL");

 上面的代码有一个竞争问题:通过pid获取到task_struct后,有可能这个task会退出,这就有可能导致取task的成员时发生控制在访问的情况。如何解决这个问题还待进一步探索。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值