警告
本文最后更新于 2024-01-27,文中内容可能已过时。
一、CMake:为Eigen库使能向量化
导言
本篇开始将涉及检测外部库相关的内容,期间会穿插着一些其他的内容。为了能够使得系统在系统中运行Eigen库,我们首先需要在系统中配置好Eigen库。然后介绍与Eigen库相关的CMake配置。
二、构建Eigen
Windows
ubuntu
https://eigen.tuxfamily.org/index.php?title=Main_Page

下载Eigen
三、Linear_algebra项目举例
项目结构
| 1
2
3
 | .
├── CMakeLists.txt
└── linear_algebra.cpp
 | 
项目地址:
https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter2/05
CMakeLists.txt文件
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 | cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(eigen_tensor LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Eigen3 3.4 REQUIRED CONFIG)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-march=native" _march_native_works)
check_cxx_compiler_flag("-xHost" _xhost_works)
set(_CXX_FLAGS)
if(_march_native_works)
    message(STATUS "Using processor's vector instructions (-march=native compiler flag set)")
    set(_CXX_FLAGS "-march=native")
elseif(_xhost_works)
    message(STATUS "Using processor's vector instructions (-xHost compiler flag set)")
    set(_CXX_FLAGS "-xHost")
else()
    message(STATUS "No suitable compiler flag found for vectorization")
endif()
add_executable(linear-algebra-unoptimized linear_algebra.cpp)
target_link_libraries(linear-algebra-unoptimized
  PRIVATE Eigen3::Eigen
)
add_executable(linear-algebra linear_algebra.cpp)
target_compile_options(linear-algebra
  PRIVATE ${_CXX_FLAGS}
)
target_link_libraries(linear-algebra
  PRIVATE Eigen3::Eigen
)
 | 
| ```find_package(Eigen3 3.4 REQUIRED CONFIG)``` | 
- find_package是- CMake中的一个命令,用于查找和加载特定的第三方库(例如- Eigen3)的- CMake配置文件。
 
- Eigen3是一个用于线性代数计算的- C++模板库,它提供了矩阵、向量、矢量计算等功能。通过在- CMake中使用- find_package(Eigen3 3.4 REQUIRED CONFIG)命令,告诉- CMake去查找- Eigen3库,并且要求它的版本至少是- 3.4。- REQUIRED参数表示如果找不到- Eigen3库,- CMake将会报错并停止构建。
 
- CONFIG参数指示- CMake查找- Eigen3的- CMake配置文件(通常是- Eigen3Config.cmake或类似名称),其中包含有关库的信息和设置。
 
- 一旦找到- Eigen3库的- CMake配置文件,- CMake会加载该配置文件并设置相关的变量,例如- EIGEN3_INCLUDE_DIR,其中包含了- Eigen3库的头文件路径。在接下来的- CMake构建中,你可以使用这些设置的变量来链接和包含- Eigen3库。
 
| ```include(CheckCXXCompilerFlag)``` | 
在CMake中,include(CheckCXXCompilerFlag) 是一个用于检查C++编译器标志是否可用的CMake命令。
这个命令的作用是为了检查特定的C++编译器标志是否受支持。在某些情况下,需要根据编译器的不同来启用或禁用一些特性或优化选项。
使用这个命令的一般形式是:
| 1
 | include(CheckCXXCompilerFlag <flag>)
 | 
其中<flag>是你要检查的C++编译器标志,例如 -std=c++11、-fPIC 等。
此命令将尝试将指定的编译器标志添加到C++源代码,并编译一个简单的测试程序来检查编译器是否支持该标志。如果支持,那么CMake将定义一个CMake变量,例如 CMAKE_REQUIRED_FLAGS 或 CMAKE_REQUIRED_LIBRARIES,来表示该标志是可用的。
通过这种方式,可以在CMake脚本中根据编译器支持情况进行条件编译或设置不同的选项。
例如,假设我们要检查编译器是否支持C++11标准:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 | include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11)
if (COMPILER_SUPPORTS_CXX11)
    # 设置C++11标准
    set(CMAKE_CXX_STANDARD 11)
    message(STATUS "C++11 supported by the compiler.")
else ()
    message(FATAL_ERROR "C++11 is not supported by the compiler.")
endif ()
check_cxx_compiler_flag("-march=native" _march_native_works)
check_cxx_compiler_flag("-xHost" _xhost_works)
set(_CXX_FLAGS)
if(_march_native_works)
    message(STATUS "Using processor's vector instructions (-march=native compiler flag set)")
    set(_CXX_FLAGS "-march=native")
elseif(_xhost_works)
    message(STATUS "Using processor's vector instructions (-xHost compiler flag set)")
    set(_CXX_FLAGS "-xHost")
else()
    message(STATUS "No suitable compiler flag found for vectorization")
endif()
 | 
这段CMake代码片段用于检查编译器是否支持特定的矢量指令优化标志,并根据结果设置 _CXX_FLAGS 变量以启用适当的矢量化优化。
-march=native 是一个编译器标志,用于告诉编译器根据当前主机的处理器架构来优化生成的机器码。这个标志会让编译器针对当前的 CPU 架构生成最优化的代码,以充分利用处理器的特性和指令集。
例如,在使用 -march=native 标志编译代码时,如果你的计算机的处理器支持 AVX2 指令集,编译器将会针对 AVX2 进行优化。如果运行这个优化过的代码在支持 AVX2 的处理器上,它将能够获得更高的性能。
请注意,使用 -march=native 标志编译代码可能会导致生成的可执行文件在其他不同架构的计算机上运行不正确或不稳定。因此,在分发或共享可执行文件时,最好使用更加通用的编译选项,除非确实需要充分利用特定处理器架构的优化。
-xHost 是 Intel 编译器的编译选项,用于指示编译器使用主机处理器支持的最高级别的指令集来优化生成的机器码。
类似于 -march=native,-xHost 也会让编译器根据当前主机的处理器架构来选择最优化的指令集。它会自动根据当前系统的处理器类型来决定使用最高级别的指令集,以充分利用处理器的性能和功能。
然而,与 -march=native 不同的是,-xHost 是特定于 Intel 编译器的选项,而不是在其他编译器中通用的标志。
请注意,与 -march=native 一样,使用 -xHost 也可能会导致生成的可执行文件在其他不同架构的计算机上运行不正确或不稳定,因此在分发或共享可执行文件时需谨慎使用。
相关源码
linear_algebra.cpp
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 | #include <eigen3/Eigen/Dense>
#include <chrono>
#include <iostream>
EIGEN_DONT_INLINE
double simple_function(Eigen::VectorXd &va, Eigen::VectorXd &vb) {
  // this simple function computes the dot product of two vectors
  // of course it could be expressed more compactly
  double d = va.dot(vb);
  return d;
}
int main() {
  int len = 1000000;
  int num_repetitions = 100;
  // generate two random vectors
  Eigen::VectorXd va = Eigen::VectorXd::Random(len);
  Eigen::VectorXd vb = Eigen::VectorXd::Random(len);
  double result;
  auto start = std::chrono::system_clock::now();
  for (auto i = 0; i < num_repetitions; i++) {
    result = simple_function(va, vb);
  }
  auto end = std::chrono::system_clock::now();
  auto elapsed_seconds = end - start;
  std::cout << "result: " << result << std::endl;
  std::cout << "elapsed seconds: " << elapsed_seconds.count() << std::endl;
}
 | 
输出结果
| 1
2
3
4
5
6
7
 | ./linear-algebra-unoptimized
result: -261.505
elapsed seconds: 1.97964
./linear-algebra
result: -261.505
elapsed seconds: 1.05048
 |