Linux下代码性能优化

相关书籍

第一阶段:《嵌入式内存使用和性能优化》

第二阶段:《Systems Performance》(性能之巅)

https://www.cnblogs.com/arnoldlu/p/6874328.html#performance_optimization_method

概述

整个对于Linux代码的优化,应该区分为从整个层面的系统优化,和从模块角度的算法性能优化。最终追寻的优化是原来原理层面的追寻。Linux系统的优化也是,属于系统层面的优化。针对特定的场景要求根据优先级做出取舍关系。

一、内存性能

1.1、内存测量或者统计

1、系统内存的测量:free用以获得当前系统内存的使用情况。

查看缓存的命令

  free -m

清理缓存的命令 

    echo 1 > /proc/sys/vm/drop_caches

          echo 2 > /proc/sys/vm/drop_caches

          echo 3 > /proc/sys/vm/drop_caches

2、进程的内存测量

在进程的proc中与内存有关的节点有statm、maps、memmap。

cat /proc/PID(进程号)/statm

cat /proc/PID(进程号)/maps

1.2、内存优化配置

对于Linux系统内存的回收有一套默认的配置参数,但是对于内存性能较差的设备,我们有时候需要优化该配置。

其主要参数,主要包括上文说的手动清空缓存的drop_caches,也包括min_free_kbytes参数等等

  参数 说明 备注
保证linux有足够的物理内存,可以调整vm的如下参数 vm.min_free_kbytes 默认值是3797,保证物理内存有足够空闲空间,防止突发性换页。 如果设置的值小于1024KB,系统很容易崩溃,在负载较高时很容易死锁。如果设置的值太大,系统会经常OOM。  
  vm.vfs_cache_pressure 默认是100,增大这个参数设置了虚拟内存回收directory和i-node缓冲的倾向,这个值越大。越易回收  
  vm.swappiness

缺省60,减少这个参数会使系统尽快通过swapout不使用的进程资源来释放更多的物理内存

 
改善io系统的性能 vm.overcommit_memory

默认值为:0从内核文档里得知,该参数有三个值,分别是:0:当用户空间请求更多的的内存时,内核尝试估算出剩余可用的内存。

1:当设这个参数值为1时,内核允许超量使用内存直到用完为止,主要用于科学计算

2:当设这个参数值为2时,内核会使用一个决不过量使用内存的算法,即系统整个内存地址空间不能超过swap+50%的RAM值,50%参数的设定是在overcommit_ratio中设定。

 
  vm.overcommit_ratio 默认值是50,用于虚拟内存的物理内存的百分比。这个参数值只有在vm.overcommit_memory=2的情况下,这个参数才会生效。该值为物理内存比率,当overcommit_memory=2时,进程可使用的swap空间不可超过PM * overcommit_ratio/100  
  vm.dirty_ratio 默认值是40,为了保持稳定,持续的写入,把这个值调整的小一些,经验值是20。增大会使用更多系统内存用于缓冲,可以提高系统的读写性能。当需要持续、恒定的写入场合时,应该降低该数值。  
  vm.dirty_background_ratio 缺省数值是500,也就是5秒,如果系统要求稳定持续的写,可以适当降低该值,把峰值的写操作平均多次,也避免宕机丢失更多的数据  
  vm.dirty_expire_centisecs 缺省是3000,也就是30秒,如果系统写操作压力很大,可以适当减小该值,但也不要太小;建议设置为 1500  
       

