宏中,我需要判断I列中数字,当出现1或2时就让B26填充红色,但I列中数字是公式计算出来的?

1.线上内核bug日志

lockup就是说,这个bug没有让系统彻底死机,但是若干个进程(或者kernel thread)被锁死在了某个状态(一般在内核区域),很多情况下这个是由于内核锁的使用的问题。

watchdog能够看见,进程名称大概是watchdog/X(数字:cpu逻辑编号1/2/3/4之类的)。这个进程或者线程每一秒钟运行一次,否则会睡眠和待机。这个进程运行会收集每一个cpu运行时使用数据的时间并且存放到属于每个cpu自己的内核数据结构。在内核中有很多特定的中断函数。这些中断函数会调用soft lockup计数,他会使用当前的时间戳与特定(对应的)cpu的内核数据结构中保存的时间对比,如果发现当前的时间戳比对应cpu保存的时间大于设定的阀值,他就假设监测进程或看门狗线程在一个相当可观的时间还没有执。Cpu软锁为什么会产生,是怎么产生的?如果linux内核是经过精心设计安排的CPU调度访问,那么怎么会产生cpu软死锁?那么只能说由于用户开发的或者第三方软件引入,看我们服务器内核panic的原因就是qmgr进程引起。因为每一个无限的循环都会一直有一个cpu的执行流程(qmgr进程示一个后台邮件的消息队列服务进程),并且拥有一定的优先级。Cpu调度器调度一个驱动程序来运行,如果这个驱动程序有问题并且没有被检测到,那么这个驱动程序将会暂用cpu的很长时间。根据前面的描述,看门狗进程会抓住(catch)这一点并且抛出一个软死锁(soft lockup)错误。软死锁会挂起cpu使你的系统不可用。

3.根据linux内核源码分析错误

首先根据我们的centos版本安装相应的linux内核源码,具体步骤如下:

下面开始真正的根据内核bug日志分析源码:

(1)第一阶段内核错误日志分析(时间在Dec 4 14:03:34这个阶段的日志输出代码分析,其实这部分代码不会导致cpu软死锁,主要是第二阶段错误日志显示导致cpu软死锁)

这个宏很简单保证传递进来的条件值为0或者1(两次逻辑非操作的结果),然后使用分支预测技术(保证执行概率大的分支紧邻上面的指令)判断是否需要调用__WARN()宏定义。如果满足条件执行了__WARN()宏定义也接着执行一条空指令;。上面调用WARN_ON宏是传递的1,所以会执行__WARN()。下面继续看一下__WARN()宏定义如下:

从接下来的call trace信息中我们也确实发现调用了warn_slowpath_null这个函数。通过在linux内核源代码中搜索这个函数的实现,发现在panic.c(内核恐慌时的相关功能实现)中实现如下:

分析这个函数的实现不难发现我们的很多日志信息从这里开始输出,包括打印一些系统信息,就不继续深入分析了(请看代码注释,里面调用相关函数打印对应信息,通过我分析这些函数的实现和我们的日志信息完全能够对应,其中dump_stack是与cpu体系结构相关的,我们的服务器应该是属于x86体系)。这里在继续分析一下dump_stack函数的实现,因为这个是与cpu体系结构相关的,而且这个函数直接反应出导致内核panic的相关进程。这个函数实现如下:

这个函数打印出我们日志中的Call Trace信息,然后继续调用dump_trace函数(x86-64相关的体系结构,也就是64位的,还有一个32位的相应实现),如下:

通过这个函数的注释我们可以清楚的知道这个函数打印很多信息,包括进程堆栈信息、中断堆栈信息以及一些服务异常的硬件堆栈信息(如双重故障,NMI,堆栈错误,调试,MCE)。

通过上面这些分析只想说明一点,整个流程是没有问题的。到目前为止只有第一行日志信息还没有找到输出的地址,其实看源码很容易就看出来了,就在WARN_ON宏的上一行代码就是了,代码如下:

Printk函数的作用相当于printf,只是这个是专门用于内核的(有一些特殊实现)。通过一句代码我们也可以发现local_clock_stable是为0,因为没有打印最后那一点信息出来。到这里为止基本把第一阶段出现内核错误和bug的代码全部理解清楚了(日志时间为:Dec 4 14:03:34这个时间输出的),后面附件具体分析导致这个原因代码的原因。

(2)第二阶段(时间在Dec 4 14:03:41,与第一阶段只相差了几秒钟,应该还是存在一定的关联)内核错误日志输出代码分析,这部分日志输出显示了导致了cpu软死锁。

下面首先需要分析一下什么情况下会调用这个函数并且导致cpu软死锁,根据第二部分cpu软死锁产生原因的分析,每一个cpu都会启动一个对应的watchdog线程来监控cpu的执行状态,创建watchdog线程是在使能watchdog功能的时候,在函数watchdog_enable里面实现,代码如下:

从上面这个watchdog使能函数可以看出,每一个cpu的watchdog监控线程的入口函数是watchdog函数,还注册了一个softlockup软死锁响应函数。下面开始从watchdog函数继续开始分析,代码如下:

这个函数首先设置watchdog线程的cpu的调度策略为FIFO(先来先服务),并且优先级最低,然后初始化一个时间戳,设置当前的cpu状态为可中断的状态。然后就进入while循环了,通过while循环上面的注释我们可以清楚的知道每一秒钟都会重新设置softlockup的时间戳,如果超过60秒钟那么就会触发debug信息被打印,打印信息是在函数watchdog_timer_fn里面,这个函数是在watchdog模块初始化的时候注册的,每一个模块加载最先执行的都是模块初始化函数,当然卸载模块的时候也有相应的资源清理函数。

