热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

用户USER_HZ与内核HZ的值

HZ和Jiffies系统定时器timer能够以可编程的方式设定频率,来中断cpu处理器。此频率即hz,为每秒的定时器节拍(tick)数,对应着内核变量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

 



推荐阅读
  • 本文详细介绍了优化DB2数据库性能的多种方法,涵盖统计信息更新、缓冲池调整、日志缓冲区配置、应用程序堆大小设置、排序堆参数调整、代理程序管理、锁机制优化、活动应用程序限制、页清除程序配置、I/O服务器数量设定以及编入组提交数调整等方面。通过这些技术手段,可以显著提升数据库的运行效率和响应速度。 ... [详细]
  • 解决TensorFlow CPU版本安装中的依赖问题
    本文记录了在安装CPU版本的TensorFlow过程中遇到的依赖问题及解决方案,特别是numpy版本不匹配和动态链接库(DLL)错误。通过详细的步骤说明和专业建议,帮助读者顺利安装并使用TensorFlow。 ... [详细]
  • 本文详细探讨了如何通过分析单个或多个线程在瓶颈情况下的表现,来了解处理器资源的消耗。无论是单进程还是多进程环境,监控关键指标如线程数量、占用时间及调度优先级等,有助于揭示潜在的性能问题。 ... [详细]
  • 对于许多初学者而言,遇到总线错误(bus error)或段错误(segmentation fault/core dump)是极其令人困扰的。本文详细探讨了这两种错误的成因、表现形式及解决方法,并提供了实用的调试技巧。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 本文详细介绍了Java中实现异步调用的多种方式,包括线程创建、Future接口、CompletableFuture类以及Spring框架的@Async注解。通过代码示例和深入解析,帮助读者理解并掌握这些技术。 ... [详细]
  • 本文详细介绍了如何在不同操作系统和设备上设置和配置网络连接的IP地址,涵盖静态和动态IP地址的设置方法。同时,提供了关于路由器和机顶盒等设备的IP配置指南。 ... [详细]
  • 主板IO用W83627THG,用VC如何取得CPU温度,系统温度,CPU风扇转速,VBat的电压. ... [详细]
  • 本文详细介绍了Grand Central Dispatch (GCD) 的核心概念和使用方法,探讨了任务队列、同步与异步执行以及常见的死锁问题。通过具体示例和代码片段,帮助开发者更好地理解和应用GCD进行多线程开发。 ... [详细]
  • 离线安装Grafana Cloudera Manager插件并监控CDH集群
    本文详细介绍如何离线安装Cloudera Manager (CM) 插件,并通过Grafana监控CDH集群的健康状况和资源使用情况。该插件利用CM提供的API接口进行数据获取和展示。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • vivo Y5s配备了联发科Helio P65八核处理器,这款处理器采用12纳米工艺制造,具备两颗高性能Cortex-A75核心和六颗高效能Cortex-A55核心。此外,它还集成了先进的图像处理单元和语音唤醒功能,为用户提供卓越的性能体验。 ... [详细]
  • 访问一个网页的全过程
    准备:DHCPUDPIP和以太网启动主机,用一根以太网电缆连接到学校的以太网交换机,交换机又与学校的路由器相连.学校的这台路由器与一个ISP链接,此ISP(Intern ... [详细]
  • 了解计算机的序列号和主板型号对于多种用途至关重要。本文将详细介绍如何使用命令提示符和第三方工具,在Windows 10系统中轻松获取这些关键硬件信息。 ... [详细]
  • 深入理解进程与线程:创建子进程和子线程的区别
    本文详细探讨了进程与线程的概念,解释了它们在资源分配和程序执行中的不同角色。通过对比进程和线程的创建方式及其特点,帮助读者更好地理解两者之间的差异。 ... [详细]
author-avatar
BrucelLi
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有