C语言程序优化方法
性能瓶颈识别
使用gprof,valgrind,gdb等工具识别程序的性能瓶颈和内存问题
分析工具
减少不必要的计算和函数调用
- 合并相同或重复的计算步骤。
- 减少频繁调用的函数内部不必要的操作。
如图,优化前函数中调用了许多复数相关计算的函数,将复数的乘法,取绝对值操作封装起来进行调用可以使程序看起来更简洁易懂,但其实包含了很多重复的计算,拖慢程序的运行。因此,考虑不调用这些复数计算相关函数,直接计算。
内存管理优化
1.使用栈内存分配代替堆内存分配以减少内存分配的开销。
2.缓存计算结果以避免重复计算
3.使用指针而不是索引访问数组,减少计算时间
优化前用索引访问数组,效率较低
优化后用指针访问数组,效率变高
循环优化
- 将循环中不变的计算移出循环。
- 合并循环以减少循环次数
优化前,调用meas_nr5g_mod_qam和nr_gold_pbch_oai的次数很多,造成程序性能很差。
优化后,通过改变循环结构,预先调用meas_nr5g_mod_qam和nr_gold_pbch_oai,减少这两个函数的调用次数,将计算结果放入缓存,以便进行之后的计算,程序的性能得到很大的提升。
使用SIMD指令
SIMD(Single Instruction Multiple Data,单指令多数据)是一种计算机处理技术,允许单条指令同时处理多个数据。这种技术在并行计算中非常有效,因为它可以在一个时钟周期内对多个数据元素进行相同的操作,从而显著提高计算效率和性能。
SIMD指令概述
SIMD指令集是处理器架构的一部分,支持并行处理。在现代处理器中,常见的SIMD指令集包括:
- SSE(Streaming SIMD Extensions):用于x86架构的SIMD指令集,支持单精度和双精度浮点运算以及整数运算。
- AVX(Advanced Vector Extensions):扩展了SSE,支持更宽的寄存器和更多的并行操作。
- AVX2:进一步扩展了AVX,增加了整数运算的支持。
- AVX-512:支持更宽的512位寄存器,提供更高的并行度。
SIMD指令的使用
添加头文件
#include <immintrin.h>
void vector_add(float* a, float* b, float* c, int n) {
int i;
for (i = 0; i < n; i += 8) {
__m256 va = _mm256_loadu_ps(&a[i]);
__m256 vb = _mm256_loadu_ps(&b[i]);
__m256 vc = _mm256_add_ps(va, vb);
_mm256_storeu_ps(&c[i], vc);
}
}
常用SIMD指令
加载和存储指令
加载指令 | 含义 |
---|
__mm_loadu_ps | 加载未对齐的单精度浮点数(SSE) |
__mm256_loadu_ps | 加载未对齐的单精度浮点数(AVX) |
__mm_load_si128 | 加载对齐的128位整数(SSE2) |
__mm256_load_si256 | 加载对齐的256位整数(AVX2) |
存储指令 | 含义 |
---|
__mm256_storeu_ps | 存储单精度浮点数到未对齐内存(AVX) |
__m256_store_si256 | 存储256位整数对齐内存(AVX2) |
__mm_storeu_ps | 存储单精度浮点数到未对齐内存(SSE) |
__mm_store_si128 | 存储128位整数到对齐内存(SSE2) |
算数运算指令
加法指令 | 含义 |
---|
__mm256_add_ps | 单精度浮点数加法(AVX) |
__mm256_add_epi32 | 32位整数加法(AVX2) |
__mm_add_ps | 单精度浮点数加法(SSE) |
__mm_add_epi32 | 32位整数加法(SSE2) |
减法指令 | 含义 |
---|
__mm_sub_ps | 单精度浮点数减法(SSE) |
__mm256_sub_ps | 单精度浮点数减法(AVX) |
__mm_sub_epi32 | 32位整数减法(SSE2) |
__mm256_sub_epi32 | 32位整数减法(AVX2) |
乘法指令 | 含义 |
---|
__mm_mul_ps | 单精度浮点数乘法(SSE) |
__mm256_mul_ps | 单精度浮点数乘法(AVX) |
__mm_mul_epi32 | 32位整数乘法(SSE2) |
__mm256_mul_epi32 | 32位整数乘法(AVX2) |
比较指令 | 含义 |
---|
__mm_cmpeq_ps | 比较单精度浮点数是否相等(SSE) |
__mm256_cmpeq_ps | 比较单精度浮点数是否相等(AVX) |
__mm_cmpeq_epi32 | 比较32位整数是否相等(SSE2) |
__mm256_cmpeq_epi32 | 比较32位整数是否相等(AVX2) |
逻辑运算指令
逻辑运算指令 | 含义 |
---|
__mm_and_ps | 按位与运算(SSE) |
__mm256_and_ps | 按位与运算(AVX) |
__mm_or_ps | 按位或运算(SSE) |
__mm256_or_ps | 按位或运算(AVX) |
__mm_xor_ps | 按位异或运算(SSE) |
__mm256_xor_ps | 按位异或运算(AVX) |
数据混合和排列指令
数据混合和排列指令 | 含义 |
---|
__mm_shuffle_ps | 单精度浮点数打乱(SSE) |
__mm256_shuffle_ps | 单精度浮点数打乱(AVX) |
__mm_unpacklo_ps | 解压低位单精度浮点数(SSE) |
__mm256_unpacklo_ps | 解压低位单精度浮点数(AVX) |
特定功能指令
特定功能指令 | 含义 |
---|
__mm_sqrt_ps | 计算单精度浮点数平方根(SSE) |
__mm256_sqrt_ps | 计算单精度浮点数平方根(AVX) |
__mm_hadd_ps | 水平加法(SSE3) |
__mm256_hadd_ps | 水平加法(AVX) |