12
10

More than 3 years have passed since last update.

ある環境でstd::chronoが遅い

Last updated at Posted at 2021-04-15

概要

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]

やったね!

12
10
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10