C#で1ms以下の計測、そして1000FPSキープ
はじめに
こんにちはこんばんは。繰繰廻(くるくる・めぐる)です。ECSの記事をのんびり書いていたら続き書く前に飽きたので、今回は別の小ネタです。今回Unityで作っているプロジェクトでUDP通信の処理を書く必要が出てきたのですが、通信のスレッドを1000FPSに固定する必要があったので、そこの処理の備忘録です。
失敗したこと
とりあえず「C# 時間計測」でググったら、Stopwatchクラスなるものが出てきた。
Stopwatch クラス (System.Diagnostics)
ので、それを使ってざっくり書いてみた
while (isRunning) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); //処理 sw.Stop(); while ((float)sw.ElapsedMilliseconds < 1.0f) { sw.Start(); sw.Stop(); } }
結果、ダメでした
そりゃそうですよ。Stopwatch.ElapsedMillisecondsの戻り値、long型なんだから、1ms単位のもの測ろうとしてもうまく行きませんでした。
Stopwatch.ElapsedMilliseconds プロパティ (System.Diagnostics)
結局どうしたか
C++で60FPS固定するときに使ったような、CPUの周期で時間測るやつ使いました。
using System.Runtime.InteropServices; public class UDPSender : MonoBehaviour { //1000Hzにするための高精度カウンター [DllImport("kernel32.dll")] extern static int QueryPerformanceCounter(ref long x); [DllImport("kernel32.dll")] extern static int QueryPerformanceFrequency(ref long x); //ここは別スレッド void SendFunc() { long freq, before, after; freq = before = after = 0; QueryPerformanceFrequency(ref freq); while (isRunning) { before = after = 0; QueryPerformanceCounter(ref before); //処理 QueryPerformanceCounter(ref after); while ((after - before) * 1000 / (float)freq < 1.0f) { QueryPerformanceCounter(ref after); } } } }
だいぶざっくりと処理を書きましたがこんな感じ。処理の間に経過したクロック数を測っておいて、それを周波数で割り算すると経過秒が出てきて、それを1000倍することでミリ秒の計測。
そして1ms超えるまでwhileで処理を止めることで1000FPSの完成。
DllImportとかは今回初めて使いました。なんで奥まったところに処理隠されちゃったんだろう。