Merge remote-tracking branch 'Justastic/master' #1, #2, #5

Add support for Mac OSX from Justastic.  Refactors the code from Justastic so it
works with the Linux code and so it also works for the new colors support.

Still need to test on OSX.

Conflicts:
	tmux-mem-cpu-load.cpp
This commit is contained in:
Matt McCormick 2013-06-09 20:49:21 -04:00
commit 9d072d4ec1
3 changed files with 174 additions and 27 deletions

@ -15,6 +15,5 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(tmux-mem-cpu-load tmux-mem-cpu-load.cpp)
install(TARGETS tmux-mem-cpu-load
RUNTIME
DESTINATION bin
RUNTIME DESTINATION bin
)

@ -27,7 +27,7 @@ Example output::
^ ^ ^ ^ ^ ^ ^
| | | | | | |
1 2 3 4 5 6 G
1 2 3 4 5 6 7
1. Currently used memory.
2. Available memory.
@ -48,10 +48,13 @@ Installation
Dependencies
------------
Currently only tested on Linux. Mac OSX is known not to work. Patches or
hardware are welcome.
Building
~~~~~~~~
* >= cmake_ -2.6
* >= CMake_ -2.6
* C++ compiler (e.g. gcc/g++)
@ -107,6 +110,6 @@ Matt McCormick (thewtex) <matt@mmmccormick.com>
.. _tmux: http://tmux.sourceforge.net/
.. _cmake: http://www.cmake.org
.. _CMake: http://www.cmake.org
.. _`project homepage`: http://github.com/thewtex/tmux-mem-cpu-load
.. _`terminals with 256 color support`: http://misc.flogisoft.com/bash/tip_colors_and_formatting#terminals_compatibility

@ -19,11 +19,90 @@
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h> // sleep
#include <cmath> // for floorf
// Apple specific.
#if defined(__APPLE__) && defined(__MACH__)
// Mach kernel includes for getting memory and CPU statistics
# include <mach/vm_statistics.h>
# include <mach/processor_info.h>
# include <mach/mach_types.h>
# include <mach/mach_init.h>
# include <mach/mach_host.h>
# include <mach/host_info.h>
# include <mach/mach_error.h>
# include <mach/vm_map.h>
# include <mach/mach.h>
# include <sys/sysctl.h> // for sysctl
# include <sys/types.h> // 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
// Tmux color lookup tables for the different metrics.
#include "luts.h"
// Function declarations.
float cpu_percentage( unsigned int cpu_usage_delay );
std::string cpu_string( unsigned int cpu_usage_delay,
unsigned int graph_lines,
bool use_colors = false );
std::string mem_string( bool use_colors = false );
std::string load_string( bool use_colors = false );
#if defined(BSD_BASED) || (defined(__APPLE__) && defined(__MACH__))
// OSX or BSD based system, use BSD APIs instead
// 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;
#else // Linux
float cpu_percentage( unsigned int cpu_usage_delay )
{
std::string stat_line;
@ -79,13 +158,14 @@ float cpu_percentage( unsigned int cpu_usage_delay )
diff_system = next_system - current_system;
diff_nice = next_nice - current_nice;
diff_idle = next_idle - current_idle;
#endif // platform
return static_cast<float>(diff_user + diff_system + diff_nice)/static_cast<float>(diff_user + diff_system + diff_nice + diff_idle)*100.0;
}
std::string cpu_string( unsigned int cpu_usage_delay,
unsigned int graph_lines,
bool use_colors = false )
bool use_colors )
{
std::string meter( graph_lines + 2, ' ' );
meter[0] = '[';
@ -99,7 +179,7 @@ std::string cpu_string( unsigned int cpu_usage_delay,
percentage = cpu_percentage( cpu_usage_delay );
float meter_step = 99.9 / graph_lines;
meter_count = 1;
while( meter_count*meter_step < percentage )
while(meter_count*meter_step < percentage)
{
meter[meter_count] = '|';
meter_count++;
@ -121,15 +201,56 @@ std::string cpu_string( unsigned int cpu_usage_delay,
return oss.str();
}
std::string mem_string( bool use_colors = false )
std::string mem_string( bool use_colors )
{
std::ostringstream oss;
#if defined(BSD_BASED) || (defined(__APPLE__) && defined(__MACH__))
// OSX or BSD based system, use BSD APIs instead
#if defined(__APPLE__) && defined(__MACH__)
// These values are in bytes
int64_t total_mem;
int64_t used_mem;
int64_t unused_mem;
vm_size_t page_size;
mach_port_t mach_port;
mach_msg_type_number_t count;
vm_statistics_data_t vm_stats;
// 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;
}
// To kilobytes
#endif // Apple
// TODO BSD
used_mem /= 1024;
total_mem /= 1024;
#else // Linux
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" );
@ -154,6 +275,8 @@ std::string mem_string( bool use_colors = false )
}
meminfo_file.close();
#endif // platform
if( use_colors )
{
oss << mem_lut[(100 * used_mem) / total_mem];
@ -167,27 +290,47 @@ std::string mem_string( bool use_colors = false )
return oss.str();
}
std::string load_string( bool use_colors = false )
std::string load_string( bool use_colors )
{
std::ostringstream oss;
#if defined(BSD_BASED) || (defined(__APPLE__) && defined(__MACH__))
// Both apple and BSD style systems have these api calls
// 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 )
{
oss << "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<float>(averages[i]) * 100 + 0.5) / 100;
oss << avg << " ";
}
}
#else // Linux
std::ifstream loadavg_file( "/proc/loadavg" );
std::string load_line;
std::getline( loadavg_file, load_line );
loadavg_file.close();
#endif // platform
if( use_colors )
{
std::ostringstream oss;
std::ifstream stat_file( "/proc/stat" );
std::string stat_line;
std::getline( stat_file, stat_line );
unsigned int number_of_cpus = 0;
std::getline( stat_file, stat_line );
do
{
++number_of_cpus;
std::getline( stat_file, stat_line );
}
while( stat_line.compare( 0, 3, "cpu" ) == 0 && stat_file.good() );
stat_file.close();
// Likely does not work on BSD, but not tested
unsigned int number_of_cpus = sysconf( _SC_NPROCESSORS_ONLN );
std::istringstream iss( load_line.substr( 0, 4 ) );
float recent_load;
@ -199,17 +342,19 @@ std::string load_string( bool use_colors = false )
{
load_percent = 100;
}
oss << load_lut[load_percent];
oss << load_line.substr( 0, 14 );
oss << "#[fg=default,bg=default]";
return oss.str();
}
return load_line.substr( 0, 14 );
oss << load_line.substr( 0, 14 );
if( use_colors )
{
oss << "#[fg=default,bg=default]";
}
return oss.str();
}
int main(int argc, char** argv)
{
unsigned int cpu_usage_delay = 900000;