Реальный счетчик FPS
Материал из Blitz Et Cetera
Почему реальный? А потому, что он считает реальное количество ФПС, а не гипотетическое. Просматривая некоторые исходники, я заметил, что есть определенная тенденция считать предполагаемое, а не фактическое количество кадров. Такой подход, конечно, дает возможность наблюдать значение ФПС сразу после запуска, но нам ведь важно настоящее значение, а не предполагаемое (надеюсь что так).
Кратко о разнице в подходах (назову их расчетным и подсчетным):
- Расчетный: Предполагаемое количество считается исходя из времени обработки кадра. Зная это время, мы можем определить количество кадров, которое у нас получится за больший промежуток.
- Подсчетный: считается тупо подсчетом кадров за отрезок времени.
В чем недостатки расчетного метода: в связи с многозадачностью современных ОС, из-за параллельных процессов время от начала до завершения одного процесса будет разным, даже если выполняться будет одинаковая задача. Из-за этого происходят определенные колебания расчетного значения. Плюс получаемое значение можно отнести только к данному кадру, а для другого кадра, оно будет уже другим, что не дает общей картины производительности. Плюс этого метода один – расчетное значение можно получить уже после первого кадра. Недостаток подсчетного метода в том, что мы можем узнать количество ФПС только после какого-то промежутка времени.
Вот пример с классом счетчика ФПС:
Strict
Local bExit% = False
Const fBaseFPS# = 50
Const cTimeDelta% = 1000/fBaseFPS '1000 - milisec in second / fps
Local fps:TFPSCounter = New TFPSCounter
Global fSpeedMul# = 1;
Graphics800 , 600 , 0 , fBaseFPS
WhileNot bExit
bExit = KeyDown(KEY_ESCAPE) | AppTerminate()
Local startTime = MilliSecs();
fps.start()
DrawScene()
'draw info
DrawText"FPS: " + round(fps.fps,1) , 8 , 8
DrawText"Min/Max: " + round(fps.fps_min,1) +"/" + round(fps.fps_max,1), 100, 8
DrawText"Average: " + round(fps.fps_average,3), 300, 8
'animate scene
UpdateScene()
'fps.finish()
Flip -1 'by Graphics refresh rate
fps.finish()
Wend
Global x#=0, y#=300
Function UpdateScene()
x :+ 0.5 * fSpeedMul
If x > GraphicsWidth() Then x = 0
'Delay(Rand(1,30))
EndFunction
Function DrawScene()
Cls
DrawOval(x,y, 50, 50)
EndFunction
End
Type TFPSCounter
Field _fps_start#
Field _fps_count#
Field _avfps_start#
Field _fps_average_count#
Field fps#
Field fps_average#
Field fps_min# = 1000
Field fps_max# = 0
Method Start()
Local ms# = MilliSecs()
If _fps_start = 0 Then _fps_start = ms
If _avfps_start = 0 Then _avfps_start = ms
EndMethod
Method Finish()
Local millis# = MilliSecs()
Local time# = millis - _fps_start
_fps_count :+ 1
If time > 1000
fps = _fps_count*1000/time
If fps < fps_min Then fps_min = fps
If fps > fps_max Then fps_max = fps
_fps_start = 0
_fps_count = 0
EndIf
_fps_average_count :+ 1
time = millis - _avfps_start
If time > 1000
fps_average = _fps_average_count * 1000 / time
EndIf
EndMethod
EndType
Function Round$(value#, nDecimals%=2)
Local str$ = value
Local pos% = Instr(str , ".")
If nDecimals > 0
str = str[..pos + nDecimals]
Else
str = str[..pos - 1]
EndIf
Return str
EndFunction
Комментарии к коду:
- Можно поиграть с задержкой в UpdateScene.
- Дополнена функция форматированного вывода плавающих чисел Round$.
- И еще внимание на положение вызова метода Finish класса счетчика в коде. Если его поставить там, где он закомментирован (сразу после апдейта сцены), то количество кадров странным образом считается на 1 больше. А дело в том, что если его ставить до синхронизации (Flip -1), то получится, что последний кадр в отрезке времени посчитается до завершения самого отрезка времени. Поэтому надо ставить вызов fps.finish() после синхронизации, чтобы и временные интервалы и количество кадров считались правильно.
Автор: Oxid
|