コグノスケ


link 未来から過去へ表示(*)
link 過去から未来へ表示

link もっと前
   2006年 8月 7日 >>> 2006年 7月 29日
link もっと後

2006年 8月 7日

timeBeginPeriod() API の挙動

昔書いた記事の供養です。2006/04/15 加筆修正したもので、現在もこの情報が正しいかどうかは不明です。

Windows API に、マルチメディアタイマーの最小分解能を指定する timeBeginPeriod() という関数があります。使ってみたところ、こやつはかなり挙動不審です。本ページに気づいた点をまとめました。またタイマーと分解能について、解説を加筆いたしました。ご参考になれば幸いです。

※当方の環境は Windows 2000 SP4 with VC++ 6.0 SP5 です。Windows 9x 系はカーネル等が根本的に異なるため、この限りではありません。

Windows のタイマー

Windows には 2種類のタイマーがあります。

  • SetTimer() API による標準タイマー
  • timeSetEvent() API によるマルチメディアタイマー

です。同様に、システム時刻の取得にもいくつかの手法があります。

  • time() ライブラリ関数
  • GetTickCount() API によるシステム稼働時間(ms オーダ)
  • timeGetTime() API による最大 1ms の分解能を持つカウンタ
  • QueryPerformanceCounter() API で取得できる 3MHz 程度の高分解能カウンタ

などがあります。カウンタの値が現在時刻など特定の意味を持つとは限らず、差分として用いることにだけ意味があるカウンタ(高分解能カウンタがそう)もあります。自分のシステムで、現在時刻と一致したからといって他のシステムでも同じとは限りません。ここではそれぞれの API の詳細を述べることはしません。

分解能について

先ほど述べた timeGetTime() API で得られる値は ms 単位ですが、分解能を変更することができます。分解能というのはなんでしょうか?もう少し説明しましょう。アナログ(デジタルでも構いませんが)時計を思い浮かべてください。

このとき分解能は時計の針が一度にどれだけ進むかに相当します。分解能を細かくすると、1秒に一度 1/60 度だけ進む律儀な時計になり、分解能を荒くすると、5秒に一度 1/12(= 5/60) 度だけ進むルーズな時計になります。

分解能の適正な値は用途によって異なります。普段の生活では腕時計(1秒の分解能)で十分ですが、短距離走のタイムを計るときに腕時計は使いません。短距離走は 1秒以下のタイムで勝負が決しますが、1秒以下の値を指せない腕時計では秒以下のタイムが計れないからです。用途に合った分解能を持つ時計、例えばストップウォッチ(分解能 10ms 程度)を用います。

同様にコンピュータのタイマーも用途に合った分解能を用います。常に最も分解能の細かいカウンタを用いても良いですが、ストップウォッチが高価なように高分解能のカウンタには制約がある場合があります。例えば Windows の高分解能カウンターは非常に大きな値を返すため、少し処理が複雑です。適材適所が良いでしょう。

高分解能にこだわる理由

分解能が荒いとゲーム製作で非常に難儀します。60fps において、1フレームが消費する時間は 16.67ms です。Windows 2000 では初期値の分解能が 10ms のため、16ms 待ちたくて Sleep(16) としても 20ms 待ってしまいます。Sleep(n) がきちんと n[ms] で返ってこなければ 60fps より低い、あるいは高いフレーム数になってしまいます。

高分解能カウンタをスピンウェイト(全力でポーリングして監視する方法)は最も正確ですが、ゲームの処理を終えて時間が余ったとしても、時間の経過を待つ作業で CPU 資源を浪費するため、省電力などの観点から見てもあまりよろしくありません。時間が過ぎるのを待つだけの処理なのですから、Sleep() 関数を呼び他のプロセスに実行権を譲り CPU 負荷を減らすのが道理です。

timeBeginPeriod() の不思議な挙動

冒頭で述べたとおり timeGetTime() の分解能は最大で 1ms ですが、Windows 2000 では分解能の初期値は 10ms です。変更するには timeBeginPeriod() API を用います。timeBeginPeriod() を呼び出せば、当然分解能が変更されます。

