Linux环境下程序的多核CPU占用率高的问题分析和解决

1.项目问题

前端PDC双目倾斜相机客流统计项目中排查平台服务程序延时大的问题时,平台demo程序测试发现多核cpu中的某个核的占用率达到100%,导致组件中的目标检测线程和客流统计线程的单帧耗时达不到实时,存在延时和丢帧的问题。通过使用strace、pstack进行程序分析,最终找到导致单核占用率很高的原因和解决方法。本文详细描述了该问题的排查过程,并对排查流程做了相关总结。

2.背景技术及术语解释

在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率,也就是说,任务管理器中显示的是每个刷新周期内CPU占用率的统计平均值。

3.方案详细描述

1)CPU占用率概念,以及top命令和tegrastats命令的使用

在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率,也就是说,任务管理器中显示的是每个刷新周期内CPU占用率的统计平均值。top命令经常用来监控linux的系统状况,比如cpu、内存的使用,显示各进程(任务)的状态监控。

如图1所示。

PID                         —       进程id

USER                     —       进程所有者

PR                          —        进程优先级

NI                           —        nice值。负值表示高优先级,正值表示低优先级

VIRT                      —        进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES

RES                      —        进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA

SHR                      —        共享内存大小,单位kb

S                           —        进程状态。

                D = 不可中断的睡眠状态

                R = 运行

                S = 睡眠

                T = 跟踪/停止

               Z = 僵尸进程

%CPU                 —         上次更新到现在的CPU时间占用百分比

%MEM                —          进程使用的物理内存百分比

TIME+                 —          进程使用的CPU时间总计,单位1/100秒

COMMAND         —          进程名称(命令名/命令行)示各个进程(任务)

 

./tegrastats命令经常用来监控linux的系统显存使用情况,也包含cpu、内存的使用状态,对设备的状态进行监控和显示。如图2所示。

RAM       —     内存占用

SWAP     —     交换区

cache      —     缓存

cpu          —     cpu各个核心的资源占用

EMC        —     内存频率

AVP         —     音频资源

VDE         —     视频资源

GR3D      —      GPU消耗

 

2)CPU占用率过高的问题现象和排查过程

前端PDC双目倾斜相机客流统计项目中排查平台服务程序延时大的问题时,平台demo程序测试发现多核cpu中的某个核的占用率达到100%,导致组件中的目标检测线程和客流统计线程的单帧耗时达不到实时,存在延时和丢帧的问题。Top和tegrastats命令执行,得到的状态如下图3所示。

图3 cpu占用率高的top和tegrastats命令的显示状态

因为这是个多线程的进程,实际上占用cpu的最小单位是线程,所以肯定是众线程中的某一个或几个占用CPU过 高 导 致 的 。 用 下 面 的 命 令 将cpu占 用 率 高 的 线 程 找 出 来:ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu

直接使用ps Hh-eo pid,tid,pcpu | sort-nk3 |tail   获取对于的进程号和线程号,如下图4所示。

 

如上图所示我们可以看出id为17758的线程cpu占用率最高。运行strace命令,可以看到每个线程的

调用堆栈。如下图6所示。

 

图6strace命令各个线程的堆栈状态

执行pstack脚本,看该线程的调用堆栈,很容易看出在哪一步逻辑上导致了busy loop。如下图7所示。

图7pstack脚本找出导致busyloop的代码行

根据提示,找到对应的代码行,消除busy loop代码,解决cpu占用率高的问题。

 

3)避免CPU高占用率的方法

通过以上分析,平台demo程序中的main函数中的死循环占用了大量的cpu资源,导致多核cpu中的某个核的占用率达到100%。通过修改demo程序,去掉busy loop,可以避免单核占用率达到100%的问题。同时针对多核cpu中存在0核或者其他核的占用率高的问题,将多个线程处理过程绑定到不同的cpu上,使得多核cpu负载均匀,降低线程处理的耗时。绑核前后的0核cpu占用率见下图8所示。

图8绑核前后的0核cpu占用率

 

4)正确的线程绑核

Cpu绑核时,应将子线程绑定到不同的cpu核,是cpu的各个核负载均衡。如果将主线程绑核,会导致子线程的绑核不生效。如下图所示。

图9主线程不绑核cpu占用率

图10主线程绑0核cpu占用率

图11主线程绑1核cpu占用率线程的cpu

绑核是通过设置线程的调度亲缘性来实现的。因为Linux操作系统下进程和线程的创建都是通过系统调用clone来实现的,所以实际上调度亲缘性也是被用pthread_create创建的线程所继承的。这意味着,如果主线程在创建其它线程之前设定亲缘性,那么它所设定的亲缘性将被继承,因为这时所有线程的亲缘性相同。

 

总结:

(1)程序中的高CPU占用率问题,可以通过strace工具和pstack脚本进行定位;

(2)CPU的高占用率可以通过消除代码中的busyloop和线程绑核的方式避免或使多核CPU负载均匀;

(3)多核CPU绑定时,应避免将主线程进行绑核,将处理子线程分别绑定至不同的CPU核,可以实现CPU负载均匀,提高运行效率;

你可能感兴趣的:(Linux)