Performance monitoring
This commit is contained in:
parent
86c0be9dbb
commit
de3e842425
@ -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);
|
||||
}
|
@ -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
81
Engine/Utils/Perfs.cpp
Normal 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
6
Engine/Utils/Perfs.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
const size_t PerfsGetVirtMem(void);
|
||||
const size_t PerfsGetPhysMem(void);
|
@ -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;
|
||||
|
62
Game.cpp
62
Game.cpp
@ -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();
|
||||
|
9
Game.hpp
9
Game.hpp
@ -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;
|
||||
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user