linux内核源代码分析-定时器与时间管理
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
定时器与时间管理、内存管理
内核中的时间概念 Linux中时间表示 硬件时钟和定时器 Linux下的时钟中断和相关时间应用 Linux内存页 Linux内存区 内存管理提供的服务 内存管理缓存机制 内存映射
上次内容回顾 系统调用和中断(回顾上节课内容) 中断处理程序的上、下半部机制 LINUX下半部处理机制 同步的经典问题 LINUX内核同步实现
统计的不精确性 根据上面的处理可以看出,一个节拍的时间要么给一 个用户进程,要么给系统,这样做很不精确,因为在 一个节拍中进程可能多次进入。这也是要采取更高频 率的原因。
Linux下的时钟中断和相关时间应用
更新墙上时钟 Void update_times(void) { unsigned long ticks; ticks = jiffies – wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); last_time_offset = 0; calc_load(ticks); }
Leabharlann Baiduinux下的时钟中断和相关时间应用
Do_timer() void do_timer(struct pt_regs *regs) { jiffies_64++; update_process_times(user_mode(regs)); update_times(); }
Linux下的时钟中断和相关时间应用
Void update_process_times(int user_tick) { Struct task_struct *p = current; Int cpu = smp_processor_id() Int system = user_tick ^1; … }(见书上P123)
Linux下的时钟中断和相关时间应用
多时会产生中断频繁 但提高精度(分析:平均误差)
Linux中时间表示(HZ)
精度提高的进一步讨论
– – – – 一些关键系统调用的效率提高(poll(),select()) 进程抢占的精度提高 时间测量方面精度提高 中断次数增加带来的问题
综合考虑认为目前体系结构的系统设为1000可以忍受。
Linux中时间表示(jiffies)
其他几个函数
– Mod_timer() – Del_timer()
Linux下的时钟中断和相关时间应用
定时器竞争条件 定时器的实现
– 在时钟中断处理程序的下半部执行:update_process_timers()函 数,该函数调用run_local_timers() { raise_softirq(TIMER_SOFTIRQ); }
释放页
– __free_pages – Free_pages – Free_page
内存管理提供的服务 Kmalloc Kfree Vmalloc vfree
内存管理提供的服务 Slab层
– 一种缓存机制(P143-P148)
Linux中时间表示(HZ)
节拍率(HZ)
– 系统定时器频率,可以通过设置修改,系统启动时设置,不 同体系结构下不同。 如:在include/asm-i386/param.h中: #define Hz 1000 //相当于1秒中断1000次 思考:时间的精确性 – 书上P116表9-1给出一般情况下各种体系结构下的时钟中断频 率 – 理想的HZ值应该是多少?
内核中的时间概念
事件驱动与时间驱动 内核中需管理相对时间和绝对时间 内核时间的硬件基础(系统定时器以某种频率触发, hitting or poping,该频率可以通过编程预定(tick rate) poping, tick rate 直接用处:
– – – – – 更新系统运行时间 更新实际时间 定期均衡运行队列(SMP上) 时间片 定期统计
Linux下的时钟中断和相关时间应用
延迟执行
– 忙等待 – 短延迟
Linux内存页
内核中内存的分配要复杂的多 内核以物理页为单位分配内存 物理页的大小取决于体系结构,一般
– 4kB – 8kB
Linux内存页
数据结构:<linux/mm.h>中定义: Struct page { unsigned long flags; Atomic_t count; Struct list_head list; Struct address_space *mapping; Unsigned long index; Struct list_head lru; Union { struct pte_chain *chain; pte_addr_t direct;} pte Unsigned long private; Void *virtual;}
– 溢出时间问题 – 64位问题(2.6中)
Linux中时间表示(jiffies)
64位与32位的结合 Jiffies的回绕 unsigned long timeout = jiffies + HZ/2; /*执行一些任务….*/ if (timeout <jiffies) { 未超时,正常处理} else { 超时,错误处理; }
– #define jiffies_to_clock(x) ((x)/(HZ/USER_HZ)) – 否则,需要向时间上做一下转换,误差会小一些。 思考一下,为什么?
硬件时钟和定时器
体系结构提供了两种设备计时
– 系统定时器 – 实时时钟(RTC),不开机时靠电池供电工作,系统启动时, 初始化xtime变量。 xtime
全局变量,用来记录系统启动以来产生的节拍总数 在<linux/jiffies.h>中定义: Extern unsigned long volatile jiffies;响应地有: Seconds* HZ = jiffies; (jiffies/HZ) = seconds;(还有一些其他的转换) 有关jiffies的内部位数问题:
Linux中时间表示(jiffies)
回绕的处理: time_after Time_before Time_after_eq Time_before_eq 分析怎样避免的回绕影响(借用了LONG的符号)
Linux中时间表示(用户空间和HZ)
内核改变HZ的值会影响一些基于原来值的应用 内核需要导出合适的jeffies值 若新旧HZ数差整数倍则比较简单
内存管理提供的服务
获得页
– – – – – Alloc_pages() Page_address(struct page *page) __get_free_pages() alloc_page() __get_free_page()
内存管理提供的服务
获得填充为0的页
– Get_zeroed_page()
Linux下的时钟中断和相关时间应用
从用户空间获取时间的调用为
– Gettimeofday() 内核中对应的系统调用为:sys_gettimeofday() P125
Linux下的时钟中断和相关时间应用
动态定时器
– 一些工作要在后面一个相当的时间执行,这就需要定时器的 控制,定时器有时也称内核定时器 – 使用定时器 定时器由timer_list表示,定义在<linux/timer.h>中。 具体结构见:P126
Linux内存区
由于硬件的限制,内核并不能对所有的页一样看待。 这样内核需要对页进行分类,分不同的区域。
– 一些硬件只能允许某些特定的内存地址来执行DMA. – 一些体系结构其内存的物理地址范围比虚拟寻址范围大得多。 这样有一些内存就不能总是映射到内核空间上。 Linux对应有三个区 ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM (P135)
Linux下的时钟中断和相关时间应用
时钟中断处理程序做的工作:
– 获得xtime_lock锁,对jiffies_64和xtime进行保护(为什么jiffies 不用保护) – 应答或重新设置系统时钟 – 周期性地使用墙上时间更新实时时钟 – 调用体系结构无关的时钟例程:do_timer():
Jiffies_64变量加1 更新资源消耗的统计值 执行到期的动态定时器 执行sheduler_tick()函数 更新墙上时间并存到xtime变量中 计算平均负载值
Linux下的时钟中断和相关时间应用
实际时间
– – – – – 定义在<linux/time.h>中,形式如下: Struct timespec{ Time_t tv_sec; Long tv_nsec; }
Linux下的时钟中断和相关时间应用
实际时间的更新和读取都需要锁。
– Write_seqlock(&xtime_lock); – /* 更新xtime…*/ – Write_sequnlock(&xtime_lock); – Read_seqbegin() , read_seqretry();(P125)
定义:struct timer_list my_timer; 初始化:init_timer(&my_timer); 填充结构中需要的值:my_timer.expires =…
my_timer.function = myfunction;
激活定时器:add_timer(&my_timer);
Linux下的时钟中断和相关时间应用
内核中的时间概念 Linux中时间表示 硬件时钟和定时器 Linux下的时钟中断和相关时间应用 Linux内存页 Linux内存区 内存管理提供的服务 内存管理缓存机制 内存映射
上次内容回顾 系统调用和中断(回顾上节课内容) 中断处理程序的上、下半部机制 LINUX下半部处理机制 同步的经典问题 LINUX内核同步实现
统计的不精确性 根据上面的处理可以看出,一个节拍的时间要么给一 个用户进程,要么给系统,这样做很不精确,因为在 一个节拍中进程可能多次进入。这也是要采取更高频 率的原因。
Linux下的时钟中断和相关时间应用
更新墙上时钟 Void update_times(void) { unsigned long ticks; ticks = jiffies – wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); last_time_offset = 0; calc_load(ticks); }
Leabharlann Baiduinux下的时钟中断和相关时间应用
Do_timer() void do_timer(struct pt_regs *regs) { jiffies_64++; update_process_times(user_mode(regs)); update_times(); }
Linux下的时钟中断和相关时间应用
Void update_process_times(int user_tick) { Struct task_struct *p = current; Int cpu = smp_processor_id() Int system = user_tick ^1; … }(见书上P123)
Linux下的时钟中断和相关时间应用
多时会产生中断频繁 但提高精度(分析:平均误差)
Linux中时间表示(HZ)
精度提高的进一步讨论
– – – – 一些关键系统调用的效率提高(poll(),select()) 进程抢占的精度提高 时间测量方面精度提高 中断次数增加带来的问题
综合考虑认为目前体系结构的系统设为1000可以忍受。
Linux中时间表示(jiffies)
其他几个函数
– Mod_timer() – Del_timer()
Linux下的时钟中断和相关时间应用
定时器竞争条件 定时器的实现
– 在时钟中断处理程序的下半部执行:update_process_timers()函 数,该函数调用run_local_timers() { raise_softirq(TIMER_SOFTIRQ); }
释放页
– __free_pages – Free_pages – Free_page
内存管理提供的服务 Kmalloc Kfree Vmalloc vfree
内存管理提供的服务 Slab层
– 一种缓存机制(P143-P148)
Linux中时间表示(HZ)
节拍率(HZ)
– 系统定时器频率,可以通过设置修改,系统启动时设置,不 同体系结构下不同。 如:在include/asm-i386/param.h中: #define Hz 1000 //相当于1秒中断1000次 思考:时间的精确性 – 书上P116表9-1给出一般情况下各种体系结构下的时钟中断频 率 – 理想的HZ值应该是多少?
内核中的时间概念
事件驱动与时间驱动 内核中需管理相对时间和绝对时间 内核时间的硬件基础(系统定时器以某种频率触发, hitting or poping,该频率可以通过编程预定(tick rate) poping, tick rate 直接用处:
– – – – – 更新系统运行时间 更新实际时间 定期均衡运行队列(SMP上) 时间片 定期统计
Linux下的时钟中断和相关时间应用
延迟执行
– 忙等待 – 短延迟
Linux内存页
内核中内存的分配要复杂的多 内核以物理页为单位分配内存 物理页的大小取决于体系结构,一般
– 4kB – 8kB
Linux内存页
数据结构:<linux/mm.h>中定义: Struct page { unsigned long flags; Atomic_t count; Struct list_head list; Struct address_space *mapping; Unsigned long index; Struct list_head lru; Union { struct pte_chain *chain; pte_addr_t direct;} pte Unsigned long private; Void *virtual;}
– 溢出时间问题 – 64位问题(2.6中)
Linux中时间表示(jiffies)
64位与32位的结合 Jiffies的回绕 unsigned long timeout = jiffies + HZ/2; /*执行一些任务….*/ if (timeout <jiffies) { 未超时,正常处理} else { 超时,错误处理; }
– #define jiffies_to_clock(x) ((x)/(HZ/USER_HZ)) – 否则,需要向时间上做一下转换,误差会小一些。 思考一下,为什么?
硬件时钟和定时器
体系结构提供了两种设备计时
– 系统定时器 – 实时时钟(RTC),不开机时靠电池供电工作,系统启动时, 初始化xtime变量。 xtime
全局变量,用来记录系统启动以来产生的节拍总数 在<linux/jiffies.h>中定义: Extern unsigned long volatile jiffies;响应地有: Seconds* HZ = jiffies; (jiffies/HZ) = seconds;(还有一些其他的转换) 有关jiffies的内部位数问题:
Linux中时间表示(jiffies)
回绕的处理: time_after Time_before Time_after_eq Time_before_eq 分析怎样避免的回绕影响(借用了LONG的符号)
Linux中时间表示(用户空间和HZ)
内核改变HZ的值会影响一些基于原来值的应用 内核需要导出合适的jeffies值 若新旧HZ数差整数倍则比较简单
内存管理提供的服务
获得页
– – – – – Alloc_pages() Page_address(struct page *page) __get_free_pages() alloc_page() __get_free_page()
内存管理提供的服务
获得填充为0的页
– Get_zeroed_page()
Linux下的时钟中断和相关时间应用
从用户空间获取时间的调用为
– Gettimeofday() 内核中对应的系统调用为:sys_gettimeofday() P125
Linux下的时钟中断和相关时间应用
动态定时器
– 一些工作要在后面一个相当的时间执行,这就需要定时器的 控制,定时器有时也称内核定时器 – 使用定时器 定时器由timer_list表示,定义在<linux/timer.h>中。 具体结构见:P126
Linux内存区
由于硬件的限制,内核并不能对所有的页一样看待。 这样内核需要对页进行分类,分不同的区域。
– 一些硬件只能允许某些特定的内存地址来执行DMA. – 一些体系结构其内存的物理地址范围比虚拟寻址范围大得多。 这样有一些内存就不能总是映射到内核空间上。 Linux对应有三个区 ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM (P135)
Linux下的时钟中断和相关时间应用
时钟中断处理程序做的工作:
– 获得xtime_lock锁,对jiffies_64和xtime进行保护(为什么jiffies 不用保护) – 应答或重新设置系统时钟 – 周期性地使用墙上时间更新实时时钟 – 调用体系结构无关的时钟例程:do_timer():
Jiffies_64变量加1 更新资源消耗的统计值 执行到期的动态定时器 执行sheduler_tick()函数 更新墙上时间并存到xtime变量中 计算平均负载值
Linux下的时钟中断和相关时间应用
实际时间
– – – – – 定义在<linux/time.h>中,形式如下: Struct timespec{ Time_t tv_sec; Long tv_nsec; }
Linux下的时钟中断和相关时间应用
实际时间的更新和读取都需要锁。
– Write_seqlock(&xtime_lock); – /* 更新xtime…*/ – Write_sequnlock(&xtime_lock); – Read_seqbegin() , read_seqretry();(P125)
定义:struct timer_list my_timer; 初始化:init_timer(&my_timer); 填充结构中需要的值:my_timer.expires =…
my_timer.function = myfunction;
激活定时器:add_timer(&my_timer);
Linux下的时钟中断和相关时间应用