linux进程创建时间计算

欢迎访问小站,阅读此文http://www.yandong.org/archives/501

简介

墙上时间,也就是距离1970年1月1日的时间,在linux kernel内部没多大用处,对其的应用多在用户空间。

本文的目的在于在kernel里面计算得到 进程创建的墙上时间

计算公式

 xtime.tv_sec - (jiffies/HZ ) + 300 + p->real_start_time.tv_sec

意思就是,当前的 墙上时间(xtime) 减去 系统启动后的节拍(jiffies) / 频率(HZ)   这样得到的是系统启动的墙上时间,即距离1970.1.1的秒数,然后再加上进程结构体中 保存的距离系统启动时间的秒数(p->real_start_time.tv_sec)

下面分别解释:

task_struct中的时间

p->real_start_time.tv_sec

其中的p是task_struct指针,指向的是进程创建距离系统启动的时间.

task_struct中有两个时间:start_time 和 real_start_time,其中后者包含睡眠时间。

下面是进程创建的部分源码

do_posix_clock_monotonic_gettime(&p->start_time); p->real_start_time = p->start_time; monotonic_to_bootbased(&p->real_start_time); //真实启动时间还须要加 上总的睡眠时间 

xtime介绍

摘自《深入理解linux内核》

所有的PC都包含一个叫实时时钟(Renl Time Clock RTC)的时钟,它是独立于CPU和所有其他芯片的。
即使当PC呗切断电源,RTC还继续工作,因为它靠一个小电池或蓄电池供电。CMOS RAM和RTC被集成在一个芯片上。

Linux只用RTC来获取时间和日期。不过对/dev/rtc设备文件操作,也允许对RTC编程。

内核利用 get_cmos_time函数从实时时钟上读取字1970.1.1(UTC)午夜以来经过的秒数。

xtime_lock顺序所(seqlock)消除了对xtime变量同时访问而可能发生的竞争条件,

对于2.6内核,其定义为(/include/linux/time.h)

extern struct timespec xtime;

对于3.5内核,其定义为(kernel/time/timekeeping.c)

struct timekeeper { ... struct timespec xtime; ... }; static struct timekeeper timekeeper;

xtime的获取

因为很难原子的访问结构体中的两个变量,所以kernel并不鼓励直接访问xtime变量,可以使用相关函数

//include/linux/time.h struct timespec current_kernel_time(void); extern void do_gettimeofday(struct timeval *tv);

所以如果在module里面直接使用 xtime,是不行的。但是可以通过硬编码的方式获取

比如:

long * xtime_ptr = &xtime; 或者 long * xtimr_ptr = 0xc0803980

其中的 0xc0803980这个值,是从System.map中获得的,xtime是个全局符号,所有从sytem.map中可以获得它的地址

root@hyd:/home/l# cat /boot/System.map-2.6 | grep xtime c0156230 T update_xtime_cache
c06e3c00 D xtime_lock
c072f654 D inet_peer_gc_maxtime
c0803980 B xtime
c08039a0 b xtime_cache

jiffies介绍

简介

全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
它被用来记录系统自开机以来,已经过了多少tick。每发生一次timer interrupt,Jiffies变数会被加一。
启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。
因为一秒内时钟中断的次数等于Hz,所以jiffes一秒内增加的值也就为Hz,系统运行时间以秒为单位计算,就等于jiffes/Hz。

定义

extern u64 __jiffy_data jiffies_64; extern unsigned long volatile __jiffy_data jiffies;

其中,jiffies_64 和 jiffies 的低32位是重合的,因为32为的jiffies 最多50天就溢出了,而jiffies_64则不用关注溢出问题。

初始化

#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) jiffies =INITIAL_JIFFIES

可以看出 jiffies 被初始化为5分钟后溢出的一个值,这是为了方便内核调试,以便故障早点出来。

获取

由于jiffies_64 是一个符合变量,不能直接获取,需要下面的使用辅助函数

#if (BITS_PER_LONG < 64) u64 get_jiffies_64(void); #else static inline u64 get_jiffies_64(void) { return (u64)jiffies; } #endif

当然也可以使用硬编码的方式使用  jiffies

root@hy:/home/# cat /boot/System.map | grep "D jiffies" c06e3b00 D jiffies
c06e3b00 D jiffies_64

从中也可以看到 jiffies 与 jiffies_64的地址是相同的

使用

由于jiffies在五分钟之后,便溢出,所以使用jiffies的原则如下

//如果jiffies变量类型是32位无符号int max_count = 0xffffffff or
max_count = 0xffffffff ffffffff (64-bit) //如果没有溢出,系统启动后运行的节拍数: jiffies - ITIAL_JIFFIES //系统启动来5分钟的节拍数就是(到jiffies溢出的前一拍): max_count - INITIAL_JIFFIES

在我的代码中,我是这样使用的

unsigend long jiffies_test = jiffies + HZ; if( time_after(jiffies, jiffies_test)) { jiffies = MAX_JIFFIES - jiffies; }else { jiffies = jiffies - INITIAL_JIFFIES; }

其中的 time_after 是内核提供的四个比较函数之一

 #define time_after(a,b) \ (typecheck(unsigned long, a) && \
          typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) #define time_before(a,b) time_after(b,a) #define time_after_eq(a,b) \ (typecheck(unsigned long, a) && \
          typecheck(unsigned long, b) && \ ((long)(a) - (long)(b) >= 0)) #define time_before_eq(a,b) time_after_eq(b,a)

为什么time_after能判断溢出呢?

待续,或者 参考下面链接

链接

http://book.51cto.com/art/200810/93773.htm

http://blog.csdn.net/michaelcao1980/article/details/7826326

http://lxr.oss.org.cn/source/include/linux/jiffies.h?v=2.6.30#L167

http://blog.csdn.net/chchchdx123/article/details/6270022

http://linux.gongxiang8.com/456430/

如果您喜欢这篇文章,欢迎分享订阅。本文内容遵CC版权协议 转载请注明出处www.yandong.org

你可能感兴趣的:(linux进程创建时间计算)