272
edits
mNo edit summary |
Hamzaalloush (talk | contribs) (→Proof of concept (patch): patch update for Nvidia GPU, and GPUInfo objects) |
||
Line 258: | Line 258: | ||
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 - | diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt | ||
--- a/src/Main/CMakeLists.txt | index 4b6926e..31d3a8f 100644 | ||
+++ b/src/Main/CMakeLists.txt | --- a/src/Main/CMakeLists.txt | ||
@@ -17,12 +17,17 @@ | +++ b/src/Main/CMakeLists.txt | ||
main.cxx | @@ -17,12 +17,17 @@ set(SOURCES | ||
options.cxx | main.cxx | ||
util.cxx | options.cxx | ||
+ ram_usage.cxx | util.cxx | ||
positioninit.cxx | + ram_usage.cxx | ||
subsystemFactory.cxx | positioninit.cxx | ||
screensaver_control.cxx | subsystemFactory.cxx | ||
${RESOURCE_FILE} | screensaver_control.cxx | ||
) | ${RESOURCE_FILE} | ||
) | |||
+IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||
+ list(APPEND SOURCES ram_usage_linux.cxx) | + list(APPEND SOURCES ram_usage_linux.cxx) | ||
+ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||
+ | + | ||
set(HEADERS | set(HEADERS | ||
fg_commands.hxx | fg_commands.hxx | ||
fg_init.hxx | fg_init.hxx | ||
@@ -35,12 +40,19 @@ | @@ -35,12 +40,19 @@ set(HEADERS | ||
main.hxx | main.hxx | ||
options.hxx | options.hxx | ||
util.hxx | util.hxx | ||
+ ram_usage.hxx | + ram_usage.hxx | ||
positioninit.hxx | positioninit.hxx | ||
subsystemFactory.hxx | subsystemFactory.hxx | ||
AircraftDirVisitorBase.hxx | AircraftDirVisitorBase.hxx | ||
screensaver_control.hxx | screensaver_control.hxx | ||
) | ) | ||
+IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||
+ list(APPEND HEADERS ram_usage_linux.hxx) | + list(APPEND HEADERS ram_usage_linux.hxx) | ||
+ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||
+ | + | ||
+ | + | ||
+ | + | ||
get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) | get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) | ||
get_property(FG_HEADERS GLOBAL PROPERTY FG_HEADERS) | get_property(FG_HEADERS GLOBAL PROPERTY FG_HEADERS) | ||
diff - | diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx | ||
--- a/src/Main/fg_init.cxx | index 30ffa0e..5548f76 100644 | ||
+++ b/src/Main/fg_init.cxx | --- a/src/Main/fg_init.cxx | ||
+++ b/src/Main/fg_init.cxx | |||
@@ -141,6 +141,7 @@ | @@ -141,6 +141,7 @@ | ||
#include "globals.hxx" | #include "globals.hxx" | ||
#include "logger.hxx" | #include "logger.hxx" | ||
#include "main.hxx" | #include "main.hxx" | ||
+#include "ram_usage.hxx" | +#include "ram_usage.hxx" | ||
#include "positioninit.hxx" | #include "positioninit.hxx" | ||
#include "util.hxx" | #include "util.hxx" | ||
#include "AircraftDirVisitorBase.hxx" | #include "AircraftDirVisitorBase.hxx" | ||
@@ -715,6 +716,10 @@ | @@ -715,6 +716,10 @@ void fgCreateSubsystems(bool duringReset) { | ||
//////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////// | ||
globals->add_subsystem("properties", new FGProperties); | globals->add_subsystem("properties", new FGProperties); | ||
+ //////////////////////////////////////////////////////////////////// | + //////////////////////////////////////////////////////////////////// | ||
+ // Add the ram usage statistics system | + // Add the ram usage statistics system | ||
+ //////////////////////////////////////////////////////////////////// | + //////////////////////////////////////////////////////////////////// | ||
+ globals->add_subsystem("memory-stats", new MemoryUsageStats, SGSubsystemMgr::INIT, 5.00); | + globals->add_subsystem("memory-stats", new MemoryUsageStats, SGSubsystemMgr::INIT, 5.00); | ||
//////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////// | ||
// Add the performance monitoring system. | // Add the performance monitoring system. | ||
diff - | diff --git a/src/Main/ram_usage.cxx b/src/Main/ram_usage.cxx | ||
--- | new file mode 100644 | ||
+++ b/src/Main/ram_usage.cxx | index 0000000..a84ea7c | ||
@@ -0,0 +1, | --- /dev/null | ||
+++ b/src/Main/ram_usage.cxx | |||
@@ -0,0 +1,25 @@ | |||
+#include "ram_usage_linux.hxx" | +#include "ram_usage_linux.hxx" | ||
+ | + | ||
Line 337: | Line 341: | ||
+void | +void | ||
+MemoryUsageStats::update(double dt) { | +MemoryUsageStats::update(double dt) { | ||
+ _mem->update(); | + _mem->update(); | ||
+ double swap = _mem->getSwapSize(); | + int vram = _mem->getVRAMUsageInKB(); // vram stuff | ||
+ double total = _mem->getTotalSize(); | + double swap = _mem->getSwapSize(); | ||
+ SG_LOG(SG_GENERAL, SG_DEBUG, "Updating Memory Stats:" << total << " kb"); | + double total = _mem->getTotalSize(); | ||
+ fgSetInt("/memory-usage/swap-usage-kb", swap ); | + SG_LOG(SG_GENERAL, SG_DEBUG, "Updating Memory Stats:" << total << " kb"); | ||
+ fgSetInt("/memory-usage/total-usage-kb", total ); | + fgSetInt("/memory-usage/swap-usage-kb", swap ); | ||
+ fgSetInt("/memory-usage/total-usage-kb", total ); | |||
+ fgSetInt("/memory-usage/vram-usage-kb", vram ); | |||
+ | |||
+} | +} | ||
+ | + | ||
+ | + | ||
+ | + | ||
diff - | diff --git a/src/Main/ram_usage.hxx b/src/Main/ram_usage.hxx | ||
--- | new file mode 100644 | ||
+++ b/src/Main/ram_usage.hxx | index 0000000..cef9cc2 | ||
@@ -0,0 +1, | --- /dev/null | ||
+++ b/src/Main/ram_usage.hxx | |||
@@ -0,0 +1,142 @@ | |||
+#ifndef __RAM_USAGE | +#ifndef __RAM_USAGE | ||
+#define __RAM_USAGE | +#define __RAM_USAGE | ||
+ | |||
+#include<stdio.h> | |||
+#include<stdlib.h> | |||
+#include<X11/X.h> | |||
+#include<X11/Xlib.h> | |||
+#include<GL/gl.h> | |||
+#include<GL/glx.h> | |||
+#include<GL/glu.h> | |||
+ | |||
+ | + | ||
+#include <simgear/timing/timestamp.hxx> | +#include <simgear/timing/timestamp.hxx> | ||
Line 364: | Line 382: | ||
+ | + | ||
+using std::map; | +using std::map; | ||
+ | |||
+// 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 | |||
+ | |||
+ // this is the base class, with the only method being a virtual method | |||
+ // which needs to be implemented by any child classes | |||
+ // a pointer of this class will be added to the LinuxMemoryInterface class | |||
+ class GPUInfo { | |||
+ private: | |||
+ protected: | |||
+ public: | |||
+ virtual ~GPUInfo() {}; | |||
+ virtual int getVRAMUsageInKB() = 0; | |||
+ }; | |||
+ | |||
+ // Actually implement the GPUInfo class for all 3 GPU vendors: | |||
+ | |||
+ class NVIDIA_GPU: public GPUInfo { | |||
+ public: | |||
+ virtual int getVRAMUsageInKB() { | |||
+ GLint total_mem_kb = 0; | |||
+ glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, | |||
+ &total_mem_kb); | |||
+ | |||
+ GLint cur_avail_mem_kb = 0; | |||
+ glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, | |||
+ &cur_avail_mem_kb); | |||
+ | |||
+ SG_LOG(SG_GENERAL, SG_ALERT,"NVIDIA VRAM tracking function says:"<<total_mem_kb<<" (total) and used:"<<cur_avail_mem_kb); | |||
+ return cur_avail_mem_kb; | |||
+ } | |||
+ | |||
+ }; | |||
+ | |||
+ class ATI_GPU: public GPUInfo { | |||
+ public: | |||
+ virtual int getVRAMUsageInKB() { | |||
+ SG_LOG(SG_GENERAL, SG_ALERT,"ATI VRAM tracking function not yet implemented !"); | |||
+ return 200; | |||
+ } | |||
+ | |||
+ }; | |||
+ | |||
+ class INTEL_GPU : public GPUInfo { | |||
+ public: | |||
+ virtual int getVRAMUsageInKB() { | |||
+ SG_LOG(SG_GENERAL, SG_ALERT,"Intel VRAM tracking function not yet implemented !"); | |||
+ return 500; | |||
+ } | |||
+ | |||
+ }; | |||
+ | + | ||
+// Linux: /proc/pid/smaps | +// Linux: /proc/pid/smaps | ||
Line 370: | Line 440: | ||
+class MemoryInterface { | +class MemoryInterface { | ||
+public: | +public: | ||
+ MemoryInterface() {} | + virtual ~MemoryInterface() { | ||
+ delete _gpu; | |||
+ }; | |||
+ MemoryInterface() { | |||
+ // get the string | |||
+ std::string fallback = "NVIDIA"; //default value | |||
+ | |||
+ // get the actual GL vendor string from the property tree, using the fallback | |||
+ std::string glvendor = fgGetString("/sim/rendering/gl-vendor",fallback.c_str() ); | |||
+ | |||
+ // make it upper case: http://stackoverflow.com/questions/735204/convert-a-string-in-c-to-upper-case | |||
+ std::transform(glvendor.begin(), glvendor.end(), glvendor.begin(), ::toupper); | |||
+ | |||
+ // look for the "NVIDIA" substring: http://www.cplusplus.com/reference/string/string/find/ | |||
+ std::size_t found = glvendor.find("NVIDIA"); | |||
+ if (found!=std::string::npos) { | |||
+ SG_LOG(SG_GENERAL, SG_ALERT, "Supported GPU found: NVIDIA"); | |||
+ _gpu = new NVIDIA_GPU; | |||
+ } | |||
+ | |||
+ // else if ATI/AMD ... | |||
+ // else if INTEL ... | |||
+ else { | |||
+ SG_LOG(SG_GENERAL, SG_ALERT, "Unsupported GPU vendor:" << glvendor); | |||
+ } | |||
+ | |||
+ | |||
+} | |||
+ typedef map<const char*, double> RamMap; | + typedef map<const char*, double> RamMap; | ||
+//protected: | +//protected: | ||
+ virtual void update() = 0; | + virtual void update() = 0; | ||
+ | |||
+ int getVRAMUsageInKB() const {return _gpu->getVRAMUsageInKB();} | |||
+ | + | ||
+ double getTotalSize() const {return _total_size;} | + double getTotalSize() const {return _total_size;} | ||
+ //virtual void setTotalSize(double t) {_total_size=t;} | + //virtual void setTotalSize(double t) {_total_size=t;} | ||
+ | + | ||
+ double getSwapSize() const {return _swap_size;} | + double getSwapSize() const {return _swap_size;} | ||
+ //virtual void setSwapSize(double s) {_swap_size=s;} | + //virtual void setSwapSize(double s) {_swap_size=s;} | ||
+protected: | +protected: | ||
+ RamMap _size; | + RamMap _size; | ||
+ std::string _path; | + std::string _path; | ||
+ std::stringstream _pid; | + std::stringstream _pid; | ||
+ GPUInfo* _gpu; | |||
+ | + | ||
+ double _total_size; | + double _total_size; | ||
Line 392: | Line 492: | ||
+{ | +{ | ||
+public: | +public: | ||
+ MemoryUsageStats(); | + MemoryUsageStats(); | ||
+ ~MemoryUsageStats(); | + ~MemoryUsageStats(); | ||
+ virtual void update(double); | + virtual void update(double); | ||
+protected: | +protected: | ||
+private: | +private: | ||
+ MemoryInterface* _mem; | + MemoryInterface* _mem; | ||
+}; | +}; | ||
+ | + | ||
+#endif | +#endif | ||
+ | + | ||
diff - | diff --git a/src/Main/ram_usage_linux.cxx b/src/Main/ram_usage_linux.cxx | ||
--- | new file mode 100644 | ||
+++ b/src/Main/ram_usage_linux.cxx | index 0000000..bb214a8 | ||
--- /dev/null | |||
+++ b/src/Main/ram_usage_linux.cxx | |||
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
+// https://gist.github.com/896026/c346c7c8e4a9ab18577b4e6abfca37e358de83c1 | +// https://gist.github.com/896026/c346c7c8e4a9ab18577b4e6abfca37e358de83c1 | ||
Line 426: | Line 528: | ||
+ file = fopen(_path.c_str(),"r" ); | + file = fopen(_path.c_str(),"r" ); | ||
+ if (!file) { | + if (!file) { | ||
+ throw("MemoryTracker:Cannot open /proc/pid/smaps"); | + throw("MemoryTracker:Cannot open /proc/pid/smaps"); | ||
+ } | + } | ||
+ SG_LOG(SG_GENERAL, SG_DEBUG, "Opened:"<< _path.c_str() ); | + SG_LOG(SG_GENERAL, SG_DEBUG, "Opened:"<< _path.c_str() ); | ||
+} | +} | ||
Line 439: | Line 541: | ||
+ if (!file) throw("MemoryTracker: ProcFile not open"); | + if (!file) throw("MemoryTracker: ProcFile not open"); | ||
+ | + | ||
+ _total_size = 0; | + _total_size = 0; | ||
+ _swap_size = 0; | + _swap_size = 0; | ||
+ | + | ||
+ char line[1024]; | + char line[1024]; | ||
+ while (fgets(line, sizeof line, file)) | + while (fgets(line, sizeof line, file)) | ||
+ { | + { | ||
+ char substr[32]; | + char substr[32]; | ||
+ int n; | + int n; | ||
+ if (sscanf(line, "%31[^:]: %d", substr, &n) == 2) { | + if (sscanf(line, "%31[^:]: %d", substr, &n) == 2) { | ||
+ if (strcmp(substr, "Size") == 0) { _total_size += n; } | + if (strcmp(substr, "Size") == 0) { _total_size += n; } | ||
+ else if (strcmp(substr, "Swap") == 0) { _swap_size += n; } | + else if (strcmp(substr, "Swap") == 0) { _swap_size += n; } | ||
+ } | + } | ||
+ } | + } | ||
+ fclose(file); | + fclose(file); | ||
+} | +} | ||
+ | + | ||
diff - | diff --git a/src/Main/ram_usage_linux.hxx b/src/Main/ram_usage_linux.hxx | ||
--- | new file mode 100644 | ||
+++ b/src/Main/ram_usage_linux.hxx | index 0000000..59b7134 | ||
--- /dev/null | |||
+++ b/src/Main/ram_usage_linux.hxx | |||
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
+#ifndef __RAM_USAGE_LINUX | +#ifndef __RAM_USAGE_LINUX | ||
Line 480: | Line 584: | ||
+ | + | ||
+ | + | ||
+#endif | +#endif</syntaxhighlight> | ||
</syntaxhighlight> | |||
[[Category:Core development projects]] | [[Category:Core development projects]] |
edits