歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux管理 >> Linux維護 >> Linux全局變量jiffies的用法

Linux全局變量jiffies的用法

日期:2017/3/2 10:32:07   编辑:Linux維護

jiffies是Linux系統中的全局變量,與時間有關,那麼jiffies變量具體有哪些作用呢?下面小編就給大家介紹下Linux全局變量jiffies的用法,感興趣的朋友不妨來了解下吧。

系統運行時間以秒為單位,等於jiffies/Hz。

注意,jiffies類型為無符號長整型(unsigned long),其他任何類型存放它都不正確。

將以秒為單位的時間轉化為jiffies:

seconds * Hz

將jiffies轉化為以秒為單位的時間:

jiffies / Hz

相比之下,內核中將秒轉換為jiffies用的多些。

jiffies的內部表示

jiffies定義於文件中:

/*

* The 64-bit value is not atomic - you MUST NOT read it

* without sampling the sequence number in xtime_lock.

* get_jiffies_64() will do this for you as appropriate.

*/

extern u64 __jiffy_data jiffies_64;

extern unsigned long volatile __jiffy_data jiffies;

ld(1)腳本用於連接主內核映像(在x86上位於arch/i386/kernel/vmlinux.lds.S中),然後用jiffies_64變量的初值覆蓋jiffies變量。因此jiffies取整個jiffies_64變量的低32位。

訪問jiffies的代碼只會讀取jiffies_64的低32位,通過get_jiffies_64()函數就可以讀取整個64位的值。在64位體系結構上,jiffies_64和jiffies指的是同一個變量。

#if (BITS_PER_LONG 《 64)

u64 get_jiffies_64(void);

#else

static inline u64 get_jiffies_64(void)

{

return (u64)jiffies;

}

#endif

在中

#if (BITS_PER_LONG 《 64)

u64 get_jiffies_64(void)

{

unsigned long seq;

u64 ret;

do {

seq = read_seqbegin(&xtime_lock);

ret = jiffies_64;

} while (read_seqretry(&xtime_lock, seq));

return ret;

}

jiffies的回繞wrap around

當jiffies的值超過它的最大存放范圍後就會發生溢出。對於32位無符號長整型,最大取值為(2^32)-1,即429496795。如果節拍計數達到了最大值後還要繼續增加,它的值就會回繞到0。

內核提供了四個宏來幫助比較節拍計數,它們能正確的處理節拍計數回繞的問題:

/*

* These inlines deal with timer wrapping correctly. You are

* strongly encouraged to use them

* 1. Because people otherwise forget

* 2. Because if the timer wrap changes in future you won‘t have to

* alter your driver code.

*

* time_after(a,b) returns true if the time a is after time b.

*

* Do this with “《0” and “》=0” to only test the sign of the result. A

* good compiler would generate better code (and a really good compiler

* wouldn’t care)。 Gcc is currently neither.

*/

#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)

/* Same as above, but does so with platform independent 64bit types.

* These must be used when utilizing jiffies_64 (i.e. return value of

* get_jiffies_64() */

#define time_after64(a,b) /

(typecheck(__u64, a) && /

typecheck(__u64, b) && /

((__s64)(b) - (__s64)(a) 《 0))

#define time_before64(a,b) time_after64(b,a)

#define time_after_eq64(a,b) /

(typecheck(__u64, a) && /

typecheck(__u64, b) && /

((__s64)(a) - (__s64)(b) 》= 0))

#define time_before_eq64(a,b) time_after_eq64(b,a)

用戶空間和HZ

問題提出:

在2.6以前的內核中,如果改變內核中的HZ值會給用戶空間中某些程序造成異常結果。因為內核是以節拍數/秒的形式給用戶空間導出這個值的,應用程序便依賴這個特定的HZ值。如果在內核中改變了HZ的定義值,就打破了用戶空間的常量關系---用戶空間並不知道新的HZ值。

解決方法:

內核更改所有導出的jiffies值。內核定義了USER_HZ來代表用戶空間看到的HZ值。在x86體系結構上,由於HZ值原來一直是100,所以USER_HZ值就定義為100。內核可以使用宏jiffies_to_clock_t()將一個有HZ表示的節拍計數轉換為一個由USER_HZ表示的節拍計數。

在中

/*

* Convert jiffies/jiffies_64 to clock_t and back.

*/

clock_t jiffies_to_clock_t(long x)

{

#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0

return x / (HZ / USER_HZ);

#else

u64 tmp = (u64)x * TICK_NSEC;

do_div(tmp, (NSEC_PER_SEC / USER_HZ));

return (long)tmp;

#endif

}

unsigned long clock_t_to_jiffies(unsigned long x)

{

#if (HZ % USER_HZ)==0

if (x 》= ~0UL / (HZ / USER_HZ))

return ~0UL;

return x * (HZ / USER_HZ);

#else

u64 jif;

/* Don‘t worry about loss of precision here 。。 */

if (x 》= ~0UL / HZ * USER_HZ)

return ~0UL;

/* 。。 but do try to contain it here */

jif = x * (u64) HZ;

do_div(jif, USER_HZ);

return jif;

#endif

}

u64 jiffies_64_to_clock_t(u64 x)

{

#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0

do_div(x, HZ / USER_HZ);

#else

/*

* There are better ways that don’t overflow early,

* but even this doesn‘t overflow in hundreds of years

* in 64 bits, so.。

*/

x *= TICK_NSEC;

do_div(x, (NSEC_PER_SEC / USER_HZ));

#endif

return x;

}

在中

/*

* do_div() is NOT a C function. It wants to return

* two values (the quotient and the remainder), but

* since that doesn’t work very well in C, what it

* does is:

*

* - modifies the 64-bit dividend _in_place_

* - returns the 32-bit remainder

*

* This ends up being the most efficient “calling

* convention” on x86.

*/

#define do_div(n,base) ({ /

unsigned long __upper, __low, __high, __mod, __base; /

__base = (base); /

asm(“”:“=a” (__low), “=d” (__high):“A” (n)); /

__upper = __high; /

if (__high) { /

__upper = __high % (__base); /

__high = __high / (__base); /

} /

asm(“divl %2”:“=a” (__low), “=d” (__mod):“rm” (__base), “0” (__low), “1” (__upper)); /

asm(“”:“=A” (n):“a” (__low),“d” (__high)); /

__mod; /

})

用戶空間期望HZ=USER_HZ,但是如果它們不相等,則由宏完成轉換。

上面就是Linux中jiffies變量的用法介紹了,如果你要計算系統運算了多少時間,那麼你就可以使用jiffies變量來計算了,jiffies變量還有很多用途,使用多了你就會了解。

Copyright © Linux教程網 All Rights Reserved