程序注释-计算程序的挂钟时间、虚拟时间...(《kernel projects for linux》)

/*

 * This solution 1 based on those provided by 

 * Don Lindsay, Fall, 1995, and Sam Siewert, Spring, 1996

 * comment by MANIO
 
 
*/

 

 

#include 
< sys / time.h >
#include 
< signal.h >
#include 
< unistd.h >
#include 
< stdio.h >
 

#define  MAXSEC 1
#define  MAXUSEC 0

 

long  unsigned  int  fibonacci(unsigned  int  n);

long  elapsed_usecs( long  sec,  long  usec) // 求出已经过去的时间 (纳秒) 
{
  
if (usec  &&  (sec  <  MAXSEC)) // 时间大于0,小于MAXSEC秒,则返回剩下的纳秒数 
     return   1000000   -  usec;
  
else   if (usec  &&  (sec  >=  MAXSEC)) { // 纳秒数大于0,秒数大于等于MAXSEC
    printf( " possibly inaccurate interval time: " ); // 时间可能不准确 
    fflush(stdout); // 将缓冲区内容写到文件stdout,即屏幕 
     return   0 ;
  }
  
else
    
return   0 ; // 纳秒数等于0或者秒数小于MAXSEC ,返回0 
};

 

static   long  p_realt_secs  =   0 , c1_realt_secs  =   0 , c2_realt_secs  =   0 ;
static   long  p_virtt_secs  =   0 , c1_virtt_secs  =   0 , c2_virtt_secs  =   0 ;
static   long  p_proft_secs  =   0 , c1_proft_secs  =   0 , c2_proft_secs  =   0 ;
static   struct  itimerval p_realt, c1_realt, c2_realt;
static   struct  itimerval p_virtt, c1_virtt, c2_virtt;
static   struct  itimerval p_proft, c1_proft, c2_proft;
/*
struct itimerval {
    struct timeval it_interval;    // timer interval 
    struct timeval it_value;    // current value 
};

struct timeval {
    time_t        tv_sec;        // seconds ,type is long 
    suseconds_t    tv_usec;    // microseconds ,type is long 
};

*/  




void  p_realt_handler()
{
  p_realt_secs
++ ; // 记录这个函数被执行的次数,也是realtime走过的时间数 
/*

  printf("p_realt_handler ");
  fflush(stdout);
*/
  signal(SIGALRM, p_realt_handler);
// 当SIGALRM(ITIMER_REAL超时的时候产生)信号到来时,启动p_realt_handler函数 
}
 

void  c1_realt_handler()
{
  c1_realt_secs
++ ;
/*

  printf("c1_realt_handler ");

  fflush(stdout);

*/
  signal(SIGALRM, c1_realt_handler);
// 当SIGALRM(ITIMER_REAL超时的时候产生)信号到来时

}

 

void  c2_realt_handler()
{
  c2_realt_secs
++ ;
/*
  printf("c2_realt_handler ");
  fflush(stdout);
*/

  signal(SIGALRM, c2_realt_handler);
// 当SIGALRM(ITIMER_REAL超时的时候产生)信号到来时
}

void  p_virtt_handler()
{
  p_virtt_secs
++ ;
/*
  printf("p_virtt_handler ");
  fflush(stdout);
*/
  signal(SIGVTALRM, p_virtt_handler);
// 当SIGVTALRM(ITIMER_VIRTUAL超时的时候产生)信号到来时
}

 

void  c1_virtt_handler()
{
  c1_virtt_secs
++ ;
/*

  printf("c1_virtt_handler ");

  fflush(stdout);

*/
  signal(SIGVTALRM, c1_virtt_handler);

}

 

void  c2_virtt_handler()
{
  c2_virtt_secs
++ ;
/*

  printf("c2_virtt_handler ");

  fflush(stdout);

*/
  signal(SIGVTALRM, c2_virtt_handler);
}

 

