ZPN项目 2:在CMake中配置使用Intel One API并启用OpenMP
本示例尝试使用CMake配置使用Intel One API编译器编译支持OpenMP的程序。
环境
- Visual Studio 2022 Community with C++ desktop
- Intel One API 2023.2 with VS intergration
- CMake 3.27.7
样例
程序代码
OpenMPDemo.cpp
// File: OpenMPDemo.cpp
// Coding: utf-8
#include <iostream>
#include <vector>
#include <cstdlib>
#include <omp.h>
#include <chrono>
void matrix_multiplication(const std::vector<std::vector<double>> &A,
const std::vector<std::vector<double>> &B,
std::vector<std::vector<double>> &C)
{
int N = A.size();
int M = B[0].size();
int K = A[0].size();
#pragma omp parallel for
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
for (int k = 0; k < K; ++k)
{
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
void matrix_multiplicationNoMP(const std::vector<std::vector<double>> &A,
const std::vector<std::vector<double>> &B,
std::vector<std::vector<double>> &C)
{
int N = A.size();
int M = B[0].size();
int K = A[0].size();
// #pragma omp parallel for
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
for (int k = 0; k < K; ++k)
{
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
void TestMatrixMultiplication(const std::vector<std::vector<double>> &A,
const std::vector<std::vector<double>> &B,
std::vector<std::vector<double>> &C, bool bOpenMP)
{
// double start_time = omp_get_wtime();
auto start = std::chrono::high_resolution_clock::now();
// 执行矩阵乘法
if (bOpenMP)
matrix_multiplication(A, B, C);
else
matrix_multiplicationNoMP(A, B, C);
// double end_time = omp_get_wtime();
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
if (bOpenMP)
std::cout << "Using OpenMP:" << std::endl;
else
std::cout << "Bot using OpenMP:" << std::endl;
std::cout << "Time taken: " << duration.count() / 1000.0 << " seconds." << std::endl;
// std::cout << "Time taken: " << end_time - start_time << " seconds." << std::endl;
}
int main()
{
//Heroius: 将维度从2000减小到500,以加快调试
const int N = 500; // 设置矩阵的维度
std::vector<std::vector<double>> A(N, std::vector<double>(N));
std::vector<std::vector<double>> B(N, std::vector<double>(N));
std::vector<std::vector<double>> C(N, std::vector<double>(N, 0));
// 使用随机数填充矩阵 A 和 B
#pragma omp parallel for
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
A[i][j] = rand() / 100.0;
B[i][j] = rand() / 100.0;
}
}
TestMatrixMultiplication(A, B, C, true);
TestMatrixMultiplication(A, B, C, false);
std::cin.get();
return 0;
}
MakeList
CMakeLists.txt
# File: CMakeLists.txt
# Heroius: min version of cmake who supports IntelLLVM is 3.25 according to https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2023-2/use-cmake-with-the-compiler.html
cmake_minimum_required(VERSION 3.25)
# 指定使用C++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Set the project name
# Heroius: add CXX parameter to use cpp compiler only, so the c language settings are no longer needed
project(OpenMPDemo CXX)
# Look for Intel oneAPI CMake toolchain files
# find_package shall be called after project command
find_package(IntelSYCL REQUIRED)
# 指定 C++ 编译器
# Heroius: compilers could only be set in user toolchain file according to https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER.html
# Heroius: however the effective settings depands on the cmake generator, see Configure_CMake.bat command line
#set(CMAKE_CXX_COMPILER "C:/Program Files (x86)/Intel/oneAPI/compiler/latest/windows/bin/icpx.exe")
# 指明编译工具链
# Heroius: it is suggested that generator toolset set only in a toolchain file according to https://cmake.org/cmake/help/latest/variable/CMAKE_GENERATOR_TOOLSET.html
# Heroius: however the effective settings depands on the cmake generator, see Configure_CMake.bat command line
#set(CMAKE_GENERATOR_TOOLSET "Intel(R) oneAPI DPC++ Compiler 2023")
# Set executable path
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin)
# OpenMP 编译标志
# Heroius: OpenMP flags should be '/Qiopenmp' according to https://www.intel.com/content/www/us/en/docs/oneapi/programming-guide/2023-0/c-c-or-fortran-with-openmp-offload-programming.html
# Heroius: however the find_package() commands will set those flags properly itself
#set(OpenMP_CXX_FLAGS "${OpenMP_CXX_FLAGS} /Qiopenmp")
# OpenMP 库名称
# Heroius: Their should not be space between symbol 'OpenMP_C_LIB_NAMES' and 'libiomp5'
#set(OpenMP_CXX_LIB_NAMES "${OpenMP_CXX_LIB_NAMES}libiomp5")
#set(OpenMP_libiomp5_LIBRARY "${OpenMP_CXX_LIB_NAMES}")
# 查找OpenMP库
# Heroius: under this instruction, cmake will call 'c:\Program Files\CMake\share\cmake-3.27\Modules\FindOpenMP.cmake' file, in the lines 605-606 of which, the 'if' command has grammatical error:
# Heroius: the 2nd 'CMAKE_${LANG}_COMPILER_ID' should not enbraced in command: if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Fujitsu" OR ${CMAKE_${LANG}_COMPILER_ID} STREQUAL "IntelLLVM")
# Heroius: notice: back up the file before editing FindOpenMP.cmake with admin privilege!
find_package(OpenMP REQUIRED)
# Add the executable
add_executable(OpenMPDemo OpenMPDemo.cpp)
add_sycl_to_target(TARGET OpenMPDemo SOURCES OpenMPDemo.cpp)
# 如果找到OpenMP库,链接到目标可执行文件
if(OpenMP_CXX_FOUND)
target_link_libraries(OpenMPDemo OpenMP::OpenMP_CXX)
endif()
Configure脚本
Configure_CMake.bat
:: 如果存在 Build,删除
if exist Build rd /S /Q Build
:: 如果不存在 Build,创建
if not exist Build md Build
:: 调用批处理设置 Intel oneAPI 的编译环境
Call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" intel64 vs2022
Set Lib=%lib%;"C:\Program Files (x86)\Intel\oneAPI\compiler\2023.2.0\windows\compiler\lib\intel64_win"
:: 当前文件夹为 Source,子文件夹 .\Build 为构建目录
:: Heroius: the default cmake generator is 'Visual Studio 17 2022', which is not fully featured.
:: Heroius: it seems the Visual Studio generator allways reset compilers to MSVC.
:: Heroius: the only Intel compiler supports cmake is icx, and the only generator supports icx is ninja according to https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2023-2/use-cmake-with-the-compiler.html
cmake -G Ninja -DCMAKE_CXX_COMPILER=icx -S . -B .\Build
pause
编译脚本
Build_CMake.bat
:: 调用批处理设置 Intel oneAPI 的编译环境
:: Heroius: enable basic environments to make sure the std libs could be found
Call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" intel64 vs2022
:: Set MPI compiler environment
Call "C:\Program Files (x86)\Intel\oneAPI\mpi\Latest\env\vars.bat"
:: 进入构建目录
cd Build
:: 构建,项目文件在当前目录
cmake --build .
pause
运行脚本
Run_App.bat
@ECHO OFF
:: 加载ONEAPI环境,使得引用库在运行环境可见;将加载过程的输出重定向隐藏
Call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" intel64 vs2022 >NUL 2>&1
cd ./build/bin/
OpenMPDemo.exe
注意事项
- 支持2023.2版本IntelLLVM编译器的CMake最低版本为3.25
- 在project()中,指定CXX语言,就不用配置C语言选项(CMake默认启用C和C++)
- CMAKE_CXX_COMPILER 、CMAKE_GENERATOR_TOOLSET 等变量建议通过 toolchain 文件设置
- CMake使用的默认生成器为 Visual Studio 17 2022,因尚未探明之原因,其总将编译器设置为MSVC,故若要使用Intel编译器,推荐使用Ninja生成器
- 在Intel编译器中,支持CMake的是icx
- 编译时,需要设置OneAPI环境以使引用的标准库可见
- 使用find_package(OpenMP REQUIRED)即可启用OpenMP支持,无需另行设置编译标记