コグノスケ


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

link もっと前
2006年8月7日 >>> 2006年7月25日
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↓
・
・

値の変化が1msであることがわかると思います。

おまけ

昔書いたメモを発掘したので、これも供養しておきます。

QueryPerformanceCounter() とQueryPerformanceFrequency() の使い方

LARGE_INTEGER freq;
LARGE_INTEGER st, ed;

QueryPerformanceFrequency(&freq);

QueryPerformanceCounter(&st);
Sleep(100);
QueryPerformanceCounter(&ed);

簡単なAPIではありますが、動作チェックはしていませんのでご注意ください。

編集者:すずき(2023/07/08 22:09)

コメント一覧

  • コメントはありません。
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 この記事にコメントする



2006年7月28日

エンジンオイル交換に行ってきました。オイル交換って簡単そうですが「オイルの缶&4Lの廃油処理が面倒だ。」とか「下手に持ち上げて作業中に車が落ちたら死んじゃう。」など、やりたくない要素満載です。
それに加えて新筑波モータースは、工賃サービスなので、自分でやるメリットはゼロ。

オイルといえば、昔はリッター2000円とか3000円のエンジンオイルに目を引かれたもんです。でも私はちょっとしたオイルの質の違いがわかるほど通でもないですし、街乗りしかしないので、単なる贅沢になってしまいます。お財布にも車にも安いオイルが一番です。

ドラミの声優が千秋に変わるらしい。こうしてどんどんドラえもんが暴走していく、ショックだなあ。

編集者:すずき(2006/11/19 16:16)

コメント一覧

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



2006年7月27日

日光旅行3日目。
ポンテ(ガラス工房)で、ガラス吹きを体験しました。ガラスと聞くと難しそうですが、ほとんど職人さんが作ってくれますのでまず失敗しません。頑張って吹いたら「そんなに強く吹かなくて良いですよ」って言われた。ガラスって意外に軽く膨らむんですね。
作品は後ほど宅配便で届くそうです。

霧降高原有料道路(930円、意外と高い)で、霧降高原を駆け上ります。途中のキスゲ平でリフトに乗り、ハイキングして駐車場まで戻りました。雲が厚くてあまり景色が良くなかったのが残念です。

有料道路の終点にある大笹牧場で一休みして、復路は東側の一般道路(けっこう細いので注意)で下って、一気に帰宅しました。
大笹牧場の伊藤園の自販機がお茶を強調しすぎ…つーか全部お茶かよ!!(写真、クリックで拡大)中谷美紀の「これがお茶」というポスターもこの自販機なら説得力がある。

商品全部お茶の自販機

いろは坂を二往復(実は1日目も登った)したわりに、燃費は11km/Lと意外に好調でした。最近遠出続きで、結構走ったし、土曜に備えて明日はオイル交換かな。

編集者:すずき(2006/11/19 16:16)

コメント一覧

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



2006年7月26日

日光旅行2日目。
ペンションで朝食、いろは坂を登って中禅寺湖で遊覧船に乗りました。景色が最高に良くて、この季節なのに涼しいのが最高!

昼を定食屋で済ませて、華厳の滝に向かいました。エレベータ(有料、530円)に乗って滝の近くまで。連日の雨の影響で増水しているらしく、観瀑台まで激しい水しぶきが襲ってきます。おかげで服も頭もびしょ濡れです…夏だからこれもまたいいかな。写真は華厳の滝です。クリックで拡大します。

華厳の滝、遠景

その後、湖畔の土産を見て回り、風呂は日光アストリアホテルの温泉(湯本温泉かけ流し、硫黄泉質)に日帰り入浴しました。温泉もさることながら、ホテルの周りに広がる静寂が実に良い雰囲気でした。今度はこのホテルに泊まってみたい…。

ペンションに戻って夕ご飯をいただいて、明日のロングドライブに備えて就寝しました。
ああ、そうそう、このペンションは以前園芸で来たヴィラ・リバージュのすぐそばです。このあたりが、山の上へも下へも一番アクセスが良いですよね。

編集者:すずき(2006/11/19 16:16)

コメント一覧

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



2006年7月25日

日光旅行1日目。
まずは車で日光まで。宇都宮がやや混んでいましたが、日光宇都宮道路(宇都宮IC〜日光IC 450円)に乗ってしまえばあとはスイスイ日光へ。

とりあえずこの旅行の目的(大下さんの)である、日光山輪王寺日光東照宮二荒山神社、輪王寺大猷院の順に、全部制覇しました。
料金が1,000円(二社一寺拝観券)です。東照宮の眠り猫(520円)と宝物館(500円)は別料金です。他も何かあったような気がするけど…まあいいや。写真はクリックで拡大します。

東照宮、五重塔

日光植物園に行きました。植物名を記したプレートが地面のあちこちに刺してあって、名前を調べながら散策できるようになっています。ぐるーっと回って一時間くらいの散歩道です。
公式ページにあるとおり東京大学の付属施設ですが、ろくに調べずに行ったために、料金払ってパンフレット貰ってから「へー?東大だったの!?」なんてさわいでいました。

夕方、サンシャイン・ブルーバード・インにチェックインしました。お得な2泊3食プランなので、今晩の夕ご飯はありません(3食 =1日目なし、2日目の朝食、夕食、3日目の朝食)。飯屋を探しに出ても、みんな18時には閉店、どこも開いていない。
なんとか遅くまで開いてるお好み焼き屋さんを見つけて入りました。店内で近所のおばさんと思しき人と、店主のばーちゃんとの会話が、これぞ田舎の近所づきあいって感じで和みまくった。

夜はペンションの露天風呂に浸かりました。温泉ではないけれどこれは良いわー。
盛りだくさんの一日でした。

編集者:すずき(2006/11/19 16:16)

コメント一覧

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



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

管理用メニュー

link 記事を新規作成

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

最近のコメント5件

  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」
  • link 24年1月24日
    すずきさん (02/13 11:48)
    「ありがとうございます。\n私のPCはもう...」
  • link 24年1月24日
    えはらさん (02/12 15:00)
    「Powershellのスクリプトは以下の...」

最近の記事3件

  • link 24年2月18日
    すずき (02/20 02:54)
    「[JavaとM5Stamp C3とBluetooth LE - ビルド準備編] 目次: ArduinoM5Stamp C3をB...」
  • link 23年6月2日
    すずき (02/20 02:49)
    「[Arduino - まとめリンク] 目次: Arduino一覧が欲しくなったので作りました。 M5Stackとesp32とA...」
  • link 24年2月16日
    すずき (02/20 02:22)
    「[JavaとM5Stamp C3とBluetooth LE - 導入編] 目次: Arduino以前の日記(2024年2月12...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
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 2024年
open/close 過去日記について

その他の情報

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

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 02/20 02:54