今回は 楽をするために cocos2d-x 3.8.1 を用いて検証しました。
検証に使ったコードは以下のとおり。
AppDelegate::AppDelegate()
{
std::thread th{[]{
using clock = std::chrono::steady_clock;
constexpr int64_t LOOP_COUNT = 100000;
constexpr int64_t DIST_FREQ = 200;
constexpr int64_t DIST_SIZE = 16;
std::this_thread::sleep_for(std::chrono::seconds{10});
int64_t min = std::numeric_limits<int64_t>::max();
int64_t total = 0;
int64_t max = std::numeric_limits<int64_t>::min();
float total2 = 0;
std::array<int, DIST_SIZE> dist{0};
int overCount = 0;
for (int i = 0; i < LOOP_COUNT; i++) {
auto a = clock::now();
auto b = clock::now();
auto diff = std::chrono::duration_cast<std::chrono::nanoseconds>(b - a).count();
if (diff < DIST_FREQ * DIST_SIZE) {
dist[diff / DIST_FREQ]++;
}
else {
overCount++;
}
total += diff;
total2 += diff * diff;
if (diff < min) min = diff;
if (diff > max) max = diff;
}
float mean = (float)total / LOOP_COUNT;
float sd = std::sqrt(total2 / LOOP_COUNT - mean * mean);
CCLOG("min:%lldns, max:%lldns, mean:%f.2ns, sd:%f.2ns", min, max, mean, sd);
for (int i = 0; i < DIST_SIZE; i++) {
CCLOG("%5lld - %5lld : %d", DIST_FREQ * i, DIST_FREQ * (i + 1) - 1, dist[i]);
}
CCLOG(" %5lld+: %d", DIST_FREQ * DIST_SIZE, overCount);
}};
th.detach();
}
AppDelegate のコンストラクタを用いているのは、
既存のプロジェクトでも計測しやすくするためです。
Android では gcc4.9 を用い、指定したコンパイルオプションは以下のとおり
-std=c++14 -fexceptions -frtti -fsigned-char
-DCC_ENABLE_SCRIPT_BINDING=1
-DCC_USE_PHYSICS=0 -DCC_USE_3D_PHYSICS=0 -DCC_USE_TIFF=0 -DCC_USE_WEBP=0
-DCC_DIRECTOR_STATS_INTERVAL=0.5f
iOS では Xcode7.2 を用い、c++14 に設定した上で、以下のマクロを定義してあります。
COCOS2D_DEBUG=1
USE_FILE32API
USE_PHYSICS=0
CC_USE_TIFF=0
CC_USE_WEBP=0
なおどちらもデバッグビルド (-O0) です。
計測した結果は以下のとおり。
https://gist.github.com/mezum/0ff696d046da133663fa
執筆時ではまだ Android4.4, iOS7.0 の 2 端末でしか検証していないのですが、
約 1-2 マイクロ秒オーダーの精度は望めそうです。 (要検証)
少なくとも iOS なら 2 マイクロ秒前後、Android ならば 32 マイクロ秒前後の精度で値は取れるようです。
#考察
gnustl の実装を見てみると、clock_gettime を用いて CLOCK_MONOTONIC の時刻を取得して time_point に詰め替えています。
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B11/chrono.cc
また、libc++ の実装を見てみると、gnustl と同じく clock_gettime を用いるか、mach_absolute_time を用いて居るようです。
(CLOCK_MONOTONIC を使う場合の警告文から察するに iOS の場合はmach_absolute_time を用いている感じがします。)
https://github.com/llvm-mirror/libcxx/blob/master/src/chrono.cpp
clock_gettime を用いているのであれば、clock_getres で精度を取れるかもしれない。