一,softlockup: watchdog软狗/软锁----用于检测系统调度是否正常。 能响应中断,但调度异常。
软件死锁:内核在内核模式下循环超过20s (watchdog_thresh*2),没有给其它进程机会去运行。
默认系统保持死锁显示当前堆栈信息。可以通过softlockup_panic=1来配置主动panic系统。
运行时参数sysctl:
1, /proc/sys/kernel/watchdog -->watchdog_enable //默认为1,使能,开启watchdog
2, /proc/sys/kernel/watchdog_thresh -->watchdog_thresh //默认为10s,但watchdog的定时器检查时间是: watchdog_thresh*2/5
3, /proc/sys/kernel/softlockup_panic -->softlockup_panic //默认为0, 即默认只是显示告警堆栈, 为1表示会panic系统。
4, /proc/sys/kernel/nmi_watchdog -->watchdog_enabled // 0(关闭hardlockup,softlockup); panic,nopanic
:~ # sysctl -a | grep watchdog
kernel.watchdog = 1
kernel.watchdog_thresh = 10
kernel.nmi_watchdog = 1
:~ # sysctl -a | grep softlockup
kernel.softlockup_panic = 0
softlockup与hardlockup的启动参数:
1>,softlockup_panic=1 在检测到softlockup时panic系统, 如果为0,watchdog也会检测softlockup但不会panic.
2>,nosoftlockup/nowatchdog : watchdog_enable=0,即关闭softlockup也会关闭hardlockup,即关闭软狗与硬狗.
启动参数:
3>,nmi_watchdog=[panic,] [nopanic,] [num] ----> hardlockup_panic_setup( )
设置非屏蔽中断(NMI)watchdog的特性。"0"表示禁用NMI watchdog(也会关闭softlockup);
panic: 表示在hardlockup发生时,主动panic系统。nopanic:只打印告警信息。
运行时关闭与开启:
echo 0 >/proc/sys/kernel/nmi_watchdog 运行时关闭硬锁检测。
echo 1> /proc/sys/kernel/nmi_watchdog 运行时重新使能硬锁检测。
4>,nowatchdog: watchdog_enable=0,关闭softlockup 和hardlockup,即关闭软狗与硬狗.
softlockup原理图:
初始化流程:
init/main.c
start_kernel()
rest_init()
-->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); //创建1号进程,它最后会执行用户态的init进程
kernel_init()--> //1号进程
lockup_detector_init(); //watchdog初始化,开启第一个watchdog/%d
cpu_callback(&cpu_nfb,CPU_UP_PREPARE,cpu)
register_cpu_notifier(&cpu_nfb); //把通知块cpu_nfb(回调函数为cpu_callback)加入到通知链cpu_chain
smp_init(); //唤起其它CPU,开启其它watchdog/%d
cpu_up(cpu)
->_cpu_up(cpu, 0);
->__cpu_notify
->notifier_call_chain() //遍历cpu_chain,并执行cpu_nfb通知块对应的函数cpu_callback
kernel/watchdog.c
static int __cpuinit cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
watchdog_prepare_cpu(hotcpu); //初始化定时器watchdog_hrtimer
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
if (watchdog_enabled)
watchdog_enable(hotcpu); //创建"watchdog/%d"内核线程,也会调用watchdog_nmi_enable(cpu)使能hardlockup
break;
...
}
二,hardlockup: nmi_watchdog硬狗/硬锁----用于检测中断系统是否正常。
硬件死锁:CPU在内核模式下循环超过10s(watchdog_thresh)没有给其它中断机会运行则默认系统保持死锁。可以通过nmi_watchdog=panic配置当检查到hardlockup时主动panic系统.
在当前X86/X86_64的通用平台上,有一个硬件特性:能产生 watchdog NMI interrupts. 即产生:不可屏蔽中断。
通过周期性的执行NMI中断,可以监视每个CPU是否被锁死。
hardlockup: 硬锁实现原理 (当前用PMU实现, Performance monitor units性能管理监视单元)
为了使能NMI watchdog, 内核需要支持APIC。
X86 SMP系统内核:APIC已自动编译进内核。
X86 UP系统内核:需启用CONFIG_X86_UP_APIC(Processor type and features -> Local APIC support on uniprocessors)
或CONFIG_X86_UP_IOAPIC(Processor type and features -> IO-APIC support on uniprocessors)。
注:CONFIG_X86_UP_APIC用于没有IO-APIC的单处理器机器。
CONFIG_X86_UP_IOAPIC用于具有IO-APIC的单处理器。
对于X86_64, APIC也已自动编译进内核。
NMI watchdog中断:
当使用 Local-APIC时,NMI interrupts 频率取决于系统load负载。
因为Local-APIC NMI watchdog没有更好的"中断源". 使用的是"cycles unhalted"事件。当系统idle,CPU在halted状态时不会产生tick事件.
如果系统硬死锁在除了"hlt"指令的任何地方,硬狗watchdog会在每个时钟周期clock tick中因"cycles unhalted"事件很快触发。
但是如果系统硬死锁在了"hlt"指令内, 则"cycles unhalted"事情就不会被触发,即不会触发watchdog.
--这就是Local-APIC watchdog的缺点。不幸的是:没有"clock ticks"事性可以始终工作。
使用 IO-APIC NMI watchdog 没有这个缺点。但是因为它是由外部设备驱动的, 由于它的中断频率比较高,对整个系统的性能有比较大的影响。
硬锁死锁的判断:
如果系统中的任何一个CPU没有执行"周期性的时钟中断"超过10s, 那么NMI处理程序就会产生一个oops并杀死进程.
初始化流程:
kernel/watchdog.c
watchdog_enable(cpu)
-->watchdog_nmi_enable(cpu);
wd_attr = &wd_hw_attr;
wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); // cpu_khz*1000*watchdog_thresh
perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
PMU说明:翻译 tools/perf/design.txt
linux性能计数器:Performance Counters for Linux
------------------------------
性能计数器(Performance counters)是一类多数现代CPU中都有的特殊硬件寄存器。
这些寄存器计录了一些特定的硬件事件hw events: (不会减慢内核或应用程序)
如:
执行的指令数,instructions executed.
缓存未命中的损失,cachemisses suffered.
分支预测错误,branches mis-predicted.
这些寄存器也可以用来触发中断:比如设置一个事情的阈值,当此事性的阈值到时,就可以产生中断。
因此可以用(寄存器产生的中断)来分析在该CPU上运行的代码。
性能监视:可以参考使用命令perf
源码注释:kernel/watchdog.c