相关书籍
第一阶段:《嵌入式内存使用和性能优化》
第二阶段:《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
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可能会比轮询的方式还影响性能,不过影响的不大。