実験していると不思議なことが 2つあって、1つ目は timeBeginPeriod() を呼び出す前から、分解能の初期値が 1ms になっていることで、2つ目は副スレッドから timeBeginPeriod() を呼び出しても timeBeginPeriod() が機能していないようにみえることです。

調べると MSN Messenger 6.1 が起動していると最小分解能が変化することがわかりました。あるプロセスで timeBeginPeriod() を呼ぶと他のプロセスに影響するのではないでしょうか?

実験結果 - 他プロセスとの関係

自作の timeBeginPeriod() を呼ぶプログラムで実験すると、timeBeginPeriod() は最も細かい分解能を「システム全体に」適用することがわかります。

あるプロセスが timeBeginPeriod() を呼び出し最小分解能を指定した後、他のプロセスが timeBeginPeriod() を使用すると最小分解能はその値に上書きされます。後に起動したプロセスが終了しても最小分解能は元に戻りません。最小分解能を 1ms に設定して、その後 5ms に設定しても分解能が変化しません。

例外として 10ms 以上の値を指定すると、他のプロセスに最小分解能を上書きされなくなります。しかし最小分解能は 10ms 固定になります。

もし timeEndPeriod() を呼ばずに終了する「行儀の悪い」プログラムがあったときは、プロセスが終了すれば timeEndPeriod() を呼んだときと同様に分解能の変更が無効化されます。

全く timeBeginPeriod() を呼び出さないプロセスの場合は、他プロセスが timeBeginPeriod() の呼び出しの影響を受け分解能が変化しますが、timeBeginPeriod() 呼んでいた他のプロセスが全て終了すると初期値の 10ms に戻ります。

実験結果 - マルチスレッド環境における振る舞い

プロセスに複数のスレッドがある場合、メインスレッドから timeBeginPeriod() を呼ばないと効果がないようです。関数の帰り値は分解能の変更に成功したと報告しますが、最小分解能は変化しません。

ちなみにこの現象は、後述するプログラムでは確認できません。ごめんなさい。

実験結果 - timeEndPeriod() API の効力

同一プロセス、同一スレッド内で timeEndPeriod() を呼び出した場合「だけ」最小分解能の指定が解除されます。この条件下ではネストした指定も可能です。例えば begin(3) begin(2) begin(1) end(2) end(1) とすると、内側にある 1ms の設定と 2ms の設定が解除されて、3ms の設定に戻ります。

しかし他に timeBeginPeriod() を利用するプロセスが 1つでも存在すると、timeEndPeriod() は機能しません。

結論

最小分解能が変化すると困る場合は、指定できる最も細かい分解能(timeGetDevCaps() API で取得できます)以外の値は指定しないほうが良いでしょう。途中で他のプロセスに影響されて変わってしまうかもしれません。

Windows でどこまで計れるか?

脱線話ですが、Windows 上で得られる最高の分解能が気になる方もいるかと思います。

おそらく Windows 2000 において最も細かい分解能を持つのは高分解能カウンタです。周波数は約 3.5MHz で、分解能に直せば 300ns 程度です。ただしここまで細かい間隔だと、CPU が十分に速くないと取りこぼしてしまいそうです。

近年の OS はカーネルが任意の地点で実行権を取り上げて他のプロセスに渡せる(プリエンプティブ)ため、Windows は正確なリアルタイム処理には向きません。UNIX なども同様の理由でリアルタイム処理には用いません。しかし最近は組み込み機器向けにリアルタイム処理に対応した Linux が登場しています。

それとですね……書いた後で気づきましたが、PSX Alternative! にも当ページと同様の実験が紹介されていました。実験方法は違います(向こうは Sleep(1) にかかる時間を見ている)が、やはり同様に timeBeginPeriod() はおかしいと指摘していました。

検証方法

検証方法と用いたプログラムは以下の通りです。

ビジーループして timeGetTime() で取得できるカウンターの差分が最小分解能と一致しているか確かめます。最小分解能は高々 1ms であること、ループに 1ms 以上かからないことを仮定しています。

検証用プログラム

// mmtimer.c

#include <stdio.h>
#include <windows.h>

int main()
{
  unsigned long mmt, mmt_b;

  timeBeginPeriod(1);
  mmt = mmt_b = 0;
  while (true) {
    mmt = timeGetTime();
    if (mmt != mmt_b)
      printf("%d ms\n", mmt - mmt_b);

    mmt_b = mmt;
  }

  timeEndPeriod(1);
  return 0;
}

