程序优化那些事儿_第1页
程序优化那些事儿_第2页
程序优化那些事儿_第3页
程序优化那些事儿_第4页
程序优化那些事儿_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

程序优化那些事儿一、程序优化概述二、一个典型的优化范例三、程序性能分析四、程序框架优化四、程序逻辑优化五、代码优化技巧六、编译器优化七、程序优化实施步骤内容一览程序优化: 运用各种方法、技巧对现有的代码重新进行编排、调整,以达到更高的运行性能。程序优化的目标: 提高运行速度

降低资源消耗(程序体积,内存占用、cpu、进程数、句柄等)下面介绍一个优化的例子,有图有真相概述一个例子目标:把彩色相片转成黑白相片公式:Y=0.299*R+0.587*G+0.114*B一个例子优化结果机型普通去浮点去除法查表展开循环性能提高嵌入式s12045302199%笔记本ms441280060240941090%台式机ms36562360123465657984%决定程序运行性能的因素: 硬件平台 软件平台 程序架构 程序逻辑 算法与数据结构 代码编写技巧 编译器性能分析1.硬件平台:cpu的架构、频率,内存大小等 监控采用多个多核x86cpu代替sparc,内存也提高到4G,以解决300个节点的性能问题。 不同架构的CPU,其特点也不相同,根据应用需求选择。2.软件平台:操作系统、数据库、第三方库、JVM 相同硬件下,cosmos在solaris9上比solaris10上效率更高,在debian4上比在debian5上更少占cpu,和操作系统内核设计有关系。平台优化1.程序架构优化重新调整程序的架构,消除不合理的架构设计引起的程序性能瓶颈。2.程序逻辑优化在仔细分析业务逻辑的前提下,寻求更合理、更简单、更高效的程序处理逻辑,以提高程序处理性能。3.代码优化使用各种代码编写技巧,按照编译器优化的方法和处理器执行指令的特点,对已有正确代码重新安排、调整,以获得更好的性能

程序优化的三个层次程序架构优化程序架构:轮询/触发、多线程/单线程、共享内存/管道、同步/异步

优点:能够从根本上解决性能问题

缺点:改动大,成本高,并且可能造成程序的不稳定61850服务器端处理报告的方式:

sisco默认的是定期向装置读取所有报告中配置的数据,扫描周期可以配置。扫描周期长了,数据上送的慢;短了,cpu受不了。

咱们装置可以主动上送变化数据,后来改成触发模式,上送速度快且cpu占用低。61850客户端下发请求的方式:

采用异步请求方式,在等待请求返回的时候不耽误其他工作程序逻辑优化逻辑优化一般只涉及到模块内的功能的调整,对程序整体影响较小,且往往能同时提高运行速度、减小程序体积、提高程序的可维护性。1.去除程序中无用的逻辑处理,去除cosmos初始化过程中的getalldatavalue过程2.根据业务特点,舍弃部分通用性和模块性asn1固定长度的编码asn1_parse函数3.按照业务逻辑流程定制程序流程gsv_on_recved_gooseMessage4.合并同类数据的处理,减少程序执行次数如客户端处理报告的方法,缓存零散报告,统一处理;如客户端调定值的处理,一次下发多个定值请求1.代码优化一般只对代码进行的较小规模的修改,大多数情况下只针对热点函数进行。2.了解一些代码优化技巧,养成习惯,在不影响可读性的前提下编写普遍高效的代码。3.代码优化往往对程序的其他方面造成影响,如可读性、模块性等,要慎重使用。代码优化-概述代码优化-降低运算的强度1.用移位操作代替乘除法

a=b/8;改为:a=b>>3;a=a*8;改为:a=b<<3;a=b%8;改为:a=b&7;a=a*9;改为:a=b<<3+b 位操作只需一个指令周期即可完成,而大部分的C编译器的乘除运算均是调用子程序来完成,代码长、执行速度慢。代码优化-降低运算的强度2.用加法代替乘法

for(i=0;i<MAX;i++)h=14*i;for(i=h=0;i<MAX;i++)h+=14;3.合并除法以减少除法的次数doublex=a/b/c;优化成doublex=a/(b*c)doublex=a/b+c/b;优化成doublex=(a+c)/b代码优化-降低运算的强度4.如果被除数比除数大的倍数不多,可以用减法代替除法。intx=200; inty=70; inta=x/y; intb=x%y; 优化后: intx1=200; inty1=70; inta1=0; intb1=x; while(b1>=y1){ b1-=y1; a1++; }代码优化-降低运算的强度5.用乘法代替除法

doublex=a/b;doubley=c/b;优化后:doubletmp=1/b;doublex=a*tmp;doubley=b*tmp6.在误差允许的情况下,采用近似计算除法比如颜色处理时,uint8color=a/255;优化成uint8color=a/256即a>>8。代码优化-降低运算的强度6.整数代替浮点数7.按需选择赋值符号a=a+1要写为a++;