到这里为止我们知道了如果要打印出我们服务器内核的错误信息就必须得满足一个条件,就是已经超过60秒钟没有重新设置softlockup的时间戳了(每一,秒钟重新设置softlockup的时间戳,有一个比较通俗的说法叫做喂狗,因为上面的watchdog程序也俗称看门狗程序,cpu就是通过这种方式来检测cpu是否运行正常的,已经超过60秒钟没有喂狗了,那么狗肯定饿了,也就是cpu处于饥饿状态,浪费了cpu的时间了,最大的可能就是cpu产生了软死锁)。这里就不详细分析cpu调度相关的功能了,还是继续分析产生这种bug的原因。下面最主要的就是分析为什么超过60秒钟没有喂狗(重新设置softlockup时间戳)了。分析这个应该需要结合第一阶段的错误日志分析,第一阶段也是由于计算时间差值大于了一个设定的时间。

         上面我们已经分析到了函数watchdog_timer_fn打印debug信息的地方了,这个函数的在前面已经粘贴出来了,我们结合我们的错误日志分析一下对应的输出内核,通过函数的分析下面这句代码就是打印我们第二阶段错误日志信息的第一条:

而输出这一条的条件就是linux内核检测出了已经存在软死锁(通过前面if条件判断的代码以及前面的代码注释都可以说明这一点),通过这条日志信息我们可以看到cpu的逻辑编号、进程名称和进程id(通过我们的日志信息可以看出分别是11、qmgr进程、进程id是5492)。我们在看看一个更重要的值,这个值就是决定了是否产生了软死锁,这个值就是duration,这里显示是秒。下面详细分析一下这个值是怎么被计算出来的,通过代码发现是通过下面这个函数计算出来的:

30LL;这句代码计算出来的)。接着通过调用time_after函数判断现在的时间戳now与上一次喂狗的时间戳加上softlockup_thresh(60)的先后关系,也就是判断是不是有超过60秒钟没有喂狗了,如果是就会返回一个现在的时间戳减去上一次喂狗的时间戳,如果没有就会返回0。根据我们的日志信息,很明显已经超过了,所以返回值不为0,就导致了软死锁被检测到。

后面接着打印了linux内核加载了的相关模块信息,然后打印中断trace的事件信息,一直跟踪下去,发现和我们打印的内核bug信息完全符合。

下面开始分析一下call trace,不管是第一阶段的日志还是第二阶段的日志堆栈最上层的函数都是tracesys,说明这些信息都是在trace子系统中发生的,至少说明当时都处于trace子系统的运行。其实tracesys是用汇编实现的,主要用于跟踪系统调用的功能。第二阶段的call trace基本是没有什么信息,分析不出什么效果。有一点需要说明一下,第一阶段的日志打印的信息显示是master进程,第二阶段显示是qmgr进程。在centos上master进程是qmgr进程的父进程。下面看第一阶段日志的call trace信息,如下(去掉了公共前缀信息):

我们首先看一下这个函数的参数:其中有两个比较复杂和重要的结构体ring_buffer_per_cpu和ring_buffer,分析这两个结构体主要是为了后面的函数内部分析做一个准备。我们先看看ring_buffer结构体(简称为RB结构体)的定义,如下:

在RB的操作中,我们可以禁止全局的RB操作,例如,完全禁用掉Trace功能后,整个RB都是不允许再操做的,这时,就可以将原子变量record_disabled 加1。相反的,如果启用的话,将其减1即可。只有当record_disabled的值等于0时,才允许操作RB。

同时,有些时候,要对RB的一些数据进行更新,比如,我要重新设置一下RB的缓存区大小,这都需要串行操作,因此,在ring_buffer结构中有mutex成员,用来避免这些更改RB的操作的竞争。

我们也可以看到,每个cpu都有一系列的页面,这样页面都链入在pages中。

具体的缓存区是由structbuffer_data_page指向的,实际上,它是具体页面的管理头部,结构如下:

把所有基本的结构体解析清楚以后我们就可以正在分析这个函数了,代码已经在前面写出来了。函数里面首先定义了一个ring_buffer_event结构体的变量,先看一下这个结构体的定义如下:

这个结构体注释提醒不要直接使用,只能在函数体里面使用,这里是在函数体里面定义和使用的。里面加入了动态内存检测的字段kmemcheck,这个特性类似用户态动态内存检测工具valgrind,只是实现上有很大的区别,而且这个主要是用于内核动态内存检测技术。继续上面函数的分析,然后定义了一些需要用到的变量。继续就开始调用函数rb_start_commit,函数代码如下:

