3

I have been experimenting with all kind of timers on Linux and OSX, and would like to try and wrap some of them with the same interface used by std::chrono.

That's easy to do for timers that have a well-defined "period" at compile time, e.g. the POSIX clock_gettime() familiy, the clock_get_time() family on OSX, or gettimeofday().

However, there are some useful timers for which the "period" - while constant - is only known at runtime. For example: - POSIX states the period of clock(), CLOCKS_PER_SEC, may be a variable on non-XSI systems - on Linux, the period of times() is given at runtime by sysconf(_SC_CLK_TCK) - on OSX, the period of mach_absolute_time() is given at runtime by mach_timebase_info() - on recent Intel processors, the DST register ticks at a constant rate, but of course that can only be determined at runtime

To wrap these timers in the std::chrono interface, one possibility would be to use a period of std::chrono::nanosecond , and convert the value of each timer to nanoseconds. An other approach could be to use a floating point representation. However, both approaches would introduce a (very small) overhead to the now() function, and a (probably small) loss in precision.

The solution I'm trying to pursue is to define a set of classes to represent such "run-time constant" periods, built along the same lines as the std::ratio class. However I expect that will require rewriting all the related template classes and functions (as they assume constexpr values).

How do I wrap these kind of timers a la std:chrono ?

Or use non-constexpr values for the time period of a clock ?

4

3 に答える 3

4

これらの種類のタイマーを std:chrono でラップした経験がある人はいますか?

実際、私はそうします。そして、関心のあるプラットフォームの 1 つである OSX 上で。:-)

あなたは言及します:

OSX では、mach_absolute_time() の期間は実行時に mach_timebase_info() によって与えられます。

絶対に正しい。また、OSX では、 と のlibc++実装はhigh_resolution_clocksteady_clock実際には に基づいていmach_absolute_timeます。私はこのコードの作成者であり、寛大なライセンスを持つオープン ソースです (著作権を保持している限り、好きなことをしてください)。

libc++ のsteady_clock::now()ソースは次のとおりです。それはあなたが推測したように構築されています。実行時間は、返される前にナノ秒に変換されます。OS X では、変換係数は非常に頻繁に 1 であり、コードは最適化によってその事実を利用します。ただし、コードは 1 以外の変換係数を処理するのに十分一般的です。

への最初の呼び出しnow()では、ランタイム変換係数をナノ秒に照会するためのわずかなコストがかかります。一般的なケースでは、浮動小数点変換係数が計算されます。一般的なケース (変換係数 == 1) では、後続のコストは関数ポインターを介して呼び出されます。オーバーヘッドが非常に合理的であることがわかりました。

OS X では、変換係数は実行時まで決定されませんが、依然として定数です (つまり、プログラムの実行時に変化しません)。そのため、一度だけ計算する必要があります。

生理が実際に動的に変化する状況にある場合は、これを処理するためにより多くのインフラストラクチャが必要になります。基本的に、期間と時間の曲線を統合 (計算) し、2 つの時点間の平均期間を計算する必要があります。これには、時間の経過とともに変化する期間を常に監視する必要があり、その<chrono>ための適切なツールではありません。このようなツールは通常、OS レベルで処理されます。

于 2013-02-27T01:18:57.437 に答える
0

I have done a similar thing for my purposes, only for Linux though. You find the code here; feel free to use the code in whatever way you want.

The challenges my implementation addresses overlap partially with the ones mentioned in your question. Specifically:

  • The tick factor (required to convert from clock ticks to a time unit based on seconds) is retrieved at run time, but only the first time now() is used. If you are concerned about the small overhead this causes, you may call the now() function once at start-up before you measure any actual intervals. The tick factor is stored in a static variable, which means there is still some overhead as – on the lowest level – each call of the now() function implies checking whether the static variable has been initialized. However, this overhead will be the same in each call of now(), so it shouldn't impact measuring time intervals.

  • I do not convert to nanoseconds by default, because when measuring relatively long periods of time (e.g. a few seconds) this causes overflows very quickly. This is in fact the main reason why I don't use the boost implementation. Instead of converting to nanoseconds, I implement the base unit as a template parameter (called Precision in the code). I use std::ratio from C++11 as template arguments. So I can choose, for example, a clock<micro>, which implies that calling the now() function will internally convert to microseconds rather than nanoseconds, which means I can measure periods of many seconds or minutes without overflows and still with good precision. (This is independent of the unit used to produce output. You can have a clock<micro> and display the result in seconds, etc.)

  • My clock type, which is called combined_clock combines user time, system time and wall-clock time. There is a boost clock type for this, too, but it's not compatible with the ratio types and units from std, whereas mine is.

The tick factor is retrieved using the ::sysconf() call you suggest, and that is guaranteed to return one and the same value throughout the life time of the process.

So the way you use it is as follows:

#include "util/proctime.hpp"

#include <ratio>
#include <chrono>
#include <thread>
#include <utility>
#include <iostream>

int main()
{
  using std::chrono::duration_cast;
  using millisec   = std::chrono::milliseconds;
  using clock_type = rlxutil::combined_clock<std::micro>;

  auto tp1 = clock_type::now();

  /* Perform some random calculations. */
  unsigned long step1 = 1;
  unsigned long step2 = 1;
  for (int i = 0 ; i < 50000000 ; ++i) {
    unsigned long step3 = step1 + step2;
    std::swap(step1,step2);
    std::swap(step2,step3);
  }

  /* Sleep for a while (this adds to real time, but not CPU time). */
  std::this_thread::sleep_for(millisec(1000));

  auto tp2 = clock_type::now();

  std::cout << "Elapsed time: "
            << duration_cast<millisec>(tp2 - tp1)
            << std::endl;

  return 0;
}

The usage above involves a pretty-print function that generates output like this:

Elapsed time: [user 40, system 0, real 1070 millisec]
于 2013-02-27T02:10:49.467 に答える
0

[経験のある人はいますか] または、クロックの期間に constexpr 以外の値を使用していますか?

標準 (20.11.5、クラス テンプレート期間) を読んだ後、「期間」は「比率の特殊化」であることが期待されます。

備考: Period が ratio の特殊化でない場合、プログラムの形式は正しくありません。

そして、すべての chrono テンプレートは constexpr 機能に大きく依存しています。

これらの種類のタイマーを std:chrono でラップした経験がある人はいますか?

具体的な例はありませんが、 period = 1, boost::rational を rep として期間を使用するという提案をここで見つけました。

于 2013-02-09T12:19:23.170 に答える