UWSCのループ速度と時間取得精度について

UWSCのループは三種類。
同じ回数のループでどれだけ早さが違うかと、時刻取得APIの精度を検証してみた。

修正 2015/06/11
時刻取得に1msec精度が必要ならAPIコールをすること。ただしGETTIMEの方が早い。

手元の環境では

  • ループは、Forが最も早い
  • 時刻取得はGETTIMEが推奨(15msec程度の精度)だが、1msec精度が欲しいならAPIコールすべし

検証に使ったスクリプト

OPTION EXPLICIT

// timeGetTimeは1ms、GetTickCountは5msの精度らしいですが、、、
DEF_DLL timeGetTime(): LONG: winmm
DEF_DLL timeBeginPeriod(DWORD): LONG: winmm
DEF_DLL timeEndPeriod(DWORD): LONG: winmm
DEF_DLL GetTickCount(): LONG: kernel32

PUBLIC num[10000], i, m = LENGTH(num)

PRINT timeBeginPeriod(1)
SLEEP(0.5)	// timeBeginPeriodを反映するのに少し時間が必要。多分500msecもいらいないけど
PRINT "<#CR>timeGetTime"
FOR i = 0 TO m - 1
	num[i] = timeGetTime()
NEXT
PrintResult()
PRINT timeEndPeriod(1)
// 1msecの変化が拾える。100ループ前後で値が変わる。1万ループで103〜105msec

PRINT "<#CR>GetTickCount"
FOR i = 0 TO m - 1
	num[i] = GetTickCount()
NEXT
PrintResult()
// 15ないし16msecの変化しか拾えない。1500ループ前後で値が変わる。1万ループで94〜109msec

PRINT "<#CR>GetTime"
FOR i = 0 TO m - 1
	num[i] = GetTime() * 1000 + G_TIME_ZZ
NEXT
PrintResult()
// 15ないし16msecの変化しか拾えない。1750ループ前後で値が変わる。1万ループで78〜94msec

PRINT "<#CR>While"
i = 0
WHILE i < m
	num[i] = GetTime() * 1000 + G_TIME_ZZ
	i = i + 1
WEND
PrintResult()
// 1200ループ弱で値が変わる。1万ループで125〜141msec

PRINT "<#CR>Repeat"
i = 0
REPEAT
	num[i] = GetTime() * 1000 + G_TIME_ZZ
	i = i + 1
UNTIL i >= m
PrintResult()
// 1200ループ弱で値が変わる。1万ループで125〜140msec

PRINT "<#CR>Recursive"
Recursive(700)
PrintResult()
// 1000も再帰はできない(落ちる)


PROCEDURE PrintResult()
	PRINT "0 " + num[0]
	FOR i = 1 TO m - 1
		IF num[i] <> num[i - 1] THEN PRINT i + " " + num[i]
	NEXT
	PRINT "res " + (num[m - 1] - num[0])
FEND

PROCEDURE Recursive(n)
	num[n] = GetTime() * 1000 + G_TIME_ZZ
	IF n > 0 THEN Recursive(n - 1)
FEND

単純に全力ループして、num配列にミリ秒単位の値を入れるだけ。
PrintResultは、値の変わった時と末尾-先頭を出すので、
たくさんPrintされる方が、時刻取得精度が良く、差分が小さい方がループが早い。
再帰は都合により逆順なのと、末尾が未取得なので、差分はあてにならない。

結論

APIのGetTickCountを呼ぶ価値はない。UWSCのGETTIMEと精度は同じ。
APIのtimeGetTimeは、timeBeginPeriod/timeEndPeriodを使うのなら、1msec精度で取れる。
FORはWHILE/REPEATの1.5倍速い。
再帰は800くらい積むとアウト。