Help us understand the problem. What is going on with this article?

iOS の時間関数の精度

More than 1 year has passed since last update.

Optimized C++ で色々ある Windows の時刻取得関数の精度を測っているのを見て iOS の時刻取得関数を測ってみました。通常、Swift で時間を扱う時には Date/NSDate を使いますが、iOS ではこのほかに UNIX 由来の C の関数を使って時刻を取得できます。

Java や C# と違ってラッパーコードを書かずに C 言語の関数を直接呼べるのは Swift のいいところですね。

time()

1970/1/1 00:00:00 からの経過秒数を取得します。Swift から呼ぶとこんな感じです。

let t = Double(time(nil))

仕様により精度は 1 秒です。

getimeofday()

1970/1/1 00:00:00 からの経過秒数をマイクロ秒の精度で取得します。

var tv = timeval() // これは関数呼び出しではなくイニシャライザ
gettimeofday(&tv, nil)
let t = Double(tv.tv_sec) + Double(tv.tv_usec) / 1000000.0

clock_gettime()

この関数は実時間、プロセスの CPU 時間、スレッドの CPU 時間など取得する時間の種類を指定できます。性能計測のため実時間を取得するならこのようになります。UNIX では古くからある関数ですが、iOS で使えるようになったのは iOS10 からです。

var tp = timespec() // これもイニシャライザ
clock_gettime(_CLOCK_REALTIME, &tp)
let t = Double(tp.tv_sec) + Double(tp.tv_nsec) / 1000000000.0

clock_gettime_nsec_np()

clock_gettime() の結果を 64bit 整数として取得できます。

let t = Double(clock_gettime_nsec_np(_CLOCK_REALTIME)) / 1000000000.0

mach_absolute_time()

CPU のタイムスタンプカウンタ(CPU が一定周期でインクリメントするレジスタ)の値を取得します。他より高精度です。

var tb = mach_timebase_info() // イニシャライザ
mach_timebase_info(&tb) // こっちは関数呼び出し
let tsc = mach_absolute_time()
let t = Double(tsc) * Double(tb.numer) / Double(tb.denom) / 1000000000.0

精度は CPU 依存なので定数を掛けたり割ったりしても秒に変換できません。まず、mach_timebase_info() でタイムスタンプカウンタの値をナノ秒に変換するための値を取得して変換します。

iOS の生い立ちを感じさせる名前ですね。

Date/NSDate

これは説明不要ですね。Swift 標準の時刻を表す型です。

gettimeofday() にシンボリックブレークポイントを設定して Date の引数なしイニシャライザを呼んでみるとそのブレークポイントにヒットします。Dategettimeofday() で実装されていることがわかります。したがって同じ精度を持ちます。

実測

Optimized C++ での測り方で各関数の精度を測ってみました。環境は iPhone 6s、iOS 10.2.1、Xcode 8.2.1 です。

関数/型 精度
time() 1.00s
gettimeofday() 1.01μs
clock_gettime() 1.00μs
clock_gettime_nsec_np() 1.01μs
mach_absolute_time() 41.7ns
Date 1.09μs

time() は仕様通り 1s、mach_absolute_time() は圧倒的に高精度で、あとはだいたい 1μs という結果になりました。clock_gettime(), clock_gettime_nsec_np() は 1ns の精度を持っていそうな型名、関数名をしていますが、少なくとも今の iOS の実装では違うようです。

また iPad Mini 4 で測ってみると mach_absolute_time() は 76.7ns であとはだいたい一緒でした。

通常のプログラムの実行時間計測では 1ms の精度があれば十分なので使いやすい Date を使えばよく、本当に精度が必要な時だけ mach_absolute_time() を使えばよさそうです。

計測に使ったコードは https://github.com/yamoridon/TimeResolution に置いておきますね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away