/*
* linux/drivers/char/timer_cpu_rate.c
*
* Copyright (C) 2012
*
* Created by ryan, 03/17/12, for cpu rating
*/
#include <linux/module.h>
#include <linux/init.h>
#include <asm/page.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
static const int rate_delta_in_ticks = HZ;
static struct timer_list rate_timer;
typedef struct
{
unsigned long cur;
unsigned long count;
unsigned int flag;
unsigned int result;
/*
* extra info
*/
int start_record;
int cpu;
}pmedia_cpu_rate;
#define NUM_MEDIA 32
#define CPU_MONITOR 0
#define DEVNAME "timer_rate"
#define MAGIC_IOCTL_NUM 'R'
#define MAX_IOCTL_SERNR 50
#define IOCTL_SETADDR _IOWR(MAGIC_IOCTL_NUM, 0,pmedia_cpu_rate)
pmedia_cpu_rate* user_cpu_calc_rate[NUM_MEDIA];
unsigned int mask_cpu_rate = 0;
static long ioctl_notify_calc_rate(void* args)
{
int cpu = -1;
int start_record_calc = 0;
//\\pmedia_cpu_rate* tmp_user_calc_rate = (pmedia_cpu_rate*)(__va(args));
pmedia_cpu_rate* tmp_user_calc_rate = (pmedia_cpu_rate*)(args);
if(tmp_user_calc_rate!=NULL){
start_record_calc = tmp_user_calc_rate->start_record;
cpu = tmp_user_calc_rate->cpu;
/*
* begin to calc in array?
*/
if(start_record_calc==1){
if(user_cpu_calc_rate[cpu] == NULL){
/*
* update kernel calc array
*/
user_cpu_calc_rate[cpu] = tmp_user_calc_rate;
}
/*
* calc op on this cpu will be opened
*/
mask_cpu_rate|=(1UL<<cpu);
}else{
/*
* otherwise close
*/
mask_cpu_rate&=~(1UL<<cpu);
}
}
return 0;
}
static void calc_cpu_media_rate(pmedia_cpu_rate *p)
{
p->cur += p->flag;
if(++p->count >= 4096)
{
unsigned long result = p->cur;
/* result = p->cur * 100 /4096 */
result = (result << 3) + (result << 1);
result = (result << 3) + (result << 1);
result >>= 12;
p->result = result;
p->cur = 0;
p->count = 0;
}
}
void timer_monitor_handler(void* data)
{
int i = 0;
for(;i<NUM_MEDIA;++i){
if((1UL<<i)&mask_cpu_rate)
calc_cpu_media_rate(user_cpu_calc_rate[i]);
}
mod_timer(&rate_timer, jiffies + rate_delta_in_ticks);
}
struct cdev timer_rate_dev;
static int major_devid = 0;
int chr_timer_rate_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int chr_timer_rate_ioctl(struct inode *inodep,struct file *filep,
unsigned int cmd, unsigned long arg){
if (_IOC_TYPE(cmd) != MAGIC_IOCTL_NUM)
return -EINVAL;
if (_IOC_NR(cmd) > MAX_IOCTL_SERNR)
return -EINVAL;
switch (cmd)
{
case IOCTL_SETADDR:
ioctl_notify_calc_rate((void*)arg);
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations timer_rate_fops =
{
.open = chr_timer_rate_open,
.ioctl = chr_timer_rate_ioctl
};
static void chr_timer_rate_setup(void)
{
int err,devno = MKDEV(major_devid,0);
cdev_init(&timer_rate_dev,&timer_rate_fops);
timer_rate_dev.owner = THIS_MODULE;
err = cdev_add(&timer_rate_dev,devno,1);
if(err)
printk("Erro %d adding timer_rate\n",err);
}
static int timer_rate_init(void)
{
int result = 0;
dev_t devno = MKDEV(major_devid,0);
if(major_devid){
result = register_chrdev_region(devno,1,DEVNAME);
}else{
result = alloc_chrdev_region(&devno,0,1,DEVNAME);
major_devid = MAJOR(devno);
}
if(result < 0 )
return result;
chr_timer_rate_setup();
init_timer(&rate_timer);
rate_timer.expires = jiffies + 1;
rate_timer.data = (unsigned long)&rate_timer;
rate_timer.function = (void *)&timer_monitor_handler;
add_timer_on(&rate_timer,CPU_MONITOR);
return 0;
}
static void __exit timer_rate_exit(void)
{
cdev_del(&timer_rate_dev);
unregister_chrdev_region(MKDEV(major_devid,0), 1);
}
module_init(timer_rate_init);
module_exit(timer_rate_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#define __USE_GNU
#include <sched.h>
#include <pthread.h>
#define LOOP_TIME 10
typedef struct
{
unsigned long cur;
unsigned long count;
unsigned int flag;
unsigned int result;
/*
* extra info
*/
int start_record;
int cpu;
}pmedia_cpu_rate;
#define CPU_NUM 32
pmedia_cpu_rate p_test[CPU_NUM];
#define MAX_LOOP 1000000
void mdelay(int delay)
{
int i = 0;
for(;i<((MAX_LOOP)*delay);++i)
;
}
#define DEVFILENAME "/dev/timer_rate"
#define MAGIC_IOCTL_NUM 'R'
#define IOCTL_SETADDR _IOWR(MAGIC_IOCTL_NUM, 0,pmedia_cpu_rate)
void start_pmedia_test(int cpu)
{
p_test[cpu].start_record = 1;
p_test[cpu].cpu = 0;
}
void stop_pmedia_test(int cpu)
{
p_test[cpu].start_record = 0;
p_test[cpu].cpu = 0;
}
void print_result(int cpu)
{
printf("cpu%d rate:%d%%\n",p_test[cpu].result);
}
void* MediaThread(void* data)
{
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
sched_setaffinity((long)syscall(SYS_gettid),sizeof(cpu_set_t),&cpuset);
while(1)
{
mdelay(10);
sleep(1);
}
return NULL;
}
int main(int argc,char* argv[])
{
int fd = -1,result=-1;
int i = 0;
int result;
pthread_t media;
pthread_create(&media, NULL, &MediaThread, NULL);
pthread_join(media, (void *)&result);
fd = open(DEVFILENAME, O_RDWR);
if(fd==-1)
{
perror("open device error!\n");
return -1;
}
start_pmedia_test(0);
result=ioctl(fd, IOCTL_SETADDR,p_test[0]);
if(result<0)
{
printf("%d",result);
perror("ioctol error\n");
return -1;
}
for(i=0;i<LOOP_TIME;++i){
print_result(0);
sleep(1);
}
stop_pmedia_test(0);
return 0;
}