一、从一个问题说起

  相信很多人在玩手机还是PC时,都曾碰到过这样一种情况,安装的软件多了系统性能就变慢了,但是去查看CPU利用率一直都低于10%,内存也很充足。我在近期的开发工作中就碰到了类似的情况,不同的是,系统此时只有一个测试程序和几个睡眠的后台进程,说明是系统,特别是驱动部分可能出现问题导致的。 从操作系统角度上分析,以下是一些比较可能的原因:

  1. 大量的中断
    可能是在不断磁盘读写,网络通讯, 也可能是模块使用不当或者硬件上出问题导致外设不断给CPU送中断;
  2. 系统负载高(注意:不是CPU利用率)
    负载高表示有很多程序等待调度运行,它会导致上下文切换频繁。
  3. 上下文切换过于频繁
    上下文切换是指CPU从一个进程切换到另一个进程,这个过程也是需要消耗一定时间的。如果说上下文切换过于频繁,说明CPU用于执行进程代码的时间少了。第2点有提到负载高会引起上下文切换频繁,但是上下文切换频繁负载不一定就高。

  在以往的排查经验中,系统性能下降主要由1引起的,在影响系统性能上表现得比较明显;而2,3则比较隐蔽,即使数值已经异常,只要应用对实时性要求不高,最多就是响应稍慢一些,看不出有什么不妥。因此,底层驱动开发人员一般不会去考虑2,3两点,更别说将它作为评价系统性能的测试指标。刚好我要测试的模块对实时性要求很高,而由于系统在空闲时的上下文切换已经很频繁,测试结果自然不佳。

二、怎么确认上下文切换频繁?

  要解决空闲时上下文切换频繁的问题,首先要了解下多频繁才不正常。/proc/stat文件包含了CPU的活动信息,上下文切换就是其中一项,下面命令输出的粗体大号字体所示,以ctxt开头,它表示系统开机到目前为止的上下文切换总数。

 ~ # cat /proc/stat
cpu
cpu0
intr
ctxt

btime
processes
procs_running
procs_blocked
softirq

  对于分析问题而言,我们更关心每秒钟的上下文切换次数,可通过以下命令计算。

 $cat /proc/stat | grep ctxt && sleep  && cat /proc/stat | grep ctxt
ctxt
ctxt

  每秒上下文切换次数=两者差值/30。针对本例,每秒有237次切换,对于一个空闲的系统,这是相当不正常的。正常数值范围一般不超过50次/秒。不过这也不是固定的,需要根据不同的系统环境决定,比如本人在嵌入式开发主要从事开发POS产品,它与作为服务器的Linux系统相比,实际运行的服务会少很多,上下文切换自然应该更少。另外,如果要求更高的实时性,则数值范围还应进一步缩小,本人分析的产品所定的数值范围就要求空闲时不超过30次/秒。 上面介绍的方法在所有Linux产品上都能支持,如果系统带 vmstat ,通过vmstat查看是一个更便捷的方法。测试结果如下图红色方框所示。

三、上下文切换频繁时怎么排查?

  仅靠总的上下文切换次数无法定位到哪个进程或者哪个驱动出的问题,这时就需要pidstat(在sysstat包里)可以查看具体到每个进程每秒的上下文切换次数,下图是执行 $pidstat -w 1的结果。

  在继续分析上图之前我们先谈一个概念:CPU密集型的进程和IO密集型的进程。CPU密集型的进程时间片总是不够用,CPU使用率必然升高,不需要查看上下文切换;而IO密集型的进程,会被频繁调度,但是每次只处理一小会,从CPU使用率是看不出异常的,这时就需要查看上下文切换。一般来讲IO密集型的进程(内核线程或用户进程)主要是处理读写磁盘,或者网络进来的数据;但是也可能有的进程没有任何IO交互但是表现得像IO密集型进程,比如使用如下方式:

  1. 创建一个内核线程,一启动就睡眠;然后创建一个10MS的timer,每次都去唤醒这个内核线程。
  2. 创建一个用户进程,通过系统调用陷入内核就睡眠,然后创建一个10MS的timer,每次都去唤醒这个进程。

