0Pricing
C++ Academy · レッスン

コードのパフォーマンス測定

chronoでベンチマークを行います

「コードのパフォーマンス測定」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。

なぜベンチマークを行うのか

コードの実行時間を測定すると、ボトルネックを見つけたり、最適化の効果を確認したりできます。<chrono>を使うと、移植性があり型安全な時間計測を行えます。

  • 最適化する前に測定します。
  • 信頼できる間隔の計測にはsteadyなClockを使用します。
#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    auto end = steady_clock::now();
    std::cout << "Timed a block: " << ((end - start).count() >= 0) << '\n';
    return 0;
}

基本パターン

ベンチマークのパターンは常に同じです。処理の前にnow()を取得し、処理を実行し、処理の後にもう一度now()を取得して減算します。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 100000; ++i) sum += i;
    auto end = steady_clock::now();
    std::cout << "Sum: " << sum << ", elapsed >= 0: " << ((end - start).count() >= 0) << '\n';
    return 0;
}

単位の選択

処理内容に合った単位を選びます。短時間のループにはmicrosecondsまたはnanosecondsを、大きな処理にはmillisecondsを使用します。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 500000; ++i) sum += i;
    auto end = steady_clock::now();
    auto us = duration_cast<microseconds>(end - start);
    std::cout << "Result: " << sum << ", us non-negative: " << (us.count() >= 0) << '\n';
    return 0;
}

浮動小数点数による時間計測

小数を含む、人間に読みやすい秒単位の値が必要な場合は、duration<double>を使用して1秒未満の精度を保ちます。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 200000; ++i) sum += i % 7;
    auto end = steady_clock::now();
    duration<double> secs = end - start;
    std::cout << "Computed " << sum << ", seconds >= 0: " << (secs.count() >= 0) << '\n';
    return 0;
}

再利用可能なタイマー

このパターンを小さなヘルパーにまとめると、任意の呼び出し可能オブジェクトの時間を簡潔に計測でき、同じコードの繰り返しを避けられます。

#include <iostream>
#include <chrono>

long long timeWork() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    long acc = 0;
    for (int i = 0; i < 100000; ++i) acc += i;
    auto e = steady_clock::now();
    return duration_cast<microseconds>(e - s).count();
}

int main() {
    std::cout << "Microseconds non-negative: " << (timeWork() >= 0) << '\n';
    return 0;
}

デッドコード削除を避ける

コンパイラーは、結果が使われない処理を削除することがあり、ベンチマークが無意味になる可能性があります。必ず結果を消費してください。たとえば、結果を出力したり、観測可能な変数へ累積したりします。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    volatile long sink = 0;
    for (int i = 0; i < 100000; ++i) sink += i;
    auto e = steady_clock::now();
    std::cout << "Sink used: " << (sink > 0) << ", elapsed >= 0: " << ((e - s).count() >= 0) << '\n';
    return 0;
}

ウォームアップ実行

キャッシュや遅延初期化の影響で、最初の実行は遅くなることがあります。より安定した数値を得るため、測定前にウォームアップのパスを実行してください。

#include <iostream>
#include <chrono>

long work() {
    long a = 0;
    for (int i = 0; i < 50000; ++i) a += i;
    return a;
}

int main() {
    using namespace std::chrono;
    work();
    auto s = steady_clock::now();
    long r = work();
    auto e = steady_clock::now();
    std::cout << r << " measured, ok: " << ((e - s).count() >= 0) << '\n';
    return 0;
}

複数回の実行結果を平均する

1回の測定にはノイズが含まれます。処理を何度も実行し、経過時間の合計を求めてから回数で割ると、安定した平均値を得られます。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    long long total = 0;
    const int runs = 5;
    for (int r = 0; r < runs; ++r) {
        auto s = steady_clock::now();
        long acc = 0;
        for (int i = 0; i < 100000; ++i) acc += i;
        auto e = steady_clock::now();
        total += duration_cast<microseconds>(e - s).count();
    }
    std::cout << "Average us non-negative: " << ((total / runs) >= 0) << '\n';
    return 0;
}

2つのアプローチの比較

ベンチマーク測定は、実装を比較するときに威力を発揮します。それぞれを同じ方法で計測し、得られた所要時間を比較します。

#include <iostream>
#include <chrono>
#include <vector>

int main() {
    using namespace std::chrono;
    std::vector<int> v;
    auto s1 = steady_clock::now();
    for (int i = 0; i < 10000; ++i) v.push_back(i);
    auto e1 = steady_clock::now();
    v.clear();
    v.reserve(10000);
    auto s2 = steady_clock::now();
    for (int i = 0; i < 10000; ++i) v.push_back(i);
    auto e2 = steady_clock::now();
    std::cout << "Both timed: " << (((e1 - s1).count() >= 0) && ((e2 - s2).count() >= 0)) << '\n';
    return 0;
}

分解能に注意

測定対象の処理がクロックの1ティックより短い場合、ゼロと読み取られることがあります。クロックの分解能を超えるように、処理を十分な回数繰り返します。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    int x = 1 + 1;
    auto e = steady_clock::now();
    auto ns = duration_cast<nanoseconds>(e - s).count();
    std::cout << "x=" << x << ", tiny work may read low: " << (ns >= 0) << '\n';
    return 0;
}

結果の報告

最終的な所要時間を読みやすい単位に変換して出力します。オプティマイザーが処理を削除できないように、消費した結果を見える状態にしておきます。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    long acc = 0;
    for (int i = 0; i < 300000; ++i) acc += (i * 3) % 11;
    auto e = steady_clock::now();
    auto ms = duration_cast<milliseconds>(e - s).count();
    std::cout << "acc=" << acc << ", ms >= 0: " << (ms >= 0) << '\n';
    return 0;
}

クイックチェック

ベンチマーク測定の落とし穴について理解度を確認します。

まとめ

<chrono>を使ったコードのベンチマーク測定方法を学びました。

  • 前後でsteady_clock::now()を取得し、その差を計算する
  • duration_castで適切な単位を選ぶ
  • ウォームアップを行い、複数回の実行を平均し、結果を消費してデッドコード除去を防ぐ
  • 小さな処理ではクロックの分解能に注意する

次は、C++20のカレンダー型とタイムゾーン型について学びます。

よくある質問

「コードのパフォーマンス測定」レッスンは無料ですか?

はい。「コードのパフォーマンス測定」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。

「コードのパフォーマンス測定」で何を学びますか?

chronoでベンチマークを行います ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C++ Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「コードのパフォーマンス測定」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC++ Academyレッスンでコードを書いて実行できますか?

はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 継続時間とクロック
  2. 時点
  3. コードのパフォーマンス測定
  4. カレンダーとタイムゾーン
← C++ Academyに戻る