程序运行在arm上, linux版本是Linux version 5.10.35-dirty (root@Newu) (aarch64-linux-gnu-gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1)
从启动开始,每次大约在75min左右,协议栈里面运行的函数就会卡住,卡的时间一般在3-5ms(调用clock_gettime()看的卡顿时间.)
最开始怀疑应用程序的问题,针对问题进行的业务模型简化,在隔离的独立的core上单独只跑出问题的线程,这个线程设置为schd_FIFO, 优先级设置为99. 发现还是在75min卡顿(可能卡顿在不同的函数,或者不同赋值语句地方。)。例如:
clock_gettime(CLOCK_REALTIME,&starttime);
Fun(); //空函数
clock_gettime(CLOCK_REALTIME,&endtime); 两个时间差相减就是3-5ms. 这个空函数肯定不需要这么久。不清楚这个时候系统出了什么问题。
在75min卡顿后,后面可能出现卡顿多次,也可能一直不出现卡顿,没有周期性。
对业务程序进行极致版简化后问题依然出现,接着怀疑是否系统有问题。后面通过ftrace来分析内核调用过程,显示每次在73min左右会出现do_mem_abort出发缺页流程。如下所示
但是在进行缺页处理的时候,拿不到mmap_sew这个锁,在这个地方卡住了几ms. 但是是谁持有了这把锁, 怎么去优化,这些都是linux 内核知识。
从网上找了两篇关于这方面的介绍:
mmap_sem信号量死锁故障分析
https://blog.csdn.net/lijzheng/article/details/23216633
内核mmap_sem锁的危害和相关优化
https://blog.csdn.net/buhui912/article/details/124984815
但由于缺少这方面的知识,没有继续往下查,而是转去优化mem这方面的问题。
针对mmap_sew这个信号量,下面描述是比较清楚的 :
mmap_sem是读写信号量,对于这种信号量,你有什么了解么?”
“略知一二,读写信号量可以同时存在多个读者,但有且只能同时存在一个写者。”
“那么等待信号量会有哪些情况呢?”
“这难不倒我,可能是,
1)存在一个或多个读者,此时出现写者,那么写者等待全部读者释放信号量
2)存在一个写者,此时出现读者,那么读者等待写者释放信号量
3)存在写者和读者同时等待,会按照先后顺序来进行唤醒,如果在一个处于等待状态的写者前存在多个读者等待,那么这些读者都将被唤醒。”
“本身还是系统中的任务存在不合理的情况,例如有A,B两个CPU消耗型任务,为了避免对其他任务的干扰,将A,B任务都绑定在7核上。同时A,B任务还都被设置为SCHED_FIFO 50的优先级。然后,A,B任务都想要获取读锁并失败,进入等待。”
“随着写者释放信号量,A,B两个等待的读者都会被唤醒,假设A任务先得到了运行,那么B任务只有在A任务主动让出CPU时才能得到运行,就可能造成B任务一直作为“王储”而无法登基,也就无法真正的拥有信号量,这也意味着无法操作信号量的count值,造成后续任务的阻塞!”
https://zhuanlan.zhihu.com/p/103874259