20,741
edits
Line 276: | Line 276: | ||
Here's a first stab at a simple subsystem to monitor FlightGear memory usage on Linux at 5 second intervals, consider it a "proof of concept" prototype now, as this would need to be cleaned up and implemented for Mac/Windows respectively - on Linux it simply works such that it merely fopen()s /proc/pid/smaps and copies two metrics to the property tree: | Here's a first stab at a simple subsystem to monitor FlightGear memory usage on Linux at 5 second intervals, consider it a "proof of concept" prototype now, as this would need to be cleaned up and implemented for Mac/Windows respectively - on Linux it simply works such that it merely fopen()s /proc/pid/smaps and copies two metrics to the property tree: | ||
<syntaxhighlight lang="diff"> | <syntaxhighlight lang="diff"> | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt | |||
index 4808f9d..5b45fa6 100644 | |||
--- a/CMakeLists.txt | |||
+++ b/CMakeLists.txt | |||
@@ -194,6 +194,7 @@ option(ENABLE_TESTS "Set to ON to build test applications (default)" ON) | |||
option(ENABLE_FGCOM "Set to ON to build the FGCom application (default)" ON) | |||
option(ENABLE_FLITE "Set to ON to build the Flite text-to-speech module" ON) | |||
option(ENABLE_QT "Set to ON to build the internal Qt launcher" ON) | |||
+#option(ENABLE_SIGAR "Set to ON to build with SIGAR support (experimental)" OFF) | |||
if(LOGGING) | |||
# nothing | |||
@@ -328,6 +329,13 @@ if(ENABLE_PROFILE) | |||
message(STATUS "Built-in profiler using gperftools available") | |||
endif() | |||
+if(ENABLE_SIGAR) | |||
+ # find_package(SIGAR REQUIRED) | |||
+ set(FG_HAVE_SIGAR 1) | |||
+ message(STATUS "Built-in process monitoring using SIGAR available") | |||
+endif(ENABLE_SIGAR) | |||
+ | |||
+ | |||
if(ENABLE_RTI) | |||
message(STATUS "RTI: ENABLED") | |||
find_package(RTI) | |||
diff --git a/CMakeModules/FindSIGAR.cmake b/CMakeModules/FindSIGAR.cmake | |||
new file mode 100644 | |||
index 0000000..4c890a7 | |||
--- /dev/null | |||
+++ b/CMakeModules/FindSIGAR.cmake | |||
@@ -0,0 +1,52 @@ | |||
+# - Find SIGAR: https://support.hyperic.com/display/SIGAR/Home | |||
+# Find the native SIGAR includes and library | |||
+# | |||
+# SIGAR_INCLUDE_DIR - where to find SIGAR.h, etc. | |||
+# SIGAR_LIBRARIES - List of libraries when using SIGAR. | |||
+# SIGAR_FOUND - True if SIGAR found. | |||
+# | |||
+# Redistribution and use is allowed according to the terms of the BSD license. | |||
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file. | |||
+ | |||
+ | |||
+if (SIGAR_INCLUDE_DIR) | |||
+ # Already in cache, be silent | |||
+ set(SIGAR_FIND_QUIETLY TRUE) | |||
+endif () | |||
+ | |||
+find_path(SIGAR_INCLUDE_DIR sigar.h | |||
+ /opt/local/include | |||
+ /usr/local/include | |||
+ /usr/include | |||
+) | |||
+ | |||
+# SIGAR support a lot more platforms than listed here. | |||
+# cf. sigar.hyperic.com | |||
+set(SIGAR_NAMES sigar-x86-linux sigar-x86_64-linux sigar-amd64-linux sigar-universal-macosx sigar) | |||
+find_library(SIGAR_LIBRARY | |||
+ NAMES ${SIGAR_NAMES} | |||
+ PATHS /usr/lib /usr/local/lib /opt/local/lib | |||
+) | |||
+ | |||
+if (SIGAR_INCLUDE_DIR AND SIGAR_LIBRARY) | |||
+ set(SIGAR_FOUND TRUE) | |||
+ set(SIGAR_LIBRARIES ${SIGAR_LIBRARY} ${CMAKE_DL_LIBS}) | |||
+else () | |||
+ set(SIGAR_FOUND FALSE) | |||
+ set(SIGAR_LIBRARIES) | |||
+endif () | |||
+ | |||
+if (SIGAR_FOUND) | |||
+ message(STATUS "Found SIGAR: ${SIGAR_LIBRARIES}") | |||
+else () | |||
+ message(STATUS "Not Found SIGAR: ${SIGAR_LIBRARY}") | |||
+ if (SIGAR_FIND_REQUIRED) | |||
+ message(STATUS "Looked for SIGAR libraries named ${SIGAR_NAMES}.") | |||
+ message(FATAL_ERROR "Could NOT find SIGAR library") | |||
+ endif () | |||
+endif () | |||
+ | |||
+mark_as_advanced( | |||
+ SIGAR_LIBRARY | |||
+ SIGAR_INCLUDE_DIR | |||
+) | |||
diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt | diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt | ||
index 4b6926e..31d3a8f 100644 | index 4b6926e..31d3a8f 100644 | ||
Line 319: | Line 403: | ||
diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx | diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx | ||
index 30ffa0e.. | index 30ffa0e..ae936ab 100644 | ||
--- a/src/Main/fg_init.cxx | --- a/src/Main/fg_init.cxx | ||
+++ b/src/Main/fg_init.cxx | +++ b/src/Main/fg_init.cxx | ||
Line 335: | Line 419: | ||
+ //////////////////////////////////////////////////////////////////// | + //////////////////////////////////////////////////////////////////// | ||
+ // Add the | + // Add the RAM/VRAM utilization statistics system (SIGAR) | ||
+ //////////////////////////////////////////////////////////////////// | + //////////////////////////////////////////////////////////////////// | ||
+ globals->add_subsystem(" | + globals->add_subsystem("process-stats", new MemoryUsageStats, SGSubsystemMgr::INIT, 1.00); | ||
//////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////// | ||
// Add the performance monitoring system. | // Add the performance monitoring system. | ||
diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx | diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx | ||
index d41e00d.. | index d41e00d..c8805b6 100644 | ||
--- a/src/Main/globals.cxx | --- a/src/Main/globals.cxx | ||
+++ b/src/Main/globals.cxx | +++ b/src/Main/globals.cxx | ||
@@ - | @@ -63,6 +63,7 @@ | ||
#include "fg_props.hxx" | |||
#include "fg_io.hxx" | |||
+#include "ram_usage.hxx" | |||
class AircraftResourceProvider : public simgear::ResourceProvider | |||
{ | |||
@@ -503,7 +504,12 @@ FGGlobals::add_subsystem (const char * name, | |||
SGSubsystemMgr::GroupType type, | |||
double min_time_sec) | double min_time_sec) | ||
{ | { | ||
+ MemoryUsageStats* stats = (MemoryUsageStats*) subsystem_mgr->get_subsystem("process-stats"); | |||
subsystem_mgr->add(name, subsystem, type, min_time_sec); | subsystem_mgr->add(name, subsystem, type, min_time_sec); | ||
+ | + if(stats) { | ||
+ SG_LOG(SG_GENERAL, SG_ALERT, "Process snapshot after adding subsystem:"<< name); | |||
+ stats->snapshot(); | |||
+ } | |||
} | } | ||
Line 355: | Line 452: | ||
diff --git a/src/Main/ram_usage.cxx b/src/Main/ram_usage.cxx | diff --git a/src/Main/ram_usage.cxx b/src/Main/ram_usage.cxx | ||
new file mode 100644 | new file mode 100644 | ||
index 0000000.. | index 0000000..a9da94d | ||
--- /dev/null | --- /dev/null | ||
+++ b/src/Main/ram_usage.cxx | +++ b/src/Main/ram_usage.cxx | ||
@@ -0,0 +1, | @@ -0,0 +1,17 @@ | ||
+#include "ram_usage_linux.hxx" | +#include "ram_usage_linux.hxx" | ||
+ | + | ||
+MemoryUsageStats::MemoryUsageStats() { | +MemoryUsageStats::MemoryUsageStats() { | ||
+ | + _ram = new LinuxMemoryInterface(); //FIXME: should be implemented for Win/Mac & Linux (use SIGAR) | ||
+} | +} | ||
+ | + | ||
+MemoryUsageStats::~MemoryUsageStats() { | +MemoryUsageStats::~MemoryUsageStats() { | ||
+ delete | + delete _ram; | ||
+} | +} | ||
+ | + | ||
+void | +void | ||
+MemoryUsageStats::update(double dt) { | +MemoryUsageStats::update(double dt) { | ||
+ | +update(); | ||
+} | +} | ||
+ | + | ||
Line 388: | Line 475: | ||
diff --git a/src/Main/ram_usage.hxx b/src/Main/ram_usage.hxx | diff --git a/src/Main/ram_usage.hxx b/src/Main/ram_usage.hxx | ||
new file mode 100644 | new file mode 100644 | ||
index 0000000.. | index 0000000..58abdf5 | ||
--- /dev/null | --- /dev/null | ||
+++ b/src/Main/ram_usage.hxx | +++ b/src/Main/ram_usage.hxx | ||
@@ -0,0 +1, | @@ -0,0 +1,186 @@ | ||
+#ifndef __RAM_USAGE | +#ifndef __RAM_USAGE | ||
+#define __RAM_USAGE | +#define __RAM_USAGE | ||
Line 408: | Line 495: | ||
+ | + | ||
+#include <simgear/timing/timestamp.hxx> | +#include <simgear/timing/timestamp.hxx> | ||
+ | |||
+// http://wiki.flightgear.org/Howto:Create_new_subsystems | |||
+#include <simgear/structure/subsystem_mgr.hxx> | +#include <simgear/structure/subsystem_mgr.hxx> | ||
+ | + | ||
Line 417: | Line 506: | ||
+ | + | ||
+using std::map; | +using std::map; | ||
+ | + | ||
+ // this is the base class, with the only method being a virtual method | + // this is the base class, with the only method being a virtual method | ||
Line 442: | Line 517: | ||
+ simgear::PropertyObject<int> total_vram_kb,available_vram_kb, used_vram_kb; | + simgear::PropertyObject<int> total_vram_kb,available_vram_kb, used_vram_kb; | ||
+ public: | + public: | ||
+ GPUInfo(): total_mem_kb(-1), | + GPUInfo(std::string &glvendor): total_mem_kb(-1), | ||
+ cur_avail_mem_kb(-1), | + cur_avail_mem_kb(-1), | ||
+ total_vram_kb("/stats/vram/total-size-kb"), | + total_vram_kb("/stats/vram/total-size-kb"), | ||
+ available_vram_kb ("/stats/vram/available-kb"), | + available_vram_kb ("/stats/vram/available-kb"), | ||
+ used_vram_kb ("/stats/vram/used-kb") { } | + used_vram_kb ("/stats/vram/used-kb") { | ||
+ virtual ~GPUInfo() { | + SG_LOG(SG_GENERAL, SG_ALERT, "VRAM Tracking: Supported GPU found:"<< glvendor); | ||
+ } | |||
+ virtual ~GPUInfo() {} | |||
+ virtual void updateVRAMStats() {}; | + virtual void updateVRAMStats() {}; | ||
+ }; | + }; //GPUInfo | ||
+ | + | ||
+ // Actually implement the GPUInfo class for all 3 GPU vendors: | + // Actually implement the GPUInfo class for all 3 GPU vendors: | ||
+ | + | ||
+ | +// http://www.geeks3d.com/20100531/programming-tips-how-to-know-the-graphics-memory-size-and-usage-in-opengl/ | ||
+ | +#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX 0x9048 | ||
+#define GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX 0x9049 | |||
+ | |||
+ struct NVIDIA_GPU: public GPUInfo { | |||
+ NVIDIA_GPU(std::string glvendor) : GPUInfo(glvendor) { | |||
+ // determine total memory and store it (this wont change at runtime, so only do it once) | + // determine total memory and store it (this wont change at runtime, so only do it once) | ||
+ glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &total_mem_kb); | + glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &total_mem_kb); | ||
Line 463: | Line 542: | ||
+ } | + } | ||
+ virtual void updateVRAMStats() { | + virtual void updateVRAMStats() { | ||
+ | |||
+ glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &cur_avail_mem_kb); | + glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &cur_avail_mem_kb); | ||
+ SG_LOG(SG_GENERAL, SG_DEBUG,"NVIDIA VRAM tracking function says:"<<total_mem_kb<<" (total) available:"<<cur_avail_mem_kb); | + SG_LOG(SG_GENERAL, SG_DEBUG,"NVIDIA VRAM tracking function says:"<<total_mem_kb<<" (total) available:"<<cur_avail_mem_kb); | ||
+ // update property objects | + // update property objects | ||
Line 470: | Line 549: | ||
+ used_vram_kb = total_vram_kb - available_vram_kb; | + used_vram_kb = total_vram_kb - available_vram_kb; | ||
+ } | + } | ||
+ }; //NVIDIA_GPU | |||
+ | + | ||
+ | + struct ATI_GPU: public GPUInfo { | ||
+ ATI_GPU(std::string glvendor) : GPUInfo(glvendor) { | |||
+ } | |||
+ | |||
+ | |||
+ // https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2038%20Monitoring%20Graphics%20Memory%20Usage/Ch38AMD/Ch38AMD/Ch38AMDDlg.cpp#L280 | + // https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2038%20Monitoring%20Graphics%20Memory%20Usage/Ch38AMD/Ch38AMD/Ch38AMDDlg.cpp#L280 | ||
+ virtual void updateVRAMStats() { | + virtual void updateVRAMStats() { | ||
+// https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2038%20Monitoring%20Graphics%20Memory%20Usage/Ch38AMD/Ch38AMD/Ch38AMDDlg.cpp | |||
+#ifndef GL_VBO_FREE_MEMORY_ATI | |||
+ #define GL_VBO_FREE_MEMORY_ATI 0x87FB | |||
+ #define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC | |||
+ #define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD | |||
+#endif | |||
+ | |||
+ SG_LOG(SG_GENERAL, SG_ALERT,"Sorry:ATI VRAM tracking function not yet implemented (nvidia only)!"); | + SG_LOG(SG_GENERAL, SG_ALERT,"Sorry:ATI VRAM tracking function not yet implemented (nvidia only)!"); | ||
+ used_vram_kb = total_vram_kb = available_vram_kb = -1; | + used_vram_kb = total_vram_kb = available_vram_kb = -1; | ||
+ } | + } | ||
+ };//ATI_GPU | |||
+ | + | ||
+ | + struct INTEL_GPU : public GPUInfo { | ||
+ INTEL_GPU(std::string glvendor) : GPUInfo(glvendor) { | |||
+ | +} | ||
+ | |||
+ virtual void updateVRAMStat() { | + virtual void updateVRAMStat() { | ||
+ SG_LOG(SG_GENERAL, SG_ALERT,"Sorry:Intel VRAM tracking function not yet implemented (nvidia only)!"); | + SG_LOG(SG_GENERAL, SG_ALERT,"Sorry:Intel VRAM tracking function not yet implemented (nvidia only)!"); | ||
Line 491: | Line 576: | ||
+ } | + } | ||
+ | + | ||
+ }; | + }; // INTEL_GPU | ||
+ | |||
+ struct UNKNOWN_GPU: public GPUInfo { | |||
+ UNKNOWN_GPU(std::string glvendor) : GPUInfo(glvendor) { | |||
+ } | |||
+ virtual void updateVRAMStat() { | |||
+ SG_LOG(SG_GENERAL, SG_DEBUG,"Sorry:VRAM tracking function not yet implemented for your GPU (nvidia only)!"); | |||
+ used_vram_kb = total_vram_kb = available_vram_kb = -1; | |||
+ } | |||
+ | |||
+ }; // UNKNOWN_GPU | |||
+ | + | ||
+// Linux: /proc/pid/smaps | +// Linux: /proc/pid/smaps | ||
Line 515: | Line 610: | ||
+ std::size_t found = glvendor.find("NVIDIA"); | + std::size_t found = glvendor.find("NVIDIA"); | ||
+ if (found!=std::string::npos) { | + if (found!=std::string::npos) { | ||
+ _gpu = new NVIDIA_GPU; | + _gpu = new NVIDIA_GPU(glvendor); | ||
+ } | + } | ||
+ else if (glvendor.find("INTEL") != std::string::npos) { | + else if (glvendor.find("INTEL") != std::string::npos) { | ||
+ _gpu = new INTEL_GPU; | + _gpu = new INTEL_GPU(glvendor); | ||
+ } | + } | ||
+ else if (glvendor.find("ATI") != std::string::npos) { | + else if (glvendor.find("ATI") != std::string::npos) { | ||
+ _gpu = new ATI_GPU; | + _gpu = new ATI_GPU(glvendor); | ||
+ } | + } | ||
+ else { | + else { | ||
+ | + _gpu = new UNKNOWN_GPU(glvendor); | ||
+ } | + } | ||
+} | +} | ||
+ typedef map<const char*, double> RamMap; | + typedef map<const char*, double> RamMap; | ||
+ virtual void update() = 0; | + virtual void update() = 0; | ||
+ | + | ||
Line 539: | Line 630: | ||
+} | +} | ||
+ | + | ||
+protected: | +protected: | ||
+ RamMap _size; | + RamMap _size; | ||
+ std::string _path; | + std::string _path; | ||
+ std::stringstream _pid; | + std::stringstream _pid; | ||
+ GPUInfo* _gpu; | + GPUInfo* _gpu; // wraps VRAM utilization gathering | ||
+ | + | ||
+ simgear::PropertyObject<int> _total_size; | +public: | ||
+ simgear::PropertyObject<int> _swap_size; | + simgear::PropertyObject<int> _total_size; // memory used by process | ||
+ simgear::PropertyObject<int> _swap_size; // swap used by process | |||
+}; | +}; | ||
+ | + | ||
Line 560: | Line 647: | ||
+ ~MemoryUsageStats(); | + ~MemoryUsageStats(); | ||
+ virtual void update(double); | + virtual void update(double); | ||
+ void snapshot() { | |||
+ update(); | |||
+ simgear::PropertyObject<int> used_vram_kb ("/stats/vram/used-kb"); | |||
+ SG_LOG(SG_GENERAL, SG_ALERT, "Process size: " <<_ram->_total_size << "kb" << std::endl); | |||
+ // SG_LOG(SG_GENERAL, SG_ALERT, "VRAM utilization: " << used_vram_kb << " kb" << std::endl); | |||
+ } | |||
+ | |||
+protected: | +protected: | ||
+private: | +private: | ||
+ MemoryInterface* | + MemoryInterface* _ram; | ||
+ void update() { | |||
+ _ram->update(); // will update ram/swap utilization by reading /proc/pid/smaps | |||
+ _ram->updateVRAMStats(); // will update vram utilization by using NVIDIA/AMD APIs | |||
+ } | |||
+}; | +}; | ||
+ | + | ||
Line 651: | Line 749: | ||
+ | + | ||
+#endif | +#endif | ||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Category:Core development projects]] | [[Category:Core development projects]] |