其实最终就是使用汇编实现一个长整型变量的原子加(addl)1操作。接下来是一段需要使能了RB交换swap功能(和虚拟内存交换,linux系统称为交换区,有硬盘充当)。接下来调用函数rb_calculate_event_length计算事件长度。继续我们就会看到一大段英文注释,大体上是说,在调用这个函数之前禁止了抢占,中断和NMI在这里存在着竞争,因此在下面的运行中,随时都会被中断/NMI所抢占。由于在从struct ring_buffer_per_cpu中取页面的时候,会有当前页面空间不足,需要前进一个页面的情况.每次前进一个页面都会跳转到again,此时nr_loops都会增加1,如果在一次请求中,这样的情况出现了1000次,说明中断抢占的次数太多了,很可能是由于中断风暴(interrupte trace信息,根据我们的服务器日志这里没有打印。继续就是调用函数ring_buffer_time_stamp取当前的时间戳并赋值给ts临时变量。下面又是一大段英文注释,意思是只有第一次处于提交状态的请求才能够更新cpu_buffer->write_stamp(cpu的写时间戳),这里存在着竞争。下面详细分析这里代码执行的情况,因为涉及到delta计算的问题,这也是导致我们服务器bug的最基本和开始的原因。

从这里的if判断可以看到,只有在fistcommit的时候才会计算delta,其它的情况下,会获取下一个event。我们来思考一下,为什么在确认了是fist commit,进入到了if,还需要进行:

的判断呢? 这个delta到底是用来做什么的呢?它为什么要用这样的判断方式呢?我们在之前说过,在ring_buffer_per_cpu中的每一块数据都带有一个event的头部,即:

它里面有一个time_delta的成员占27位。在每一个页面的头部,即Structbuffer_data_page里面也有一个时间戳,即:

那这几个时间戳有什么样的关联呢?在ring_buffer_per_cpu中有一个timestamp,它表示最近commit时的时间戳。每次切换进一个新页面时,该页面对应的:

综上所述,存在以下关系:

页面中的第一个event,event1在进行写操作时的时间戳为:

第二个event,event2在进行写操作时的时间戳为:

分析到这里我们发现计算出来的delta值超过了设定的阀值,所以打印处理debug信息,我们分析一下打印出来的几个时间值(应该是系统节拍值),日志如下:

cpu_buffer->write_stamp;通过计算器计算确实满足。那下面在看看ts是怎么计算出来的,他是计算linux服务器冲启动到现在的节拍数,和设置的HZ有关系,最终还是调用sched_clock函数计算所得,这个函数代码实现如下:

以上函数是cpu调度的节拍数计算方式,全局变量jiffies用来记录从系统启动以来产生的节拍的总数,启动时,内核将该变量初始化为INITIAL_JIFFIES,网上有的说法又是初始化为0,为了验证到底初始化为多少我们使用一个内核模块在启动的时候就把这个值打印出来看一看就清楚,通过测试初始化值确实是INITIAL_JIFFIES。此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于HZ,所以jiffies一秒内增加的值也就是HZ。系统运行时间以秒为单位,等于jiffies/HZ。注意,jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。将以秒为单位的时间转化为jiffies:seconds * Hz。将jiffies转化为以秒为单位的时间:jiffies / HZ。HZ的值在param.h中设置为100,那么通过日志中打印出来的ts值(单位是纳秒)计算服务器已经启动了多少天:/60/60=213504(天),这个值明显不对,那我们在计算一下上一次cpu记录的写入值(write stamp = 46377)是否正确?同样的计算方式如下:/60=208(天)这个值还算比较正确,就是上一次写入对应的值已经是208天以前的时候。

SEC_PER_SEC是每一秒钟的纳秒数()。

于是整个表达式计算为:系统当前运行的节拍值(INITIAL_JIFFIES计算所得),然后再除以/100=。从我们的日志中可以看出当前计算出来的值是ts:。根据这个值我们可以反推出jiffies-INITIAL_JIFFIES=2。这个值明显不对,在看cpu软死锁产生的一条日志信息如下:

通过这条日子好也可以看出这个时间s完全不正常。造成这种不正常的原因可能是内存破坏造成的。

新发现:在使用内核模块修改jiffies值的时候,直接导致了centos产生了cpu softlockup错误,而且从内核打印出的错误信息可以看出最后加载的模块就是我写的那个测试模块,对比线上服务器崩溃的内核日志查看最后加载的内核模块是scsi_scan_wait。由此可以推断可能是由于scsi_scan_wait这个内核模块导致了qmgr进程产生了cpu软死锁,也就是导致了qmgr已经超过了60秒没有得到中断响应了。

         由于一直不能重现这个错误,所以一直没有排查出问题的正在原因,目前还是继续排查,想办法还原错误。如果有哪位以前遇到过同样的问题并且得到了解决麻烦告知一声,非常感谢!

}

1.线上内核bug日志

watchdog能够看见,进程名称大概是watchdog/X(数字:cpu逻辑编号1/2/3/4之类的)。这个进程或者线程每一秒钟运行一次,否则会睡眠和待机。这个进程运行会收集每一个cpu运行时使用数据的时间并且存放到属于每个cpu自己的内核数据结构。在内核中有很多特定的中断函数。这些中断函数会调用soft lockup计数,他会使用当前的时间戳与特定(对应的)cpu的内核数据结构中保存的时间对比,如果发现当前的时间戳比对应cpu保存的时间大于设定的阀值,他就假设监测进程或看门狗线程在一个相当可观的时间还没有执。Cpu软锁为什么会产生,是怎么产生的?如果linux内核是经过精心设计安排的CPU调度访问,那么怎么会产生cpu软死锁?那么只能说由于用户开发的或者第三方软件引入,看我们服务器内核panic的原因就是qmgr进程引起。因为每一个无限的循环都会一直有一个cpu的执行流程(qmgr进程示一个后台邮件的消息队列服务进程),并且拥有一定的优先级。Cpu调度器调度一个驱动程序来运行,如果这个驱动程序有问题并且没有被检测到,那么这个驱动程序将会暂用cpu的很长时间。根据前面的描述,看门狗进程会抓住(catch)这一点并且抛出一个软死锁(soft lockup)错误。软死锁会挂起cpu使你的系统不可用。

3.根据linux内核源码分析错误

首先根据我们的centos版本安装相应的linux内核源码,具体步骤如下:

下面开始真正的根据内核bug日志分析源码:

(1)第一阶段内核错误日志分析(时间在Dec 4 14:03:34这个阶段的日志输出代码分析,其实这部分代码不会导致cpu软死锁,主要是第二阶段错误日志显示导致cpu软死锁)

这个宏很简单保证传递进来的条件值为0或者1(两次逻辑非操作的结果),然后使用分支预测技术(保证执行概率大的分支紧邻上面的指令)判断是否需要调用__WARN()宏定义。如果满足条件执行了__WARN()宏定义也接着执行一条空指令;。上面调用WARN_ON宏是传递的1,所以会执行__WARN()。下面继续看一下__WARN()宏定义如下:

从接下来的call trace信息中我们也确实发现调用了warn_slowpath_null这个函数。通过在linux内核源代码中搜索这个函数的实现,发现在panic.c(内核恐慌时的相关功能实现)中实现如下:

分析这个函数的实现不难发现我们的很多日志信息从这里开始输出,包括打印一些系统信息,就不继续深入分析了(请看代码注释,里面调用相关函数打印对应信息,通过我分析这些函数的实现和我们的日志信息完全能够对应,其中dump_stack是与cpu体系结构相关的,我们的服务器应该是属于x86体系)。这里在继续分析一下dump_stack函数的实现,因为这个是与cpu体系结构相关的,而且这个函数直接反应出导致内核panic的相关进程。这个函数实现如下:

这个函数打印出我们日志中的Call Trace信息,然后继续调用dump_trace函数(x86-64相关的体系结构,也就是64位的,还有一个32位的相应实现),如下:

通过这个函数的注释我们可以清楚的知道这个函数打印很多信息,包括进程堆栈信息、中断堆栈信息以及一些服务异常的硬件堆栈信息(如双重故障,NMI,堆栈错误,调试,MCE)。

通过上面这些分析只想说明一点,整个流程是没有问题的。到目前为止只有第一行日志信息还没有找到输出的地址,其实看源码很容易就看出来了,就在WARN_ON宏的上一行代码就是了,代码如下:

Printk函数的作用相当于printf,只是这个是专门用于内核的(有一些特殊实现)。通过一句代码我们也可以发现local_clock_stable是为0,因为没有打印最后那一点信息出来。到这里为止基本把第一阶段出现内核错误和bug的代码全部理解清楚了(日志时间为:Dec 4 14:03:34这个时间输出的),后面附件具体分析导致这个原因代码的原因。

(2)第二阶段(时间在Dec 4 14:03:41,与第一阶段只相差了几秒钟,应该还是存在一定的关联)内核错误日志输出代码分析,这部分日志输出显示了导致了cpu软死锁。

下面首先需要分析一下什么情况下会调用这个函数并且导致cpu软死锁,根据第二部分cpu软死锁产生原因的分析,每一个cpu都会启动一个对应的watchdog线程来监控cpu的执行状态,创建watchdog线程是在使能watchdog功能的时候,在函数watchdog_enable里面实现,代码如下:

从上面这个watchdog使能函数可以看出,每一个cpu的watchdog监控线程的入口函数是watchdog函数,还注册了一个softlockup软死锁响应函数。下面开始从watchdog函数继续开始分析,代码如下:

这个函数首先设置watchdog线程的cpu的调度策略为FIFO(先来先服务),并且优先级最低,然后初始化一个时间戳,设置当前的cpu状态为可中断的状态。然后就进入while循环了,通过while循环上面的注释我们可以清楚的知道每一秒钟都会重新设置softlockup的时间戳,如果超过60秒钟那么就会触发debug信息被打印,打印信息是在函数watchdog_timer_fn里面,这个函数是在watchdog模块初始化的时候注册的,每一个模块加载最先执行的都是模块初始化函数,当然卸载模块的时候也有相应的资源清理函数。

到这里为止我们知道了如果要打印出我们服务器内核的错误信息就必须得满足一个条件,就是已经超过60秒钟没有重新设置softlockup的时间戳了(每一,秒钟重新设置softlockup的时间戳,有一个比较通俗的说法叫做喂狗,因为上面的watchdog程序也俗称看门狗程序,cpu就是通过这种方式来检测cpu是否运行正常的,已经超过60秒钟没有喂狗了,那么狗肯定饿了,也就是cpu处于饥饿状态,浪费了cpu的时间了,最大的可能就是cpu产生了软死锁)。这里就不详细分析cpu调度相关的功能了,还是继续分析产生这种bug的原因。下面最主要的就是分析为什么超过60秒钟没有喂狗(重新设置softlockup时间戳)了。分析这个应该需要结合第一阶段的错误日志分析,第一阶段也是由于计算时间差值大于了一个设定的时间。

         上面我们已经分析到了函数watchdog_timer_fn打印debug信息的地方了,这个函数的在前面已经粘贴出来了,我们结合我们的错误日志分析一下对应的输出内核,通过函数的分析下面这句代码就是打印我们第二阶段错误日志信息的第一条:

而输出这一条的条件就是linux内核检测出了已经存在软死锁(通过前面if条件判断的代码以及前面的代码注释都可以说明这一点),通过这条日志信息我们可以看到cpu的逻辑编号、进程名称和进程id(通过我们的日志信息可以看出分别是11、qmgr进程、进程id是5492)。我们在看看一个更重要的值,这个值就是决定了是否产生了软死锁,这个值就是duration,这里显示是秒。下面详细分析一下这个值是怎么被计算出来的,通过代码发现是通过下面这个函数计算出来的:

30LL;这句代码计算出来的)。接着通过调用time_after函数判断现在的时间戳now与上一次喂狗的时间戳加上softlockup_thresh(60)的先后关系,也就是判断是不是有超过60秒钟没有喂狗了,如果是就会返回一个现在的时间戳减去上一次喂狗的时间戳,如果没有就会返回0。根据我们的日志信息,很明显已经超过了,所以返回值不为0,就导致了软死锁被检测到。

后面接着打印了linux内核加载了的相关模块信息,然后打印中断trace的事件信息,一直跟踪下去,发现和我们打印的内核bug信息完全符合。

下面开始分析一下call trace,不管是第一阶段的日志还是第二阶段的日志堆栈最上层的函数都是tracesys,说明这些信息都是在trace子系统中发生的,至少说明当时都处于trace子系统的运行。其实tracesys是用汇编实现的,主要用于跟踪系统调用的功能。第二阶段的call trace基本是没有什么信息,分析不出什么效果。有一点需要说明一下,第一阶段的日志打印的信息显示是master进程,第二阶段显示是qmgr进程。在centos上master进程是qmgr进程的父进程。下面看第一阶段日志的call trace信息,如下(去掉了公共前缀信息):

我们首先看一下这个函数的参数:其中有两个比较复杂和重要的结构体ring_buffer_per_cpu和ring_buffer,分析这两个结构体主要是为了后面的函数内部分析做一个准备。我们先看看ring_buffer结构体(简称为RB结构体)的定义,如下:

在RB的操作中,我们可以禁止全局的RB操作,例如,完全禁用掉Trace功能后,整个RB都是不允许再操做的,这时,就可以将原子变量record_disabled 加1。相反的,如果启用的话,将其减1即可。只有当record_disabled的值等于0时,才允许操作RB。

同时,有些时候,要对RB的一些数据进行更新,比如,我要重新设置一下RB的缓存区大小,这都需要串行操作,因此,在ring_buffer结构中有mutex成员,用来避免这些更改RB的操作的竞争。

我们也可以看到,每个cpu都有一系列的页面,这样页面都链入在pages中。

具体的缓存区是由structbuffer_data_page指向的,实际上,它是具体页面的管理头部,结构如下:

把所有基本的结构体解析清楚以后我们就可以正在分析这个函数了,代码已经在前面写出来了。函数里面首先定义了一个ring_buffer_event结构体的变量,先看一下这个结构体的定义如下:

这个结构体注释提醒不要直接使用,只能在函数体里面使用,这里是在函数体里面定义和使用的。里面加入了动态内存检测的字段kmemcheck,这个特性类似用户态动态内存检测工具valgrind,只是实现上有很大的区别,而且这个主要是用于内核动态内存检测技术。继续上面函数的分析,然后定义了一些需要用到的变量。继续就开始调用函数rb_start_commit,函数代码如下:

其实最终就是使用汇编实现一个长整型变量的原子加(addl)1操作。接下来是一段需要使能了RB交换swap功能(和虚拟内存交换,linux系统称为交换区,有硬盘充当)。接下来调用函数rb_calculate_event_length计算事件长度。继续我们就会看到一大段英文注释,大体上是说,在调用这个函数之前禁止了抢占,中断和NMI在这里存在着竞争,因此在下面的运行中,随时都会被中断/NMI所抢占。由于在从struct ring_buffer_per_cpu中取页面的时候,会有当前页面空间不足,需要前进一个页面的情况.每次前进一个页面都会跳转到again,此时nr_loops都会增加1,如果在一次请求中,这样的情况出现了1000次,说明中断抢占的次数太多了,很可能是由于中断风暴(interrupte trace信息,根据我们的服务器日志这里没有打印。继续就是调用函数ring_buffer_time_stamp取当前的时间戳并赋值给ts临时变量。下面又是一大段英文注释,意思是只有第一次处于提交状态的请求才能够更新cpu_buffer->write_stamp(cpu的写时间戳),这里存在着竞争。下面详细分析这里代码执行的情况,因为涉及到delta计算的问题,这也是导致我们服务器bug的最基本和开始的原因。

从这里的if判断可以看到,只有在fistcommit的时候才会计算delta,其它的情况下,会获取下一个event。我们来思考一下,为什么在确认了是fist commit,进入到了if,还需要进行:

的判断呢? 这个delta到底是用来做什么的呢?它为什么要用这样的判断方式呢?我们在之前说过,在ring_buffer_per_cpu中的每一块数据都带有一个event的头部,即:

它里面有一个time_delta的成员占27位。在每一个页面的头部,即Structbuffer_data_page里面也有一个时间戳,即:

那这几个时间戳有什么样的关联呢?在ring_buffer_per_cpu中有一个timestamp,它表示最近commit时的时间戳。每次切换进一个新页面时,该页面对应的:

综上所述,存在以下关系:

页面中的第一个event,event1在进行写操作时的时间戳为:

第二个event,event2在进行写操作时的时间戳为:

分析到这里我们发现计算出来的delta值超过了设定的阀值,所以打印处理debug信息,我们分析一下打印出来的几个时间值(应该是系统节拍值),日志如下:

cpu_buffer->write_stamp;通过计算器计算确实满足。那下面在看看ts是怎么计算出来的,他是计算linux服务器冲启动到现在的节拍数,和设置的HZ有关系,最终还是调用sched_clock函数计算所得,这个函数代码实现如下:

以上函数是cpu调度的节拍数计算方式,全局变量jiffies用来记录从系统启动以来产生的节拍的总数,启动时,内核将该变量初始化为INITIAL_JIFFIES,网上有的说法又是初始化为0,为了验证到底初始化为多少我们使用一个内核模块在启动的时候就把这个值打印出来看一看就清楚,通过测试初始化值确实是INITIAL_JIFFIES。此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于HZ,所以jiffies一秒内增加的值也就是HZ。系统运行时间以秒为单位,等于jiffies/HZ。注意,jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。将以秒为单位的时间转化为jiffies:seconds * Hz。将jiffies转化为以秒为单位的时间:jiffies / HZ。HZ的值在param.h中设置为100,那么通过日志中打印出来的ts值(单位是纳秒)计算服务器已经启动了多少天:/60/60=213504(天),这个值明显不对,那我们在计算一下上一次cpu记录的写入值(write stamp = 46377)是否正确?同样的计算方式如下:/60=208(天)这个值还算比较正确,就是上一次写入对应的值已经是208天以前的时候。

SEC_PER_SEC是每一秒钟的纳秒数()。

于是整个表达式计算为:系统当前运行的节拍值(INITIAL_JIFFIES计算所得),然后再除以/100=。从我们的日志中可以看出当前计算出来的值是ts:。根据这个值我们可以反推出jiffies-INITIAL_JIFFIES=2。这个值明显不对,在看cpu软死锁产生的一条日志信息如下:

通过这条日子好也可以看出这个时间s完全不正常。造成这种不正常的原因可能是内存破坏造成的。

新发现:在使用内核模块修改jiffies值的时候,直接导致了centos产生了cpu softlockup错误,而且从内核打印出的错误信息可以看出最后加载的模块就是我写的那个测试模块,对比线上服务器崩溃的内核日志查看最后加载的内核模块是scsi_scan_wait。由此可以推断可能是由于scsi_scan_wait这个内核模块导致了qmgr进程产生了cpu软死锁,也就是导致了qmgr已经超过了60秒没有得到中断响应了。

         由于一直不能重现这个错误,所以一直没有排查出问题的正在原因,目前还是继续排查,想办法还原错误。如果有哪位以前遇到过同样的问题并且得到了解决麻烦告知一声,非常感谢!

}