結果は以下のとおりです。

実行結果
%./mmtimer↓
・
・
1 ms↓
1 ms↓
1 ms↓
1 ms↓
1 ms↓
・
・
編集者: すずき(更新: 2023年 2月 3日 14:01)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 6日

立命(高校)のみんなと食事&カラオケ。少なくとも半年空いてるので、毎回すごーく久しぶりに会った気がします。高校卒業からだいぶ経つけど、みんな良い意味で変わってないよ。ずっとこうやって集まりたいね。

昨日の日記で泣くとか泣かないとか書いて思い出した。私はけっこう涙もろくて、特に一人で感動モノ見ると泣けて仕方ないです。仕方なさ過ぎて、頬を涙が伝います。
映画なんかでも OK ですが、短い文章の方が良いかも。これって普段のイメージ(って自分じゃわからんけど)からすると当然?意外?

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 5日

母方の祖母のお見舞いに行きました。ペースメーカーを埋めると聞いていて不安でしたが、結局埋めないそうです。微妙な状態なんでしょうけど、医者が要らんって言うなら要らんのでしょう。

テレビで SWING GIRLS をやっていたので、鑑賞。おかっぱの人(パーカッション)がすげー。ジャズってサックスがカッコいいねえ。

実家でボーっとしててと、ふと思った。働き始めるとまとまった休みはないから、今年の冬って北海道に長期間帰省できる最後の機会じゃね?今年の冬は感慨深いものになるはず……ってのはちと大げさか?
別れは悲しいものですが、私は死別でもなければあまり気にならないかも。卒業式とかお別れ会で全く泣かないタイプです。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 4日

母と妹が出かけたので、父方のばーさまと一緒に留守番でした。昼頃、ばーさまが財布がないとか言って、家捜しを始め、しまいには父(つまりばーさまの息子)に盗られたとか言い始める。なんだかな…。

ついに半年分のジャンプを全部読み終えたぞお。長かった。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 3日

母はコンピュータ関連の話に理解があるので、ルータや無線 LAN 環境の購入許可がさらっと得られました。おかげで実家のネットワーク環境がかなり充実しております。
今日も、妹の転入届を出しに札幌市北区役所へ行くついでに、ベスト電器で無線 LAN ルータを買ってきました。これできしめんみたいな LAN ケーブルとおさらばです。

さらに聞いたら ADSL を 1.5Mbps タイプから 8Mbps タイプに(4〜5Mbps しか出ないかも?)する許可も得られたのですが、契約書が見つからなくて契約変更できず。それほど必要性も感じないからまあいいか。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 2日

ゲド戦記を見に行きました。小難しいし、急展開すぎてよくわかんないなあ…。見に行く前に期待しすぎたのかなあ…。

ボクシング WBA ライトフライ級、あの判定は素人目にも贔屓しすぎに映りました。でも負けちゃうと TBS が既に組んである大晦日の防衛戦とか、地元でやる優勝パレードがパアになりますから、大人の事情で勝たせないといかんのよね。
マスコミのいい食い物ってやつでしょうか。願わくば次の防衛戦でボッコボコにされて使い捨て、なんてことにならないことを。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 8月 1日

北海道に帰省しました。ちょっとミスって 6,000円ほど損しました。

昨日、チケットを二回予約してしまったことに気づきました。それも単なる予約じゃなくて、予約時にメールアドレスを間違って入力したせいで、予約確認メールが来ておらず、カードで支払い処理を済ませてしまった状態です。ひじょーに面倒な状態です。
全部お伝えするとクドいので、以下、今日に至るまでの流れ。

解約したい
→ 解約には予約番号が必要
→ 予約番号は予約確認メールに書いてある
→ そもそもメールが来てねー!
→ そんなときはサポートデスク
→ 全然繋がりません、本当にありがとうございました
→ 諦めて寝る
→ 本日、空港に行って聞く
→ 「その便は、もう飛びましたね」
→ 糸冬  了

「もう飛んじゃった」と言われたときは、さ、3万円がー!!とブルー入ったんですが、飛行機って乗り過ごしてもキャンセルできるそうな。手数料は 6,000円(行き先により異なる)と高いけど、3万よりはマシ。まったくつまらんミスで痛い目に遭ったよ。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 7月 31日

