其中-march选项就是就是指定目标架构的名字,gcc就会生成针对目标架构优化的目标代码,如-march=prescott会生成针对i5或i7的目标码,从而充分发挥cpu的性能。自gcc4.2,引入了-march=native,从而允许编译器自动探测目标架构并生成针对目标架构优化的目标代码,这比手工设置要安全的多。如何知道-march=native启用了哪些优化指令呢?
找一个任意c源代码文件,用gcc编译看一下即知答案。
gcc -Q --help=target -march=native [xxx].c
启用了哪些优化指令一目了然。
CFLAGS=“-O2 -march=native -pipe”
多核系统用-pipe可以提高编绎速度。
GCC编绎C程序时首先生成汇编文件,再调用汇编器生成目标文件。-pipe可以使这两个过程同时进行。GCC一边输出汇编代码,汇编器一边进行汇编。如果是多核系统,这两个过程由不同的CPU运行,就可以加快速度。如果是单核系统,就起不到提速的效果了,反而会多用内存。
GCC 的-pipe选项用于将编译器的输出直接传递给下一个阶段,而不是将中间文件写入磁盘,这样可以节省磁盘空间,提高编译速度,因为避免了中间文件的磁盘读写操作。
通常情况下,机器如果有足够的内存,建议使用-pipe选项,加快编译速度,减少磁盘读取。但是如果内存不足,会导致系统使用交换空间,降低编译速度,影响系统性能。
总之-pipe提高的是编译速度,如果编译对你来说没那么重要可以不设置。
优化等级
fPIC的全称是 Position Independent Code, 用于生成位置无关代码(看不懂没关系,总之加上这个参数,别的代码在引用这个库的时候才更方便,反之,稍不注意就会有各种乱七八糟的报错)。
使用-fPIC选项生成的动态库,是位置无关的。这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。通常的方法是获取指令指针的值,加上一个偏移得到全局变量/函数的地址。
果指定-shared不指定-fPIC会报错
-L 添加链接库路径
-L 后跟路径,告诉链接器从哪找库(.so文件),只有在链接时会用到。
如:-L /home/hello/lib
表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找顺序是:/home/hello/lib–>/usr/lib–>/usr/local/lib。
可以加多个包含路径,链接器的寻找顺序为添加的顺序。
-l 在链接时用到,它的作用是告诉链接器,要用到哪个库。 如:-l pthread
告诉链接器(linker),程序需要链接pthread这个库,这里的pthread是库名不是文件名,具体来说文件句是libpthread.so。
示例:
g++ -march=native -O3 src.cpp -o out /opt/mkl/mkl/lib/intel64/libmkl_rt.so -I/opt/mkl/mkl/include -L/opt/mkl/mkl/lib/intel64
`pkg-config --cflags opencv4 --libs opencv4`
用于生成动态和静态链接库
启用openmp多线程。
`pkg-config --cflags opencv4 --libs opencv4`
g++ -fopenmp -march=native -O3 src.cpp -o out /opt/mkl/mkl/lib/intel64/libmkl_rt.so -I/opt/mkl/mkl/include -L/opt/mkl/mkl/lib/intel64
`pkg-config --cflags opencv4 --libs opencv4`
利用eigen库实现矩阵相乘,实验不同的编译选项得到的程序的运行时间。用了三种测量运行时间的方法。
为什么用三种方法测时间呢,因为用clock()测多线程程序是不准确的。
源代码如下:eigen.cpp
//#define EIGEN_USE_MKL_ALL //如果适用mkl,取消该行注释
#define EIGEN_VECTORIZE_SSE4_2
#include
#include
using Eigen::MatrixXd;
#include
#include
#include
using namespace Eigen;
using namespace std;
int main()
{
int n;
n = 1000;
MatrixXd a = MatrixXd::Random(n,n);
MatrixXd b = MatrixXd::Random(n,n);
MatrixXd c;
struct timeval t1,t2;
double timeuse;
gettimeofday(&t1,NULL);
auto t_start = std::chrono::high_resolution_clock::now();
clock_t start = clock();
int N = 10;
for (int i =0;i < N; i++)
{
c = a * b;
}
clock_t end = clock();
double elapsed_time = (double (end) - double(start)) / CLOCKS_PER_SEC / N;
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_us = std::chrono::duration<double, std::micro>(t_end-t_start).count();
cout << "time in micro second " << elapsed_time_us/N <<endl;
gettimeofday(&t2,NULL);
timeuse = (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec)/1000000.0;
printf("timeuse:%lf\n", timeuse / N);
cout << "Elapsed time is :" << elapsed_time << " (s)" << endl;
return 0;
}
不同的编译命令得到的时间
7.52826 s
3.65 s
0.182 s
0.05 s
3.3 s 什么原因,感觉是挺快的,不像3.3 s
因为是多线程的原因,不应该使用clock()计时,使用下面代码
#include
struct timeval t1,t2;
double timeuse;
gettimeofday(&t1,NULL);
func();
gettimeofday(&t2,NULL);
timeuse = (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec)/1000000.0;
printf("timeuse:%lf\n", timeuse);
得到结果 0.042 s
python numpy同样的矩阵相乘只要
0.012 s
import time
import numpy as np
def main():
n = 1000
a = np.random.rand(n, n)
b = np.random.rand(n, n)
N = 10
start = time.time()
for i in range(N):
c = np.dot(a, b)
end = time.time()
print("Elapsed time is %f (s)" % ((end - start) / N))
if __name__ == '__main__':
main()
4和6进行比较
n = 1000时候,0.042和 0.012 s
n = 2000时候,0.39 和 0.029
n = 3000时候,1.27 和 0.06
n = 4000时候,3.08 和 0.12 s, -fopenmp 0.45s 仍然大于 0.12s
python numpy 更快
1)mkl安装
我是参考一下第一个链接下载和安装的。
Linux下MKL库的安装部署与使用
cpp, mkl 加速 eigen 实例
Linux 版的 Intel MKL 的安装使用
2)eigen中使用mkl
c++文件开头加入
#define EIGEN_USE_MKL_ALL
#define EIGEN_VECTORIZE_SSE4_2
编译命令变为
g++ -march=native -O2 eigen.cpp -o eigen /opt/mkl/mkl/lib/intel64/libmkl_rt.so -I/opt/mkl/mkl/include -L/opt/mkl/mkl/lib/intel64
eigen use mkl
1000 0.013 s
2000 0.047 s
3000 0.18 s
4000 0.22 s
5000 0.35 s
10000 2.5s
与4和6进行比较 eigen, numpy
n = 1000时候,0.042和 0.012 s
n = 2000时候,0.39 和 0.029
n = 3000时候,1.27 和 0.06
n = 4000时候,3.08 和 0.12 s, -fopenmp 0.45s 仍然大于 0.12s
n = 5000 - 和 0.2
n = 10000 - 和 1.1
eigen use mkl的时间比only eigen少挺多,但仍然是numpy的2倍左右。