a=a+b要写为a+=b,后者生成的汇编指令更少8.查表法彩图转换黑白图的例子 如果表很大,不好写,就写一个init函数,在循环外临时生成表格。 如果怕初始化时间太长,或者用到的点比较少且比较固定,可以在用到的时候再计算,存到表里。代码优化-函数1.使用宏定义代替函数定义#defineasn1_GetBOOL(pdata,punit,value)\{\value=pdata[(punit)->offset]&0x01;\}优点:避免函数调用带来的开销:传递参数的开销和保存当前程序上下文信息所花费的开销,函数越复杂需要花费的开销就越大缺点:1.使用这种方法在优化程序速度的同时,却增加了内存的开销,因为在每个应用宏的地方宏都会展开;2.无法跟踪调试;3.宏可读性比较差,容易出现问题代码优化-函数2.减少函数的参数个数,把多个参数合成一个结构体,或者使用全局变量代替,传递的参数越多开销越大3.用合适参数传递方法,数据结构等体积较大的参数,传递指针4.不需要返回值时,声明返回值为void代码优化-if判断If判断的特点: 1.从左到右对表达式求值; 2当结果确定后就不再计算其他表达式的值1.把计算速度快的表达式放到左边:if(strlen(a)>100||b>10)改为if(b>10||strlen(a)>100)2.把概率大的放到左边:if(a>100||b>0)改为if(b>0||a>100)代码优化-if判断3.Ifelse语句和switch中,把最常出现的判断放在前面示例见code_opt工程switch.cpp4.变换表达式,通过代数恒等式代替复杂操作if(!a&&!b)改为if(!(a||b)),可以少一次!操作;用if(a<b)代替if(sqrt(a)<sqrt(b))代码优化-循环1循环展开,减少维护循环所有做的工作for(i=0;i<100;i++) do_stuff(i);新代码:for(i=0;i<100;i+=5){do_stuff(i);do_stuff(i+1);do_stuff(i+2);do_stuff(i+3);do_stuff(i+4);}性能测试见code_opt.cpp代码优化-循环2.循环合并,把多个对相同一组元素进行操作的循环合并到一起示例见code_opt.cpp3.循环中找到相应的值后就停止循环while((i++)<1000){ if(i==100){ do_something();

break; } }代码优化-循环4.把循环中不变的判断拿到循环外面 如果循环过程中,判断的条件不会变,就把它拿到循环外,从而避免在循环中进行判断示例见code_opt.cpp代码优化-循环5.尽可能减少在循环内部做的工作

编写高效循环的关键在于尽可能减少循环内部所做的工作,如果可以在循环外面完成某语句或某个运算,而在循环内只是使用计算结果,就把它放到循环外面For(inti=0;i<count;i++) A=b->c->d->e*(75.5/23)*rate[i];优化成:Tmp=75.5/23;E_tmp=b->c->d->e;For(inti=0;i<count;i++) A=e_tmp*tmp*rate[i];减少了三次指针解引用和一个除法运算的时间代码优化-循环6.循环嵌套时,把最忙的循环放到最内层,可以减少总循环的次数

for(column=0;column<100;column++)for(row=0;row<5;row++) sum=sum+table[row][column]; 里面的循环执行5*100次,外面的循环执行100次,共600次,把外层循环拿到内层后,外层是5次循环,内层是100*5次,共505次,节省了(600-505)/600即16%的时间。代码优化-缓存利用缓存机制提高程序性能1.使用缓存提高访问速度:如cpu的高速缓存机制2.减少函数调用:如报告接收处理,把多个报告的结果进行缓存,通过一次回调给上层。3.防止数据丢失:如网卡驱动中的缓存和61850服务器中的缓存报告4.减少运算次数:缓存需要大量计算的值,如查表法代码优化-编译期初始化发现程序中可能存在的运算结果不变的表达式,使用事先计算好的值代替

比如在计算以2为底的函数中

UnsignedintLog2(unsignedintx) { Return(unsignedint)(log(x)/log(2)); } 其中log(2)是个常量,事先计算好替代,减少一次log()调用代码优化-系统函数注意耗时的系统函数,根据实际需求选择合适的系统函数 如上一个例子,log()函数是系统提供的函数,为了满足绝大多数应用,它的精度很高,内部还会把你传入的整数转成double处理,而我们只需要返回一个整数,因此log()对我们来书是大材小用,因此改成如下UnsignedintLog2(unsignedintx){ if(x<2)return0; if(x<4)return1; if(x<8)return2; if(x<16)return3; .... if(x<2147483648)return30;} 这个函数只用到了整数,根本没有浮点的计算,性能得到大幅优化。代码优化-系统函数 另一种简化写法,能适应更多位的情形,32位、64位等UnsignedintLog2(unsignedintx){ Unsignedinti=0; While((x=(x>>1))!=0) i++; Retruni;}代码优化-数据结构1.选用够用的类型,减少空间浪费但是哪种效率最高是由cpu决定的,比如charshortint对armv6的效率是一样的2.使用联合体节约内存3.使用正确的变量类型,避免没必要的强制类型转换;代码优化-数据结构4.巧用字节对齐的原则节省内存