参数作用的介绍(https://blog.csdn.net/jiajiren11/article/details/78822171)

参数使用的介绍(https://blog.csdn.net/wyzxg/article/details/5661489)
vm的相关参数在/proc/sys目录下,相关命令

sysctl -p  //修改vm参数后,运行这个命令可以立即生效
sysctl -a  //查看所有的vm参数

1.3、进程内存优化

1.执行文件所占用的内存

2.动态库对内存的影响

3.线程对内存的影响

1.4、参考地址

https://www.cnblogs.com/arnoldlu/p/6874328.html

https://blog.csdn.net/hixiaoxiaoniao/article/details/85982350

二、CPU运行性能

性能优化也就是下面的几个策略:

  • 用空间换时间。各种cache如CPU L1/L2/RAM到硬盘,都是用空间来换时间的策略。这样策略基本上是把计算的过程一步一步的保存或缓存下来,这样就不用每次用的时候都要再计算一遍,比如数据缓冲,CDN,等。这样的策略还表现为冗余数据,比如数据镜象,负载均衡什么的。
  • 用时间换空间。有时候,少量的空间可能性能会更好,比如网络传输,如果有一些压缩数据的算法(如前些天说的“Huffman 编码压缩算法” 和 “rsync 的核心算法”),这样的算法其实很耗时,但是因为瓶颈在网络传输,所以用时间来换空间反而能省时间。
  • 简化代码。最高效的程序就是不执行任何代码的程序,所以,代码越少性能就越高。关于代码级优化的技术大学里的教科书有很多示例了。如:减少循环的层数,减少递归,在循环中少声明变量,少做分配和释放内存的操作,尽量把循环体内的表达式抽到循环外,条件表达的中的多个条件判断的次序,尽量在程序启动时把一些东西准备好,注意函数调用的开销(栈上开销),注意面向对象语言中临时对象的开销,小心使用异常(不要用异常来检查一些可接受可忽略并经常发生的错误),…… 等等,等等,这连东西需要我们非常了解编程语言和常用的库。
  • 并行处理。如果CPU只有一个核,你要玩多进程,多线程,对于计算密集型的软件会反而更慢(因为操作系统调度和切换开销很大),CPU的核多了才能真正体现出多进程多线程的优势。并行处理需要我们的程序有Scalability,不能水平或垂直扩展的程序无法进行并行处理。从架构上来说,这表再为——是否可以做到不改代码只是加加机器就可以完成性能提升?

总之,根据2:8原则来说,20%的代码耗了你80%的性能,找到那20%的代码,你就可以优化那80%的性能

1、算法调优

过滤算法、哈希算法、分而治之和预处理

2、代码调优

字符串操作:能用整型最好用整型。

多线程调优:线程不是越多越好,线程间的调度和上下文切换也是很夸张的事,尽可能的在一个线程里干,尽可能的不要同步线程。这会让你有很多的性能。

内存分配:不要小看程序的内存分配。malloc/realloc/calloc这样的系统调非常耗时,尤其是当内存出现碎片的时候。

异步操作:我们知道Unix下的文件操作是有block和non-block的方式的,像有些系统调用也是block式的,如:Socket下的select,Windows下的WaitforObject之类的,如果我们的程序是同步操作,那么会非常影响性能,我们可以改成异步的,但是改成异步的方式会让你的程序变复杂。异步方式一般要通过队列,要注间队列的性能问题,另外,异步下的状态通知通常是个问题,比如消息事件通知方式,有callback方式,等,这些方式同样可能会影响你的性能。但是通常来说,异步操作会让性能的吞吐率有很大提升(Throughput),但是会牺牲系统的响应时间(latency)。这需要业务上支持。

语言和代码库:

参考网址:

http://www.bubuko.com/infodetail-981218.html

2.1、PS top《性能之巅》P241

CPU分析工具
LINUX 描述 备注
uptime 平均负载  
vmstate 包括系统范围的CPU平均负载  
mpstate 单个CPU的统计信息  
sar 历史统计信息  
ps 进程状态  
top 监控每个进程/线程CPU用量  
pidstat 每个进程/线程CPU用量分解  
time 给一个命令计时,带CPU用量分解  
DTrace, perf CPU剖析和跟踪  
perf CPU性能计数器分析  

 

2.2、函数级别运行性能优化

2.2.1、oProfile

oProfile是Linux平台上的一个功能强大的性能分析工具,支持两种采样(sampling)方式:基于事件的采样(eventbased)和基于时间的采样(timebased),它可以工作在不同的体系结构上,包括MIPS、ARM、IA32、IA64和AMD。

cpu无端占用高?应用程序响应慢?苦于没有分析的工具?

oprofile利用cpu硬件层面提供的性能计数器(performance counter),通过计数采样,帮助我们从进程、函数、代码层面找出占用cpu的"罪魁祸首"。下面我们通过实例,了解oprofile的具体使用方法。

常用命令

使用oprofile进行cpu使用情况检测,需要经过初始化、启动检测、导出检测数据、查看检测结果等步骤,以下为常用的oprofile命令。

初始化

  • opcontrol --no-vmlinux : 指示oprofile启动检测后,不记录内核模块、内核代码相关统计数据
  • opcontrol --init : 加载oprofile模块、oprofile驱动程序

检测控制

  • opcontrol --start : 指示oprofile启动检测
  • opcontrol --dump : 指示将oprofile检测到的数据写入文件
  • opcontrol --reset : 清空之前检测的数据记录
  • opcontrol -h : 关闭oprofile进程

查看检测结果

  • opreport : 以镜像(image)的角度显示检测结果,进程、动态库、内核模块属于镜像范畴
  • opreport -l : 以函数的角度显示检测结果
  • opreport -l test : 以函数的角度,针对test进程显示检测结果
  • opannotate -s test : 以代码的角度,针对test进程显示检测结果
  • opannotate -s /lib64/libc-2.4.so : 以代码的角度,针对libc-2.4.so库显示检测结果

参考网址:

https://www.cnblogs.com/274914765qq/p/4976415.html

https://www.cnblogs.com/bangerlee/archive/2012/08/30/2659435.html

2.2.2、perf

Perf是内置于Linux内核源码树中的性能剖析工具。它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析。可用于性能瓶颈的查找与热点代码的定位。

参考网址:

https://blog.csdn.net/kelsel/article/details/52758229

2.3、CPU运行时访问内存的速度优化

如果代码设计的不够合理,如代码的内存非连续,那么内存访问不在高速缓存中,那么频繁的去DDR处读取数据将导致内存的访问浪费大量的时间,从而最终造成CPU占比升高。(cache miss)

虽然内核已经有较好的内存访问缓存机制,但是如果我们的代码设计的不合理,将会导致设备性能运行变慢。

参考地址:

https://www.jianshu.com/p/8a72f1fede21

三、网络性能

ifconfig

TCP调优:TCP链接是有很多开销的,一个是会占用文件描述符,另一个是会开缓存,一般来说一个系统可以支持的TCP链接数是有限的,我们需要清楚地认识到TCP链接对系统的开销是很大的。注意配置KeepAlive参数,这个参数的意思是定义一个时间,如果链接上没有数据传输,系统会在这个时间发一个包,如果没有收到回应,那么TCP就认为链接断了,然后就会把链接关闭,这样可以回收系统资源开销。

UDP调优:UDP的调优,有一些事我想重点说一样,那就是MTU——最大传输单元。

网卡调优

其它网络性能:多路复用技术,也就是用一个线程来管理所有的TCP链接,有三个系统调用要重点注意:一个是select,这个系统调用只支持上限1024个链接,第二个是poll,其可以突破1024的限制,但是select和poll本质上是使用的轮询机制,轮询机制在链接多的时候性能很差,因主是O(n)的算法,所以,epoll出现了,epoll是操作系统内核支持的,仅当在链接活跃时,操作系统才会callback,这是由操作系统通知触发的,但其只有Linux Kernel 2.6以后才支持(准确说是2.5.44中引入的),当然,如果所有的链接都是活跃的,过多的使用epoll_ctl可能会比轮询的方式还影响性能,不过影响的不大。

 

四、启动时间优化

你可能感兴趣的:(Linux下代码优化)