mirror of
https://github.com/libretro/RetroArch
synced 2025-04-17 11:43:00 +00:00
Rework FPS measurement.
This commit is contained in:
parent
d80e0df9e9
commit
1df86a722a
36
driver.c
36
driver.c
@ -444,7 +444,7 @@ void init_audio(void)
|
||||
static void compute_audio_buffer_statistics(void)
|
||||
{
|
||||
unsigned samples = min(g_extern.measure_data.buffer_free_samples_count, AUDIO_BUFFER_FREE_SAMPLES_COUNT);
|
||||
if (!samples)
|
||||
if (samples < 2)
|
||||
return;
|
||||
|
||||
uint64_t accum = 0;
|
||||
@ -460,7 +460,7 @@ static void compute_audio_buffer_statistics(void)
|
||||
accum_var += diff * diff;
|
||||
}
|
||||
|
||||
unsigned stddev = (unsigned)sqrtf((float)accum_var / samples);
|
||||
unsigned stddev = (unsigned)sqrt((double)accum_var / (samples - 1));
|
||||
|
||||
float avg_filled = 1.0f - (float)avg / g_extern.audio_data.driver_buffer_size;
|
||||
float deviation = (float)stddev / g_extern.audio_data.driver_buffer_size;
|
||||
@ -487,27 +487,35 @@ static void compute_audio_buffer_statistics(void)
|
||||
|
||||
static void compute_monitor_fps_statistics(void)
|
||||
{
|
||||
unsigned samples = min(g_extern.measure_data.fps_samples_count, MEASURE_FPS_SAMPLES_COUNT);
|
||||
if (!samples)
|
||||
unsigned samples = min(g_extern.measure_data.frame_time_samples_count,
|
||||
MEASURE_FRAME_TIME_SAMPLES_COUNT);
|
||||
|
||||
if (samples < 2)
|
||||
return;
|
||||
|
||||
// Measure statistics on frame time, *not* FPS.
|
||||
double accum = 0.0;
|
||||
// Measure statistics on frame time (microsecs), *not* FPS.
|
||||
rarch_time_t accum = 0;
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
accum += 1.0 / g_extern.measure_data.fps_samples[i];
|
||||
accum += g_extern.measure_data.frame_time_samples[i];
|
||||
|
||||
double avg = accum / samples;
|
||||
double accum_var = 0.0;
|
||||
rarch_time_t avg = accum / samples;
|
||||
rarch_time_t accum_var = 0;
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
{
|
||||
double diff = avg - 1.0 / g_extern.measure_data.fps_samples[i];
|
||||
rarch_time_t diff = avg - g_extern.measure_data.frame_time_samples[i];
|
||||
accum_var += diff * diff;
|
||||
}
|
||||
|
||||
double stddev = sqrt(accum_var / samples);
|
||||
double stddev = sqrt((double)accum_var / (samples - 1));
|
||||
double avg_fps = 1000000.0 / avg;
|
||||
double max_stddev_fps = 1000000.0 / (avg - stddev);
|
||||
double stddev_fps = max_stddev_fps - avg_fps;
|
||||
double sigma_deviation = (g_settings.video.refresh_rate - avg_fps) / stddev_fps;
|
||||
|
||||
RARCH_LOG("Average monitor FPS: %.6f FPS. Standard deviation: %.6f FPS.\n",
|
||||
1.0 / avg, 1.0 / (avg - stddev) - 1.0 / avg);
|
||||
RARCH_LOG("Average monitor Hz: %.6f Hz. Standard deviation: %.6f Hz (%.3f %% deviation, based on %u last samples).\n",
|
||||
avg_fps, stddev_fps, 100.0 * stddev_fps / avg_fps, samples);
|
||||
RARCH_LOG("Configured monitor FPS %.6f Hz deviates %.3f sigma from average.\n",
|
||||
g_settings.video.refresh_rate, sigma_deviation);
|
||||
}
|
||||
|
||||
void uninit_audio(void)
|
||||
@ -837,7 +845,7 @@ void init_video_input(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
g_extern.measure_data.fps_samples_count = 0;
|
||||
g_extern.measure_data.frame_time_samples_count = 0;
|
||||
}
|
||||
|
||||
void uninit_video_input(void)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "cheats.h"
|
||||
#include "audio/ext/rarch_dsp.h"
|
||||
#include "compat/strl.h"
|
||||
#include "performance.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -412,9 +413,9 @@ struct global
|
||||
unsigned buffer_free_samples[AUDIO_BUFFER_FREE_SAMPLES_COUNT];
|
||||
uint64_t buffer_free_samples_count;
|
||||
|
||||
#define MEASURE_FPS_SAMPLES_COUNT (8 * 1024)
|
||||
float fps_samples[MEASURE_FPS_SAMPLES_COUNT];
|
||||
uint64_t fps_samples_count;
|
||||
#define MEASURE_FRAME_TIME_SAMPLES_COUNT 256
|
||||
rarch_time_t frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT];
|
||||
uint64_t frame_time_samples_count;
|
||||
} measure_data;
|
||||
|
||||
struct
|
||||
|
@ -14,94 +14,37 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#pragma comment(lib, "winmm")
|
||||
#endif
|
||||
|
||||
#include "gfx_common.h"
|
||||
#include "../general.h"
|
||||
#include "../performance.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#ifndef _XBOX
|
||||
#include <winsock2.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__PSL1GHT__)
|
||||
#include <sys/time.h>
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <sys/sys_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(_MSC_VER) || defined(GEKKO)
|
||||
static int gettimeofday2(struct timeval *val, void *dummy)
|
||||
static float time_to_fps(rarch_time_t last_time, rarch_time_t new_time, int frames)
|
||||
{
|
||||
(void)dummy;
|
||||
#if defined(_MSC_VER) && !defined(_XBOX360)
|
||||
DWORD msec = timeGetTime();
|
||||
#elif defined(_XBOX360)
|
||||
DWORD msec = GetTickCount();
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
uint64_t usec = sys_time_get_system_time();
|
||||
#elif defined(GEKKO)
|
||||
uint64_t usec = ticks_to_microsecs(gettime());
|
||||
#else
|
||||
uint64_t usec = msec * 1000;
|
||||
#endif
|
||||
|
||||
val->tv_sec = usec / 1000000;
|
||||
val->tv_usec = usec % 1000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GEKKO has gettimeofday, but it's not accurate enough for calculating FPS, so hack around it
|
||||
#define gettimeofday gettimeofday2
|
||||
#endif
|
||||
|
||||
static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, int frames)
|
||||
{
|
||||
float time = new_tv->tv_sec - tv->tv_sec + (new_tv->tv_usec - tv->tv_usec) / 1000000.0;
|
||||
return frames/time;
|
||||
return (1000000.0f * frames) / (new_time - last_time);
|
||||
}
|
||||
|
||||
bool gfx_get_fps(char *buf, size_t size, bool always_write)
|
||||
{
|
||||
static struct timeval tv;
|
||||
static rarch_time_t time;
|
||||
static float last_fps;
|
||||
struct timeval new_tv;
|
||||
bool ret = false;
|
||||
|
||||
if (g_extern.frame_count == 0)
|
||||
{
|
||||
gettimeofday(&tv, NULL);
|
||||
time = rarch_get_time_usec();
|
||||
snprintf(buf, size, "%s", g_extern.title_buf);
|
||||
ret = true;
|
||||
}
|
||||
else if ((g_extern.frame_count % 180) == 0)
|
||||
{
|
||||
gettimeofday(&new_tv, NULL);
|
||||
struct timeval tmp_tv = tv;
|
||||
tv = new_tv;
|
||||
rarch_time_t new_time = rarch_get_time_usec();
|
||||
last_fps = time_to_fps(time, new_time, 180);
|
||||
|
||||
last_fps = tv_to_fps(&tmp_tv, &new_tv, 180);
|
||||
unsigned write_index = g_extern.measure_data.frame_time_samples_count++ &
|
||||
(MEASURE_FRAME_TIME_SAMPLES_COUNT - 1);
|
||||
g_extern.measure_data.frame_time_samples[write_index] = (new_time - time) / 180;
|
||||
|
||||
unsigned write_index = g_extern.measure_data.fps_samples_count++ & (MEASURE_FPS_SAMPLES_COUNT - 1);
|
||||
g_extern.measure_data.fps_samples[write_index] = last_fps;
|
||||
time = new_time;
|
||||
|
||||
#ifdef RARCH_CONSOLE
|
||||
snprintf(buf, size, "FPS: %6.1f || Frames: %d", last_fps, g_extern.frame_count);
|
||||
@ -138,7 +81,10 @@ static dylib_t dwmlib = NULL;
|
||||
static void gfx_dwm_shutdown(void)
|
||||
{
|
||||
if (dwmlib)
|
||||
{
|
||||
dylib_close(dwmlib);
|
||||
dwmlib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_dwm(void)
|
||||
|
@ -15,24 +15,50 @@
|
||||
*/
|
||||
|
||||
#include "performance.h"
|
||||
#include "general.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#pragma comment(lib, "winmm")
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "android/native/jni/cpufeatures.h"
|
||||
#endif
|
||||
|
||||
#ifdef PERF_TEST
|
||||
#if !defined(_WIN32) && !defined(RARCH_CONSOLE)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__) || defined(GEKKO)
|
||||
#ifndef _PPU_INTRINSICS_H
|
||||
#include <ppu_intrinsics.h>
|
||||
#endif
|
||||
#elif defined(_WIN32) && !defined(_XBOX)
|
||||
#include <mmsystem.h>
|
||||
#elif defined(_XBOX360)
|
||||
#include <PPCIntrinsics.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/time.h>
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID)
|
||||
// POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present.
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__PSL1GHT__)
|
||||
#include <sys/time.h>
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <sys/sys_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
#endif
|
||||
|
||||
// OSX specific. OSX lacks clock_gettime().
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#ifdef PERF_TEST
|
||||
#define MAX_COUNTERS 64
|
||||
static struct rarch_perf_counter *perf_counters[MAX_COUNTERS];
|
||||
static unsigned perf_ptr;
|
||||
@ -82,7 +108,7 @@ rarch_perf_tick_t rarch_get_perf_counter(void)
|
||||
time = (rarch_perf_tick_t)a | ((rarch_perf_tick_t)d << 32);
|
||||
#endif
|
||||
|
||||
#elif defined(__ARM_ARCH_6__) || defined(ANDROID)
|
||||
#elif defined(__ARM_ARCH_6__)
|
||||
asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time) );
|
||||
#elif defined(__CELLOS_LV2__) || defined(GEKKO) || defined(_XBOX360)
|
||||
time = __mftb();
|
||||
@ -92,6 +118,33 @@ rarch_perf_tick_t rarch_get_perf_counter(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
rarch_time_t rarch_get_time_usec(void)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX360)
|
||||
return timeGetTime() * INT64_C(1000); // FIXME: Need more accurate measurement, i.e. QueryPerformanceCounter.
|
||||
#elif defined(_XBOX360)
|
||||
return GetTickCount() * INT64_C(1000); // FIXME: Need more accurate measurement.
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return sys_time_get_system_time();
|
||||
#elif defined(GEKKO)
|
||||
return ticks_to_microsecs(gettime());
|
||||
#elif defined(__MACH__) // OSX doesn't have clock_gettime ...
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
return mts.tv_sec * INT64_C(1000000) + mts.tv_nsec / 1000;
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID)
|
||||
struct timespec tv;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||
return 0;
|
||||
return tv.tv_sec * INT64_C(1000000) + tv.tv_nsec / 1000;
|
||||
#else
|
||||
#error "Your platform does not have a timer function implemented in rarch_get_time_usec(). Cannot continue."
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__)
|
||||
#define CPU_X86
|
||||
#endif
|
||||
|
@ -17,14 +17,14 @@
|
||||
#ifndef _RARCH_PERF_H
|
||||
#define _RARCH_PERF_H
|
||||
|
||||
#include "general.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "boolean.h"
|
||||
#include <stdint.h>
|
||||
typedef unsigned long long rarch_perf_tick_t;
|
||||
typedef int64_t rarch_time_t;
|
||||
|
||||
typedef struct rarch_perf_counter
|
||||
{
|
||||
@ -37,6 +37,7 @@ typedef struct rarch_perf_counter
|
||||
} rarch_perf_counter_t;
|
||||
|
||||
rarch_perf_tick_t rarch_get_perf_counter(void);
|
||||
rarch_time_t rarch_get_time_usec(void);
|
||||
void rarch_perf_register(struct rarch_perf_counter *perf);
|
||||
void rarch_perf_log(void);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user