【gcc, cmake, eigen, opencv,ubuntu】二.gcc编译选项

news/2024/12/23 20:58:58/

文章目录

    • gcc编译选项
      • 1.-march=native
      • 2.-pipe
      • 3.-O2
      • 4.-fPIC
      • 5.-L
      • 6.-l 添加引用链接库
      • 7. -I 添加头文件路径
      • 8.-shared和-static
      • 9. -fopenmp
      • 10.opencv依赖
      • 11.示例1
      • 12.示例2:实践 eigen编译选项和运行时间示例
        • 1.g++ eigen.cpp -o eigen
        • 2.g++ -march=native eigen.cpp -o eigen
        • 3.g++ -O2 eigen.cpp -o eigen
        • 4.g++ -O2 -march=native eigen.cpp -o eigen
        • 5.g++ -fopenmp -march=native -O2 eigen.cpp -o eigen
        • 6.python numpy
        • 7.方案4和6比较
        • 8.eigen使用mkl , 编译选项

gcc编译选项

1.-march=native

其中-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”

2.-pipe

多核系统用-pipe可以提高编绎速度。
GCC编绎C程序时首先生成汇编文件,再调用汇编器生成目标文件。-pipe可以使这两个过程同时进行。GCC一边输出汇编代码,汇编器一边进行汇编。如果是多核系统,这两个过程由不同的CPU运行,就可以加快速度。如果是单核系统,就起不到提速的效果了,反而会多用内存。

GCC 的-pipe选项用于将编译器的输出直接传递给下一个阶段,而不是将中间文件写入磁盘,这样可以节省磁盘空间,提高编译速度,因为避免了中间文件的磁盘读写操作。
通常情况下,机器如果有足够的内存,建议使用-pipe选项,加快编译速度,减少磁盘读取。但是如果内存不足,会导致系统使用交换空间,降低编译速度,影响系统性能。

总之-pipe提高的是编译速度,如果编译对你来说没那么重要可以不设置。

3.-O2

优化等级

4.-fPIC

fPIC的全称是 Position Independent Code, 用于生成位置无关代码(看不懂没关系,总之加上这个参数,别的代码在引用这个库的时候才更方便,反之,稍不注意就会有各种乱七八糟的报错)。
使用-fPIC选项生成的动态库,是位置无关的。这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。通常的方法是获取指令指针的值,加上一个偏移得到全局变量/函数的地址。

果指定-shared不指定-fPIC会报错

5.-L

-L 添加链接库路径
-L 后跟路径,告诉链接器从哪找库(.so文件),只有在链接时会用到。

如:-L /home/hello/lib

表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找顺序是:/home/hello/lib–>/usr/lib–>/usr/local/lib。

可以加多个包含路径,链接器的寻找顺序为添加的顺序。

6.-l 添加引用链接库

-l 在链接时用到,它的作用是告诉链接器,要用到哪个库。 如:-l pthread

告诉链接器(linker),程序需要链接pthread这个库,这里的pthread是库名不是文件名,具体来说文件句是libpthread.so。

7. -I 添加头文件路径

示例:

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`

8.-shared和-static

用于生成动态和静态链接库

9. -fopenmp

启用openmp多线程。

10.opencv依赖

`pkg-config --cflags opencv4 --libs opencv4`

11.示例1

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`
  1. g++ -fopenmp -march=native -O3 src.cpp -o out
  2. /opt/mkl/mkl/lib/intel64/libmkl_rt.so
  3. -I/opt/mkl/mkl/include
  4. -L/opt/mkl/mkl/lib/intel64
    编译, 依赖库, 依赖库的头文件目录,依赖库的库文件目录

12.示例2:实践 eigen编译选项和运行时间示例

利用eigen库实现矩阵相乘,实验不同的编译选项得到的程序的运行时间。用了三种测量运行时间的方法。
为什么用三种方法测时间呢,因为用clock()测多线程程序是不准确的。

源代码如下:eigen.cpp

//#define EIGEN_USE_MKL_ALL //如果适用mkl,取消该行注释
#define EIGEN_VECTORIZE_SSE4_2
#include <iostream>
#include <eigen3/Eigen/Dense>using Eigen::MatrixXd;
#include <sys/time.h>
#include <ctime>
#include <chrono>
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;
}

不同的编译命令得到的时间

1.g++ eigen.cpp -o eigen

7.52826 s

2.g++ -march=native eigen.cpp -o eigen

3.65 s

3.g++ -O2 eigen.cpp -o eigen

0.182 s

4.g++ -O2 -march=native eigen.cpp -o eigen

0.05 s

5.g++ -fopenmp -march=native -O2 eigen.cpp -o eigen

3.3 s 什么原因,感觉是挺快的,不像3.3 s
因为是多线程的原因,不应该使用clock()计时,使用下面代码

#include <sys/time.h>
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

6.python numpy

python numpy同样的矩阵相乘只要
0.012 s

import time
import numpy as npdef main():n = 1000a = np.random.rand(n, n)b = np.random.rand(n, n)N = 10start = 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()

7.方案4和6比较

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 更快

8.eigen使用mkl , 编译选项

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倍左右。


http://www.ppmy.cn/news/382620.html

相关文章

3.3 掌握RDD分区

一、RRD分区 &#xff08;一&#xff09;RDD分区概念 RDD是一个大的数据集合&#xff0c;该集合被划分成多个子集合分布到了不同的节点上&#xff0c;而每一个子集合就称为分区&#xff08;Partition&#xff09;。因此&#xff0c;也可以说&#xff0c;RDD是由若干个分区组成的…

ModelSim的使用详解

一、建立ModelSim工程 1、打开ModelSim软件 打开ModelSim软件&#xff0c;如下图所示&#xff1a; 2、建立工程 在modelsim中建立project&#xff0c;选择File->New->Project&#xff0c;如下图所示&#xff1a; 弹出如下界面&#xff1a; 在“ Project Name”栏中填…

【实验技术笔记】利用重组载体做基因过表达(pCDH载体)

文章目录 1. 构建基因过表达载体1.1 设计 PCR 引物1.2 PCR 扩增目的基因1.3 酶切载体和 PCR 产物1.4 电泳并回收酶切产物1.5 连接1.6 转化1.7 挑选阳性克隆并鉴定 2. 转染3. 检测过表达效果附表&#xff1a;常用酶切位点保护碱基 为什么要做基因表达操作&#xff1f; 探寻影响细…

python:并发编程(二)

前言 本文将和大家一起探讨python的并发编程&#xff0c;涉及到python的并发编程模块&#xff0c;先简单介绍这些模块。后续文章&#xff0c;我们再进行详细使用。你至少应该分别掌握多进程、多线程、多协程的并发模块的一个&#xff0c;也可以分别掌握他们中的多个。模块就像…

MySQL数据库概念、管理以及SQL语句的基本命令操作

MySQL数据库概念、管理以及SQL语句的基本命令操作 一、数据库概念1、数据库的组成&#xff1a;数据、表、数据库2、数据库类型3、数据库的管理系统&#xff08;DBMS)4、数据库系统&#xff08;DBS&#xff09; 二、数据库系统发展史三、当今主流数据库四、关系型数据库五、MySQ…

局部聚集系数

最近在打一个图数据库算法的比赛&#xff0c;分到了计算局部聚集系数这道题&#xff0c;要求速度快&#xff0c;空间复杂度可以不首要考虑。这对我是一个全新的知识&#xff0c;用此博客记录我的学习历程。 搜了一圈视频教程&#xff0c;b站没有这块的知识&#xff0c;只有yout…

创建autotool项目

GNU Autotools是linux系统一套自动化编译工具&#xff0c;生成的项目可移植&#xff0c;通过configure && make即可生成目标程序。GNU Autotools组件有&#xff1a;autoscan, aclocal, autoconf, automake,autoheader等。 不用管这些工具的原理&#xff0c;只要知道他们…

Binder对象的流转(系统服务的调用过程、AIDL的使用过程)

零、Binder的传递 Android系统中&#xff0c;存在大量的 IPC 交互&#xff0c;同时也使用了大量的 Binder&#xff0c;那么Binder是怎么在各进程中进行对象的传递&#xff1f; 一、调用系统服务时&#xff0c;Binder的传递 回忆一下&#xff0c;Android系统的启动流程&#x…