sigwaittest测试超标的调试过程
1,问题描述
硬件环境:飞腾S2500(64核)
OS:kylinOS, linux preempt rt, 4.19.90
测试命令:sigwaittest -p 90 -i 1000 -a 1
测试结果:信号混洗值最大超过了80us,与飞腾其他CPU的设备相比较,增大了很多
2,调试过程
1)日志分析
使用trace-cmd命令来抓取ftrace log:trace-cmd start -e all; sigwaittest -p 90 -i 1000 -a 1 -b 80
得到如下日志:
sigwaitt-13091 1....0 1741.963614: sys_enter: NR 131 (3321, 3322, a, 20c49ba5e353f7cf, 3b9ac9ff, 44cc0)
sigwaitt-13091 1...10 1741.963615: sys_enter_tgkill: tgid: 0x00003321, pid: 0x00003322, sig: 0x0000000a
sigwaitt-13091 1d..11 1741.963616: sched_waking: comm=sigwaittest pid=13090 prio=9 target_cpu=001
sigwaitt-13091 1d..21 1741.963617: sched_wakeup: sigwaittest:13090 [9] success=1 CPU:001
sigwaitt-13091 1....1 1741.963618: signal_generate: sig=10 errno=0 code=-6 comm=sigwaittest pid=13090 grp=0 res=0
=====chensong:70us
sigwaitt-13091 1d..21 1741.963689: sched_waking: comm=sigwaittest pid=13089 prio=120 target_cpu=041
sigwaitt-13091 1d..31 1741.963690: sched_wakeup: sigwaittest:13089 [120] success=1 CPU:041
=====
sigwaitt-13091 1....0 1741.963691: kfree: (__audit_syscall_exit+0x1d8) call_site=ffff0000081d26b0 ptr=(nil)
sigwaitt-13091 1....0 1741.963691: sys_exit: NR 131 = 0
sigwaitt-13091 1...10 1741.963692: sys_exit_tgkill: 0x0对比正常时候的日志:
sigwaitt-13091 1....0 1741.962569: sys_enter: NR 131 (3321, 3322, a, 20c49ba5e353f7cf, 3b9ac9ff, 44cc0)
sigwaitt-13091 1...10 1741.962570: sys_enter_tgkill: tgid: 0x00003321, pid: 0x00003322, sig: 0x0000000a
sigwaitt-13091 1d..11 1741.962571: sched_waking: comm=sigwaittest pid=13090 prio=9 target_cpu=001
sigwaitt-13091 1d..21 1741.962572: sched_wakeup: sigwaittest:13090 [9] success=1 CPU:001
sigwaitt-13091 1....1 1741.962573: signal_generate: sig=10 errno=0 code=-6 comm=sigwaittest pid=13090 grp=0 res=0
sigwaitt-13091 1....0 1741.962574: kfree: (__audit_syscall_exit+0x1d8) call_site=ffff0000081d26b0 ptr=(nil)
sigwaitt-13091 1....0 1741.962574: sys_exit: NR 131 = 0
sigwaitt-13091 1...10 1741.962574: sys_exit_tgkill: 0x0
sigwaitt-13091 1....0 1741.962575: sys_enter: NR 137 (fffdf677e848, fffdf677e6b8, 0, 8, 0, fffdf677f0e0)
sigwaitt-13091 1...10 1741.962575: sys_enter_rt_sigtimedwait: uthese: 0xfffdf677e848, uinfo: 0xfffdf677e6b8, uts: 0x00000000, sigsetsize: 0x00000008
sigwaitt-13091 1d..10 1741.962576: rcu_utilization: Start context switch
sigwaitt-13091 1d..10 1741.962577: rcu_utilization: End context switch
sigwaitt-13091 1d..20 1741.962578: sched_switch: sigwaittest:13091 [9] S ==> sigwaittest:13090 [9]我们会发现,在signal_generate后,sigwaittest的测试线程又唤醒了一个线程,消耗了70us。
2)过程分析
命令“sigwaittest -p 90 -i 1000 -a 1 -b 80”会创建三个线程,一个主线程main thread,,是一个CFS的普通线程,很大一部分工作是打印测试的结果,一个是sender,是一个实时线程,负责发送信号,还有一个是receiver,负责接收信号,sigwaittest主要就是测试sender发送信号到receiver接收到信号所花费的时间。
3)代码分析
首先看一下发送信号的kill函数,对应内核中系统调用tgkill:
使用function_grath来看一下tgkill的调用过程:trace-cmd start -p function_graph -g sys_tgkill;sigwaittest -p 90 -i 1000 -a 1 -l 100;trace-cmd stop
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |1) | sys_tgkill() {1) | do_tkill() {1) | __task_pid_nr_ns() {1) 0.770 us | __rcu_read_lock();1) 0.500 us | __rcu_read_unlock();1) 3.062 us | }1) | from_kuid_munged() {1) 0.500 us | map_id_up();1) 1.563 us | }1) | do_send_specific() {1) 0.479 us | __rcu_read_lock();1) 0.666 us | find_task_by_vpid();1) | __task_pid_nr_ns() {1) 0.500 us | __rcu_read_lock();1) 0.479 us | __rcu_read_unlock();1) 2.542 us | }1) | check_kill_permission() {1) | audit_signal_info() {1) | auditd_test_task() {1) 0.500 us | __rcu_read_lock();1) 0.479 us | __rcu_read_unlock();1) 2.604 us | }1) | audit_signal_info_syscall() {1) 0.500 us | __rcu_read_lock();1) 0.500 us | __rcu_read_unlock();1) 2.458 us | }1) 7.042 us | }1) 0.604 us | security_task_kill();1) 9.271 us | }1) | do_send_sig_info() {1) | __lock_task_sighand() {1) 0.500 us | __rcu_read_lock();1) | rt_spin_lock() {1) 0.500 us | __rcu_read_lock();1) 0.500 us | migrate_disable();1) 2.480 us | }1) 0.500 us | __rcu_read_unlock();1) 5.459 us | }1) | send_signal() {1) 0.563 us | siginfo_layout();1) 0.479 us | __rcu_read_lock();1) 0.500 us | __rcu_read_lock();1) 0.500 us | __rcu_read_unlock();1) 0.500 us | __rcu_read_unlock();1) 0.563 us | task_active_pid_ns();1) | __task_pid_nr_ns() {1) 0.500 us | __rcu_read_lock();1) 0.480 us | __rcu_read_unlock();1) 2.479 us | }1) | __send_signal() {1) 0.583 us | prepare_signal();1) | __sigqueue_do_alloc() {1) 0.563 us | __rcu_read_lock();1) 0.480 us | __rcu_read_unlock();1) | kmem_cache_alloc() {1) 0.479 us | should_failslab();1) 1.708 us | }1) 4.833 us | }1) | complete_signal() {1) 0.604 us | _raw_spin_lock_irqsave();1) 0.500 us | _raw_spin_unlock_irqrestore();1) | signal_wake_up_state() {1) | wake_up_state() {1) | try_to_wake_up() {1) 0.562 us | _raw_spin_lock_irqsave();1) 0.542 us | _raw_spin_lock();1) 0.541 us | update_rq_clock();1) | ttwu_do_activate() {1) | activate_task() {1) | enqueue_task_rt() {1) | dequeue_rt_stack() {1) 0.521 us | dequeue_top_rt_rq();1) 1.521 us | }1) 0.500 us | update_rt_migration();1) 0.500 us | _raw_spin_lock();1) 0.521 us | enqueue_top_rt_rq();1) 5.604 us | }1) 6.958 us | }1) | ttwu_do_wakeup() {1) | check_preempt_curr() {1) 0.625 us | check_preempt_curr_rt();1) 1.625 us | }1) 0.521 us | task_woken_rt();1) 4.605 us | }1) + 13.084 us | }1) 0.541 us | _raw_spin_unlock_irqrestore();1) + 19.104 us | }1) + 20.146 us | }1) + 21.188 us | }1) + 24.542 us | }1) + 32.709 us | }1) + 42.792 us | }1) | rt_spin_unlock() {1) 0.563 us | migrate_enable();1) 0.521 us | __rcu_read_unlock();1) 2.750 us | }1) + 53.271 us | }1) 0.541 us | __rcu_read_unlock();1) + 70.500 us | }1) + 77.562 us | }1) + 81.333 us | }------------------------------------------1) sigwait-31931 => sigwait-31930 ------------------------------------------简化一下调用过程就是:
tgkill--> do_tkill-->do_send_specific-->do_send_sig_info--> lock_task_sighand //申请锁tsk->sighand->siglocksend_signal //唤醒receiverunlock_task_sighand(p, &flags); //释放tsk->sighand->siglock在通常情况下,sender调用send_signal唤醒receiver,这个过程就结束了。但在发生错误的日志中,我们发现sender还唤醒了main thread,那么,很可能main thread也在申请tsk->sighand->siglock,这个时候它正在siglock的等待队列中等待,那么,当sender调用unlock_task_sighand的时候,就会去唤醒main thread。
我们再来看看main thread的代码:
26 while (!mustshutdown) {
527 int printed;
528 int errorlines = 0;
529
530 for (i = 0; i < num_threads; i++)
531 mustshutdown |= receiver[i].shutdown |
532 sender[i].shutdown;
533
534 if (receiver[0].samples > oldsamples || mustshutdown) {...//打印结果581 pthread_sigmask(SIG_SETMASK, &sigset, NULL);
582
583 nanosleep(&maindelay, NULL);
584
585 sigemptyset(&sigset);
586 pthread_sigmask(SIG_SETMASK, &sigset, NULL);}其中pthread_sigmask(SIG_SETMASK, &sigset, NULL)会进入内核调用:
2870 int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
2871 {
2872 struct task_struct *tsk = current;
2873 sigset_t newset;
2874
2875 /* Lockless, only current can change ->blocked, never from irq */
2876 if (oldset)
2877 *oldset = tsk->blocked;
2878
2879 switch (how) {
2880 case SIG_BLOCK:
2881 sigorsets(&newset, &tsk->blocked, set);
2882 break;
2883 case SIG_UNBLOCK:
2884 sigandnsets(&newset, &tsk->blocked, set);
2885 break;
2886 case SIG_SETMASK:
2887 newset = *set;
2888 break;
2889 default:
2890 return -EINVAL;
2891 }
2892
2893 __set_current_blocked(&newset);
2894 return 0;
2895 }
在函数 __set_current_blocked(&newset)中,也需要申请tsk->sighand->siglock
2846 void __set_current_blocked(const sigset_t *newset)
2847 {
2848 struct task_struct *tsk = current;
2849
2850 /*
2851 * In case the signal mask hasn't changed, there is nothing we need
2852 * to do. The current->blocked shouldn't be modified by other task.
2853 */
2854 if (sigequalsets(&tsk->blocked, newset))
2855 return;
2856
2857 spin_lock_irq(&tsk->sighand->siglock);
2858 __set_task_blocked(tsk, newset);
2859 spin_unlock_irq(&tsk->sighand->siglock);
2860 }
所形成的关系大概是这样
sender main threadlock_task_sighandsend_signal(sig, info, p, type) spin_lock_irq(&tsk->sighand->siglock) //被阻塞unlock_task_sighand(p, &flags) 获取锁,继续调用sigprocmask其他的事情 __set_task_blocked(tsk, newset); spin_unlock_irq(&tsk->sighand->siglock);//释放锁 本来这个锁的释放,唤醒进程都是很简短的过程,通常都是几微秒,为什么这个设备上会出现70us的问题呢,我们看sender和receiver都运行在CPU1上,而main thread是运行在CPU41上,是不是不在一个numa node上,对远端的内存访问会消耗很长时间?
3, 解决方案:将main thread与sender,receiver放到同一个node上
taskset -c 2 ./sigwaittest -p 90 -i 1000 -a 1 -b 80 //不再重现
如果将main thread强制放在CPU41上呢:
taskset -c 41 ./sigwaittest -p 90 -i 1000 -a 1 -b 80 // 很快重现
相关文章:
sigwaittest测试超标的调试过程
1,问题描述硬件环境:飞腾S2500(64核)OS:kylinOS, linux preempt rt, 4.19.90测试命令:sigwaittest -p 90 -i 1000 -a 1测试结果:信号混洗值最大超过了80us,与飞腾其他CPU…...
Python进阶-----面对对象4.0(面对对象三大特征之--继承)
目录 前言: Python的继承简介 1.什么是继承 2.继承的好处 3.object类 继承的相关用法 1.继承的定义与法则 2.对继承的重写 3.(单继承)多层继承 4.多继承 5.多继承重写时调用父类方法 前言: 在讲之前,我想说说中…...
九龙证券|利好政策密集发布,机构扎堆看好的高增长公司曝光
新能源轿车销量和保有量快速增长,带来了充电桩商场的微弱需求。 日前,商务部部长王文涛表明,本年将在落实好方针的一起,活跃出台新方针办法,比方辅导当地展开新能源轿车下乡活动,优化充电等使用环境&#x…...
stm32CubeIDE FMC 驱动LCD(8080)
一,TFT屏硬件接口16位,80并口。二,FMC介绍。FSMC(Flexible Static Memory Controller),译为灵活的静态存储控制器。STM32F1 系列芯片使用 FSMC 外设来管理扩展的存储器,它可以用于驱动包括 SRAM…...
Java 数据类型
数据类型用于对数据归类,以便开发者理解和操作。 基本数据类型 Java 确定了每种基本数据类型所占存储空间的大小,不会像其它语言那样随机器硬件架构的变化而变化,这使 Java 程序更具可移植性。 Java 中定义了如下的基本数据类型。 byte …...
Prometheus 监控云Mysql和自建Mysql(多实例)
本文您将了解到 Prometheus如何配置才能监控云Mysql(包括阿里云、腾讯云、华为云)和自建Mysql。 Prometheus 提供了很多种Exporter,用于监控第三方系统指标,如果没有提供也可以根据Exporter规范自定义Exporter。 本文将通过MySQL server exporter 来监控…...
Vue3中的h函数
文章目录简介简单使用参数使用计数器进阶使用函数组件插槽专栏目录请点击 简介 众所周知,vue内部构建的其实是虚拟DOM,而虚拟DOM是由虚拟节点生成的,实质上虚拟节点也就是一个js对象事实上,我们在vue中写的template,最终也是经过…...
阿尔法开发板 IMX6ULL 说明
一. IMX6ULL开发板 IMX6ULL开发板即正点原子的阿尔法(ALPHA)开发板,采用恩智浦芯片,cortex-A7架构的。 二. IM6ULL开发板说明 1. IO说明 对于IMX6ULL芯片,一个IO对应两个寄存器,第一个寄存器负责配置其复用功能,…...
Altium Designer19 #学习笔记# | 基础应用技巧汇总
全文目录一.元件符号库二.元件封装库1.AD09 集成元件库/封装库三.电路原理图1. 巧用查找"相似对象功能"1.1 查找相同元件1.2. 查找相同文本1.3. 查找相同网络 :E - S - C四.PCB原理图【AD PCB模式下的常用快捷键】PCB视图放大/缩小PCB视图左/右移动PCB切换…...
Python 元类编程实现一个简单的 ORM
概述 什么是ORM? ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。 现在我们就要实…...
《C++ Primer Plus》第18章:探讨 C++ 新标准(7)
C11 新增的其他功能 C11 增加了很多功能,本书无法全面介绍;另外,本书编写期间,其中很多功能还未得到广泛实现。然而,有些功能有必要简要地介绍一下。 并行编程 当前,为提高计算机性能,增加处…...
Redis学习(二):Redis安装测试
概述 Redis是什么 Redis, Remote Dictionary Server, 即远程字典服务。免费开源的数据库。 由C语言编写,支持网络,可基于内存亦可持久化的日志型、KV数据库,并提供所种语言的API。 Redis能干嘛 用于内存存储,持久化。rdb、ao…...
Vector - CAPL - 简介及数据结构
对于想进入车载行业或者已经在车载行业工作的朋友对于CAPL这个词都会相当的熟悉,都知道他是做车载网络测试脚本的语言,并且跟C有点类似,但是它到底是什么呢?CAPL全称(Communication Access Programming Language&#…...
20230304英语学习
What Would Happen if the Moon Disappeared Tomorrow? 如果明天月球消失了会怎样? The closest object to our planet, the Moon, may seem like Earth’s little sibling.Since its birth, the satellite has mostly just hung around, playing gravitational t…...
【基础算法】单链表的OJ练习(3) # 移除链表元素 # 相交链表 #
文章目录前言移除链表元素相交链表写在最后前言 本章的OJ练习也是相对简单的,只要能够理解解题的思路,并且依照这个思路能够快速的写出代码,我相信,你的链表水平已经足够了。 对于OJ练习(2) : ->传送门…...
【自用】SpringBoot项目通用类整理
文章目录全局Json序列化Controller日志切面全局异常拦截GlobalExceptionHandlerApiResultBusinessExceptionResponseEntityUtil全局返回体包装MP自动填充接口文档配置类自定义Async异步线程池本文主要整理各类项目中通用的配置类、工具类,便于复查自用。 全局Json序…...
动态规划法(总述)多阶段决策最优化问题
动态规划: 研究最优控制问题提出的 该问题有n个输入,问题的解由这n个输入组成,这个子集必须满足事先给定的条件,这些条件称为约束条件,满足约束条件的可行解可能不只有一个为了衡量可行解的优劣,通常以一些函数的形式&…...
MySQL跨服务器数据映射
MySQL跨服务器数据映射环境准备1. 首先是要查看数据库的federated引擎 开启/关闭 状态2. 打开任务管理器,并重启mysql服务3. 再次查看FEDERATED引擎状态,引擎已启动映射实现问题总结在日常的开发中经常进行跨数据库进行查询数据。 同服务器下跨数据库进…...
利用反射实现通过读取配置文件对类进行实例化-课后程序(JAVA基础案例教程-黑马程序员编著-第十二章-课后作业)
【案例12-3】:利用反射实现通过读取配置文件对类进行实例化 【案例介绍】 1.案例描述 现在有一个项目,项目中创建了一个Person类,在Person类中定义了一个sleep()方法。在工程中还定义了一个Student类继承Person类,在Student类中…...
1.2 CSS文本属性
CSS Text(文本)属性: 定义文本外观,颜色,装饰,缩进,行间距来修饰文本 文本样式 文本缩进 text-indent文本水平对齐方式:text-align文本修饰:text-decoration行高 line-height CSS文本颜色属性…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