当然,我们不会傻到直接干这样的事,但却可能在无意中间接做了这样的事情,特别是对第1条,比如

  1. 创建一个工作队列,创建一个10MS的timer,每次去schedule_work。

  工作队列也是由一个内核线程在管理,导致的结果就是该内核线程上下文切换将变得极为频繁。 对于上下文切换频繁的进程,我们的关注点就是确认它们是否是IO密集型的,以及在当前系统状态下是否应该表现得像IO密集型进程。 比如一个处理网络数据的进程,如果在没有数据的情况下,也表现得像IO密集型,有很高的切换上下文动作,可能这个进程或者该进程打开的设备驱动设计得不合理。

  有两个内核线程kswapd和events(新内核改为kworker),在特定情况下会表现得像IO密集型进程。其中kswapd是用于管理虚拟内存的,当物理内存不足,需要频繁交换虚拟内存,kswapd的上下文切换将明显增多;而events用来处理工作队列,当不断有work进入排队且这些work处理时间很短时,events的上下文切换会明显增多,对于这种情况,需要分析具体是由哪个驱动引起的。

  回到pidstat的输出,可以看到events/0的上下文切换很高,既然没有什么进程会导致该结果,就只可能是某个驱动文件(ko)在不断地排队work。目前我没有找到比较高效的方法可以迅速定位到每个ko文件对work的使用情况,只能通过lsmod打出已经加载的驱动,并跟以前的系统版本对比哪些做了修改以做对比。最终定位出确实存在某个驱动创建一个10MS的timer,并且每次都schedule_work。在对该驱动优化后,再次输入pidstat -w 1测试,可以看到所有进程的下下文切换都降得很低了。

四、附录

1、交叉编译sysstat 一般的板子都不会带pidstat,需要自己下载sysstat的包编译。好在sysstat直接使用工具链就能编译。操作步骤: 进入源码目录

 $mkdir output
$export SA_DIR=`pwd`/output/var/log/sa
$export conf_dir=`pwd`/output/etc/kksysconfig
$./configure --prefix=`pwd`/output --host=arm-none-linux-gnueabi --disable-man-group
$make
$make install

将output下的bin和lib拷到板子即可。注意交叉编译时要在configure时指名工具链名称,如果你的工具链是arm-none-linux-gnueabi-gcc,那么就传递参数--host=arm-none-linux-gnueabi,如果是arm-eabi-gcc,那么就传递参数--host=arm-eabi,按此规则修改。

2.参考文献

Linux的各种统计信息

CPU-上下文切换,运行队列和使用率

进程上下文切换-残酷的性能杀手(上)

使用pidstat查看Context Switch上下文切换

