diff --git a/CMakeLists.txt b/CMakeLists.txt index 4808f9d..0771e15 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)" ON) if(LOGGING) # nothing @@ -328,6 +329,17 @@ if(ENABLE_PROFILE) message(STATUS "Built-in profiler using gperftools available") endif() +if(ENABLE_SIGAR) + find_package(SIGAR REQUIRED) + if(SIGAR_FOUND) + set(FG_HAVE_SIGAR 1) + message(STATUS "Built-in process monitoring using SIGAR available") + else() + message(STATUS "SIGAR libs not found (system-wide installation required for now)") + endif() +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 index 4b6926e..06db7f7 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -17,6 +17,7 @@ set(SOURCES main.cxx options.cxx util.cxx + sigar.cxx positioninit.cxx subsystemFactory.cxx screensaver_control.cxx @@ -35,12 +36,14 @@ set(HEADERS main.hxx options.hxx util.hxx + sigar.hxx positioninit.hxx subsystemFactory.hxx AircraftDirVisitorBase.hxx screensaver_control.hxx ) + get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) get_property(FG_HEADERS GLOBAL PROPERTY FG_HEADERS) @@ -144,6 +147,7 @@ target_link_libraries(fgfs ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES} ${SIMGEAR_SCENE_LIBRARY_DEPENDENCIES} ${PLATFORM_LIBS} + ${SIGAR_LIBRARIES} ) if(ENABLE_FLITE) diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 30ffa0e..2b9bf7f 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -141,6 +141,7 @@ #include "globals.hxx" #include "logger.hxx" #include "main.hxx" +#include "sigar.hxx" #include "positioninit.hxx" #include "util.hxx" #include "AircraftDirVisitorBase.hxx" @@ -715,6 +716,10 @@ void fgCreateSubsystems(bool duringReset) { //////////////////////////////////////////////////////////////////// globals->add_subsystem("properties", new FGProperties); + //////////////////////////////////////////////////////////////////// + // Add the RAM/VRAM utilization statistics system (SIGAR) + //////////////////////////////////////////////////////////////////// + globals->add_subsystem("sigar", new ProcessInternals, SGSubsystemMgr::INIT, 1.00); //////////////////////////////////////////////////////////////////// // Add the performance monitoring system. diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index d41e00d..82f60d4 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -63,6 +63,7 @@ #include "fg_props.hxx" #include "fg_io.hxx" +#include "sigar.hxx" class AircraftResourceProvider : public simgear::ResourceProvider { @@ -503,7 +504,12 @@ FGGlobals::add_subsystem (const char * name, SGSubsystemMgr::GroupType type, double min_time_sec) { + ProcessInternals* stats = (ProcessInternals*) subsystem_mgr->get_subsystem("sigar"); 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(); + } } SGSoundMgr * diff --git a/src/Main/sigar.cxx b/src/Main/sigar.cxx new file mode 100644 index 0000000..d10d5b8 --- /dev/null +++ b/src/Main/sigar.cxx @@ -0,0 +1,83 @@ +#include "sigar.hxx" + +ProcessInternals::ProcessInternals() : + total_ram("/sigar/memory/total-ram-mb"), + arch("/sigar/architecture"), + machine("/sigar/machine"), + fgfspid("/sigar/process-id"), + cores("/sigar/cpu/cores"), + cpu_vendor("/sigar/cpu/vendor"), + cpu_model("/sigar/cpu/model"), + swap_used("/sigar/memory/swap-used-kb"), + swap_free("/sigar/memory/swap-free-kb"), + process_size("/sigar/process-size-kb"), + process_threads("/sigar/process-threads") +{ +// initialize sigar +sigar_open(&t); + +sigar_sys_info_t sysinfo; +sigar_sys_info_get(t, &sysinfo); + +SG_LOG(SG_GENERAL, SG_DEBUG, "Architecture: " < 0); +SG_LOG(SG_GENERAL, SG_DEBUG, "fgfs pid is:" << (int)pid); +fgfspid = pid; + +// get a list of CPUs +sigar_cpu_list_t cpulist; +sigar_cpu_list_get(t, &cpulist); + +// Get info for each core +sigar_cpu_info_list_t cpuinfo; +sigar_cpu_info_list_get(t, &cpuinfo); + +// print out vendor/model of the CPU +sigar_cpu_info_t info = cpuinfo.data[0]; +SG_LOG(SG_GENERAL, SG_DEBUG, "CPUs: "< +#include +#include +#include +#include +#include +#include + +#include + +// http://wiki.flightgear.org/Howto:Use_Property_Tree_Objects +#include + +#include + +// http://wiki.flightgear.org/Howto:Create_new_subsystems +#include + +#include
+#include
+ +#include +#include + +#include "vram_tracking.hxx" + +using std::map; + +class SIGAR_Wrapper { +public: + virtual ~SIGAR_Wrapper() { + delete _gpu; + }; + SIGAR_Wrapper() { + // see if we have a GPU that supports vram tracking: + + 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) { + _gpu = new NVIDIA_GPU(glvendor); + } + else if (glvendor.find("INTEL") != std::string::npos) { + _gpu = new INTEL_GPU(glvendor); + } + else if (glvendor.find("ATI") != std::string::npos) { + _gpu = new ATI_GPU(glvendor); + } + else { + _gpu = new UNKNOWN_GPU(glvendor); + } +} + typedef map RamMap; + virtual void update() { + +} + + void updateVRAMStats() const { +if (_gpu) +_gpu->updateVRAMStats(); +} + +protected: + RamMap _size; + GPUInfo* _gpu; // wraps VRAM utilization gathering +}; + +class ProcessInternals : public SGSubsystem +{ +public: + ProcessInternals(); + ~ProcessInternals(); + virtual void update(double); + void snapshot() { + update(); + simgear::PropertyObject 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: +private: + simgear::PropertyObject total_ram; + simgear::PropertyObject arch; + simgear::PropertyObject machine; + simgear::PropertyObject fgfspid; + simgear::PropertyObject cores; + simgear::PropertyObject cpu_vendor; + simgear::PropertyObject cpu_model; + simgear::PropertyObject swap_used; // swap used by process + simgear::PropertyObject swap_free; + simgear::PropertyObject process_size; + simgear::PropertyObject process_threads; +// SIGAR stuff + int status; + sigar_pid_t pid; // stores the process identifier + sigar_t *t; // handle to sigar + sigar_proc_state_t proc_stat; // process specific state (i.e. number of active threads) + sigar_proc_mem_t mem; // for getting memory info from sigar (total/used RAM etc) + sigar_swap_t swap; // global swap info + + SIGAR_Wrapper* _ram; + void update() { + //_ram->update(); // will update ram/swap utilization using SIGAR + //_ram->updateVRAMStats(); // will update vram utilization by using NVIDIA/AMD APIs + } +}; + +#endif + diff --git a/src/Main/vram_tracking.hxx b/src/Main/vram_tracking.hxx new file mode 100644 index 0000000..375c339 --- /dev/null +++ b/src/Main/vram_tracking.hxx @@ -0,0 +1,85 @@ +#ifndef __VRAM_TRACKING_HXX__ +#define __VRAM_TRACKING_HXX__ + // 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: + GLint total_mem_kb; + GLint cur_avail_mem_kb; + simgear::PropertyObject total_vram_kb,available_vram_kb, used_vram_kb; + public: + GPUInfo(std::string &glvendor): total_mem_kb(-1), + cur_avail_mem_kb(-1), + total_vram_kb("/stats/vram/total-size-kb"), + available_vram_kb ("/stats/vram/available-kb"), + used_vram_kb ("/stats/vram/used-kb") { + SG_LOG(SG_GENERAL, SG_ALERT, "VRAM Tracking: Supported GPU found:"<< glvendor); + } + virtual ~GPUInfo() {} + virtual void updateVRAMStats() {}; + }; //GPUInfo + + // 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) + glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &total_mem_kb); + SG_LOG(SG_GENERAL, SG_DEBUG, "NVIDIA GPU with total memory: " << total_mem_kb << " kbytes"); + total_vram_kb = total_mem_kb; + } + virtual void updateVRAMStats() { + + glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &cur_avail_mem_kb); + SG_LOG(SG_GENERAL, SG_DEBUG,"NVIDIA VRAM tracking function says:"<