知られているように、clock()
はリアルタイムの値よりも小さいか大きい場合があります。どちらの場合も、次の例1と2に示されています。
C++ 11での時間の高精度測定には、次のものを使用できます。
std::chrono::high_resolution_clock::now();
-高精度を保証しますstd::chrono::steady_clock::now();
-リアルタイムで測定することを保証しますclock();
-高精度を保証しますが、時間ではなくCPUサイクルを測定しますtime(&t_start);
-高精度ではありませんが、リアルタイムで測定します_#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>
int main(void) {
std::cout << "sleep(3) took: \n\n";
clock_t c_start, c_end;
time_t t_start, t_end;
std::chrono::high_resolution_clock::time_point h_start, h_end;
std::chrono::steady_clock::time_point steady_start, steady_end;
time(&t_start); // less precise than clock() but always get the real actual time
c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds
h_start = std::chrono::high_resolution_clock::now();
steady_start = std::chrono::steady_clock::now();
std::this_thread::sleep_for(std::chrono::seconds(3));
steady_end = std::chrono::steady_clock::now();
h_end = std::chrono::high_resolution_clock::now();
c_end = clock();
time(&t_end);
std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";
printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
printf("time() = %.2lf seconds \n", difftime(t_end, t_start));
return 0;
}
_
G ++での結果(Debian 4.9.2-10)4.9.2:clock()= 0.00秒
_sleep(3) took:
highres = 3.00098 s
steady = 3.00098 s
clock() = 0.00 seconds
time() = 3.00 seconds
_
C++ MSVS 2013 v120(Windows 7x64)での結果:
_sleep(3) took:
highres = 3.00017 s
steady = 3.00017 s
clock() = 3.00 seconds
time() = 3.00 seconds
_
2-2番目の例OpenMPまたは_<thread>
_: http://coliru.stacked-crooked.com/a/2922c85385d197e1
_#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>
#include <vector>
int main(void) {
std::cout << "for-loop took: \n\n";
clock_t c_start, c_end;
time_t t_start, t_end;
std::chrono::high_resolution_clock::time_point h_start, h_end;
std::chrono::steady_clock::time_point steady_start, steady_end;
time(&t_start); // less precise than clock() but always get the real actual time
c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds
h_start = std::chrono::high_resolution_clock::now();
steady_start = std::chrono::steady_clock::now();
#pragma omp parallel num_threads(10)
{
for (volatile int i = 0; i < 200000000; ++i);
}
steady_end = std::chrono::steady_clock::now();
h_end = std::chrono::high_resolution_clock::now();
c_end = clock();
time(&t_end);
std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";
printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
printf("time() = %.2lf seconds \n", difftime(t_end, t_start));
int b = getchar();
return 0;
}
_
G ++での結果(Debian 4.9.2-10)4.9.2:clock()= 1.35秒
_for-loop took:
highres = 0.213906 s
steady = 0.213905 s
clock() = 1.35 seconds
time() = 0.00 seconds
_
C++ MSVS 2013 v120(Windows 7x64)での結果:
_for-loop took:
highres = 1.49109 s
steady = 1.49109 s
clock() = 1.49 seconds
time() = 2.00 seconds
_
履歴書:
スレッドがスリープ状態になると、g ++ 4.9.2のclock()
は他の関数とは異なり時間を測定しません。
OpenMPまたは_<thread>
_( link )を使用してマルチスレッドを使用する場合、g ++ 4.9.2のclock()
はすべてのスレッドのCPUサイクルを測定します。
また、Windows MSVS 2013では、どちらの場合もclock()
はリアルタイムで測定する必要がありますが、これはclock()
が他のプラットフォームでも同じように測定することを保証するものではありません(Linuxではg ++はスリープに対して0であり、マルチスレッドの場合はx-fold)。
これに基づいて、Windows MSVS2013とg ++ 4.9.2の両方でstd::chrono::high_resolution_clock::now();
が必要なリアルタイムを測定する場合、これは他のすべてのプラットフォームで実際の高解像度時間を測定することを保証し、保証するかどうかを確認します標準C++ 11/14?
high_resolution_clock
はあなたが探している保証を明示的に提供していません。今のところ、steady_clock
とsystem_clock
は、より適切でより明確な保証を提供します。ただし、ほとんどの実装おそらくスレッドがスリープしている間にHRCが確実に進むようにします。それでも、独自のタイプエイリアスを実行する方が望ましい場合があります。以下の「編集」セクションとコメントの説明を参照してください。
ドラフト標準 は、実際には、Clockオブジェクトがnotであることを暗黙的に確認します(注30.2.4「タイミング仕様」の注5)。 -)関連するスレッドがスリープしている間に進む必要があります。コンテキストとして、このセクションでは、標準ライブラリのタイマーオブジェクトがどのように機能するかを説明します。タイマーの動作は、タイマーの設定に使用されるクロックの動作に基づいています。
[注:クロックが安定したクロック(CPUタイムクロックなど)と同期していない場合、これらのタイムアウトは有用な機能を提供しない可能性があります。 — エンドノート]
この場合、「タイムアウトは有用な機能を提供しない可能性がある」ということは、タイマーを使用して特定のクロック時間をsleep_until
する場合非同期(非リアルタイム)クロックを使用する、スレッドを意味することに注意してください。 ウェイクアップしません。したがって、上記の注記は少し控えめな表現です。
そして、実際、クロック仕様(20.13.3)には、安定したクロックとの同期を実際に必要とするものはありません。
ただし、この標準は、20.13.7.3の定義でhigh_resolution_clock
の2つの潜在的なエイリアスを暗黙的に容認しているようです。
high_resolution_clock
は、system_clock
またはsteady_clock
の同義語である可能性があります。
steady_clock
は、もちろん安定しています。 system_clock
はnotです。これは、システム時刻が変更される可能性があるためです(たとえば、NTP更新の結果として) )プログラムの実行中。
ただし、system_clock
(20.13.7.1)isは依然として「リアルタイム」クロックです。
クラス
system_clock
のオブジェクトは、システム全体のリアルタイムクロックからの実時間を表します。
したがって、system_clock
は、スレッドがスリープしているときに進行を停止しません。これは、時計が期待どおりに動作する場合でも、is_steady
がhigh_resolution_clock
に対してfalseである可能性があるというNicol Bolasの指摘を裏付けています(つまり、関連付けられたスレッドの状態に関係なく進みます)。
これに基づいて、ほとんどの主流の実装がhigh_resolution_clock
にある種のリアルタイム(つまり同期された)クロックを使用することを期待することは合理的であるように思われます。結局のところ、実装は便利になるように設計されており、時計は、リアルタイムでない場合、特に上記の「便利な機能」に関する注記のようにタイマーとともに使用される場合、一般的にあまり役に立ちません。
ただし、guaranteedではないため、使用する各実装の動作やドキュメントを確認する必要があります。
編集:私はこの問題について ISO C++標準グループに関する議論 を開始しました。これはバグであることを示唆しています。標準。ハワード・ヒナントからの最初の返信は、それを標準にしたことで評価されていますin標準ですが、引用する価値があります。
私は
high_resolution_clock
の非推奨に反対するつもりはなく、適切な非推奨期間の後にそれを削除するつもりです。現実には、それは常にsteady_clock
またはsystem_clock
のいずれかのtypedefであり、プログラマーはhigh_resolution_clock
を選択していくつかを取得するよりも、これら2つのうちの1つを選択して何が得られるかを知っている方がよいでしょう。サイコロを振って他の時計。
...したがって、Hinnantによると、道徳はhigh_resolution_clock
を使用しないでください。
編集2:
Hinnantによるとhigh_resolution_clock
の問題は、HRCの問題に遭遇する可能性が高いほどではありません(ただし、上記の引数のように、準拠するコンパイラでもis可能です) )、ただし、通常、他の2つのクロックのいずれかよりも実際には低い解像度が得られないため(ただし、「最大解像度」を取得するには、type-aliasまたはtypedefでそれらの解像度を手動で比較する必要があります) 「眠っていない時計)、具体的なメリットはありません。したがって、適合した実装でスレッドが永久にスリープするリスクと、名前high_resolution_clock
のセマンティックな利点、および独自のtypedefまたはtype-aliasを作成しないことによる単純/簡潔な利点を比較検討する必要があります。
さまざまなアプローチの実際のコードを次に示します。
static_assert
を使用してcheckhigh_resolution_clock
が実際に実際のクロックにエイリアスされているかどうか。これはおそらく決して起動しません。つまり、独自のtypedefをいじることなく、最高解像度の「リアルタイム」クロックを自動的に取得します。
static_assert(
std::is_same<high_resolution_clock, steady_clock>::value
|| std::is_same<high_resolution_clock, system_clock>::value,
"high_resolution_clock IS NOT aliased to one of the other standard clocks!");
high_resolution_clock::is_steady
がtrueの場合は、HRCを使用します。それ以外の場合は、system_clock
とsteady_clock
の間の高解像度クロックを優先します。 [〜#〜]注[〜#〜]high_resolution_clock::is_steady
がfalseの場合、これはおそらく HRCがsystem_clock
にエイリアスされていること。この場合、最終的には新しいタイプエイリアスになります。これは実際にはhigh_resolution_clock
と同じタイプです。ただし、独自のタイプエイリアスを作成すると、これが明示的になり、悪意のあるが準拠している実装でも上記の問題が発生しないことが保証されます。
using maxres_sys_or_steady =
std::conditional<
system_clock::period::den <= steady_clock::period::den,
system_clock, steady_clock
>::type;
using maxres_nonsleeping_clock =
std::conditional<
high_resolution_clock::is_steady,
high_resolution_clock, maxres_sys_or_steady
>::type;
標準では、この動作をクロックから指定していません。ではない正確に。
時計にはis_steady
静的プロパティがあり、これを確認できます。 is_steady
がtrueを返すクロックcannotは、スレッドをスリープ状態にしたという理由だけで実行を停止する種類のクロックです。ただし、その値がfalseであるクロックは、さまざまな理由で非定常である可能性があります。システム時刻が変わると変わる掛け時計なので、安定しない場合があります。または、ティック間の期間が正確な数ではなく平均であるためです。
したがって、is_steady
は実際にはあなたの質問に答えません。
この規格ではhigh_resolution_clock::is_steady
は指定されていませんが、その質問に答えるために実装が必要です。安定している場合は、スレッドをスリープしてもクロックが停止しないことが保証されます。しかし、それが安定していない場合...あなたはまったく保証を得ることができません。