スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | | - | - | - | - |
Entry: main  << >>
Linuxの時間関数について
 Linuxは複数のプロセスがタイムシェアリングで小刻みに切り替えられて(この切り替えのサイクルのことをtickという)、同時並行に処理を進行させます。しかも、この切り替えをユーザーには全く意識させず(逆の意味では「強制的」)に行うため、タイトルのような時間を扱う関数の挙動に関しては注意しないと、意図したように動かない、おかしな動作をする、ということになります。
 
■sleep系関数の精度と挙動
一定時間ごとの周期処理や、リソース競合時の遅延リトライ。そんな時に用いられるのがsleep系関数(sleep/usleep/nanosleep)です。一定時間呼び出しスレッドを停止させる関数(システムコール)であり、sleepなら秒、usleepならマイクロ秒(1/1000000秒)、nanosleepならナノ秒精度(1/1000000000秒)の指定が可能になっています。
しかし、実際この精度で、次に起床されるタイミングを制御できるわけではありません。問題になるのは、usleep/nanosleepです。実際、x86系のLinuxの実装では10ms以下の精度の指定は、10ms精度に丸めらてしまいます(※1)。これは、sleepによって、待ちキューに入ったスレッド(プロセス)を起床させるタイミングが、tick単位であるためです。tickは、上位アプリケーションの開発者にはあまり馴染みがないかもしれませんが、OSが周期的な処理間隔であり、x86 Linuxの場合、これが10msなのです。(※2)(※3)
大抵のOSでは、tick単位で、タイマ割り込みが発生し、このタイマ割り込みのタイミングで、時間指定でsleepしていたスレッド(プロセス)が起床されるという実装になっています。このため、tick以下のsleep時間を指定しても起こされるタイミングがないのです。
 
※1 Linuxのnanosleepでは、リアルタイムスレッドで2ms以下のsleep指定をするとbusy waitによるsleepを行います。よって、2ms以下の精度のsleepも可能にはなっていますが、busy waitのため、他のスレッドは動作できません(スレッドを停止させないという意味です)ただ、現在では※3の様な状態のため、kernel 2.6.18 x86_64 RHEL5(64bit)で実験してみると、スレシホールドが1msecになっているようです
※2 従って、通常のLinuxでは1msecでloop制御を行う必要のあるようなHWILは実現できません。(RTLinuxのような専用のディストリビューションが必要になります)逆にいえば、60Hz程度の周期でよい訓練用シミュレータなら汎用のLinuxでも実現できる可能性があります
※3 つい最近まで1 tick = 10msecでしたが、最近はCPUやメモリが急速に速くなってきているためデフォルトがこれよりも短くなっているようです。簡単なプログラム書いて試してみましたが、kernel 2.6.19 CentOS5では4msecになっているようです。一方、kernel 2.6.18 x86_64 RHEL5(64bit)では2msecでした
 
 
■時間情報取得関数の精度
sleep以外の時間処理としては、時刻や経過時間等の時間情報を取得するというケースがあります。リアルタイム系の処理では、定期的なポーリングで経過時間を取得しつつ処理を行ったりする時等に用いられます。リアルタイム処理以外でも、処理の実行時間等のプロファイル計測に用いられることが多いでしょう。
さて、この時間情報取得関数、POSIX準拠のC言語ライブラリだけでもいくつか種類があります。時間情報を正しく取得するためには、これらの違いとメリット・デメリットを正しく理解しておく必要があります。

◎clock( )
clock( )はANSI Cで定義されており、その返り値の型はclock_tです。clock_tの単位はCLOCKS_PER_SECとして定義されており、POSIXではこれ(CLOCKS_PER_SEC)が1000000(1us)である亊を要求しています。しかし、この精度があるというわけではなく、大抵はtick程度しか精度がでません。なお、clockは実行中のプロセスの処理経過時間を返すため、APIのプロファイル等には便利です。
◎gettimeofday( ) & clock_gettime( )
時間情報取得の定番です。現在の時刻情報が取得できます。これも単位はusecだが、こちらはtick以下の精度もでる。但し、関数をCallしたときのクロックの値を返すので、プロファイリングで用いる時には注意が必要です。(計測の途中でtickの切り替えが発生してもユーザーには判断できない)また、現在時刻を取得するというものであるため、バックグラウンドでntp等が動いていると、時刻情報に補正が入ったために経過時間計測が狂うことがあるのでこれも注意が必要です。
関数が2個挙げてありますが、実はclock_gettime(CLOCK_REALTIME, )と、gettimeofday( )は同じ動きをします。(kernel-2.6.18以前ではclock_gettime( )はgettimeofday( )の値を使っていた)またkernel-2.6.18以前のclock_gettime( )等には細かいことをいうと問題がありました。それはCPU(正確にはコア)のタイマの値を使って実装されていたため、最近の様にマルチコアのCPUではスレッドがコア間で切り替わってしまうと誤差が発生したそうです。(特に最近のCPUでは周波数が可変のため、更に誤差が増えたそうです)現状、PPC, IA64, x86_64の実装はgettimeofday( )に修正が加えられてよくなったとのことです
◎times( )
clock( )同様にスレッドの実行時間をtick精度で取得できます。tick精度の情報であれば十分です。 
◎getrusage
POSIX系ならこれば一番無難でしょう。gettimeofday同様精度が高く、times、clockのようにプロセス単位の経過時間も取得できます。
 
■番外編
ところで、UNIXの2038年問題を知っていますか?これはUNIXのクロックの0の開始時間がUNIXが生まれた時、(1970年1月1日)を基点にして32bit整数で持っているため、それがオーバーフローするのが2038年であることから発生する問題です。これに対して特に対策はとられてないが、元々32bitというのはその時代、その時代の「普通の」整数のbit長を使う慣習から決めたもので明確な定義はありません。(intの定義と同じ)
現在、64bitのLinuxが増えているが、これらは当然64bitで保持するので、この2038年問題は発生しません。

| ヒロ | 12:22 | comments(0) | trackbacks(0) | - | - |
スポンサーサイト
| スポンサードリンク | 12:22 | - | - | - | - |
Comment








Trackback

Calendar

      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< April 2017 >>

Sponsored Links

Profile

Recommend

Search

Entry

Archives

Category

Link

Feed

Others

無料ブログ作成サービス JUGEM

Mobile

qrcode