ドコモミーティング。10月の目標に向け作業はいよいよ佳境に入るっぽい。頑張る。

TX 秋葉原駅で 1周年のイベントをやっていました。バックアップは国土地理院や産総研で、キログラム原器のレプリカとか、立体地図とか、アザラシロボット「パロ」が居ました。
テーブルに鎮座していたパロその1 の写真です。クリックで拡大します。目が据わってて奇声を発しながらうねうね動く。カワイイやらカワイクないやら、びみょー…。

アザラシロボ、パロ

ちなみに電池切れで、コンセント咥えてるパロその 2 も居ました。これもクリックで拡大します。充電中はピクリともせず、どうみても人工呼吸器付きの瀕死アザラシです。

充電中のパロ

全然脈絡無いですが、明日から 7日まで北海道に里帰りします。帰省すると食事の誘いが多いように感じるのは、きっと気のせいだ。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 7月 30日

最近お出かけが多くて研究のテンションは低め。夜中、明日に向けて資料を作りながら、うとうとー……ああ、もう朝だ。

このサイトにコメント機能をつけられないか、って言われてから考えてたんだけど、やっぱり今のままじゃ無理。何らかのシステムに移行するとしても、今まで書いた文をどうするやら。先の長そう(今後もしばらくメンテされる)で有名な日記システムっていうと何じゃろなー??

ちなみに自分で書くのも一つの勉強だけど、ネットで公開するだけにバグとかセキュリティホールで他人に迷惑かけるリスクを考えると、勇気が要るね。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2006年 7月 29日

園芸の皆さんとひたちなか市の国営ひたち海浜公園へ遊びに行きました。ここは県内でも数カ所しかない、パターゴルフやディスクゴルフを体験できる場所だそうです。

パターゴルフは名前そのままで、パターを使ってミニコースを回っていくものです。初めての割に結構上手くいったように思います。
ディスクゴルフはフリスビーをゴールに投げ入れるゲームです。森と草原のコースがありましたが、Rock in Japan Festival の施設工事のため、草原コースが使えませんでした。残念。
願わくばもう少し涼しい時期に行きたいですね。季節としては秋か晩夏あたりで。

運動の後は風呂!っつーことで常陸太田市の梅里ガーデンアクアビラに行きました。湯船に浸かっていたらやたら汗が口に入ってくるから、熱くもないのにおかしいなー?とか思ってたら、単に温泉がナトリウム泉なだけだった。そらしょっぱいよな。

そのあとカラオケに行って 6人(山下さん歌わないから実質 5人)で 5時間も歌った…。非常に疲れました。

編集者: すずき(更新: 2006年 11月 19日 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2006年 8月 7日 >>> 2006年 7月 29日
link もっと後

管理用メニュー

link 記事を新規作成

<2006>
<<<08>>>
--12345
6789101112
13141516171819
20212223242526
2728293031--

最近のコメント 5件

  • link 23年01月06日
    すずき 「ありがとうございます。アップデートとかセ...」
    (更新:01/24 23:19)
  • link 23年01月06日
    カナやん 「あまり褒められた方法じゃないですが、Am...」
    (更新:01/24 21:37)
  • link 22年10月10日
    すずき 「ああー、懐かしいですね。いきなりWind...」
    (更新:10/12 00:51)
  • link 22年10月10日
    hdk 「いつ頃だったかのMicrosoft Of...」
    (更新:10/11 20:31)
  • link 22年09月19日
    すずき 「それもありますね。さらに調べていたら今回...」
    (更新:09/26 11:51)

最近の記事 3件

  • link 23年03月10日
    すずき 「[誕生日] ついに 40歳の大台(?)に乗りました。いわゆる老害と...」
    (更新:03/11 15:06)
  • link 23年03月03日
    すずき 「[Docker のお掃除コマンド] Docker を使っていると要...」
    (更新:03/08 14:52)
  • link 20年01月27日
    すずき 「[クロスビルド用ツールチェーン - GCC 10.0 にしたら] ...」
    (更新:03/06 17:07)
link もっとみる

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 3/11 15:06