HZ和Jiffies

系统定时器timer能够以可编程的方式设定频率,来中断cpu处理器。此频率即hz,为每秒的定时器节拍(tick)数,
对应着内核变量HZ。选择合适的HZ值需要权衡。
tick为两个连续中断的时间间隔。
//查看我们系统为 7.9centos,3.1内核
[root@k3master ~]# cat /boot/config-`uname -r` | grep 'CONFIG_HZ='
CONFIG_HZ=1000 //这个就是内核hz
而在2.6.13中,它又被降低到了250。 2.5之前是100,3.10是10000,
在目前的内核中,可以在编译内核时通过配置菜单选择一个HZ值。该选项的默认值取决于体系架构的版本。
jiffies变量记录了系统启动以来,系统定时器已经触发的次数。内核每秒钟将jiffies变量增加HZ数。
因此,对于HZ值为100的系统,1个jiffy等于10ms,而对于HZ为1000的系统,1个jiffy仅为1ms。
jiffies既反应了次数指标,又反映的是精度的指标,HZ值大,定时器间隔时间就小,因此进程调度的准确性会更高。
但是,HZ值越大也会导致开销和电源消耗更多,因为更多的处理器将被耗费在系统定时器中断上下文中。

HZ的值取决于体系架构。在x86系统上,在2.4内核中,该值默认设置为100;在2.6内核中,该值变为1000;
系统的运行时间(jiffies/Hz), 将jiffies转化为以秒为单位的时间,计算公式为 jiffies/hz=?s 
HZ为1秒钟的时钟中断次数,jiffies类型 unsigned long 表示无整形都是正整数 
1、HZ=1000时 1jiffies = 1ms(1毫秒) 
2、HZ=100时 1jiffies=10ms
3、HZ=10时 1jiffies=100ms

这里实际基本都是100或1000,只是理解jiffies的计算方法.

注: 1 秒=1000 毫秒

//E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\arch\x86\include\asm\param.h
//E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\include\asm-generic\param.h

linux内核定义了两者的值:

#ifndef __ASM_GENERIC_PARAM_H
#define __ASM_GENERIC_PARAM_H #ifdef __KERNEL__
# define HZ CONFIG_HZ /* Internal kernel timer frequency */
# define USER_HZ 100 /* some user interfaces are */
# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */
#endif

其中CONFIG_HZ为通过make menuconfig配置的HZ值,一般为1000,
[root@k3master ~]# cat /boot/config-`uname -r` | grep 'CONFIG_HZ='
CONFIG_HZ=1000
即表示每秒钟jiffies增加1000个计数。
系统时钟每1ms(毫秒)中断一次, 时钟频率,用HZ宏表示,设定为1000,即每秒运行了时钟中断1000次.
实际值可参见代码中include/generated/autoconf.h文件。USER_HZ固定为100,用户层调用 times 系统调用,
返回的是按照USER_HZ计算的jiffies值。
#ifndef HZ
#define HZ 100
#endif
#ifndef EXEC_PAGESIZE
#define EXEC_PAGESIZE 4096
#endif #ifndef NOGROUP
#define NOGROUP (-1)
#endif #define MAXHOSTNAMELEN 64 /* max length of hostname */ #endif /* __ASM_GENERIC_PARAM_H */

用户层与内核之间相关交互

E:\linux内核\linux-2.6.0\linux-2.6.0\include\linux\times.h 

//内核定义了USER_HZ来代表用户空间看到的HZ值
//在x86体系结构上,由于HZ值原来一直是2.5之前是100 ,所以USER_HZ值就定义为100。2.6之后就是1000
//内核可以使用宏 jiffies_to_clock_t()将一个有HZ表示的节拍计数转换为一个由USER_HZ表示的节拍计数
//HZ的值就是CONFIG_HZ值.
//取模运算(%)就是两个整数相除的余数,那么这里就是1000%100=0

#if (HZ % USER_HZ)==0
# define jiffies_to_clock_t(x) ((x) / (HZ / USER_HZ))
#else
# define jiffies_to_clock_t(x) ((clock_t) jiffies_64_to_clock_t((u64) x))
#endif
static inline 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
} static inline u64 jiffies_64_to_clock_t(u64 x)
{
#if (HZ % 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 *= USER_HZ;
do_div(x, HZ);
#endif
return x;
}
#endif
struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
}; #endif

E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\kernel\time.c

两者定义的差别导致用户层与内核交互时,需要进行转换。除了以上的64位转换函数 jiffies_64_to_clock_t。

内核还提供了另外两个互换函数,实现函数:

/*
* Convert jiffies/jiffies_64 to clock_t and back.
*/
clock_t jiffies_to_clock_t(long x)
{
//一个中断时间间隔叫做一个节拍(tick),它的长度以纳秒为单位存放在tick_nsec变量中
//NSEC_PER_SEC单位是每毫秒有多少纳秒
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ
return x * (USER_HZ / HZ);
# else
return x / (HZ / USER_HZ);
# endif
#else
return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ);
#endif
}
//EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,
//即使用
EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用
EXPORT_SYMBOL(jiffies_to_clock_t); 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
/* Don't worry about loss of precision here .. */
if (x >= ~0UL / HZ * USER_HZ)
return ~0UL; /* .. but do try to contain it here */
return div_u64((u64)x * HZ, USER_HZ);
#endif
}
EXPORT_SYMBOL(clock_t_to_jiffies); u64 jiffies_64_to_clock_t(u64 x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ
x = div_u64(x * USER_HZ, HZ);
# elif HZ > USER_HZ
x = div_u64(x, HZ / USER_HZ);
# else
/* Nothing to do */
# endif
#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 = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ));
#endif
return x;
}
EXPORT_SYMBOL(jiffies_64_to_clock_t);

