soft lockup和hard lockup介绍
转自:http://www.cnblogs.com/openix/p/4034530.html
转自:http://blog.csdn.net/panzhenjie/article/details/10074551/
在linux kernel里,有一个debug选项LOCKUP_DETECTOR。
使能它可以打开kernel中的soft lockup和hard lockup探测。
这两个东西到底有什么用处那?
首先,soft/hard lockup的实现在kernel/watchdog.c中,
主体涉及到了3个东西:kernel线程,时钟中断,NMI中断(不可屏蔽中断)。
这3个东西具有不一样的优先级,依次是kernel线程 < 时钟中断 < NMI中断。
而正是用到了他们之间优先级的区别,所以才可以调试系统运行中的两种问题:
1. 抢占被长时间关闭而导致进程无法调度(soft lockup)
2. 中断被长时间关闭而导致更严重的问题(hard lockup)
接下来我们从具体代码入手分析linux(3.10)是如何实现这两种lockup的探测的:
- static struct smp_hotplug_thread watchdog_threads = {
- .store = &softlockup_watchdog,
- .thread_should_run = watchdog_should_run,
- .thread_fn = watchdog,
- .thread_comm = "watchdog/%u",
- .setup = watchdog_enable,
- .park = watchdog_disable,
- .unpark = watchdog_enable,
- };
- void __init lockup_detector_init(void)
- {
- set_sample_period();
- if (smpboot_register_percpu_thread(&watchdog_threads)) {
- pr_err("Failed to create watchdog threads, disabled\n");
- watchdog_disabled = -ENODEV;
- }
- }
首先,系统会为每个cpu core注册一个一般的kernel线程,名字叫watchdog/0, watchdog/1...以此类推。
这个线程会定期得调用watchdog函数
- static void __touch_watchdog(void)
- {
- __this_cpu_write(watchdog_touch_ts, get_timestamp());
- }
- static void watchdog(unsigned int cpu)
- {
- __this_cpu_write(soft_lockup_hrtimer_cnt,
- __this_cpu_read(hrtimer_interrupts));
- __touch_watchdog();
- }
我们先不理会这个线程处理函数watchdog多久被调用一次,我们就先简单的认为,这个线程是负责更新watchdog_touch_ts的。
然后我们要看一下时钟中断了:
- static void watchdog_enable(unsigned int cpu)
- {
- struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
- /* kick off the timer for the hardlockup detector */
- hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer->function = watchdog_timer_fn;
- /* done here because hrtimer_start can only pin to smp_processor_id() */
- hrtimer_start(hrtimer, ns_to_ktime(sample_period),
- HRTIMER_MODE_REL_PINNED);
- }
时钟中断处理函数是watchdog_timer_fn
- static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
- {
- unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts);
- int duration;
- /* kick the hardlockup detector */
- watchdog_interrupt_count();
- duration = is_softlockup(touch_ts);
- if (unlikely(duration)) {
- if (softlockup_panic)
- panic("softlockup: hung tasks");
- __this_cpu_write(soft_watchdog_warn, true);
- } else
- __this_cpu_write(soft_watchdog_warn, false);
- return HRTIMER_RESTART;
- }
这个函数主要做2件事情:
1. 更新hrtimer_interrupts变量。
- static void watchdog_interrupt_count(void)
- {
- __this_cpu_inc(hrtimer_interrupts);
- }
这里我们就要回顾之前创建的那个kernel线程了,多久调用一次就和hrtimer_interrupts的值密切相关。
- static int watchdog_should_run(unsigned int cpu)
- {
- return __this_cpu_read(hrtimer_interrupts) !=
- __this_cpu_read(soft_lockup_hrtimer_cnt);
- }
只有在hrtimer_interrupts发生了更新的情况下,kernel线程才会被得到运行。
那就是说,kernel线程和时钟中断函数的频率是相同的。默认情况是10*2/5=4秒一次。
- int __read_mostly watchdog_thresh = 10;
- static int get_softlockup_thresh(void)
- {
- return watchdog_thresh * 2;
- }
- static void set_sample_period(void)
- {
- /*
- * convert watchdog_thresh from seconds to ns
- * the divide by 5 is to give hrtimer several chances (two
- * or three with the current relation between the soft
- * and hard thresholds) to increment before the
- * hardlockup detector generates a warning
- */
- sample_period = get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5);
- }
2.就是要探测是否有soft lockup发生。
- static int is_softlockup(unsigned long touch_ts)
- {
- unsigned long now = get_timestamp();
- /* Warn about unreasonable delays: */
- if (time_after(now, touch_ts + get_softlockup_thresh()))
- return now - touch_ts;
- return 0;
- }
很容易理解,其实就是查看watchdog_touch_ts变量在最近20秒的时间内,有没有被创建的kernel thread更新过。
假如没有,那就意味着线程得不到调度,所以很有可能就是在某个cpu core上抢占被关闭了,所以调度器没有办法进行调度。
这种情况下,系统往往不会死掉,但是会很慢。
有了soft lockup的机制,我们就能尽早的发现这样的问题了。
分析完soft lockup,我们继续分析hard lockup
- static int watchdog_nmi_enable(unsigned int cpu)
- {
- struct perf_event_attr *wd_attr;
- wd_attr = &wd_hw_attr;
- wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
- /* Try to register using hardware perf events */
- event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
- }
perf_event_create_kernel_counter函数主要是注册了一个硬件的事件。
这个硬件在x86里叫performance monitoring,这个硬件有一个功能就是在cpu clock经过了多少个周期后发出一个NMI中断出来。
- u64 hw_nmi_get_sample_period(int watchdog_thresh)
- {
- return (u64)(cpu_khz) * 1000 * watchdog_thresh;
- }
在这里,根据当前cpu的频率,算出一个值,也就是20秒cpu clock经过的周期数。
这样一来,当cpu全负荷跑完20秒后,就会有一个NMI中断发出,而这个中断的出路函数就是watchdog_overflow_callback。
- static void watchdog_overflow_callback(struct perf_event *event,
- struct perf_sample_data *data,
- struct pt_regs *regs)
- {
- if (is_hardlockup()) {
- int this_cpu = smp_processor_id();
- if (hardlockup_panic)
- panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
- else
- WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
- return;
- }
- return;
- }
这个函数主要就是调用is_hardlockup
- static int is_hardlockup(void)
- {
- unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
- if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
- return 1;
- __this_cpu_write(hrtimer_interrupts_saved, hrint);
- return 0;
- }
而这个函数主要就是查看hrtimer_interrupts变量在时钟中断处理函数里有没有被更新。
假如没有更新,就意味着中断出了问题,可能被错误代码长时间的关中断了。
那这样,相应的问题也就暴露出来了。
soft lockup和hard lockup介绍的更多相关文章
- 内核如何检测SOFT LOCKUP与HARD LOCKUP?
内核如何检测SOFT LOCKUP与HARD LOCKUP? From article 所谓lockup,是指某段内核代码占着CPU不放.Lockup严重的情况下会导致整个系统失去响应.Lockup有 ...
- Linux soft lockup 和 hard lockup
一. 整体介绍 soft lockup:检测调度异常, 一般是驱动禁止调度或者阻塞比如while(1), 导致无法调度其他线程, 需要注意的是, 应用程序while(1)不会影响其调度, 只要有更高的 ...
- CentOS7运行报错kernel:NMI watchdog: BUG: soft lockup - CPU#0 stuck for 26s
CentOS内核,对应的文件是/proc/sys/kernel/watchdog_thresh.CentOS内核和标准内核还有一个地方不一样,就是处理CPU占用时间过长的函数,CentOS下是watc ...
- 报错kernel:NMI watchdog: BUG: soft lockup - CPU#0 stuck for 26s
近期在服务器跑大量高负载程序,造成cpu soft lockup.如果确认不是软件的问题. 解决办法: #追加到配置文件中 echo 30 > /proc/sys/kernel/watchdog ...
- C/C++ 介绍的PE文件遍历工具
在前面的笔记中,我总结了Pe结构的一些结构含义,并手动编写了几段PE结构遍历代码,这里我直接把之前的C语言代码进行了封装,形成了一个命令行版的PE文件查看工具,该工具只有20kb,但却可以遍历出大部分 ...
- cpu资源长期使用率过高导致系统内核锁问题
服务器跑大量高负载程序,会造成cpu soft lockup. 解决办法: #追加到配置文件中 echo 30 > /proc/sys/kernel/watchdog_thresh #查看 [r ...
- Linux网络驱动--snull
snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
- 基于 CodeIgniter 的各类开源项目大全
名称:STBlog 介绍:STBlog 是一套由CI中国社区驱动,基于Codeigniter MVC 框架编写的多权限博客系统,轻巧/快速/安全/易拓展/界面友好是它的最大特点. 官方:http:// ...
- 企业建站系统MiinCMP1.0.5 版公布!
2014-5-4,在青年节,Juuluu公布了其企业建站系统的新版1.0.5,经过两周多的奋战,Juuluu团队为MiinCMP新浪云版的移植工作做了大量工作.1.0.5已可完美执行于国内免费的jav ...
随机推荐
- LUA的编译、环境等
Lua的环境.编译等 Lua命令行 lua命令行选项: -i:进入交互式 -e:执行lua代码 -l:加载库文件 例如使用下面的命令启动lua解释器,可以重新定义lua提示符. lua -i -e & ...
- mysql 外键(FOREIGN KEY)
最近有开始做一个实验室管理系统,因为分了几个表进行存储·所以要维护表间的关联··研究了一下MySQL的外键. (1)只有InnoDB类型的表才可以使用外键,mysql默认是MyISAM,这种类型不支持 ...
- 远程桌面连接不上|windows server 2003 sp2 termdd.sys(转载)
远程桌面连接不上|windows server 2003 sp2 termdd.sys.请教一个问题,为什么 Windows Server 2003 打上SP2补丁,就不能通过远程桌面连接上去了?服务 ...
- SQLServer 删除所有表和删除所有存储过程
1.删除所有表 use 数据库declare @tname varchar(8000)set @tname=''select @tname=@tname + Name + ',' from sysob ...
- Swift翻译之-关于Swift
IMPORTANT 重要的 This is a preliminary document for an API or technology in development. Apple is suppl ...
- fatl exception occurred异常/错误的一种可能情况
如果,有可能是 java.lang.ClassLoader类内部出错,请自行检查
- word双面打印的方法
首先要明白打印的过程 先进入打印机的纸张顶部,肯定是先打印,这样就确定了纸张放置的方向,不会放倒了 肯定是打印在纸张的向上的那一面,这样就确定了打印的正反面 纸张打印的顺序肯定是从上到下,这样就确定了 ...
- github和bitbucket
注册一个github跟注册一个163的邮箱一样容易 页面中 div方块的 布局和 尺寸, 主要是考虑功能/ 结构/布局, 基本上与其中的内容 的多少无关: 即使内容/文字很少, 也还是要那么宽的尺寸 ...
- Linux 下的另一个密码破解工具medusa
首先,本人在此声明 此工具许合理利用非法破解很可能会被发现的因为这是一个暴力破解方式需要不断的尝试登陆服务器 ,服务器上的检测软件很快可以跟踪到并锁定你的IP地址 请大家切勿用于非法手段- -! me ...
- 用 Java 实现断点续传 (HTTP)
断点续传的原理 其实断点续传的原理很简单,就是在 Http 的请求上和一般的下载有所不同而已. 打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为 wwww.sjtu.edu ...