您的位置:首页 > 运维架构 > Linux

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

2006-10-10 12:43 274 查看
/*

* 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().

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: