概要
CentOS7 + devtoolsetの環境だとstd::chronoが遅い。
これが本当にdevtoolsetが原因かは私には分からず。。
やりたかったこと
C++コードの開発におけるベンチマークでは時間計測が重要です。これまでOpenMPやMPIで並列化したコードを作るときには、omp_get_wtime()
やMPI_Wtime()
関数で時間計測をしていました。しかし、開発したコードの運用は様々な環境で使うことを想定すると、OpenMPやMPIの使えない(使わない)環境でのコンパイルもできるようにすると思います。その時に、時間計測の関数もディレクティブで切り替えていました。もちろんラップした関数にしたりしますが。
C++11以降でstd::chrono
が登場し、HPC環境でも普及してきたので、これらの時間計測関数をhigh_resolution_clock
で置き換えて統一したくなります。
しかし、実際にやってみるとstd::chrono::high_resolution_clock
は1桁遅い。原因はdevtoolset
と予測していますが、私では特定できませんでした。情報共有の意味で記事にします。原因や思い当たる節のある方は情報提供いただけると嬉しいです。
問題の出る環境
CPU: Intel Xeon Gold 6248, and E5-1620 (実機確認の取れたもの)
CentOS 7 (3.10.0-1127.19.1.el7.x86_64)
devtoolset-9
g++(gcc) 9.3.1
icpc(icc) 2021.1
検証コード
以下のコードで時間計測を行います。
主にtimer呼び出しのコストを測っています。
#include <iostream>
#include <cstdlib>
#include <chrono>
#include <omp.h>
int main()
{
using namespace std::chrono;
constexpr int COUNT = 10000;
//time by openmp
double time_omp = 0.0;
for(int i = 0; i < COUNT; ++i){
double prev = omp_get_wtime();
time_omp += omp_get_wtime() - prev;
}
std::cout << "omp: " << (time_omp * 1.0e3) << "[ms]" << std::endl;
//time by std::chrono
high_resolution_clock::duration time_chrono{high_resolution_clock::duration{0}};
for(int i = 0; i < COUNT; ++i){
auto prev = high_resolution_clock::now();
time_chrono += high_resolution_clock::now() - prev;
}
std::cout << "std::chrono: " << ((double)std::chrono::duration_cast<std::chrono::nanoseconds>(time_chrono).count() * 1.0e-6) << "[ms]" << std::endl;
}
計測結果
コンパイルオプションと実行結果は以下の通り
# CentOS7 + devtoolset-9(実機),
# icpc -qopenmp -O2
omp: 0.216007[ms]
std::chrono: 3.11031[ms]
# CentOS7 + devtoolset-9(実機),
# g++ -fopenmp -O2
omp: 0.26315[ms]
std::chrono: 3.14209[ms]
# Windows10 x64, Core-i7 10710U
# MSVC (Visual Studio 16.9.1) オプション割愛
omp: 0.1645[ms]
std::chrono: 0.1413[ms]
# Wandbox + gcc7.2.0
# g++ prog.cc -Wall -Wextra -O2 -march=native -I/opt/wandbox/boost-1.73.0/gcc-7.2.0/include -std=gnu++17 "-fopenmp"
omp: 0.428464[ms]
std::chrono: 0.366112[ms]
このようにCentOS7 + devtoolsetの環境だけstd::chrono
が異常に遅い。
さいごに
CentOS+devtoolsetの環境はそれなりに多いと思うので、他にも悩んでいる方はいそうな気がします。解決策などの情報提供があればとても嬉しいです。
解決策(追記:2021/4/20)
コメント欄にて @gnaggnoyil さんからの情報提供で解決策が見いだせました。
コンパイル引数に-static-libstdc++
をつければdevtoolset環境でも新しいlibstdc++をリンクできるそうです。
g++だけでなくicpcでも有効です。
以下にテスト結果を示します。
# CentOS7 + devtoolset-9(実機),
#g++ -O2 -fopenmp
std::chrono: 3.09057[ms]
clock_gettime(CLOCK_REALTIME): 0.150057[ms]
# g++ -O2 -fopenmp -static-libstdc++
std::chrono: 0.166714[ms]
clock_gettime(CLOCK_REALTIME): 0.150091[ms]
# icpc -O2 -fopenmp
std::chrono: 3.11476[ms]
clock_gettime(CLOCK_REALTIME): 0.154761[ms]
# icpc -O2 -fopenmp -static-libstdc++
std::chrono: 0.166713[ms]
clock_gettime(CLOCK_REALTIME): 0.163851[ms]
やったね!