[嵌入式开发]Linux性能分析——上下文切换的更多相关文章

  1. Linux 性能分析工具汇总合集

    出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章.本文也可以作为检验基础知识的指标,另外文章涵盖了一个系统的方方面面.如果没有完善的计算机系统知识,网络知识和操作系统知识, ...

  2. [转]Linux性能分析工具汇总合集

    出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章.本文也可以作为检验基础知识的指标,另外文章涵盖了一个系统的方方面面.如果没有完善的计算机系统知识,网络知识和操作系统知识, ...

  3. 超全整理!Linux性能分析工具汇总合集

    转自:http://rdc.hundsun.com/portal/article/731.html?ref=myread 出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章. ...

  4. (转)超全整理!Linux性能分析工具汇总合集

    超全整理!Linux性能分析工具汇总合集 原文:http://rdc.hundsun.com/portal/article/731.html 出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望, ...

  5. Linux性能分析命令工具汇总

    转自:http://rdc.hundsun.com/portal/article/731.html?ref=myread 出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章. ...

  6. Linux 性能分析 工具命令

    背景知识:具备背景知识是分析性能问题时需要了解的.比如硬件 cache:再比如操作系统内核.应用程序的行为细节往往是和这些东西互相牵扯的,这些底层的东西会以意想不到的方式影响应用程序的性能,比如某些程 ...

  7. 【转】一文掌握 Linux 性能分析之网络篇(续)

    [转]一文掌握 Linux 性能分析之网络篇(续) 在上篇网络篇中,我们已经介绍了几个 Linux 网络方向的性能分析工具,本文再补充几个.总结下来,余下的工具包括但不限于以下几个: sar:统计信息 ...

  8. 【转】一文掌握 Linux 性能分析之网络篇

    [转]一文掌握 Linux 性能分析之网络篇 比较宽泛地讲,网络方向的性能分析既包括主机测的网络配置查看.监控,又包括网络链路上的包转发时延.吞吐量.带宽等指标分析.包括但不限于以下分析工具: pin ...

  9. 【转】一文掌握 Linux 性能分析之 I/O 篇

    [转]一文掌握 Linux 性能分析之 I/O 篇 这是 Linux 性能分析系列的第三篇,前两篇分别讲了 CPU 和 内存,本篇来看 IO. IO 和 存储密切相关,存储可以概括为磁盘,内存,缓存, ...

随机推荐

  1. Scala比较器:Ordered与Ordering

    在项目中,我们常常会遇到排序(或比较)需求,比如:对一个Person类 case class Person(name: String, age: Int) { override def toStrin ...

  2. 轻松理解AOP思想(面向切面编程)

    本文旨在帮助还没有理解AOP的童鞋看透弄懂AOP,也欢迎高手批评指正. 先说一个Spring是什么吧,大家都是它是一个框架,但框架这个词对新手有点抽象,以致于越解释越模糊,不过它确实是个框架的,但那是 ...

  3. Python程序高效地调试

    现在我在debug python程序就只是简单在有可能错误的地方print出来看一下,不知道python有没像c++的一些IDE一样有单步调试这类的工具?或者说各位python大神一般是怎么debug ...

  4. 什么是Servlet?

    HTML只能用来保存静态内容,而通常情况下,静态页面很难满足实际应用的需要,鉴于此,动态页面被引入.所谓动态页面,指的是能够根据不同时间,不同用户而显示不同内容的页面,例如常见的论坛.留言板.电子商务 ...

  5. Gym 100703I---Endeavor for perfection(尺取)

    题目链接 http://codeforces.com/problemset/gymProblem/100703/I Description standard input/outputStatement ...

  6. BZOJ 1044 木棍分割 解题报告(二分+DP)

    来到机房刷了一道水(bian’tai)题.题目思想非常简单易懂(我的做法实际上参考了Evensgn 范学长,在此多谢范学长了) 题目摆上: 1044: [HAOI2008]木棍分割 Time Limi ...

  7. Java基础学习总结 -- 多线程的实现

    目录: 继承Thread类 start()方法实现多线程的原理 实现Runnable接口 Thread类 与 Runnable接口 的联系与区别 多线程的实现方法: 继承Thread类 实现Runna ...

  8. 像素与rem转换

    // rem尺寸转换函数开始(function (doc, win) {    var docEl = doc.documentElement,        resizeEvt = 'orienta ...

  9. 基本排序算法——选择排序java实现

    选择排序与冒泡排序有很大的相同点,都是一次遍历结束后能确定一个元素的最终位置,其主要思路是,一次遍历选取最小的元素与第一个元素交换,从而使得一个个元素有序,而后选择第二小的元素与第二个元素交换,知道, ...

  10. Sanboxie 5.14安装图解

    Sanboxie, 即沙盘,引用官方解释:电脑就像一张纸,程序的运行与改动,就像将字写在纸上.而Sandboxie就相当于在纸上放了块玻璃,程序的运行与改动就像写在了那块玻璃上,除去玻璃,纸上还是一点 ...