EasyFAQ/22

Last-modified: 2009-02-10 (火) 00:00:32

極端なFPSの変化について

投稿者tex
重要度
状態
カテゴリ
HSPバージョン2.61/3.1
E3Dバージョン3.0.3.7
回答

ここから下を自由に編集してください。
上の投稿情報は安易に編集するとFAQリストのリストアップに支障が出るものもあります。
よく分からない方は分かる人に聞いてみてください。

  • 極端なFPSの変化について

■何も描画していないのにFPSが極端に低下する挙動のまとめ。

現在わかっている事
(1)瞬間的にFPSが10などの値になる(FPS60時)、平均では半分以下
(2)HSP2.61版でも同様の為、初期からある症状である可能性が高い。
(3)1フレーム単位でまばらに発生するので、見た目に気がつきにくい
(4)Vistaでは瞬間的にタスクバーが(反応無し)となる。

■具体的に描画無しでFPSが不安定になる
サンプルを以下に用意しました

#include "e3dhsp3.as"
E3DInit 0, -1, 0, 16, 0, scid1
FPS=60
repeat
E3DBeginScene scid1
E3DEndScene
E3DWaitByFPS FPS, chkfps1
if (chkfps1>0)&(chkfps1<chkfps2) {chkfps2=chkfps1:Counter++}
if (status\180)=0 {chkfps2=FPS:Counter=0}
status++
E3DPresent scid1
title "FPS="+chkfps1+" FPSmin="+chkfps2+" frame="+status
await 0
loop

例では3秒単位でFPS60時の最小値をタイトルバーに表示させます。
また3秒以内での最小値とフレーム数を表示します

上のソースでは何も描画していないのにFPSが10以下
まで下がる場面があります(極端なケースとして)。

3行目のFPSの値を色々変化させてみると明らか
ですが、おおきくすればするほどFPSの変化値も派手に
なるわけです。

あらためて問題を提起しますが、もっとも問題だと
思っている点は、「なにも描画していないのに」
FPSが急落する点です。

現時点ではEasy3Dの不具合
修正うんぬんを求めると言うものではなく、広く動作状況あるいは
動作報告を記していただき、その中でなんらかの解決策
を模索していこうじゃないか、と言った提案でもあります。

参考までにこれまで検証した環境は
OS:Windows Vista/cpu3gb
mRadeonX1200

OS:Windows XP/cpu2gb
mRadeonX1200

と、わずか2ケースに過ぎません。
また上記の動作状況を検証する為に当方と
同じような制作環境でもありました
トオマ氏のご協力をいただき感謝いたします

tex? 2008-02-19 (火) 11:27:14

  • FPSを3桁に設定すると瞬間的に2桁に下がりますね
    Operating System: Windows XP Home Edition Service Pack 2
    Processor : Intel(R) Celeron(R) CPU 2.40GHz
    Memory : 638MB RAM
    Chip type : GeForce FX 5200
    Display Memory : 128.0 MB -- 26℃? 2008-02-19 (火) 14:59:58
  • 情報ありがとうございます、GeForceの挙動は未知だったのですが、Radeonと似た症状になるようですね、........となると、事態は深刻かもしれませんね。 -- tex? 2008-02-19 (火) 19:41:43
  • 興味深い現象なのでチェックしてみましたが・・・私の環境では起こりません(最初の3秒目だけ24fpsが出るのですが、これは恐らく初期化動作でしょう)
    Athron1400+
    RADEON9600M
    WINDOWS2000
    です。
    OSか、あるいは他の常駐物が原因ではないでしょうか(ハードウェア的には私が一番しょぼいので)
    考えられそうな所を列挙します。
    ○CPUの違い(たぶん私だけAthronでしょうか?)周波数より種類・或いはシングル・デュアル等の情報が欲しい所です。
    →でもおそらく、元々軽い処理なのでこの辺は関係無いような気もします
    ○HSPのawait処理
    →ちょっとイレギュラーですが(終了出来なくなっちゃうので)awaitを抜いて実行してみると結果は変わりませんでしょうか?
    ○GDI(タイトルバーを書き換えてるので、或いはこの処理が時々引っかかるのかもしれません)
    →ただ、サンプルでこうなるってだけみたいなので、これも可能性は低そうな気がします。 -- ぼおん? 2008-02-19 (火) 21:36:01
  • ご協力ありがとうございます。Windows2000/Radeonという事ですが、問題なく動作する環境もあるようですね。提案のawaitを取り払って実行してみましたが、なぜか症状が悪化してしまいました、極端に10fpsから60fpsを交互にくりかえしてしまいます。タイトルバー描画については遅くなる原因のひとつですが、実際に数値をスプライトで描画しても結果は同じものでした。前述のRadeonの2件ですが、Vistaはシングルコア、XPがデュアルコアとなっていますこの2件はCPUがAMD製のものです。ただ、これまでの情報などを考えるとCPUやグラボ環境に共通点も少なく。現在の所はなんらかの原因を特定するのは難しいようです
    常駐物という可能性も残されているので、この辺を中心として調べてみる事にします -- tex? 2008-02-19 (火) 23:19:20
  • 遅レスですいません。こちらでは問題出なかったですよ。ウインドウズXP SP2で、セレロン2.8Gにメモリ256Mです。で、ビデオ機能なんですが、RADEON IGP 345Mってヤツです。チップセット内蔵型ビデオ機能です。全体的に不利なスペックなので、問題出るかな?と思ったんですが、出ないですね。RADEON系では出にくいんでしょうか?いや、ココがポイントだと言い切ってるわけではないですが。 -- pupepo? 2008-02-20 (水) 15:26:49
  • 情報ありがとうございました。XPでも正常に動作している事を
    考えると、冷静に分析すれば、機種固有の常駐物である
    可能性が高い、と考えたほうが良いのかもしれませんね。
    こらちとしても常識的な解決策はほとんど試しているのですが、
    ひとつの策として、

