web-dev-qa-db-ja.com

C ++、タイマー、ミリ秒

#include <iostream>
#include <conio.h>
#include <ctime>



using namespace std;

double diffclock(clock_t clock1,clock_t clock2)
{
    double diffticks=clock1-clock2;
    double diffms=(diffticks)/(CLOCKS_PER_SEC/1000);
    return diffms;
}
int main()
{
    clock_t start = clock();
    for(int i=0;;i++)
    {

    if(i==10000)break;
    }
    clock_t end = clock();

    cout << diffclock(start,end)<<endl;

    getch();
return 0;
}

だから私の問題はそれが私に0を返すということです、まあ正直に言うと私は私のプログラムがどれくらいの時間を動作するかをチェックしたいです...私はインターネット上でたくさんのがらくたを見つけましたほとんどそれは0を得るのと同じポイントになります開始と終了が同じであるため

この問題はC++の記憶に行きます:<

4
Przmak

一見すると、小さい値から大きい値を引いているように見えます。あなたが呼ぶ:

diffclock( start, end );

しかし、diffclockは次のように定義されます。

    double diffclock( clock_t clock1, clock_t clock2 ) {

        double diffticks = clock1 - clock2;
        double diffms    = diffticks / ( CLOCKS_PER_SEC / 1000 );

        return diffms;
    }

それとは別に、それはあなたが単位を変換している方法と関係があるかもしれません。このページでは、ミリ秒に変換するための1000の使用が異なります。

http://en.cppreference.com/w/cpp/chrono/c/clock

5
user755921

ここにはいくつかの問題があります。 1つ目は、diffclock()関数に渡すときに、明らかに開始時間と停止時間を切り替えたことです。 2番目の問題は最適化です。最適化が有効になっている適度にスマートなコンパイラーは、副作用がないため、ループ全体を破棄するだけです。ただし、上記の問題を修正しても、プログラムは0を出力する可能性があります。1秒あたり数十億の操作を実行することを想像しようとすると、最新のCPUで採用されている高度なアウトオブオーダー実行、予測、およびその他のテクノロジーが大量に投入されます。ループを最適化します。ただし、そうでない場合でも、実行時間を長くするには、10Kを超える反復が必要になります。 clock()に何かを反映させるには、おそらくプログラムを1〜2秒実行する必要があります。

しかし、最も重要な問題はclock()自体です。この機能は、パフォーマンス測定のどの時点にも適していません。それが行うことは、プログラムによって使用されるプロセッサ時間の近似を提供することです。特定の実装で使用される可能性のある近似方法のあいまいな性質は別として(標準では特定のものを必要としないため)、POSIX標準では_CLOCKS_PER_SEC_が_1000000_と等しくなければなりません。実際の解像度。言い換えると、クロックがどれほど正確であるかは関係ありません。CPUが実行されている周波数は関係ありません。簡単に言えば、これはまったく役に立たない数値であるため、まったく役に立たない関数です。それがまだ存在する唯一の理由は、おそらく歴史的な理由によるものです。なので、使わないでください。

あなたが探しているものを達成するために、人々はそれを読むために使用される対応するCPU命令の名前で「RDTSC」としても知られている CPUタイムスタンプ を読んでいました。ただし、最近では、これもほとんど役に立たない理由があります。

  1. 最新のオペレーティングシステムでは、プログラムを1つのCPUから別のCPUに簡単に移行できます。別のCPUで1秒間実行した後、別のCPUでタイムスタンプを読み取ることは、あまり意味がないことを想像できます。最新のIntelCPUでのみ、カウンターはCPUコア間で同期されます。全体として、これを行うことはまだ可能ですが、多くの特別な注意を払う必要があります(つまり、一度プロセスへの親和性を設定できるなど)。
  2. プログラムのCPU命令を測定しても、実際に使用されている時間を正確に把握できないことがよくあります。これは、実際のプログラムでは、プロセスに代わってOSカーネルによって作業が実行されるシステムコールが発生する可能性があるためです。その場合、その時間は含まれません。
  3. また、OSがプロセスの実行を長時間中断することもあります。また、実行に必要な命令はわずかでしたが、ユーザーにとっては1秒のように見えました。したがって、このようなパフォーマンス測定は役に立たない可能性があります。

じゃあ何をすればいいの?

プロファイリングに関しては、 perf のようなツールを使用する必要があります。これは、CPUクロックの数、キャッシュミス、取得された分岐、欠落した分岐、プロセスが1つのCPUから別のCPUに移動された回数などを追跡できます。ツールとして使用することも、アプリケーションに埋め込むこともできます( [〜#〜] papi [〜#〜] など)。

そして、質問が実際に費やされた時間についてである場合、人々は掛け時計を使用します。できれば、NTP調整(単調)の対象ではない高精度のものが望ましいです。これは、何が起こっていても、正確にどれだけの時間が経過したかを示します。その目的のために- clock_gettime() を使用できます。これはSUSv2、POSIX.1-2001標準の一部です。getch()を使用して端末を開いたままにしておくと、私は推測します。 Windowsを使用しています。残念ながら、clock_gettime()がなく、最も近いのはパフォーマンスカウンターAPIです。

_BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
_

ポータブルソリューションの場合、最善の策は std::chrono::high_resolution_clock() です。これはC++ 11で導入されましたが、ほとんどの産業グレードのコンパイラ(GCC、Clang、MSVC)でサポートされています。

以下はその使用例です。私のCPUはミリ秒よりも整数の10000増分を実行することがわかっているので、マイクロ秒に変更したことに注意してください。また、コンパイラーがカウンターを最適化しないことを期待して、カウンターをvolatileとして宣言しました。

_#include <ctime>
#include <chrono>
#include <iostream>

int main()
{
    volatile int i = 0; // "volatile" is to ask compiler not to optimize the loop away.
    auto start = std::chrono::steady_clock::now();
    while (i < 10000) {
        ++i;
    }
    auto end = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    std::cout << "It took me " << elapsed.count() << " microseconds." << std::endl;
}
_

コンパイルして実行すると、次のように出力されます。

_$ g++ -std=c++11 -Wall -o test ./test.cpp && ./test
It took me 23 microseconds.
_

それが役に立てば幸い。幸運を!

11
user405725

問題は、ループが短すぎることのようです。私は自分のシステムでそれを試しましたが、0ティックでした。 diffticksが何であるかを確認し、0でした。ループサイズを100000000に増やすと、顕著なタイムラグが発生し、出力として-290が得られました(バグ-diffticksはclock2-clock1である必要があるため、290を取得する必要があります-290ではありません)。部門で「1000」を「100.0」に変更してみましたが、うまくいきませんでした。

最適化を使用してコンパイルするとループが削除されるため、ループを使用しないか、ループを「何かを実行」する必要があります。ループ本体のループカウンター以外のカウンターをインクリメントします。少なくともそれはGCCが行うことです。

3
The_Sympathizer

まず第一に、あなたは終わりを引くべきです-その逆ではなく始めてください。
ドキュメントには、値が利用できない場合、clock()は-1を返すと記載されていますが、それを確認しましたか?プログラムをコンパイルするときに、どの最適化レベルを使用しますか?最適化が有効になっている場合、コンパイラはループを効果的に完全に排除できます。

1
Slava