如何高效的评估游戏帧率稳定性:99 percentile FPS
using System.Collections;
using System.Collections.Generic;
using Unity.Profiling;
using UnityEngine;
public class FPSPercentile99 : MonoBehaviour
{
public int FPS3;
public int FPS99;
public void Start()
{
InitFPS99Percentile();
}
public void Update()
{
UpdateFPS99Percentile(Time.deltaTime);
}
public void OnGUI()
{
GUIStyle style = new GUIStyle();
style.fontSize = 50;
style.normal.textColor = Color.white;
GUI.Label(new Rect(10, 10, 100, 30), "FPS3: " + FPS3.ToString(), style);
GUI.Label(new Rect(10, 100, 100, 30), "FPS99: " + FPS99.ToString(), style);
}
#region FPS 99 percentile
private static float _FPS99_INTERVAL = 3.0f;
private static int _FPS99_RINGBUF_SIZE = (int)(2000 * _FPS99_INTERVAL);
private static int _FPS99_MIN_FRAMERATE = 20;
private static int _FPS99_MAX_FRAMERATE = 150;
private static int[] _fps99_ringbuf = new int[_FPS99_RINGBUF_SIZE];
private static float[] _fps99_timestamp = new float[_FPS99_RINGBUF_SIZE];
private static int _fps99_h = 0;
private static int _fps99_t = 0;
private static int[] _fps99_count = new int[200];
private static float _lastTimeStamp = 0f;
void InitFPS99Percentile()
{
for (int i = 0; i < _FPS99_RINGBUF_SIZE; i++)
{
_fps99_ringbuf[i] = 0;
_fps99_timestamp[i] = 0;
}
for (int i = _FPS99_MIN_FRAMERATE; i <= _FPS99_MAX_FRAMERATE; i++)
_fps99_count[i] = 0;
_fps99_h = _fps99_t = 0;
_lastTimeStamp = 0f;
}
private static ProfilerMarker _UpdateFPS99PercentileMarker = new ProfilerMarker("UpdateFPS99Percentile");
void UpdateFPS99Percentile(float deltaTime)
{
using (_UpdateFPS99PercentileMarker.Auto())
{
float tm = Time.realtimeSinceStartup;
while (_fps99_t != _fps99_h && _fps99_timestamp[_fps99_t] < tm - _FPS99_INTERVAL)
{
int last = _fps99_ringbuf[_fps99_t];
last = Mathf.Clamp(last, _FPS99_MIN_FRAMERATE, _FPS99_MAX_FRAMERATE);
_fps99_count[last]--;
_lastTimeStamp = _fps99_timestamp[_fps99_t];
_fps99_t = (_fps99_t + 1) % _FPS99_RINGBUF_SIZE;
}
int fps = (int)Mathf.Round(1.0f / (deltaTime + 0.000001f));
fps = Mathf.Clamp(fps, _FPS99_MIN_FRAMERATE, _FPS99_MAX_FRAMERATE);
_fps99_count[fps]++;
_fps99_ringbuf[_fps99_h] = fps;
_fps99_timestamp[_fps99_h] = tm;
_fps99_h = (_fps99_h + 1) % _FPS99_RINGBUF_SIZE;
int interval_count = (_fps99_h + _FPS99_RINGBUF_SIZE - _fps99_t) % _FPS99_RINGBUF_SIZE;
float interval_tm = tm - _lastTimeStamp;
float avgfps = interval_count / (interval_tm + 0.000001f);
FPS3 = (int)avgfps;
float limit = interval_count * 0.01f;
int low = _FPS99_MIN_FRAMERATE;
int high = _FPS99_MIN_FRAMERATE;
int rank = 0;
for (int i = _FPS99_MIN_FRAMERATE; i <= _FPS99_MAX_FRAMERATE; i++)
{
if (_fps99_count[i] == 0) continue;
if (rank + _fps99_count[i] >= limit)
{
high = i;
break;
}
rank += _fps99_count[i];
low = i;
}
low = rank == 0 ? high : low;
int fps99 = (int)(Mathf.Lerp(low, high, (limit - rank) * (high - low)));
FPS99 = fps99;
}
}
#endregion
}