LoginSignup
3
4

More than 5 years have passed since last update.

std::chrono::steady_clock の精度 (スマホ編)

Last updated at Posted at 2015-12-13

今回は 楽をするために cocos2d-x 3.8.1 を用いて検証しました。
検証に使ったコードは以下のとおり。

AppDelegate.cpp
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 で精度を取れるかもしれない。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4