上投摩根安泽回报混合型证券投资基金招募说明书

  基金托管人:中国建设银行股份有限公司
  本基金于【2016】年【12】月【1】日经中国证券监督管理委员会证监许可[号文注册。
  基金管理人保证本招募说明书的内容真实、准确、完整。
  本招募说明书经中国证监会注册,但中国证监会对本基金募集的注册,并不表明其对本基金的价值和收益作出实质性判断或保证,也不表明投资于本基金没有风险。
  投资有风险,投资人认购(或申购)基金时应当认真阅读本招募说明书。
  基金的过往业绩并不预示其未来表现,基金管理人管理的其他基金的业绩并不构成对本基金业绩表现的保证。
  基金管理人依照恪尽职守、诚实信用、谨慎勤勉的原则管理和运用基金资产,但不保证基金一定盈利,也不保证最低收益。
  本基金投资于证券市场,基金净值会因为证券市场波动等因素产生波动,投资者在投资本基金前,需充分了解本基金的产品特性,并承担基金投资中出现的各类风险,包括:因政治、经济、社会等环境因素对证券价格产生影响而形成的系统性风险,个别证券特有的非系统性风险,由于基金投资人连续大量赎回基金产生的流动性风险,基金管理人在基金管理实施过程中产生的基金管理风险,本基金的特定风险等。
  本基金可以参与中小企业私募债券的投资。中小企业私募债发行人为中小微、非上市企业,存在着公司治理结构相对薄弱、企业经营风险高、信息披露透明度不足等特点。投资中小企业私募债将存在违约风险和流动性不足的风险,这将在一定程度上增加基金的信用风险和流动性风险。
  本基金属于混合型基金产品,预期风险和收益水平高于债券型基金和货币市场基金,属于中等风险收益水平的基金产品。
  投资者在进行投资决策前,请仔细阅读本基金的《招募说明书》及《基金合同》。
  招募说明书依据《中华人民共和国证券投资基金法》和其他有关法律法规的规定,以及《上投摩根安泽回报混合型证券投资基金基金合同》(以下简称“合同”或“基金合同”)编写。
  本招募说明书阐述了上投摩根安泽回报混合型证券投资基金(以下简称“本基金”或“基金”)的投资目标、策略、风险、费率等与投资人投资决策有关的全部必要事项,投资者在做出投资决策前应仔细阅读招募说明书。
  基金管理人承诺本招募说明书不存在任何虚假内容、误导性陈述或重大遗漏,并对其真实性、准确性、完整性承担法律责任。本基金是根据本招募说明书所载明的资料申请募集的。本基金管理人没有委托或授权任何其他人提供未在本招募说明书中载明的信息,或对本招募说明书作任何解释或者说明。
  基金管理人承诺以诚实信用、勤勉尽责的原则管理和运用基金资产,但不保证基金一定盈利,也不保证最低收益。基金根据招募说明书所载明资料发行。
  本招募说明书依据基金合同编写,并经中国证监会注册。基金合同是约定基金当事人之间权利义务的法律文件。招募说明书主要向投资者披露与本基金相关事项的信息,是投资者据以选择及决定是否投资于本基金的要约邀请文件。基金投资者自依基金合同取得基金份额,即成为基金份额持有人和基金合同的当事人,其持有基金份额的行为本身即表明对基金合同的承认和接受,并按照《基金法》、基金合同及其它有关规定享有权利,承担义务。
  基金投资人欲了解基金份额持有人的权利和义务,应详细查阅基金合同。
  在招募说明书中,除非文意另有所指,下列词语或简称具有如下含义:
  1、基金或本基金:指上投摩根安泽回报混合型证券投资基金
  2、基金管理人:指上投摩根基金管理有限公司
  3、基金托管人:指中国建设银行股份有限公司
  4、基金合同:指《上投摩根安泽回报混合型证券投资基金基金合同》及对该基金合同的任何有效修订和补充
  5、托管协议:指基金管理人与基金托管人就本基金签订之《上投摩根安泽回报混合型证券投资基金托管协议》及对该托管协议的任何有效修订和补充
  6、招募说明书:指《上投摩根安泽回报混合型证券投资基金招募说明书》及其定期的更新
  7、基金份额发售公告:指《上投摩根安泽回报混合型证券投资基金基金份额发售公告》
  8、法律法规:指中国现行有效并公布实施的法律、行政法规、规范性文件、司法解释、行政规章以及其他对基金合同当事人有约束力的决定、决议、通知等
  9、《基金法》:指2012年12月28日经第十一届全国人民代表大会常务委员会第三十次会议修订,自2013年6月1日起实施的《中华人民共和国证券投资基金法》及颁布机关对其不时做出的修订
  10、《销售办法》:指中国证监会2013年3月15日颁布、同年6月1日实施的《证券投资基金销售管理办法》及颁布机关对其不时做出的修订
  11、《信息披露办法》:指中国证监会2004年6月8日颁布、同年7月1日实施的《证券投资基金信息披露管理办法》及颁布机关对其不时做出的修订
  12、《运作办法》:指《公开募集证券投资基金运作管理办法》及颁布机关对其不时做出的修订
  13、中国证监会:指中国证券监督管理委员会
  14、银行业监督管理机构:指中国人民银行和/或中国银行业监督管理委员会
  15、基金合同当事人:指受基金合同约束,根据基金合同享有权利并承担义务的法律主体,包括基金管理人、基金托管人和基金份额持有人
  16、个人投资者:指依据有关法律法规规定可投资于证券投资基金的自然人
  17、机构投资者:指依法可以投资证券投资基金的、在中华人民共和国境内合法登记并存续或经有关政府部门批准设立并存续的企业法人、事业法人、社会团体或其他组织
  18、合格境外机构投资者:指符合相关法律法规规定可以投资于在中国境内依法募集的证券投资基金的中国境外的机构投资者
  19、投资人:指个人投资者、机构投资者和合格境外机构投资者以及法律法规或中国证监会允许购买证券投资基金的其他投资人的合称
  20、基金份额持有人:指依基金合同和招募说明书合法取得基金份额的投资人
  21、基金销售业务:指基金管理人或销售机构宣传推介基金,发售基金份额,办理基金份额的申购、赎回、转换、转托管及定期定额投资等业务
  22、销售机构:指上投摩根基金管理有限公司以及符合《销售办法》和中国证监会规定的其他条件,取得基金销售业务资格并与基金管理人签订了基金销售服务代理协议,代为办理基金销售业务的机构
  23、登记业务:指基金登记、存管、过户、清算和结算业务,具体内容包括投资人基金账户的建立和管理、基金份额登记、基金销售业务的确认、清算和结算、代理发放红利、建立并保管基金份额持有人名册和办理非交易过户等
  24、登记机构:指办理登记业务的机构。基金的登记机构为上投摩根基金管理有限公司或接受上投摩根基金管理有限公司委托代为办理登记业务的机构
  25、基金账户:指登记机构为投资人开立的、记录其持有的、基金管理人所管理的基金份额余额及其变动情况的账户
  26、基金交易账户:指销售机构为投资人开立的、记录投资人通过该销售机构买卖基金的基金份额变动及结余情况的账户
  27、基金合同生效日:指基金募集达到法律法规规定及基金合同规定的条件,基金管理人向中国证监会办理基金备案手续完毕,并获得中国证监会书面确认的日期
  28、基金合同终止日:指基金合同规定的基金合同终止事由出现后,基金财产清算完毕,清算结果报中国证监会备案并予以公告的日期
  29、基金募集期:指自基金份额发售之日起至发售结束之日止的期间,最长不得超过3个月
  30、存续期:指基金合同生效至终止之间的不定期期限
  31、工作日:指上海证券交易所、深圳证券交易所及相关的期货交易所的正常交易日
  32、T日:指销售机构在规定时间受理投资人申购、赎回或其他业务申请的开放日
  34、开放日:指为投资人办理基金份额申购、赎回或其他业务的工作日
  35、开放时间:指开放日基金接受申购、赎回或其他交易的时间段
  36、《业务规则》:指《上投摩根基金管理有限公司开放式基金业务规则》,是规范基金管理人所管理的开放式证券投资基金登记方面的业务规则,由基金管理人和投资人共同遵守
  37、认购:指在基金募集期内,投资人根据基金合同和招募说明书的规定申请购买基金份额的行为
  38、申购:指基金合同生效后,投资人根据基金合同和招募说明书的规定申请购买基金份额的行为
  39、赎回:指基金合同生效后,基金份额持有人按基金合同和招募说明书规定的条件要求将基金份额兑换为现金的行为
  40、基金转换:指基金份额持有人按照基金合同和基金管理人届时有效公告规定的条件,申请将其持有基金管理人管理的、某一基金的基金份额转换为基金管理人管理的其他基金基金份额的行为
  41、转托管:指基金份额持有人在本基金的不同销售机构之间实施的变更所持基金份额销售机构的操作
  42、定期定额投资计划:指投资人通过有关销售机构提出申请,约定每期申购日、扣款金额及扣款方式,由销售机构于每期约定扣款日在投资人指定银行账户内自动完成扣款及基金申购申请的一种投资方式
  43、巨额赎回:指本基金单个开放日,基金净赎回申请(赎回申请份额总数加上基金转换中转出申请份额总数后扣除申购申请份额总数及基金转换中转入申请份额总数后的余额)超过上一开放日基金总份额的10%
  45、基金收益:指基金投资所得红利、股息、债券利息、买卖证券价差、银行存款利息、已实现的其他合法收入及因运用基金财产带来的成本和费用的节约
  46、基金资产总值:指基金拥有的各类有价证券、银行存款本息、基金应收款项及其他资产的价值总和
  47、基金资产净值:指基金资产总值减去基金负债后的价值
  48、基金份额净值:指计算日基金资产净值除以计算日基金份额总数
  49、基金资产估值:指计算评估基金资产和负债的价值,以确定基金资产净值和基金份额净值的过程
  50、基金份额的分类:本基金根据认购费、申购费、销售服务费收取方式的不同,将基金份额分为不同的类别
  51、A类份额:指在投资人认购、申购基金时收取认购、申购费用,并不再从本类别基金资产中计提销售服务费的基金份额
  52、C类份额:指不收取认购、申购费用,而从本类别基金资产中计提销售服务费的基金份额
  53、指定媒介:指中国证监会指定的用以进行信息披露的报刊、互联网网站及其他媒介
  54、不可抗力:指基金合同当事人不能预见、不能避免且不能克服的客观事件。
  本基金的基金管理人为上投摩根基金管理有限公司,基本信息如下:
  注册地址:中国(上海)自由贸易试验区富城路99号震旦国际大楼20层
  办公地址:中国(上海)自由贸易试验区富城路99号震旦国际大楼20层
  实缴注册资本:贰亿伍仟万元人民币
  股东名称、股权结构及持股比例:
  上投摩根基金管理有限公司是经中国证监会证监基字[2004]56号文批准,于2004年5月12日成立的合资基金管理公司。2005年8月12日,基金管理人完成了股东之间的股权变更事项。公司注册资本保持不变,股东及出资比例分别由上海国际信托有限公司67%和摩根资产管理(英国)有限公司33%变更为目前的51%和49%。
  2006年6月6日,基金管理人的名称由“上投摩根富林明基金管理有限公司”变更为“上投摩根基金管理有限公司”,该更名申请于2006年4月29日获得中国证监会的批准,并于2006年6月2日在国家工商总局完成所有变更相关手续。
  2009年3月31日,基金管理人的注册资本金由一亿五千万元人民币增加到二亿五千万元人民币,公司股东的出资比例不变。该变更事项于2009年3月31日在国家工商总局完成所有变更相关手续。
  基金管理人无任何受处罚记录。
  注册地址:新疆乌鲁木齐市高新区(新市区)北京南路358号大成国际大厦20楼2005室
  办公地址:新疆乌鲁木齐市高新区(新市区)北京南路358号大成国际大厦20楼2005室(邮编:830002)
  注册地址:上海市黄浦区四川中路213号久事商务大厦7楼
  办公地址:上海市黄浦区四川中路213号久事商务大厦7楼
  注册地址:中国(上海)自由贸易试验区商城路618号
  办公地址:上海市银城中路168号上海银行大厦29层
  基金管理人可根据有关法律法规的要求,选择其它符合要求的机构代理销售本基金,并及时公告。
  上投摩根基金管理有限公司(同上)
  三、律师事务所与经办律师:
  注册地址:上海市浦东南路256号华夏银行大厦14楼
  四、审计基金财产的会计师事务所
  名称:普华永道中天会计师事务所(特殊普通合伙)
  注册地址:中国上海市浦东新区陆家嘴环路1318号星展银行大厦6楼
  办公地址:中国上海市黄浦区湖滨路202号企业天地2号楼普华永道中心11楼
  经办注册会计师:陈玲、曹阳
  本基金由基金管理人依照《基金法》、《运作办法》、《销售办法》、基金合同及其它有关法律法规的规定募集,于2016年12月1日经中国证监会注册。
  二、基金存续期间及基金类型
  2、基金类别:混合型证券投资基金
  自基金份额发售之日起最长不得超过3个月,具体发售时间见基金份额发售公告。
  符合法律法规规定的可投资于证券投资基金的个人投资者、机构投资者和合格境外机构投资者以及法律法规或中国证监会允许购买证券投资基金的其他投资人。
  通过各销售机构的基金销售网点公开发售,各销售机构的具体名单见基金份额发售公告以及基金管理人届时发布的变更销售机构的相关公告。
  5、基金的面值:每基金份额的初始发售面值为人民币)查询详情。
  二十一、招募说明书的存放及查阅方式
  本招募说明书存放在基金管理人和基金代销机构的办公场所和营业场所,基金投资者可免费查阅。在支付工本费后,可在合理时间内取得上述文件的复制件或复印件。
  (一)中国证监会准予上投摩根安泽回报混合型证券投资基金募集注册的文件
  (二)上投摩根安泽回报混合型证券投资基金基金合同
  (三)上投摩根安泽回报混合型证券投资基金托管协议
  (五)基金管理人业务资格批件、营业执照
  (六)基金托管人业务资格批件、营业执照
  (七)上投摩根基金管理有限公司开放式基金业务规则
  上述备查文件存放在基金管理人和基金代销机构的办公场所和营业场所,基金投资者可免费查阅。在支付工本费后,可在合理时间内取得上述文件的复制件或复印件。
  (本页无正文,为《上投摩根安泽回报混合型证券投资基金招募说明书》盖章页)

}

我要回帖

更多关于 a列小于b列显示红色 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信