MachTimeを使用するだけです。
これはパブリックAPIであり、macOS、iOS、およびtvOSで動作し、サンドボックス内から動作します。
Mach Timeは、私が通常「クロックティック」と呼ぶ抽象的な時間単位を返します。クロックティックの長さはシステム固有であり、CPUによって異なります。現在のIntelシステムでは、クロックティックは実際には正確に1ナノ秒ですが、これに依存することはできません(ARMでは異なる場合があり、PowerPC CPUでは確かに異なります)。システムは、クロックティックをナノ秒に変換し、ナノ秒をクロックティックに変換する変換係数も通知できます(この係数は静的であり、実行時に変更されることはありません)。システムが起動すると、クロックは開始し0
、その後はクロックティックごとに単調に増加するため、マッハタイムを使用してシステムの稼働時間を取得することもできます(もちろん、稼働時間は単調です!)。
ここにいくつかのコードがあります:
#include <stdio.h>
#include <inttypes.h>
#include <mach/mach_time.h>
int main ( ) {
uint64_t clockTicksSinceSystemBoot = mach_absolute_time();
printf("Clock ticks since system boot: %"PRIu64"\n",
clockTicksSinceSystemBoot
);
static mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
// Cast to double is required to make this a floating point devision,
// otherwise it would be an interger division and only the result would
// be converted to floating point!
double clockTicksToNanosecons = (double)timebase.numer / timebase.denom;
uint64_t systemUptimeNanoseconds = (uint64_t)(
clockTicksToNanosecons * clockTicksSinceSystemBoot
);
uint64_t systemUptimeSeconds = systemUptimeNanoseconds / (1000 * 1000 * 1000);
printf("System uptime: %"PRIu64" seconds\n", systemUptimeSeconds);
}
特定のマッハ時間に達するまでスレッドをスリープ状態にすることもできます。そのためのコードは次のとおりです。
// Sleep for 750 ns
uint64_t machTimeNow = mach_absolute_time();
uint64_t clockTicksToSleep = (uint64_t)(750 / clockTicksToNanosecons);
uint64_t machTimeIn750ns = machTimeNow + clockTicksToSleep;
mach_wait_until(machTimeIn750ns);
Mach Timeは実時間とは関係がないため、システムの日付と時刻の設定を好きなように試すことができます。これはMachTimeには影響しません。
ただし、特別な考慮事項が1つあります。これにより、マッハタイムが特定のユースケースに適さなくなる可能性があります。システムがスリープしている間はCPUクロックが実行されません。したがって、スレッドを5分間待機させ、1分後にシステムがスリープ状態になり、30分間スリープ状態を維持した場合、30分のスリープ時間はカウントされないため、システムがウェイクアップした後もスレッドはさらに4分間待機します。 !!その間、CPUクロックも停止していました。しかし、他の場合には、これはまさにあなたがしたいことです。
マッハ時間は、費やした時間を測定するための非常に正確な方法でもあります。そのタスクを示すコードは次のとおりです。
// Measure time
uint64_t machTimeBegin = mach_absolute_time();
sleep(1);
uint64_t machTimeEnd = mach_absolute_time();
uint64_t machTimePassed = machTimeEnd - machTimeBegin;
uint64_t timePassedNS = (uint64_t)(
machTimePassed * clockTicksToNanosecons
);
printf("Thread slept for: %"PRIu64" ns\n", timePassedNS);
スレッドが正確に1秒間スリープしないことがわかります。これは、スレッドをスリープ状態にしてから再度ウェイクアップするのに時間がかかり、すべてのコアがスリープ状態になってもすぐにCPU時間を取得できないためです。その時点ですでにスレッドの実行で忙しいです。
更新(2018-09-26)
macOS 10.12(Sierra)以降、も存在しmach_continuous_time
ます。mach_continuous_time
との唯一の違いはmach_absolute_time
、システムがスリープしているときに継続時間が進むことです。したがって、これがこれまでの問題であり、Mach Time 10.12以降を使用しない理由がこの問題の解決策を提供する場合は、使い方は上記と全く同じです。
また、macOS 10.9(Mavericks)からは、がmach_approximate_time
あり、10.12にはもありmach_continuous_approximate_time
ます。これら2つは同一でmach_absolute_time
ありmach_continuous_time
、唯一の違いは、高速でありながら精度が低いことです。カーネルがマッハ時間を処理するため、標準関数ではカーネルを呼び出す必要があります。このような呼び出しは、特にすでにMeltdown修正が行われているシステムでは、いくらか費用がかかります。おおよそのバージョンは、常にカーネルを呼び出す必要はありません。カーネルクロックと時々同期するだけのユーザースペースのクロックを使用して、同期がずれすぎないようにしますが、常に小さな偏差が発生する可能性があるため、これは「おおよその」マッハ時間にすぎません。