前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

jiffies

作者头像
DragonKingZhu
发布2020-03-24 16:34:56
2.2K0
发布2020-03-24 16:34:56
举报
文章被收录于专栏:Linux内核深入分析

HZ

Linux内核每隔固定周期都会发生时钟中断, 而HZ代表系统在1s中发生时钟中断的次数。如果HZ=1000,则系统在1s之内会发生1000次时钟中断。

HZ的值可以在kernel的配置文件config中配置,其中可以配置为100, 250, 1000等。

代码语言:javascript
复制
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250

可以看到自己的系统中配置的是250, 也就是说1s之内会发生250次时钟中断。

jiffies

Linux内核使用全局变量jiffies记录系统自从启动以来的滴答数。在系统启动的时初始化jiffies为0,在每个时钟中断处理例程中该值会加1。假如HZ=1000,每隔1ms系统会发生一次时钟中断,也就是说每隔1ms jiffies的值会加1,也就是说1s内jiffies的值也是HZ,所以系统启动的时间就是: jiffies/HZ

在Linux中jiffies的声明如下:

代码语言:javascript
复制
#define __jiffy_data  __attribute__((section(".data")))

/*
 * The 64-bit value is not atomic - you MUST NOT read it
 * without sampling the sequence number in jiffies_lock.
 * get_jiffies_64() will do this for you as appropriate.
 */
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

根据定义可知,jiffies变量是定义在链接脚本"vmlinux.lds"中.

代码语言:javascript
复制
OUTPUT_ARCH(aarch64)
ENTRY(_text)
jiffies = jiffies_64;

可知jiffies_64和jiffies变量的地址是一样的,只是一个表示32位,一个表示64位。

相对于jiffies而言,jiffies是个64位的变量。在32位平台上,jiffies和jiffies_64的低32位是重合的,访问jiffies_64只取低32位。但是在64位平台上jiffies和jiffies_64是同一个变量。

jiffies的访问

如果在32位平台上访问jiffies,可以直接访问。 但是想访问jiffies_64,就不能直接访问。因为在直接读取jiffies_64的低32位的时候,就有可能jiffies_64的值发生了改变,所以必须使用系统提供的函数: get_jiffies_64

代码语言:javascript
复制
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void)
{
	unsigned long seq;
	u64 ret;

	do {
		seq = read_seqbegin(&jiffies_lock);
		ret = jiffies_64;
	} while (read_seqretry(&jiffies_lock, seq));
	return ret;
}
EXPORT_SYMBOL(get_jiffies_64);
#endif

内核使用顺序锁来访问jiffies_64,关于顺序锁,可以看“顺序锁小节”

如果是64位平台,也是使用上述的函数,但是实现不一样,64位平台就可以直接读取jiffies的值即可。

代码语言:javascript
复制
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
#else
static inline u64 get_jiffies_64(void)
{
	return (u64)jiffies;
}
#endif

时间比较

系统中有时候需要对两个时间做比较,来确认时间点的前后。因为jiffies在每次时钟中断的时候都发生变化,所以就可以通过比较两个时间点的jiffies来比较。如果jiffies如果没有溢出,那就非常容易比较,不就是一大一小数值比较。但是溢出的可能性是存在的,所以就需要考虑到。所以linux内核为时间比较提供了一些列API。

代码语言:javascript
复制
#define time_after(a,b)		\
	(typecheck(unsigned long, a) && \
	 typecheck(unsigned long, b) && \
	 ((long)((b) - (a)) < 0))

如果时间a在时间b之后,则返回true

代码语言:javascript
复制
#define time_before(a,b)	time_after(b,a)

如果时间a在时间b前面,则返回true

代码语言:javascript
复制
#define time_after_eq(a,b)	\
	(typecheck(unsigned long, a) && \
	 typecheck(unsigned long, b) && \
	 ((long)((a) - (b)) >= 0))
#define time_before_eq(a,b)	time_after_eq(b,a)

如果时间a在时间b之后或者相等则返回true。 如果时间a在时间b之前或者相同则返回true。

代码语言:javascript
复制
/*
 * Calculate whether a is in the range of [b, c].
 */
#define time_in_range(a,b,c) \
	(time_after_eq(a,b) && \
	 time_before_eq(a,c))

该宏用于检查时间a是否在时间b和时间c之间,同时当a等于b或者a等于c的时候也会返回true 如果是对jiffies_64类型做时间比较,和只需要在每个函数后面添加64即可,例如:time_after64

时间转换

有时候,内核中需要将用jiffies表达的时间转化为毫秒ms或者微秒us的形式,,Linux内核为此提供了一组相关函数:

代码语言:javascript
复制
unsigned int jiffies_to_msecs(const unsigned long j);
unsigned int jiffies_to_usecs(const unsigned long j);
inline u64 jiffies_to_nsecs(const unsigned long j);

上述函数分别是将jiffies时间转化为秒,微秒,纳秒

代码语言:javascript
复制
unsigned long msecs_to_jiffies(const unsigned int m);
unsigned long usecs_to_jiffies(const unsigned int u);
unsigned long nsecs_to_jiffies(u64 n);

上述的函数是将秒,微秒,纳秒转化为jiffies.

时间转换的另一种形式

通过用户程序需要和内核,或者驱动程序打交道,这时候应用程序使用的时间就是以秒和毫秒为单位。比如系统调用gettimeofday/settiemofday

代码语言:javascript
复制
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz)

其实就用到了struct timeval结构体

代码语言:javascript
复制
struct timeval {
	__kernel_time_t		tv_sec;		/* seconds */
	__kernel_suseconds_t	tv_usec;	/* microseconds */
};

timeval是由秒和微秒组成,__kernel_time_t和__kernel_suseconds_t都是long型变量。

再比如系统调用,clock_gettime/clock_settime

代码语言:javascript
复制
int clock_gettime(clockid_t clk_id, struct timespec *tp);
int clock_settime(clockid_t clk_id, const struct timespec *tp);

其中就用到了struct timespec结构体

代码语言:javascript
复制
struct timespec {
	__kernel_time_t	tv_sec;			/* seconds */
	long		tv_nsec;		/* nanoseconds */
};

timespec是有秒和纳秒组成。

同样内核也提供了jiffies和这两个结构体之间的转化。

代码语言:javascript
复制
unsigned long timespec_to_jiffies(const struct timespec *value);
void jiffies_to_timespec(const unsigned long jiffies,struct timespec *value);
unsigned long timeval_to_jiffies(const struct timeval *value);
void jiffies_to_timeval(const unsigned long jiffies,
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • HZ
  • jiffies
  • jiffies的访问
  • 时间比较
  • 时间转换
  • 时间转换的另一种形式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档