Performance monitoring

This commit is contained in:
JackCarterSmith 2024-09-16 23:14:06 +02:00
parent 86c0be9dbb
commit de3e842425
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
9 changed files with 185 additions and 30 deletions

View File

@ -1,4 +1,8 @@
#include "DebugUI.hpp"
#include <sstream>
#include <iomanip>
#include "../Misc/Fonts.hpp"
@ -10,7 +14,22 @@ DebugUI::DebugUI() {
gDbgText.setFillColor(sf::Color::White);
}
void DebugUI::UpdateDebugData(std::shared_ptr<sf::RenderWindow> context) {
gDbgText.setString("CPU Usage: XXX.X % (ticks: XXXX.X ms)\nFPS: XXX\nRAM Usage: XXXX.X MB");
void DebugUI::UpdateDebugData(const double cpu_usage, const double loop_time, const int fps, const std::size_t ram_virt_usage, const std::size_t ram_phys_usage) {
gDbgStats.cpu_usage = cpu_usage;
gDbgStats.loop_time = loop_time;
gDbgStats.fps = fps;
gDbgStats.ram_virt_usage = ram_virt_usage;
gDbgStats.ram_phys_usage = ram_phys_usage;
}
void DebugUI::DrawDebugData(std::shared_ptr<sf::RenderWindow> context) {
std::ostringstream outStrStream;
outStrStream << std::fixed;
outStrStream << std::setprecision(0) << "CPU Usage: " << gDbgStats.cpu_usage << " % (cycle: " << std::setprecision(1) << gDbgStats.loop_time << " ms)" << std::endl;
outStrStream << std::setprecision(0) << "FPS: " << gDbgStats.fps << std::endl;
outStrStream << std::setprecision(1) << "RAM Usage: " << gDbgStats.ram_virt_usage << "MB(V) / " << gDbgStats.ram_phys_usage << "MB(P)";
gDbgText.setString(outStrStream.str());
context->draw(gDbgText);
}

View File

@ -1,21 +1,33 @@
#pragma once
#include <memory>
#include <cstddef>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
struct sDbgStats {
double cpu_usage;
double loop_time;
int fps;
std::size_t ram_virt_usage;
std::size_t ram_phys_usage;
};
class DebugUI {
public:
DebugUI();
~DebugUI() {}
void UpdateDebugData(std::shared_ptr<sf::RenderWindow> context);
void UpdateDebugData(const double cpu_usage, const double loop_time, const int fps, const std::size_t ram_virt_usage, const std::size_t ram_phys_usage);
void DrawDebugData(std::shared_ptr<sf::RenderWindow> context);
private:
sf::Font gDbgFont;
sf::Text gDbgText;
struct sDbgStats gDbgStats = {0};
};

81
Engine/Utils/Perfs.cpp Normal file
View File

@ -0,0 +1,81 @@
#include "Perfs.hpp"
#ifdef __MINGW32__
#include <windows.h>
#include <psapi.h>
#else
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#endif
#ifndef __MINGW32__
static int parseLine(char* line) {
// This assumes that a digit will be found and the line ends in " Kb".
int i = strlen(line);
const char* p = line;
while (*p <'0' || *p > '9') p++;
line[i-3] = '\0';
i = atoi(p);
return i;
}
// Returned value in KB!
static int getLinuxVirtualMemUsage() {
FILE* file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
while (fgets(line, 128, file) != NULL){
if (strncmp(line, "VmSize:", 7) == 0){
result = parseLine(line);
break;
}
}
fclose(file);
return result;
}
// Returned value in KB!
static int getLinuxPhysicalMemUsage() {
FILE* file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
while (fgets(line, 128, file) != NULL){
if (strncmp(line, "VmRSS:", 7) == 0){
result = parseLine(line);
break;
}
}
fclose(file);
return result;
}
#endif
// Returned value in KB!
const size_t PerfsGetVirtMem(void) {
size_t out;
#ifdef __MINGW32__
PROCESS_MEMORY_COUNTERS_EX memCounter;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&memCounter, sizeof(memCounter));
out = memCounter.PrivateUsage / 1000;
#else
out = getLinuxVirtualMemUsage();
#endif
return out;
}
// Returned value in KB!
const size_t PerfsGetPhysMem(void) {
size_t out;
#ifdef __MINGW32__
PROCESS_MEMORY_COUNTERS_EX memCounter;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&memCounter, sizeof(memCounter));
out = memCounter.WorkingSetSize / 1000;
#else
out = getLinuxPhysicalMemUsage();
#endif
return out;
}

6
Engine/Utils/Perfs.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
const size_t PerfsGetVirtMem(void);
const size_t PerfsGetPhysMem(void);

View File

@ -11,18 +11,21 @@ public:
}
~SysTimer() {}
void Reset() { this->t_previousDelta = std::chrono::high_resolution_clock::now(); }
const double GetElapsedTime() const {
return (double)(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - t_start).count());
}
const double GetElapsedTimeS() const {
return GetElapsedTime() / 1000000;
}
const double GetDeltaTime() {
return GetDeltaTime(false);
}
const double GetDeltaTime(bool reset) {
auto curr_time = std::chrono::high_resolution_clock::now();
double ret = std::chrono::duration_cast<std::chrono::microseconds>(curr_time - t_previousDelta).count();
double ret = std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - t_previousDelta).count();
if (reset)
this->t_previousDelta = curr_time;
return ret;

View File

