diff --git a/tmux-mem-cpu-load.cpp b/tmux-mem-cpu-load.cpp index acac931..52ee5b0 100644 --- a/tmux-mem-cpu-load.cpp +++ b/tmux-mem-cpu-load.cpp @@ -19,6 +19,228 @@ #include #include #include // sleep +#include // for floorf + +// Apple specific. +#if defined(__APPLE__) && defined(__MACH__) +// Mach kernel includes for getting memory and CPU statistics +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include // for sysctl +# include // for integer types +#endif + +// if we are on a BSD system +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +// TODO: Includes and *BSD support +# define BSD_BASED 1 +#endif + +// Function declarations for global use. +float cpu_percentage( unsigned int cpu_usage_delay ); +std::string mem_string(); +std::string load_string(); + +// This function is platform independent and therefore can be placed at the top +std::string cpu_string( unsigned int cpu_usage_delay, unsigned int graph_lines ) +{ + std::string meter( graph_lines + 2, ' ' ); + meter[0] = '['; + meter[meter.length() - 1] = ']'; + int meter_count = 0; + float percentage; + std::ostringstream oss; + oss.precision( 1 ); + oss.setf( std::ios::fixed | std::ios::right ); + + percentage = cpu_percentage( cpu_usage_delay ); + float meter_step = 99.9 / graph_lines; + meter_count = 1; + while(meter_count*meter_step < percentage) + { + meter[meter_count] = '|'; + meter_count++; + } + + oss << meter; + oss.width( 5 ); + oss << percentage; + oss << "%"; + + return oss.str(); +} + +#if defined(BSD_BASED) || (defined(__APPLE__) && defined(__MACH__)) +// OSX or BSD based system, use BSD APIs instead + +#if defined(__APPLE__) && defined(__MACH__) +std::string mem_string() +{ + // These values are in bytes + int64_t total_mem; + int64_t used_mem; + int64_t unused_mem; + // blah + vm_size_t page_size; + mach_port_t mach_port; + mach_msg_type_number_t count; + vm_statistics_data_t vm_stats; + std::ostringstream oss; + + // Get total physical memory + int mib[2]; + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + size_t length = sizeof(int64_t); + sysctl(mib, 2, &total_mem, &length, NULL, 0); + + mach_port = mach_host_self(); + count = sizeof(vm_stats) / sizeof(natural_t); + if (KERN_SUCCESS == host_page_size(mach_port, &page_size) && + KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count)) + { + unused_mem = (int64_t)vm_stats.free_count * (int64_t)page_size; + + used_mem = ((int64_t)vm_stats.active_count + + (int64_t)vm_stats.inactive_count + + (int64_t)vm_stats.wire_count) * (int64_t)page_size; + } + + oss << used_mem / 1024 / 1024 << '/' << total_mem / 1024 / 1024 << "MB"; + + return oss.str(); +} + +// See: http://www.opensource.apple.com/source/xnu/xnu-201/osfmk/mach/host_info.h +// and: http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/ +host_cpu_load_info_data_t _get_cpu_percentage() +{ + kern_return_t error; + mach_msg_type_number_t count; + host_cpu_load_info_data_t r_load; + mach_port_t mach_port; + + count = HOST_CPU_LOAD_INFO_COUNT; + mach_port = mach_host_self(); + error = host_statistics(mach_port, HOST_CPU_LOAD_INFO, (host_info_t)&r_load, &count); + if (error != KERN_SUCCESS) + return host_cpu_load_info_data_t(); + + return r_load; +} + +float cpu_percentage( unsigned int cpu_usage_delay ) +{ + // Get the load times from the XNU kernel + host_cpu_load_info_data_t load1 = _get_cpu_percentage(); + usleep(cpu_usage_delay); + host_cpu_load_info_data_t load2 = _get_cpu_percentage(); + + // Current load times + unsigned long long current_user = load1.cpu_ticks[CPU_STATE_USER]; + unsigned long long current_system = load1.cpu_ticks[CPU_STATE_SYSTEM]; + unsigned long long current_nice = load1.cpu_ticks[CPU_STATE_NICE]; + unsigned long long current_idle = load1.cpu_ticks[CPU_STATE_IDLE]; + // Next load times + unsigned long long next_user = load2.cpu_ticks[CPU_STATE_USER]; + unsigned long long next_system = load2.cpu_ticks[CPU_STATE_SYSTEM]; + unsigned long long next_nice = load2.cpu_ticks[CPU_STATE_NICE]; + unsigned long long next_idle = load2.cpu_ticks[CPU_STATE_IDLE]; + // Difference between the two + unsigned long long diff_user = next_user - current_user; + unsigned long long diff_system = next_system - current_system; + unsigned long long diff_nice = next_nice - current_nice; + unsigned long long diff_idle = next_idle - current_idle; + + return static_cast(diff_user + diff_system + diff_nice)/static_cast(diff_user + diff_system + diff_nice + diff_idle)*100.0; +} + +#else // APPLE + +// BSD type systems (FreeBSD/NetBSD/OpenBSD) +// Incomplete +float cpu_percentage( unsigned int cpu_usage_delay ) +{ + return 0.0f; +} + +std::string mem_string() +{ + return "0/0 MB"; +} + +#endif // APPLE + +// Both apple and BSD style systems have these api calls +std::string load_string() +{ + std::stringstream ss; + // Only get 3 load averages + int nelem = 3; + double averages[3]; + // based on: http://www.opensource.apple.com/source/Libc/Libc-262/gen/getloadavg.c + if(getloadavg(averages, nelem) < 0) + ss << "0.00 0.00 0.00"; // couldn't get averages. + else + { + for(int i = 0; i < nelem; ++i) + { + // Round to nearest, make sure this is only a 0.00 value not a 0.0000 + float avg = floorf(static_cast(averages[i]) * 100 + 0.5) / 100; + ss << avg << " "; + } + } + + return ss.str(); +} + +#else // APPLE || BSD_BASED + +// Linux based system, if it's windows, too much work, they can deal with their compile errors - CMD sucks anyway. +std::string mem_string() +{ + unsigned int total_mem; + unsigned int used_mem; + unsigned int unused_mem; + size_t line_start_pos; + size_t line_end_pos; + std::istringstream iss; + std::ostringstream oss; + std::string mem_line; + + std::ifstream meminfo_file( "/proc/meminfo" ); + std::getline( meminfo_file, mem_line ); + line_start_pos = mem_line.find_first_of( ':' ); + line_start_pos++; + line_end_pos = mem_line.find_first_of( 'k' ); + iss.str( mem_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); + iss >> total_mem; + + used_mem = total_mem; + + for( unsigned int i = 0; i < 3; i++ ) + { + std::getline( meminfo_file, mem_line ); + line_start_pos = mem_line.find_first_of( ':' ); + line_start_pos++; + line_end_pos = mem_line.find_first_of( 'k' ); + iss.str( mem_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); + iss >> unused_mem; + used_mem -= unused_mem; + } + meminfo_file.close(); + + oss << used_mem / 1024 << '/' << total_mem / 1024 << "MB"; + + return oss.str(); +} float cpu_percentage( unsigned int cpu_usage_delay ) { @@ -79,72 +301,6 @@ float cpu_percentage( unsigned int cpu_usage_delay ) return static_cast(diff_user + diff_system + diff_nice)/static_cast(diff_user + diff_system + diff_nice + diff_idle)*100.0; } -std::string cpu_string( unsigned int cpu_usage_delay, unsigned int graph_lines ) -{ - std::string meter( graph_lines + 2, ' ' ); - meter[0] = '['; - meter[meter.length() - 1] = ']'; - int meter_count = 0; - float percentage; - std::ostringstream oss; - oss.precision( 1 ); - oss.setf( std::ios::fixed | std::ios::right ); - - percentage = cpu_percentage( cpu_usage_delay ); - float meter_step = 99.9 / graph_lines; - meter_count = 1; - while(meter_count*meter_step < percentage) - { - meter[meter_count] = '|'; - meter_count++; - } - - oss << meter; - oss.width( 5 ); - oss << percentage; - oss << "%"; - - return oss.str(); -} - -std::string mem_string() -{ - unsigned int total_mem; - unsigned int used_mem; - unsigned int unused_mem; - size_t line_start_pos; - size_t line_end_pos; - std::istringstream iss; - std::ostringstream oss; - std::string mem_line; - - std::ifstream meminfo_file( "/proc/meminfo" ); - std::getline( meminfo_file, mem_line ); - line_start_pos = mem_line.find_first_of( ':' ); - line_start_pos++; - line_end_pos = mem_line.find_first_of( 'k' ); - iss.str( mem_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); - iss >> total_mem; - - used_mem = total_mem; - - for( unsigned int i = 0; i < 3; i++ ) - { - std::getline( meminfo_file, mem_line ); - line_start_pos = mem_line.find_first_of( ':' ); - line_start_pos++; - line_end_pos = mem_line.find_first_of( 'k' ); - iss.str( mem_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); - iss >> unused_mem; - used_mem -= unused_mem; - } - meminfo_file.close(); - - oss << used_mem / 1024 << '/' << total_mem / 1024 << "MB"; - - return oss.str(); -} - std::string load_string() { std::ifstream loadavg_file( "/proc/loadavg" ); @@ -155,6 +311,8 @@ std::string load_string() return load_line.substr( 0, 14 ); } +#endif // BSD + int main(int argc, char** argv) { unsigned int cpu_usage_delay = 900000;