用户USER_HZ与内核HZ的值
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的值的更多相关文章
- linux信号机制 - 用户堆栈和内核堆栈的变化【转】
转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...
- Linux用户空间与内核空间(理解高端内存)
Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...
- Linux用户空间与内核空间
源:http://blog.csdn.net/f22jay/article/details/7925531 Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针 ...
- 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口
Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...
- Linux操作系统学习_用户态与内核态之切换过程
因为操作系统的很多操作会消耗系统的物理资源,例如创建一个新进程时,要做很多底层的细致工作,如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录.页表等,这些操作显然不能随便让任何程序都可以做,于是就产 ...
- linux 用户空间与内核空间——高端内存详解
摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...
- 用户态与内核态 & 文件流与文件描述符 简介【转】
转自:https://www.cnblogs.com/Jimmy1988/p/7479856.html 用户态和内核态 程序代码的依赖和调用关系如下图所示: Lib:标准ASCI C函数,几乎所有的平 ...
- 用户态与内核态 & 文件流与文件描述符 简介
用户态和内核态 程序代码的依赖和调用关系如下图所示: Lib:标准ASCI C函数,几乎所有的平台都支持该库函数,因此依赖该库的程序可移植性好: System Function:系统调用函数,与系统内 ...
- Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十)
1 非抢占式和可抢占式内核 为了简化问题,我使用嵌入式实时系统uC/OS作为例子 首先要指出的是,uC/OS只有内核态,没有用户态,这和Linux不一样 多任务系统中, 内核负责管理各个任务, 或者说 ...
随机推荐
- 基于Drone+Gogs流水线-全面认识轻量级云原生CI引擎Drone
1. 介绍 Drone by Harness 是一个基于Docker容器技术的可扩展的持续集成引擎,用于自动化测试.构建.发布.每个构建都在一个临时的Docker容器中执行,使开发人员能够完全控制其构 ...
- 分布式 PostgreSQL 集群(Citus)官方安装指南
单节点 Citus Docker (Mac 与 Linux) Docker 镜像仅用于开发/测试目的, 并且尚未准备好用于生产用途. 您可以使用一个命令在 Docker 中启动 Citus: # st ...
- springcloud学习04- 断路器Spring Cloud Netflix Hystrix
依赖上个博客:https://www.cnblogs.com/wang-liang-blogs/p/12072423.html 1.断路器存在的原因 引用博客 https://blog.csdn.ne ...
- 百度Paddle速查_CPU和GPU的mnist预测训练_模型导出_模型导入再预测_导出onnx并预测
需要做点什么 方便广大烟酒生研究生.人工智障炼丹师算法工程师快速使用百度PaddelPaddle,所以特写此文章,默认使用者已有基本的深度学习概念.数据集概念. 系统环境 python 3.7.4 p ...
- GitHub如何选择合适的license(许可证)
license译为许可证,也可作为开源协议,它可以将自己创作的东西,授权给他人使用,并约定了使用者可以有的权利和必须遵从的义务.现在很多优秀的开源项目都有设置license,不同的license所约束 ...
- 羽夏逆向指引—— Hook
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的, ...
- display 不同的值及他们的作用
display 不同的值及他们的作用 常见 block 块元素类型,默认宽度为父元素宽度,可设置宽高,并独占一行 none 元素不显示,并从文档流中移除 inline 行内元素类型,默认宽度为内容宽度 ...
- 文字图片在wps中清晰化方法
在wps中双击图片出属性,然后再选择文字增强.选择对比增加即可.
- 面试问题之C++语言:说一说C++中四种cast转换
C++中四种类型转换是:static_cast.dynamic_cast.const_cast.reinterpret_cast 1.const_cast 常量转换,用于将const变量转为非cons ...
- kafka中的回调函数
kafka客户端中使用了很多的回调方式处理请求.基本思路是将回调函数暂存到ClientRequest中,而ClientRequest会暂存到inFlightRequests中,当返回response的 ...