Linux网桥的ioctl为例,设置和获取bridge表项的最大超时时间
 代码位于文件net/bridge/br_ioctl.c中

static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
unsigned char mac[ETH_ALEN];
struct net_bridge *br = netdev_priv(dev);
unsigned long args[4]; if (copy_from_user(args, rq->ifr_data, sizeof(args)))
return -EFAULT; switch (args[0]) { case BRCTL_GET_BRIDGE_INFO:
{
struct __bridge_info b;
b.max_age = jiffies_to_clock_t(br->max_age); //转化为USER_HZ表示的clock
return 0;
}
case BRCTL_SET_BRIDGE_MAX_AGE:
{
unsigned long t = clock_t_to_jiffies(args[1]); //转化为HZ表示的jiffies
br->bridge_max_age = t;
return 0;
}
}

获取运行系统HZ值(网络中邻居表的locktime参数,默认设置的是一个HZ)

通过proc文件可读取
[root@ht8 ens192]# cat /proc/sys/net/ipv4/neigh/ens192/locktime
100

用户USER_HZ与内核HZ的值的更多相关文章

  1. linux信号机制 - 用户堆栈和内核堆栈的变化【转】

    转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...

  2. Linux用户空间与内核空间(理解高端内存)

    Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...

  3. Linux用户空间与内核空间

    源:http://blog.csdn.net/f22jay/article/details/7925531 Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针 ...

  4. 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口

    Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...

  5. Linux操作系统学习_用户态与内核态之切换过程

    因为操作系统的很多操作会消耗系统的物理资源,例如创建一个新进程时,要做很多底层的细致工作,如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录.页表等,这些操作显然不能随便让任何程序都可以做,于是就产 ...

  6. linux 用户空间与内核空间——高端内存详解

    摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...

  7. 用户态与内核态 & 文件流与文件描述符 简介【转】

    转自:https://www.cnblogs.com/Jimmy1988/p/7479856.html 用户态和内核态 程序代码的依赖和调用关系如下图所示: Lib:标准ASCI C函数,几乎所有的平 ...

  8. 用户态与内核态 & 文件流与文件描述符 简介

    用户态和内核态 程序代码的依赖和调用关系如下图所示: Lib:标准ASCI C函数,几乎所有的平台都支持该库函数,因此依赖该库的程序可移植性好: System Function:系统调用函数,与系统内 ...

  9. Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十)

    1 非抢占式和可抢占式内核 为了简化问题,我使用嵌入式实时系统uC/OS作为例子 首先要指出的是,uC/OS只有内核态,没有用户态,这和Linux不一样 多任务系统中, 内核负责管理各个任务, 或者说 ...

随机推荐

  1. 使用Spring Data ElasticSearch+Jsoup操作集群数据存储

    使用Spring Data ElasticSearch+Jsoup操作集群数据存储 1.使用Jsoup爬取京东商城的商品数据 1)获取商品名称.价格以及商品地址,并封装为一个Product对象,代码截 ...

  2. 给Windows系统免疫不再受恶意代码骚扰

    所谓恶意代码,是指网页中使用了利用WSH漏洞来修改系统的一段代码(但是由于它并不具备传染性和自我复制这两个病毒的基本特征,因此不能称作病毒).WSH是"Windows Scripting H ...

  3. Java基础—构造方法

    1.构造方法概述 构造方法是一种特殊的方法,用来创建对象,当我们不定义时,系统会默认给出一个无参构造方法:一旦我们定义了任意的构造方法,系统就不会给出默认的无参构造方法 格式如下: public ca ...

  4. java web中统一结果返回封装类JsonResult

    废话不多说,直接上代码,源代码是慕课网老师风间影月写的,我拿来直接用了. package com.yb.entity; import java.util.List; import com.faster ...

  5. Linux的总线设备驱动模型

    裸机编写驱动比较自由,按照手册实现其功能即可,每个人写出来都有很大不同: 而Linux中还需要按照Linux的驱动模型来编写,也就是需要按照"模板"来写,写出来的驱动就比较统一. ...

  6. web服务器-Nginx下载限速

    web服务器-Nginx下载限速 一. 限速介绍 在生产环境中,为了保护WEB服务器的安全,我们都会对用户的访问做出一些限制,保证服务器的安全及资源的合理分配. 限流(rate limiting)是N ...

  7. P1030

    题面 给出一棵二叉树的中序排列与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度≤8). 输入格式 2行,均为大写字母组成的字符串,表示一棵二叉树的中序排列与后序排列. 输出格式 1 ...

  8. LINUX系统、磁盘与进程的相关命令

    ps ef:完整显示当前系统中所有运行的进程 kill 停止或杀死进程.9表示强制杀掉进程或任务 df 显示磁盘空间使用情况 du 用于显示指定目录下的文件以及子目录所占磁盘空间的大小. 与磁盘有关的 ...

  9. 在Unity中用UGUI制作可输入下拉框

    Unity中UGUI制作可输入下拉框 目录 Unity中UGUI制作可输入下拉框 前言 组件分析 制作流程 总结 前言 在搜索引擎以及一些网页中我们常常可以看见这样一种UI控件,看上去是一个输入框,在 ...

  10. 时序数据库之InfluxDB的基本操作

    1.进入Influxdb的客户端 [root@activity_sentinel ~]# influx 2.数据库的操作 显示所有的数据库名 > show databases name: dat ...