@ -1,16 +1,29 @@
#include "Game.hpp"
#include <numeric>
#include <SFML/System.hpp>
#include <SFML/Window/ContextSettings.hpp>
#include <SFML/Window/Event.hpp>
#include "Engine/Utils/Perfs.hpp"
#include "Engine/Utils/Timers.hpp"
using std::make_shared;
using std::make_unique;
#define TARGET_FPS (1000/60)
std::unique_ptr<SysTimer> mPerfsTimer;
Game::Game(bool dbg) : gbDbgModeEnabled(dbg) {
InitWindows();
if (gbDbgModeEnabled)
if (gbDbgModeEnabled) {
gDbgUI = make_unique<DebugUI>();
mPerfsTimer = make_unique<SysTimer>();
mPerfsTimer->Reset();
}
}
void Game::InitWindows() {
@ -32,20 +45,43 @@ void Game::InitWindows() {
gMainWindow->setMouseCursorVisible(true);
}
GAME_STATUS Game::Update(SysTimer& time) {
gLoopTimer.restart();
GAME_STATUS Game::Tick(SysTimer& time) {
static std::vector<double> msTicksMonitoring;
static double mPrevdelta = 0;
static int mFrameCnt = 0;
double mDelta = time.GetDeltaTime();
if (gDbgUI != nullptr && mPerfsTimer != nullptr) {
msTicksMonitoring.push_back((mDelta - mPrevdelta) / TARGET_FPS);
if (mPerfsTimer->GetDeltaTime() >= 1000) { // Re-evaluate CPU usage every seconds (for FP'S')
double cpuUsage = std::accumulate(msTicksMonitoring.begin(), msTicksMonitoring.end(), 0) / msTicksMonitoring.size();
gDbgUI->UpdateDebugData(cpuUsage, (mDelta - mPrevdelta), mFrameCnt, (PerfsGetVirtMem() / 1000), (PerfsGetPhysMem() / 1000));
mFrameCnt = -1; // Minus one to compensate the direct next frame
msTicksMonitoring.clear();
mPerfsTimer->Reset();
}
}
sf::Event event;
while (gMainWindow->pollEvent(event)) {
while (gMainWindow->pollEvent(event)) { // Wait for next frame (fixed FPS)
if (event.type == sf::Event::Closed)
gMainWindow->close();
}
/*
auto ticks = static_cast<int32_t>(mLoopTimer.getElapsedTime().asMilliseconds());
gTicksMonitoring.push_back(ticks);
double cpuUsage = std::accumulate(gTicksMonitoring.begin(), gTicksMonitoring.end(), 0) / gTicksMonitoring.size();
*/
if (mDelta >= TARGET_FPS) { //TODO: Replace with global var and use dynamic window loader
Update();
Render();
mFrameCnt++;
time.Reset();
mPrevdelta = -mDelta;
} else {
mPrevdelta = mDelta;
}
sf::sleep(sf::milliseconds(TARGET_FPS - (mDelta - mPrevdelta)));
if (gMainWindow->isOpen())
return GAME_RUNNING;
@ -53,7 +89,11 @@ GAME_STATUS Game::Update(SysTimer& time) {
return GAME_QUIT;
}
void Game::Render(SysTimer& time) {
void Game::Update() {
}
void Game::Render() {
// Clear the draw buffer
gMainWindow->clear();
@ -62,7 +102,7 @@ void Game::Render(SysTimer& time) {
// Draw the UI above
//UI::draw()
// Draw the debug informations if enabled
if (gDbgUI != nullptr) gDbgUI->UpdateDebugData(gMainWindow);
if (gDbgUI != nullptr) gDbgUI->DrawDebugData(gMainWindow);
// Present the draw buffer
gMainWindow->display();

View File

@ -2,7 +2,6 @@
#include <vector>
#include <memory>
#include <SFML/System/Clock.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include "Engine/Graphics/DebugUI.hpp"
@ -25,18 +24,16 @@ public:
Game(Game const&) = delete;
Game& operator= (Game const&) = delete;
GAME_STATUS Update(SysTimer& time);
void Render(SysTimer& time);
GAME_STATUS Tick(SysTimer& time);
private:
void InitWindows();
void Update();
void Render();
bool gbDbgModeEnabled;
std::shared_ptr<sf::RenderWindow> gMainWindow = nullptr;
std::unique_ptr<DebugUI> gDbgUI = nullptr;
sf::Clock gLoopTimer;
std::vector<double> gTicksMonitoring;
};

View File

@ -5,29 +5,24 @@
#include <memory>
#include "Game.hpp"
#include "Engine/Utils/Timers.hpp"
using std::cout, std::endl, std::fixed, std::setprecision;
int main(int argc, char** argv) {
SysTimer mSysTimer;
cout << fixed << setprecision(6);
std::cout << std::fixed << std::setprecision(6);
GAME_STATUS status = GAME_INIT;
cout << "[" << mSysTimer.GetElapsedTimeS() << "] Init game instance" << endl;
std::cout << "[" << mSysTimer.GetElapsedTimeS() << "] Init game instance" << std::endl;
auto arcadeGame = std::make_unique<Game>(true);
for ( ;; ) {
status = arcadeGame->Update(mSysTimer);
status = arcadeGame->Tick(mSysTimer);
if (status == GAME_QUIT)
break;
arcadeGame->Render(mSysTimer);
}
cout << "[" << mSysTimer.GetElapsedTimeS() << "] Bye bye!" << endl;
std::cout << "[" << mSysTimer.GetElapsedTimeS() << "] Bye bye!" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -7,6 +7,8 @@ set(UTILS_SCRS
Engine/Utils/3DMaths.cpp
Engine/Utils/3DMaths.hpp
Engine/Utils/Timers.hpp
Engine/Utils/Perfs.cpp
Engine/Utils/Perfs.hpp
)
set(MISC_SCRS
Engine/Misc/Console.cpp