マルチタスク環境での反応時間測定プログラムについて

長井克己

実験やCAIにおいて,被験者や学生が解答をキー入力するまでの反応時間を測ることがあります。秒単位以下の精度が要求されない場合や,専用に開発されたパッケージ(門田1998等)が利用できれば良いのですが,費用と仕様の制約から,実験者が自分でプログラムせざるを得なくなることが少なくありません。本稿ではWindowsのようなマルチタスク(同時に複数のプログラムが使える)環境下で時間測定プログラムを作成する場合に注意したい点をVisual Basic (VB)を例としていくつか述べます。

Windowsでは全ての仕事や窓に名前を付け,各アプリケーションの処理の割り込みを常時監視しています。仕事の切替やエクスプローラがいつでも最優先(Realtime_Priority_Class)で動かないとOSとして正常に機能しないため,一つのプログラムを単独で走らせることができないのです。その意味ではDISK-BASICやDOSのようなシングルタスクOSの方が望ましいのですが,内部クロックの参照やハードウェアの制御が困難になりますし,周辺機器がWindows以外で動作保証されないことも多くなりました。

最近日本でも主流となっているIBM PC/AT互換機では,ハードウェアのINT 8割り込みで18.2Hzのタイマを使用しますので,直接これを利用すると55ms程度の精度しか得られないことになります。例えばVBのTimer関数は小数点以下の秒数を返しますので1ms単位まで測定できているように錯覚しがちですが,その精度はせいぜい55ms程度であることに注意する必要があります。

ところがWindows API関数のGetTickCountやTimeGetTimeを利用すると約10msで関数が更新され,かなり高精度になります。

Private Declare Function GetTickCount _
  Lib "kernel32" () As Long
というオマジナイと共に

Dim i, j
For i = 1 to 20
  j = GetTickCount
  Do while j = GetTickCount
  Loop
  Print j; "ms"
Next i
のようなプログラムをフォームのクリックで実行してみてください。

さらに,QueryPerformanceCounterという関数を利用することもできます。この関数は桁が多すぎてLong型変数に入らず,通貨型変数Currencyに格納して使います。この関数は秒単位を返しませんので,QueryPerformanceFrequencyで割った値を利用します。他の変数と共に

Private Declare Function QueryPerformanceCounter _
  Lib "kernel32" 
  (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency
  Lib "kernel32" (lpFrequency As Currency) As Long
のように宣言しておきます。0で割らないように注意し,例えば解答のキーを押した時間を測るなら
Sub ProfileStart(secStart As Currency)
  If secFreq = 0 Then _
    QueryPerformanceFrequency secFreq
    QueryPerformanceCounter secStart
End Sub

Sub ProfileStop(secStart As Currency, _
  secTiming As Currency)
    QueryPerformanceCounter secTiming
    If secFreq = 0 Then
      secTiming = 0
    Else
      secTiming = (secTiming - _
      secStart) / secFreq
    End If
End Sub

Private Sub cmdStart_Click() 'スタートボタンを押す
  ProfileStart sec
  i = i + 1
  '音を提示するなら,ここに mciExecute を挿入する
End Sub

Private Sub cmdAns_Click() '解答ボタンを押す
  ProfileStop sec, secOut
    secTime(i, j) = secOut
    j = j + 1
End Sub
のように使えます。ハードウェアにもよりますが,さらに高い精度が得られます。

「速い」ことと「速く感じる」ことは必ずしも同じではありませんが,プログラムの高速化の技法は高精度化のヒントとなります。現在はUnicodeへの移行期ですので今後は不透明ですが,VBの場合は整数型変数Integerが16ビットで処理されるためLong型より遅いと言われます(矢沢1998)。同様の心配が残りますが,ファイルの書き込みが必要な場合はテキストでもバイナリ操作用のPutを使う方がWriteよりも高速だという報告もあります(Craig & Webb 1997)。また,マウスの座標検出は結構時間がかかるようで,反応の取り込みにはキーボードを使った方が安全なようです。画面上のオブジェクトが複雑に配置されている場合,マウスでの入力が目に見えて遅くなり驚いた経験があります。さらに,余計な条件分岐を減らし,エラー処理もカットしてしまいましょう。特にGoSubでいわゆる「スパゲッティプログラム」を作ってしまうと決定的に遅くなるようです(Microsoft 1998)。Learning Editionではネイティブコードのコンパイルができないことや,視覚刺激提示をカラーで行う場合には専用タキストスコープのCRTディスプレイでさえ最小提示時間が10ms程度(ISEL-IS701C)であることにも注意すべきでしょう。

なおWindowsの「DOS窓」と「DOSモード」は全く別物ですし,Windows 3.1はOS自体がMS-DOS上のプログラムで,それぞれ根本的に対策が異なると考えられます。特に3.1でのタイマ使用には注意が必要で,本家Microsoft (1998)も 'In no sense can Microsoft Windows (3.1) be considered a "real-time" system. It is a message-driven, event-polling system, with nonpreemptive scheduling.' と警告しています。市販の実験用ソフトウェアはたとえ3.1対応でも,95以降を使う方が安全かもしれません。

(ながい かつみ・大阪府立農芸高等学校)

参考文献

Craig, J. and Webb, J. 1997. Microsoft Visual Basic 5.0 Developer's Workshop Fourth Edition. Microsoft Press.
McKinney, B. 1998. Hardcore Visual Basic Second Edition. Microsoft Press.
Microsoft Corp. 1998. Microsoft Developers Network. (同社のサイトから)
門田修平1998. 反応時間測定用心理実験ソフト. 『ことばとコミュニケーションVol. 2』 英潮社.
矢沢久雄1998. VBプログラマが知っておくべきハードウェアの基礎. 『日経ソフトウェア』 1998年9月号.
(c) Katsumi NAGAI 1999 : Jump to the top, Centre for Research and Educational Development in Higher Education, and Faculty of Education, Kagawa University, 760-8521 JAPAN