タスクマネージャから全てのユーザープロセスを表示
として、OSの常駐物をタスクからしらみつぶしに
「プロセスの終了」させてみますが、場合によっては例外エラー
の青画面になってしまって、一向に進みませんでした。
この画面がでると再起動しかありませんからね....
消去法でなんとか調べていた所です -- tex? 2008-02-20 (水)

  • すごい探究心ですね!確かに何かの常駐物が関係してそうですね。E3Dは悪くなかったと思っておいていいようですね。ほっ。 -- pupepo? 2008-02-20 (水) 17:56:15
  • Easy3Dが原因でないかだけを調べるなら、Easy3Dを用いないサンプルで確かめれば良いですね。
    因みに、60FPSでは変化なしで、120FPSでたまに60FPSに落ちることが何回かありました。XP Geforce2MX400 64.0MB 512MB RAMです。 -- ジオ? 2008-02-20 (水) 18:50:40
  • ジオさんの環境では最低限60FPSをキープできている
    が一部で極端になるという事のようですね。
    そうですね、提案していただきました
    Easy3D以外の動作状況としては
    d3moduleサンプルにFPSを表示するものがありますが、
    極端な変化は確認できませんでした。
    その他、他言語製ですがFPSを表示する3Dアプリなどを
    検証する限りでは、おなじ結果でした。 -- tex? 2008-02-20 (水)
  • 遅ればせながら動作報告です。
    OS:Win2k sp4
    CPU:Intel(R) Celeron(R) CPU 2.00GHz
    Memory:512 MB RAM
    Chip type:GeForce FX 5700
    Display Memory:128 MB
    FPS=60でframe=2000まで見てみましたが、最低でFPSmin=22でした。FPS=120では27でした。
    FPS値が瞬間的に落ちる現象は結構前から把握はしていたんですが、そういうものだとばかり思ってました。(^ ^;グラフによる視覚化結果。 -- GENKI? 2008-02-20 (水) 21:36:41
  • Genkiさん、情報ありがとうございます。どうやら当方と
    まったく同じ現象のようですね。私の場合はEasy3D+Vistaの
    ウィンドウが一瞬反応無しになる事を詳しく調べていたら、
    この件について気がついたのです、
    確かに指定のグラフ描画プログラムでも極端になってますね。
    FPSになんらかの変化があるのは事実としても
    情報による環境もバラバラですし、
    特定の原因を断定するのは難しそうですね。 -- tex? 2008-02-20 (水)
  • グラフ描画を試させて頂きましたが、やはり明確なフレーム落ちは出ませんでした。う~ん、なんか逆にそっちの方が少数派っぽいですね。
    CPUの違いって事もどうやら無さそうですね(前にPen4とAthronで動作が違ってた事があったんですが)
    Windowsが原因とも云え無そうな感じですし。d3moduleで起こらないとなると、一番ありそうなのはE3DWaitbyFPSの挙動でしょうかね。
    ちょっと可能性は低い気はしますが、可能な限り正確なタイミングを取れるようにawaitをE3DWaitbyFPSの直前に持ってきた場合の動作はどうでしょうか? -- ぼおん? 2008-02-20 (水) 23:37:01
  • 提案ありがとうございました。
    サンプルのあらゆる所にawait 0を
    いれたり、はたまた試してみたのですが、結果は同じでした。
    さらにawait値を大きくする事も試してみたのですが、
    やはり最終的にはFPSmin=20程度まで下がって
    しまいますね。ぼおんさんに提案していただいた
    常駐物の件を調べていたのですが、例外エラー
    が出たりしてうまく進展しませんでした。 -- tex? 2008-02-20 (水)
  • FPSが不安定になる件は、E3DWaitByFPSに原因があるように思います。ためしにawaitとE3DGetFPSを組み合わせて使ってみたところ、(E3DWaitByFPSは使わないで)FPSは安定していました。E3DWaitByFPSはCPU使用率が下がるようにする処理が入っているのでそこの部分の問題かと思われます。正確にしたい場合はawaitを使ってください。 -- おちゃっこ? 2008-02-21 (木) 12:44:45
  • 回答ありがとうございました。
    この問題は致命的な問題
    だとは思いませんが、今後作られるであろうはずの
    Easy3D製ゲーム全体のクオリティに少なからず
    関係する問題ですので、提示させていただきました。
    原因についてはおちゃっこさんの見解のとおり、
    WaitByFPSの内部の処理にありそう、という事で、
    一応の結論を確定する事ができました。
    ご協力いただきました皆様ありがとうございました。 -- tex? 2008-02-21 (木) 19:00:00
  • とりあえずの解決策として
    *main
    await 15
    if gettime(7)<msec {
    fps=_frame
    _frame=1
    } else {_frame++}
    msec=gettime(7)
    title "FPS="+FPS+" frame="+_frame
    goto *main
    WaitByFPSは使わずに
    await 15、と書き換えるとFPS60を維持できる
    ようですが... -- tex? 2008-03-03 (木) 14:00:00

awaitでは無理があるようなので

月影ともさん、がブログ内で公開されているモジュール
を紹介させてください。

この仕組みはAPIのGetTimeGetで測定して
これまたAPIのSleep関数でウェイトを行うものです。

この使用方法はモジュールを利用して
mainの一番最初にサンプル部をコピペする事で
導入できます。

http://tu-sa.net/0582 -- tex? 2008-10-31 (fri) 22:00:00

モジュールの導入方法

説明が曖昧だったかもしれませんので、
補足させていただきます。

/* mod_autoFPS.hsp */
// 自動 フレームスキップ モジュール v0.01 / 月影とも
#addition "mod_qpc.hsp"
#module mod_AutoFPS
#uselib "kernel32.dll"
#func Sleep "Sleep" int
#uselib "winmm.dll"
#ifdef timeGetTimeDouble
#define timeGetTime timeGetTimeDouble
#else
#cfunc timeGetTime "timeGetTime"
#endif
#define CurrentTime (1.0*timeGetTime@mod_AutoFPS())
#func timeBeginPeriod "timeBeginPeriod" int
#deffunc autoFps_SetFPS int fps
if StartTime == 0 : StartTime = CurrentTime
SampleCount = fps*3
FrameWait = 1000.0/fps
NextDrawTime = CurrentTime + FrameWait
dimtype LapTime, vartype("double"), 1
DrawnFrames = 0
LastDrawStart = CurrentTime
return
#deffunc autoFps_StartInternal
if CurrentTime < NextDrawTime  : Sleep 1 : return 1
NextDrawTime += FrameWait : StartInternalTime = CurrentTime
return 0
#deffunc autoFps_StartDraw
CallCount++
if /* CallCount\8=0 | */ NextDrawTime>CurrentTime {
LapTime(DrawnFrames\SampleCount) = CurrentTime - LastDrawStart
LastDrawStart = CurrentTime
DrawnFrames++
return 0
}
return 1
#define global autoFps_CurrentFps _autoFps_CurrentFps()
#defcfunc _autoFps_CurrentFps
t = 0.0
repeat Length(LapTime)
t+=LapTime.cnt
loop
return 1000.0/t*length(LapTime)
#define global autoFps_mmtimer (CurrentTime@mod_autoFps-StartTime@mod_autoFps)
#global

上記ルーチンをモジュールとして保存するか、記述形式として
取り込みます。e3dhsp3.asをincludeする前で良いでしょう。

次に

autoFps_SetFPS 60 // 引数: 理想FPS値

を初期化位置に記述しておくことも忘れずに。

await 0
InternalCounter1++
autoFps_StartInternal
if stat : goto *main
InternalCounter2++
autoFps_StartDraw
if stat : goto *main
DrawnCounter++

上記がwaitbyfpsを代行する部分で、これをmainの直後に
記述します。当然ながら元にあったwaitbyfpsの記述は削除しておきます。
この導入により、従来から気になっていた「動作がひっかかる
ような描画」の挙動がなくなり、スムーズになります。
またVISTAにあった不具合の、{フリーズ}も解消されるはずです。

参照元:
つーさのくーかん
http:tu-sa.net
tex? 2008-11-2 (sun) 19:00:00

  • もしよろしければご協力ください。awaitの挙動なんですが
	;origin HSPサンプル蔵(日付・時間操作編)http://hspnext.com/hspkura/hspkura07.htm
	;***** 処理時間の計測 (microtime.hsp) *****
	;▼必要となるAPIや定数の定義
	#uselib "kernel32"
	#func QueryPFreq "QueryPerformanceFrequency" var
	#func QueryPCount "QueryPerformanceCounter" var
	#func global Sleep "Sleep" sptr
	dim lgint,4  ;LARGE_INTEGER構造体
	#define _start QueryPFreq nFreq : QueryPCount nBefore
	#define _goal  QueryPCount lgint(2) : dwTime=strf("%%.3fmSec",1000.*(lgint(2)-nBefore)/nFreq)
	_start  ;計測開始
	repeat 1000
		await 1
	loop
	_goal   ;計測終了
	resultawait = "await 1 * 1000 = " + dwTime  ;dialog命令を利用する場合
	_start  ;計測開始
	repeat 1000
		sleep 1
	loop
	_goal   ;計測終了
	resultsleep = "sleep 1 * 1000 = " + dwTime  ;dialog命令を利用する場合
	dialog resultawait + "\n" + resultsleep
	;両方とも『1msを1000回』のはずなんですが・・・。
	stop
  • これを実行してみて、awaitとsleepどちらも1000に近い数値が出ますでしょうか?私の環境ではawaitの方はでたらめな感じなんですが(10秒くらいかかりますし)
    await 1 * 1000 = 10007.301mSec
    sleep 1 * 1000 = 1004.159mSec
    (Win2K+Athron1400)
    たぶんawaitってHSP内部でsleepを呼んでるだけだと思うんですが、この差は一体なんなのでしょう。何かオーバーヘッドがあるのか、それとも私の環境だけなのでしょうか。
    -- [[ぼおん]] &new{2008-12-04 (木) 00:07:04};
  • WinXP HSP3.2B1。
    await 1 * 1000 = -1084.001mSec
    sleep 1 * 1000 = -1100.817mSec
    #uselib "winmm.dll"と#cfunc timeGetTime "timeGetTime"で計ったら、どちらも15625でした。因みに、repeat 1000のwait 1でも15625でした。 -- ジオ? 2008-12-04 (木) 10:47:45
  • ぼおんさんの言うようにHSPのawaitは
    実質的にSleepを呼んでいるのかもしれませんね。ただ以前からawait関数(Sleepの事はとりあえず除く)には
    何らかの問題があるとおもっていました、
    前述した月影さんのモジュールのような、
    工夫が必要かもしれません。サンプルですが
    Repeat~LoopにSleepが含まれているので、内部的な
    解釈が変わっていると思うのです。この場合は
    Sleep 1000
    にすれば意図どおりになるかと (^^; -- tex? 2008-12-04 (木) 18:30:00
  • >ジオ様
    マイナスの数値が出ましたか!それはちょっと意外でした。
    私もネットブックで試してみたらどちらも10秒以上かかってしまったので、どうやら2000とXpで異なる挙動がありそうですね。
    >tex様
    1000回でなく、await 1の長さを測ってもかなりバラつきが出るので、なんか変わった事してるのかもしれませんねawait。
    >Sleep 1000
    あ~すみません目的がQueryPerformanceCounter使った高精度なE3Dサンプルのwaitbyfps互換モジュールを作る事だったので(最初に書いとくべきでしたね)月影様のモジュールに手を入れるのも気がひけたので
    でも確かにsleep 1000やawait 1000なら意図通りの結果が出ますね。小さい値を複数回、に問題があるんでしょうかね~。
    しかしawaitとsleepで動作が違っててひっくりコケたんですが、ジオ様の結果で負の値が出ててまたひっくりコケました(笑)事前に教えて頂いて大変助かりましたありがとうございます~! -- ぼおん? 2008-12-04 (木) 21:21:56
  • awaitはおそらくHSP側の関数部分に何かの
    単純な問題があるんじゃないだろうか、と推測してます。
    月影さんのモジュールは使用にあたっての許可は必要ありませんが
    ぼおんさんの所のwaitbyfps代行モジュールにも期待させていただきますよ(笑)-- tex? 2008-12-04 (木) 22:30:00
  • という訳で作ってみました(笑)awaitは結局入れないとダメっぽいです(sleep1でループしてたらキー入力を受け付けなくなりました・・・)
    http://born2b.up.seesaa.net/image/waitbyfps.zip
    検証用にtex様謹製のサンプル(このページの上の方にある奴ですね)を改変したものを添付させて頂きました。
    これでもやはりFPSminがヘコんでしまう事はあるんですが、次のフレームで遅れを取り戻すようにしてあるので、数フレーム単位で見れば理屈上、速度をキープ出来てるはずなんですが、どうでしょうか。 -- ぼおん? 2008-12-05 (金) 22:58:31
  • ぼおんさんモジュールの作成お疲れ様です。
    試してみたところ正確にfpsがキープできているようです。
    SleepをRepeatで使えるとは思ってませんでしたが;。
    月影さんのと比較してみましたが遜色の無い動作で満足できました。-- tex? 2008-12-06 (土) 00:30:00
  • 動作確認ありがとうございます~!
    速度の維持と同時に、フレームスキップも組み込みたかったんですよね。3Dの場合、描画と命中判定を完全に切り離すのは難しいので・・・では大丈夫そうなのでここのサンプルリンクにもアップしときます(件のサンプルも同梱させて頂きますね) -- ぼおん? 2008-12-06 (土) 01:09:38
  • 亀ですがたまたま見かけたので補足しておきます。awaitの内部実装はSleepではなくTimerっぽいので、そのまま使うと、Win2Kで10ms、Win9xでは55ms(!)程度の精度しか期待できません。ゲームの空き時間つぶしにはまったく使えないのです。ただ、その内部でウィンドウメッセージの処理を行っているため、awaitを呼ばないと、キー入力を受け付けないどころか窓が固まってしまうので待ち時間0で呼んでやる必要があるとだけ。 -- 月影とも? 2009-02-04 (水) 03:20:52
  • 月影さんコメントありがとうございました。
    お作りになったモジュールをここに転載させていただきました。
    おっしゃるとおりawaitの不具合はバグではなくて
    仕様という結論でまとめさせていただきます。
    本題のEasy3DWAITByFPSのほうは不具合が残ったままですが、
    このFPSモジュールが役立ちました。 -- tex? &new([nodate]){date}: Invalid date string;
  • 月影ともさんのモジュールの方法ですが、FPSの数値を表示させるにはどうすればいいでしょうか。InternalCounter1 InternalCounter2 DrawnCounterで計算できるんですか? -- 26℃? 2009-02-08 (日) 04:19:12
  • その解説が抜けてましたね;。FPS値の取得はautoFps_CurrentFpsみたいです [tip] -- tex? 2009-02-08 (日) 18:50:09
  • ms="FPS="+autoFps_CurrentFps:E3DDrawText 10,130,1.0,255,255,255,msという具合で^^ -- tex? 2009-02-08 (日) 18:55:00
  • ありがとうございます、無事ひょうじできました。 -- 26℃? 2009-02-08 (日) 20:40:31
  • FPS60ならはっきり判るのですが、
    ブレのないカメラ回転に感動しませんか? (^^;)(ちょっとおおげさかな?) -- tex? 2009-02-09 (日) 01:00:00
  • 月影ともさんのFPSモジュールを使っていて、2度目の現象なんですが とつぜん停止します、3Dのブルー画面の前、白画面で停止し。パソコンを再起動するまで、そのモジュールを使えなくなるんですよね。  -- 26℃? 2009-02-09 (月) 20:55:19
  • 硬直しましたか、なるほどわかりました、うろおぼえですが30行目を。
    if (CallCount\8=0)|( NextDrawTime>CurrentTime) {
    としてみた場合、挙動はかわりますか?  -- tex? 2009-02-09 (月) 21:55:00
  • (CallCount\8=0)、コメントアウトされてた部分ですね、コメントアウトを除いたら無事動きました。 -- 26℃? 2009-02-09 (月) 22:10:58
  • 了解です、また不具合がでたら報告おねがいします -- tex? 2009-02-10 (火) 00:00:32