Linux内核|实验五 内核的定时机制实验

来源:互联网 发布:阿里云系统电视root 编辑:程序博客网 时间:2024/06/08 11:03

1 实验目的
本实验是练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。通过这个实验我们可以进一步理解 Linux 内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。
2 实验内容
A 在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)。
B 用定时器 ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,计算已经过的秒数。
C 记录一个进程运行时所占用的real time,cpu time, user time, kernel time
3 实验说明
1) 系统时间的获取和内核定时机制
从用户空间去获取系统时间数据需要以下基本代码:

#include <sys/time>struct timeval{long tv_sec; //从 1970-1-1 12:到现在经过的秒数long tv_usec;//从从上 1 秒到现在经过的微秒数} theTime;…gettimeofday(&theTime,NULL); //获取系统时间的系统调用

每个进程使用的各种定时器需要Linux 的内部定时器。内部定时器可以跟踪记录3种不同类型的定时机制,它们反映了不同时间的划分。这三种定时机制具有不同的作用和应用,分别是:
ITIMER_REAL:反映进程经过的实际时间,这种定时器到时后发 SIGALRM信号。它与struct task_struct结构中的it_real_valueit_real_incr字段有关。
ITIMER_VIRTUAL:反映进程经过的虚拟时间,只有相关进程正在执行时该时间才会增加。这种定时器到时后发 SIGVTALRM 信号。与struct task_struct 结构中的 it_virt_valueit_virt_incr字段有关
ITIMER_PROF:反映进程经过的虚拟时间加上内核为相关进程执行工作的时间之和。这种定时 器 到 时 后 发SIGPROF 信 号 。 与struct task_struct 结 构 中 的 it_prof_value it_prof_incr `字段有关。
每个定时器需要周期性的设定一个初始时间值,之后递减计数到 0 后引发定时中断,产生超时信号通知对应进程定时器时间到,然后定时器重新从设置的初始值再次开始递减计数。
2) 定时器的使用
定时器使用:定时器的使用只须执行一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。

定时器的使用步骤
 初始化,
 设置一个超时时间,
 指定超时发生时执行的函数,
 激活定时器。

3) 使用定时器时的函数
(1) 初始化:三种定时器都使用setitimer()系统调用进行初始化:

#include <sys/time.h>…函数setitimer(int timerType ,//定时器类型const struct itimerval *value, //定时器初始的和当前的秒数和毫秒数struct itimerval *oldValue   //该参数可不做处理)结构体struct itimerval{struct timeval it_it_interval; //下一次定时初值。为0定时器停止struct timeval it_value //定时器当前值} ;

(2) 三种定时器都使用getitimer()系统调用获取定时器当前值:

#include <sys/time.h>…函数getitimer(int timerType ,//定时器类型const struct itimerval *value, //定时器当前的秒数和毫秒数)

(3) 各类定时器到时的信号处理函数可以使用系统调用函数指定:

sighandler_t signal(int signum, //信号类型sighandler_t handler //信号处理函数名);

4 实验程序:
A 在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)。
设计思路:
设置定时器 ITIMER_REAL间隔为一秒钟。并为计时到时设定信号处理程序,使其输出当前所记时间。定时3秒,计时结束,给出提示、终止程序。
程序源代码清单:

/****test3.c*****/#include <sys/time.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>static void sighandle(int);static int second = 0;int main(){struct itimerval v;signal(SIGALRM,sighandle);v.it_interval.tv_sec = 1;v.it_interval.tv_usec = 0;v.it_value.tv_sec = 1;v.it_value.tv_usec = 0;setitimer(ITIMER_REAL,&v,NULL);for(;;);}static void sighandle(int s){second++;if(second<=3)printf("%d\r",second);else abort();fflush(stdout);}

运行结果:
这里写图片描述
这里写图片描述
B 用定时器ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,计算已经过的秒数。
设计思路:
设置定时器ITIMER_REAL间隔为一秒钟。并为计时到时设定信号处理程序,即 singal(SIGALRM,⋯),使其输出当前所记时间。
程序源代码清单:

/****test1.c*****/#include <sys/time.h>#include <stdio.h>#include <signal.h>static void sighandle(int);static int second = 0;int main(){struct itimerval v;signal(SIGALRM,sighandle);v.it_interval.tv_sec = 1;v.it_interval.tv_usec = 0;v.it_value.tv_sec = 1;v.it_value.tv_usec = 0;setitimer(ITIMER_REAL,&v,NULL);for(;;);}static void sighandle(int s){second++;printf("%d\r",second);fflush(stdout);}

运行结果:每隔一秒结果+1
这里写图片描述

C 记录一个进程运行时所占用的real time, cpu time, user time, kernel time
设计思路:
任务开始前设置好定时器ITIMER_REALITIMER_VIRTUALITIMER_PROF,即 其相应的信号处理程序。在任务执行过程中内核定时器通过产生等间隔的信号来记录进程所需的各种时间参量,并在任务结束后打印出来。
程序源代码清单 :

/************test2.c**********/#include <sys/time.h>#include <stdio.h>#include <signal.h>static void sighandle(int);static long realsecond = 0;static long vtsecond = 0;static long profsecond = 0;static struct itimerval realt,virtt,proft;int main(){struct itimerval v;int i,j;long moresec,moremsec,t1,t2;signal(SIGALRM,sighandle);signal(SIGVTALRM,sighandle);signal(SIGPROF,sighandle);v.it_interval.tv_sec = 10;v.it_interval.tv_usec = 0;v.it_value.tv_sec = 10;v.it_value.tv_usec = 0;setitimer(ITIMER_REAL,&v,NULL);setitimer(ITIMER_VIRTUAL,&v,NULL);setitimer(ITIMER_PROF,&v,NULL);for(j= 0;j<1000;j++){for(i= 0;i<500;i++){printf("********\r");fflush(stdout);}}getitimer(ITIMER_PROF,&proft);getitimer(ITIMER_REAL,&realt);getitimer(ITIMER_VIRTUAL,&virtt);printf("\n");moresec = 10 - realt.it_value.tv_sec;moremsec = (1000000 - realt.it_value.tv_usec)/1000;printf("realtime = %ld sec, %ld msec\n",realsecond+moresec,moremsec);moresec = 10 - proft.it_value.tv_sec;moremsec = (1000000 - proft.it_value.tv_usec)/1000;printf("cputime = %ld sec, %ld msec\n",profsecond+moresec,moremsec);moresec = 10 - virtt.it_value.tv_sec;moremsec = (1000000 - virtt.it_value.tv_usec)/1000;printf("usertime = %ld sec, %ld msec\n",vtsecond+moresec,moremsec);t1 = (10 - proft.it_value.tv_sec)*1000 + (1000000 - proft.it_value.tv_usec)/1000 +profsecond*10000;t2 = (10 - virtt.it_value.tv_sec)*1000 + (1000000 - virtt.it_value.tv_usec)/1000 +vtsecond*10000;moresec = (t1 - t2)/1000;moremsec = (t1 - t2) % 1000;printf("kerneltime = %ld sec, %ld msec\n",moresec,moremsec);fflush(stdout);}static void sighandle(int s){switch(s){case SIGALRM:realsecond+=10;break;case SIGVTALRM:vtsecond+=10;break;case SIGPROF:profsecond+=10;break;default :break;}}

运行结果:
这里写图片描述

原创粉丝点击