高性能c语言编码
来源:互联网 发布:背景音乐制作软件 编辑:程序博客网 时间:2024/04/29 02:31
c语言编码–优化tips
- 好的算法
- 减少指令数
- 减少跳转
对于cpu密集型进程来说,语言层面有下面一些tips可供参考和借鉴
1.减少指令数
1.1 简单函数使用宏或者内联函数
非内联函数会有入栈、出栈的操作,
int min(int a, int b) { return a < b ? a b;}
改成使用
#define min(a,b) ((a) < (b) ? (a) : (b))
1.2、少用乘法
定点乘需要花费n个指令周期,移位只需要一个指令周期,若乘以一个2的N次方数
可以使用移位
len = len * 4;
改为
len <<= 2;
1.3、慎用除/求余
除法需要耗费许多周期,可以将除法转化为乘法
f = f / 5.0
转化为:
f = f * 0.2
1.4、精度允许情况将浮点转化为定点运算
Pixel_C = (int) (Pixel_A * Alpha + Pixel_B(1 -Alpha)) alpha范围(0,1)浮点
转化为
Pixel_C = (int) (Pixel_A * Alpha + Pixel_B *(32 - ALpha) + 16) >> 5 alpha 取值范围(0,32) 定点整数
2、减少跳转
2.1 减少分支
cpu是流水执行,if switch等指令会带来跳转,跳转会影响水流执行效率for (i=0; i<100; i++) { if (i % 2) { a[i] = x; } else { a[i] = y; }}
转化为
for (i=0;i<100;i+=2) { a[i] = x; a[i + 1] = y;}
2.2 最可能的路径放到if 中
int a = -5;int b = 0;if (a > 0) { b = 1;} else { b = 2;}
由于没有历史信息可参考,Static Predictor 静态预测器 预测不跳转,a = 5预测错分支,错误取了b = 1指令,又要重新取指令
代码关键路径,可以借助 likely unlikely指定分支转移信息(GCC 版本需>= 2.96),将有利于分支预测的整体效率
#define likely(x) __builtin_expect((x),1)#define unlikely(x) __builtin_expect((x),0)
3.尽量避免访内
访问一级cache只需要消耗几个指令周期, 访问二级缓存也只要十几个指令周期,访问内存需要消耗上百个指令周期,也要尽量避免 cache miss
3.1 减少使用数组、指针
大块内存会被放在存储器中,局部变量才会放到寄存器中,全局变量可能被多个模块和函数使用,编译器也不会放入寄存器中c = a[i] * b[i];d = a[i] + b[i];
以上语句会访问四次内存,改为
x = a[i];y = b[i];c = x * y;d = x + y;
只访问两次内存
3.2 少用全局变量
int x;int func(){ int y, z; y = x; z = x + 1;}
最好改为
int x;int func(){ int y, z,tmp; tmp = x; y = tmp; z = tmp + 1;}
3.3、对齐访问
不对齐访问cpu将会做多余的拼接操作,使执行效率变低
3.4、大数据结构时cache line对齐
cpu 取指令和数据时,先从一级和二级的LD/LP中查找数据,Intel 大多cache line 为64 bytes,对大结构分配内存时,尽量保持64byte对齐,减少cache miss
一个64byte 的数据如果非64byte对齐时,将占用两个cache line,会产生两次cache miss
多核情况也更容易一致性问题,cache line变脏。
举例:经常使用的struct sockaddr_storage
#define _K_SS_MAXSIZE 128 /* Implementation specific max size */#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *)) /* Implementation specific desired alignment */struct __kernel_sockaddr_storage { unsigned short ss_family; /* address family */ /* Following field(s) are implementation specific */ char __data[_K_SS_MAXSIZE - sizeof(unsigned short)]; /* space to achieve desired size, */ /* _SS_MAXSIZE value minus size of ss_family */} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
3.5 程序、数据访问符合cache空间、时间局部性
for (j=0;j<500;j++) { for (i=0;i<5000;i++){ sum += a[i][j]; }}
应该采用,cache的命中率才高
for (i=0;i<500;i++) {
for (j=0;j<5000;j++){
sum += a[i][j];
}
}
a[i][j]在Cache中,a[i][j+1]也在cache中,而a[i+1][j]不一定在cache中
3.6 多线程尽量避免访内 false sharing**
cache line是cache从内存取数据的最小单位,程序开辟了一个数组Arr,Arr[0]给线程0使用,Arr[1]给线程1使用,线程0在0核上运行,线程1在1核上允许,数组Arra既被cache到核0上,又被cache到核1上,如果线程0修改了Arr[0],那么cache一致性就使核1的这行cache line无效,导致线程1发生 cache miss,同样的过程发生在核1上修改Arr[1];
false sharing 会导致大量的cache 冲突,应该尽量避免,将多个线程范文的数据放置在不同的cache line 上
3.7 自己管理内存动态分配
避免频繁 malloc/free,内存碎片、降低内存泄露风险,频繁申请内存导致内存分散,加大cache miss概率,动态申请内存后,不做无用初始化,操作系统为了提高性能也使用COW(copy-on-write)策略,在fork子进程的时候不会立即复制进程的所有页表,只有代码段或者数据段改写才重新创建新空间
- 高性能c语言编码
- 高性能编码优化
- js高性能编码
- C语言编程常用数值计算的高性能实现
- 高性能的贪吃蛇C语言实现
- c#高性能编码三
- JAVA高性能编码习惯
- 高性能JavaScript 编码建议
- C语言编码规范
- c语言字符编码
- C语言 URL编码
- C语言编码规范
- C语言编码规范
- C语言编码风格
- C语言编码规范
- C语言编码规范
- c语言编码规范
- C语言编码规范
- maven构建spring4 mvc+spring4 websocket应用
- 用adt-bundle-windows 搭建Android开发环境
- 欢迎使用CSDN-markdown编辑器
- 如何在Qt工程中正确地引用用户自定义控件
- php实现选择排序
- 高性能c语言编码
- log4j2一些简单应用
- WebView相关
- Vijos P1104 采药 动态规划
- 写一点opengl的初步入门理解
- UESTC 1264 人民币的构造
- 深入了解 Flash Cache
- 如何高效的读懂代码
- UIScrollView的代理(delegate)