为了提高数据存取效率,编译器默认会对结构体(包括其他地方的变量)进行处理,让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。示例见code_opt.cpp修改编译器设置可以指定对齐字节数,添加#pragmapack(4)或修改VC6的工程设置。代码优化-动态内存动态内存申请的问题:1.效率低,在堆上申请内存需要很多时间2.产生较多内存碎片,系统性能越来越低,最终可能导致系统崩溃3.忘记释放,导致内存泄露4.可能分配失败,导致程序异常。代码优化-动态内存如何减少动态内存申请1.事先估算所有内存需求,初始化时提前申请,一直用下去Iec61850v2中的动态内存优化例子,mvl61850_rpt.c2.使用实变量代替动态申请Char*str=malloc(strlen); 改为 charstr[MAX_LEN];4.多个变量使用一次申请int*a,*b;float*c;double*d a=malloc(sizeof(int)*2+sizeof(float)+sizeof(double); b=a+1; c=(float*)(b+1); d=(double*)(c+1);5.使用内存池模式代码优化-其他使用汇编重写热点函数,一般能提高30%以上的性能示例gsmv中asn1_parse.asm文件使用编译器优化选项优化,根据程序性能低下的特点选用相关的优化选项使用宏定义,在编译期屏蔽不同平台下不需要的功能提高关键进程的优先级选用高性能的算法示例排序算法,见qsort工程代码优化总结代码优化不是解决性能问题的唯一法宝,1.从实施效果看,完善框架设计、调整程序逻辑设计、选择更好的算法常常能带来更大幅度的性能提升2.从实施过程看,提高硬件规格或者合理设置编译器优化选项会更方便选择合适的足够精度的测量方法,找出真正影响性能的地方,并且每次修改完测试修改效果代码优化需要反复尝试,这样才能得到理想的性能提高不同的编译器和运行环境对同样的优化方法的性能提升是不一样的为性能优化工作做好准备的最佳方式是初期编写清晰易懂的代码,从而后期方便代码的理解和修改几个导致性能低下的原因编码时容错方面的考虑为提高程序的容错性,假设输入不可靠,可能导致每层接口对同样的输入都做严格的检测及错误处理,致使性能受损。代码模块化的设计模块化的设计提高了软件的可维护性和可扩展性,但如果设计不当,模块间的接口与通信可能产生性能瓶颈。需求的变化为满足新的需求,程序员不断的修改代码,而老的需求不存在时,一般也不会去除相关无用的代码;更改代码时往往考虑的是如何使改动最小而不是最合理,时间久了,程序中冗余代码增多,程序逻辑也越来越混乱,性能自然降低。兼容性的需要设计接口时,为了兼容老的版本或者满足更多应用的场景,过多的考虑了实现的兼容性、通用性,导致接口逻辑复杂,判断分支过多,很多实际上用不到的特性增加了程序的开销何时开始优化1.性能优化开始的越早越好。软件设计阶段就考虑了性能的问题,将来的改动就较少,越到后期改动的成本会越高问题:过早的考虑了代码的优化,追求代码性能的高效,而在实际运行过程中,其实只有很少一部分热点函数需要优化,结果对可读性、扩展性带来损害。何时开始优化2.待软件功能开发完成后再来考虑优化的事,功能都没做好,优化有什么用呢,防止做太多无用功问题:实现功能时,没有从程序的逻辑、算法等方面没有考虑性能问题,导致后期仅仅优化热点函数仍然无法满足要求,不得不大动干戈修改程序逻辑和算法甚至架构,造成损失更大何时开始优化正确的方法:1.在需求阶段,就要把性能指标定义下来2.在软件设计阶段,根据这些指标考量程序逻辑和算法3.软件功能基本完成后,测试性能,对逻辑做细微调整,查找热点函数,进行代码优化优化的步骤根据实际需求,确定性能指标,给出一个合适的评价性能的标准:理想值,下限值。进行优化之前,一定考虑清楚性能指标是合理且必须的测试程序当前的状况,离目标还有多远,做到心中有数分析程序,查找性能瓶颈,一般来讲20%的代码占用的80%的时间修改程序。程序优化应优先优化程序逻辑,然后才是代码级别的优化。测试,验证优化后的结果如果满足要求,就停止优化。否则回到3。防止过度优化,可能会降低代码可读性,浪费时间精力。性能分析性能低下的表现:1.程序的运算量很大,导致cpu过于繁忙2.程序需要做大量的I/O操作,读写文件、网络等,cpu更多的是等待3.程序直接互相等待,cpu利用低,但程序依然运行缓慢查找性能瓶颈的方法:1.根据程序表现,分析程序流程,走读代码2.在程序中添加日志,记录时标及相关信息3.使用性能分析工具,如linux下有top、gprof和OProfile等,windows下有aqtime等编译器-概述主流的C/C++编译器:MS的CL、GNU的gcc、Intel的icl、Codegear的bcc。衡量编译的标准:编译速度、对标准的支持度、目标程序的性能、支持的平台、编译器的体积、易用性编译器的选择在大部分平台上,gcc是C/C++编译器的首选,对C/C++标准的支持也是最完善的。intel的编译器针对

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论