void  p_proft_handler()

{

  p_proft_secs
++ ;

/*

  printf("p_proft_handler ");

  fflush(stdout);

*/

  signal(SIGPROF, p_proft_handler);

}

 

void  c1_proft_handler()

{

  c1_proft_secs
++ ;

/*

  printf("c1_proft_handler ");

  fflush(stdout);

*/

  signal(SIGPROF, c1_proft_handler);

}

 

void  c2_proft_handler()

{

  c2_proft_secs
++ ;

/*

  printf("c2_proft_handler ");

  fflush(stdout);

*/

  signal(SIGPROF, c2_proft_handler);

}

 
// 把总时间设为1秒,则每一秒都超时,每一秒都产生信号 
 

 

main(
int  argc,  char   ** argv)
{
  
long  unsigned fib  =   0 ;
  
int  pid1, pid2;
  unsigned 
int  fibarg;

  
int  status;

 

  
if (argc  ==   2 )

    sscanf(argv[
1 ],  " %ld " & fibarg);

  
else

    fibarg 
=   30 ;

 

  printf(
" fibarg = %ld " , fibarg);

 

  p_realt.it_interval.tv_sec 
=  MAXSEC; // REALTIME超时时间设为1秒 

  p_realt.it_interval.tv_usec 
=  MAXUSEC;

  p_realt.it_value.tv_sec 
=  MAXSEC; // REALTIME当前时间设为1秒 

  p_realt.it_value.tv_usec 
=  MAXUSEC;

  p_virtt.it_interval.tv_sec 
=  MAXSEC; // 虚拟时间设为1秒 

  p_virtt.it_interval.tv_usec 
=  MAXUSEC;

  p_virtt.it_value.tv_sec 
=  MAXSEC; // 虚拟当前时间设为1秒
  
  p_virtt.it_value.tv_usec 
=  MAXUSEC;

  p_proft.it_interval.tv_sec 
=  MAXSEC; // PROF时间设为1秒 

  p_proft.it_interval.tv_usec 
=  MAXUSEC;

  p_proft.it_value.tv_sec 
=  MAXSEC; // PROF当前时间设为1秒

  p_proft.it_value.tv_usec 
=  MAXUSEC;

 

  c1_realt.it_interval.tv_sec 
=  MAXSEC;

  c1_realt.it_interval.tv_usec 
=  MAXUSEC;

  c1_realt.it_value.tv_sec 
=  MAXSEC;

  c1_realt.it_value.tv_usec 
=  MAXUSEC;

  c1_virtt.it_interval.tv_sec 
=  MAXSEC;

  c1_virtt.it_interval.tv_usec 
=  MAXUSEC;

  c1_virtt.it_value.tv_sec 
=  MAXSEC;

  c1_virtt.it_value.tv_usec 
=  MAXUSEC;

  c1_proft.it_interval.tv_sec 
=  MAXSEC;

  c1_proft.it_interval.tv_usec 
=  MAXUSEC;

  c1_proft.it_value.tv_sec 
=  MAXSEC;

  c1_proft.it_value.tv_usec 
=  MAXUSEC;

 

  c2_realt.it_interval.tv_sec 
=  MAXSEC;

  c2_realt.it_interval.tv_usec 
=  MAXUSEC;

  c2_realt.it_value.tv_sec 
=  MAXSEC;

  c2_realt.it_value.tv_usec 
=  MAXUSEC;

  c2_virtt.it_interval.tv_sec 
=  MAXSEC;

  c2_virtt.it_interval.tv_usec 
=  MAXUSEC;

  c2_virtt.it_value.tv_sec 
=  MAXSEC;

  c2_virtt.it_value.tv_usec 
=  MAXUSEC;

  c2_proft.it_interval.tv_sec 
=  MAXSEC;

  c2_proft.it_interval.tv_usec 
=  MAXUSEC;

  c2_proft.it_value.tv_sec 
=  MAXSEC;

  c2_proft.it_value.tv_usec 
=  MAXUSEC;

 
// 事先设定,当此三种信号到来时,启用p字开头的三个函数 
  signal(SIGALRM, p_realt_handler);

  signal(SIGVTALRM, p_virtt_handler);

  signal(SIGPROF, p_proft_handler);

 

  
if (setitimer(ITIMER_VIRTUAL,  & p_virtt, ( struct  itimerval  * ) 0 ==   - 1 ) // 设置ITIMER_VIRTUAL的值为struct p_virtt????????????? 

    perror(
" parent virtual timer " );

  
if (setitimer(ITIMER_REAL,  & p_realt, ( struct  itimerval  * ) 0 ==   - 1 )

    perror(
" parent real timer " );

  
if (setitimer(ITIMER_PROF,  & p_proft, ( struct  itimerval  * ) 0 ==   - 1 )

    perror(
" parent profile timer " );

 

  pid1 
=  fork();

  
if (pid1  ==   0 ) { // child process

 

    signal(SIGALRM, c1_realt_handler);
// 设定c1开头的这三个函数为信号处理函数 

    signal(SIGVTALRM, c1_virtt_handler);

    signal(SIGPROF, c1_proft_handler);

 

    
if (setitimer(ITIMER_VIRTUAL,  & c1_virtt, ( struct  itimerval  * ) 0 ==   - 1 )

      perror(
" child 1 virtual timer " );

    
if (setitimer(ITIMER_REAL,  & c1_realt, ( struct  itimerval  * ) 0 ==   - 1 )

      perror(
" child 1 real timer " );

    
if (setitimer(ITIMER_PROF,  & c1_proft, ( struct  itimerval  * ) 0 ==   - 1 )

      perror(
" child 1 profile timer " );

 

    fib 
=  fibonacci(fibarg);

 

    getitimer(ITIMER_PROF, 
& c1_proft);

    getitimer(ITIMER_REAL, 
& c1_realt);

    getitimer(ITIMER_VIRTUAL, 
& c1_virtt);

    printf(
" " );

    printf(
" Child 1 fib = %ld, real time = %ld sec, %ld millisec " ,

           fib, c1_realt_secs,

           elapsed_usecs(c1_realt.it_value.tv_sec,

                         c1_realt.it_value.tv_usec) 
/   1000 );

    printf(
" Child 1 fib = %ld, cpu time = %ld sec, %ld millisec " ,

           fib, c1_proft_secs,

           elapsed_usecs(c1_proft.it_value.tv_sec,

                         c1_proft.it_value.tv_usec) 
/   1000 );

    printf(
" Child 1 fib = %ld, user time = %ld sec, %ld millisec " ,

           fib, c1_virtt_secs,

           elapsed_usecs(c1_virtt.it_value.tv_sec,

                         c1_virtt.it_value.tv_usec) 
/   1000 );

    printf(
" Child 1 fib = %ld, kernel time = %ld sec, %ld millisec " ,

           fib, c1_proft_secs 
-  c1_virtt_secs,

           (elapsed_usecs(c1_proft.it_value.tv_sec,

                          c1_proft.it_value.tv_usec) 
/   1000 -

           (elapsed_usecs(c1_virtt.it_value.tv_sec,

                          c1_virtt.it_value.tv_usec) 
/   1000 ));

    fflush(stdout);

    exit(
0 );

  }

  
else  {

    pid2 
=  fork();

    
if (pid2  ==   0 ) {

 

      signal(SIGALRM, c2_realt_handler);

      signal(SIGVTALRM, c2_virtt_handler);

      signal(SIGPROF, c2_proft_handler);

 

      
if (setitimer(ITIMER_VIRTUAL,  & c2_virtt, ( struct  itimerval  * ) 0 ==   - 1 )

        perror(
" child 1 virtual timer " );

      
if (setitimer(ITIMER_REAL,  & c2_realt, ( struct  itimerval  * ) 0 ==   - 1 )

        perror(
" child 1 real timer " );

      
if (setitimer(ITIMER_PROF,  & c2_proft, ( struct  itimerval  * ) 0 ==   - 1 )

        perror(
" child 1 profile timer " );

 

      fib 
=  fibonacci(fibarg);

 

      getitimer(ITIMER_PROF, 
& c2_proft);

      getitimer(ITIMER_REAL, 
& c2_realt);

      getitimer(ITIMER_VIRTUAL, 
& c2_virtt);

      printf(
" " );

      printf(
" Child 2 fib = %ld, real time = %ld sec, %ld millisec " ,

             fib, c2_realt_secs,

             elapsed_usecs(c2_realt.it_value.tv_sec,

                           c2_realt.it_value.tv_usec) 
/   1000 );

      printf(
" Child 2 fib = %ld, cpu time = %ld sec, %ld millisec " ,

             fib, c2_proft_secs,

             elapsed_usecs(c2_proft.it_value.tv_sec,

                           c2_proft.it_value.tv_usec) 
/   1000 );

      printf(
" Child 2 fib = %ld, user time = %ld sec, %ld millisec " ,

             fib, c2_virtt_secs,

             elapsed_usecs(c2_virtt.it_value.tv_sec,

                           c2_virtt.it_value.tv_usec) 
/   1000 );

      printf(
" Child 2 fib = %ld, kernel time = %ld sec, %ld millisec " ,

             fib, c2_proft_secs 
-  c2_virtt_secs,

             (elapsed_usecs(c2_proft.it_value.tv_sec,

                            c2_proft.it_value.tv_usec) 
/   1000 -

             (elapsed_usecs(c2_virtt.it_value.tv_sec,

                            c2_virtt.it_value.tv_usec) 
/   1000 ));

      fflush(stdout);

      exit(
0 );

    }

    
else  {  /*  this is the parent  */

 

      fib 
=  fibonacci(fibarg);

 

      waitpid(
0 & status,  0 );

      waitpid(
0 & status,  0 );

 

      getitimer(ITIMER_PROF, 
& p_proft);

      getitimer(ITIMER_REAL, 
& p_realt);

      getitimer(ITIMER_VIRTUAL, 
& p_virtt);

      printf(
" " );

      printf(
" Parent fib = %ld, real time = %ld sec, %ld millisec " ,

             fib, p_realt_secs,

             elapsed_usecs(p_realt.it_value.tv_sec,

                           p_realt.it_value.tv_usec) 
/   1000 );

      printf(
" Parent fib = %ld, cpu time = %ld sec, %ld millisec " ,

             fib, p_proft_secs,

             elapsed_usecs(p_proft.it_value.tv_sec,

                           p_proft.it_value.tv_usec) 
/   1000 );

      printf(
" Parent fib = %ld, user time = %ld sec, %ld millisec " ,

             fib, p_virtt_secs,

             elapsed_usecs(p_virtt.it_value.tv_sec,

                           p_virtt.it_value.tv_usec) 
/   1000 );

      printf(
" Parent fib = %ld, kernel time = %ld sec, %ld millisec " ,

             fib, p_proft_secs 
-  p_virtt_secs,

             (elapsed_usecs(p_proft.it_value.tv_sec,

                            p_proft.it_value.tv_usec) 
/   1000 -

             (elapsed_usecs(p_virtt.it_value.tv_sec,

                            p_virtt.it_value.tv_usec) 
/   1000 ));

      fflush(stdout);

      exit(
0 );

    }

  }

  printf(
" this line should never be printed " );

}

 

 

long  unsigned  int  fibonacci(unsigned  int  n)

{

  
if (n == 0 )

    
return   0 ;

  
else   if (n == 1   ||  n == 2 )

    
return   1 ;

  
else

    
return  (fibonacci(n - 1 +  fibonacci(n - 2 ));

}

 

 
/*
Linux provide three timers for each process (the timers are part of the
process descriptor).  The manpages for getitimer and setitimer describe
the 3 timers and associated signals.  One timer measures real "wall clock"
time, and thus "ticks" whether the associated process is running or not.
Another timer measures the time a process is running in "user mode", and
thus ticks while the process is running, but not during execution of
system calls by the kernel on behalf of a process.  A third timer, the
profile timer, measures the time a process is running in user mode and
the time that system calls take which are being executed on behalf of
the process (kernel mode).  Given these three timers, it is possible
therefore to compute real time, cpu time (time in user and kernel mode),
user time, and kernel time.  The kernel time is computer by subtracting
the "virtual" time from the "profile" time for a process.
 
All 3 timers work by counting down from a vaule set with the setitimer
system call.  When zero is reached, all three will generate a specific
signal (and may reset if a reset time has been specified).  It should
also be noted that a child process does not inherit its parent's timers,
but that timers do persist across an exec() call.
 
*/


 
/*
On Linux systems, the code is found in /usr/src/linux/kernel.  It should
first be noted that getitimer and setitimer are system calls, and therefore
like a Linux system calls have kernel source functions sys_* (sys_setitimer
and sys_getitimer), which are called from the system trap whereby an
interrupt is generated and a handler calls the appropriate kernel function
when an application calls the system call library interface (in libc).
 
The two kernel routines simply convert time to/from jiffies, the internal
relative time in 10 ms ticks since boot-up, and either setting or getting
the timer value from the current process' descriptor value.
 
In include/linux/sched.h, current is defined as a pointer to a task_struct.
This pointer simply provides access to the process descriptor for the
currently running process which includes associated timer values.
 
To understand how the time is kept, if you look in the main.c program
for linux, you see that as part of the kernel initialization sched_init()
is called.  This function does a request_irq(TIMER_IRQ, do_timer, 0, "timer")
among other things.  This means that the hardware cpu timer will cause
do_timer() to be executed whenever it expires and causes an IRQ which it
does every 10 ms on Linux and most Unix systems.  The do_timer() advances
jiffies every 10 ms, and furthermore contains code to distinguish the mode
of the current process...
 
if(user_mode(regs) {
  ...
  // Update ITIMER_VIRT for current task if not a system call
  if (current->it_virt_value && !(--current->it_virt_value)) {
    current->it_virt_value = current->it_virt_incr;
    send_sig(SIGVTALRM, current, 1);
  }
 
Note that if decrementing the it_virt_value causes it to be zero, then
the appropriate signal is raised to the current process.
 
The following code is executed whether current is in user_mode or not, and
thus implements the definition of profile time:
 
// Update ITIMER_PROF for the current task
if(current->it_prof_value && !(--currrent->it_prof_value)) {
  current->it_prof_value = current->it_prof_incr;
  send_sig(SIGPROF, current, 1);
}
 
So, we see the implementation of the time keeping for 2 of the 3 timers.
SIGALRM for the third, real time, is generated from the routine schedule().
This routine contains the code:
 
if(ticks && p->it_real_value) {
  if(p->it_real_value <= ticks) {
    send_sig(SIGALRM, p, 1);
    ...
    do {
         p->it_real_value += p->it_real_incr;
       } while (p->it_real_value <= ticks);
 
The code tests to see if the real-time timer has expired, and if so it
signals the process p and resets its timer if so configured.  Note that
all processes currently under the dispatch management of the scheduler
are handled with this code so that all real-time timers are decremented
whether the associated processes are currently running or not (unlike the
other two timers which only need to be decremented when the associated
process is the current process).
 
The file fork.c contains code to zero it_virt_value, etc.  Since these
variables are not mentioned elsewhere in the kernel, they are presumably
unaffected by other system calls such as exec().

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值