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]]  | ||