diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bfe3068 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so +sysstat +tmux-mem-cpu-load + +# CMake generated # +################### +CMakeFiles +Makefile +cmake_install.cmake +CMakeCache.txt +install_manifest.txt +version.h +config.h +CTestTestfile.cmake +DartConfiguration.tcl + +# Packages # +############ +# it's better to unpack this files and commit raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +*.swp +*.swo +*~ diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..1dc35ec --- /dev/null +++ b/AUTHORS @@ -0,0 +1,12 @@ +Original author and maintainer: + + Mattherw McCormick + +Contributors (in alphabetical order): + + Justin Crawford + krieiter + Mark Palmeri + Pawel 'l0ner' Soltys + + diff --git a/CMakeLists.txt b/CMakeLists.txt index a9d2c3e..86336e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,92 @@ +# vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap +# +# Copyright 2012 Matthew McCormick +# Copyright 2015 Pawel 'l0ner' Soltys +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + cmake_minimum_required(VERSION 2.6) if(COMMAND cmake_policy) - cmake_policy(VERSION 2.6) + cmake_policy(VERSION 2.6) endif(COMMAND cmake_policy) +### General Package stuff project( tmux-mem-cpu-load ) +set(tmux-mem-cpu-load_VERSION_MAJOR 2) +set(tmux-mem-cpu-load_VERSION_MINOR 3) +set(tmux-mem-cpu-load_VERSION_PATCH 0) +#Compute full version string +set(tmux-mem-cpu-load_VERSION + ${tmux-mem-cpu-load_VERSION_MAJOR}.${tmux-mem-cpu-load_VERSION_MINOR}.${tmux-mem-cpu-load_VERSION_PATCH}) +# Check whether we have support for c++11 in compiler and fail if we don't +include(CheckCXXCompilerFlag) +check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11) +check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) + +if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +else() + message(FATAL_ERROR " +Compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} has no C++11 support.") +endif() + +# generate header file to handle version +configure_file( + "${PROJECT_SOURCE_DIR}/version.h.in" "${PROJECT_SOURCE_DIR}/version.h" + ) + +# set build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING - "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." - FORCE) + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) endif(NOT CMAKE_BUILD_TYPE) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +# detect system type +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + message("Linux detected") + set(METER_SOURCES "linux/memory.cc" "linux/cpu.cc" "linux/load.cc") +elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") + # Mac OS X source setting will go here + message( "Darwin detected") + set(METER_SOURCES "osx/memory.cc" "osx/cpu.cc" "osx/load.cc") +elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + # FreeBSD STUFF HERE + message("FreeBSD detected") + message( WARNING "FreeBSD is still experimental!" ) + set( METER_SOURCES "bsd/memory_freebsd.cc" "bsd/cpu.cc" "bsd/load.cc" ) +elseif(CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + # OpenBSD Stuff Here + message( "OpenBSD detected") + message( FATAL_ERROR "OpenBSD is not supported! See bsd/openBSD.txt for more + info" ) + set( METER_SOURCES "bsd/memory_openbsd.cc" "bsd/cpu.cc" "bsd/load.cc" ) +else() + message( FATAL_ERROR "Cannot be compiled on this system" ) +endif() -add_executable(tmux-mem-cpu-load tmux-mem-cpu-load.cpp) -install(TARGETS tmux-mem-cpu-load - RUNTIME DESTINATION bin - ) +# set common source files +set( COMMON_SOURCES "tmux-mem-cpu-load.cpp" "graph.cc" ) + +# add binary tree so we find version.h +include_directories("${PROJECT_BINARY_DIR}" ) + +add_executable(tmux-mem-cpu-load ${COMMON_SOURCES} ${METER_SOURCES}) +install(TARGETS tmux-mem-cpu-load RUNTIME DESTINATION bin) include( CTest ) if( BUILD_TESTING ) @@ -26,17 +96,20 @@ if( BUILD_TESTING ) add_test( NAME no_arguments COMMAND tmux-mem-cpu-load ) + add_test( NAME custom_interval + COMMAND tmux-mem-cpu-load -i 3 ) + + add_test( NAME no_cpu_graph + COMMAND tmux-mem-cpu-load -g 0 ) + add_test( NAME colors COMMAND tmux-mem-cpu-load --colors ) - add_test( NAME arguments - COMMAND tmux-mem-cpu-load --colors 1 4 ) - add_test( NAME invalid_status_interval - COMMAND tmux-mem-cpu-load -1 4 ) + COMMAND tmux-mem-cpu-load -i -1 ) add_test( NAME invalid_graph_lines - COMMAND tmux-mem-cpu-load 1 -4 ) + COMMAND tmux-mem-cpu-load --graph_lines -2 ) set_tests_properties( usage invalid_status_interval diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 0000000..86b8ed0 --- /dev/null +++ b/CONTRIBUTING @@ -0,0 +1,53 @@ +============ +Contributing +============ + +Want to improve the quality of tmux-mem-cpu-load code? Great! Here's a quick +guide: + +1. Fork, then clone the repo: + + git clone git@github.com:your-username/tmux-mem-cpu-load + +2. Make your change. Add tests for your change. +3. See if it compiles and runs like it should. +4. Run tests to check if you didn't break anything: + + make test + +Push to your fork and `submit a pull request`_. + +At this point you're waiting on us. We'll review your changes as soon as we can. +Before merging your changes we may request you to make some changes or +corrections. + +Style guidelines +---------------- + +You'll need to follow the subsequent rules in order to get your code merged: + +* Use Allman_ style for block braces. +* No space before `(` +* Add space after each `(` and before each `)` +* Use braces single line statements +* Don't use mixed case naming style, use underscores instead. + Bad example: + + int myAwesomeVariable = 0; + doSomething( myAwesomeVariable ); + + Good example: + + int my_awesome_variable = 0; + do_something( my_awesome_variable ); + +* Don't vertically align tokens on consecutive lines. +* If you break up an argument list, align the line to opening brace +* Use 2 space indentation (no tabs) +* Use spaces around operators, except for unary operators, such as `!`. +* Add LICENSE header in new files you create. +* Put vim modeline as the first line of file header +* Use the lower-case for CMake commands + +.. _`submit a pull request`: https://github.com/thewtex/tmux-mem-cpu-load/compare/ +.. _Allman: http://en.wikipedia.org/wiki/Indent_style#Allman_style diff --git a/README.rst b/README.rst index 35e5991..9cf0128 100644 --- a/README.rst +++ b/README.rst @@ -53,7 +53,7 @@ Building ~~~~~~~~ * >= CMake_ -2.6 -* C++ compiler (e.g. gcc/g++) +* C++ compiler with C++11 support (e.g. gcc/g++ >= 4.6) Download -------- @@ -106,9 +106,11 @@ Contributions from: * Justin Crawford * krieiter * Mark Palmeri +* `Pawel 'l0ner' Soltys`_ .. _tmux: http://tmux.sourceforge.net/ .. _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 +.. _`Pawel 'l0ner' Soltys` : http://l0ner.github.io/ diff --git a/bsd/cpu.cc b/bsd/cpu.cc new file mode 100644 index 0000000..70e3560 --- /dev/null +++ b/bsd/cpu.cc @@ -0,0 +1,57 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on: github.com/freebsd/freebsd/blob/master/usr.bin/top/machine.c +// Based on: Apple.cpp for load_string/mem_string and apple's documentation + +#include +#include // usleep + +#include "getsysctl.h" +#include "cpu.h" + +float cpu_percentage( unsigned int cpu_usage_delay ) +{ + int32_t load1[CPUSTATES]; + int32_t load2[CPUSTATES]; + + GETSYSCTL( "kern.cp_time", load1 ); + usleep( cpu_usage_delay ); + GETSYSCTL( "kern.cp_time", load2 ); + + // Current load times + unsigned long long current_user = load1[CP_USER]; + unsigned long long current_system = load1[CP_SYS]; + unsigned long long current_nice = load1[CP_NICE]; + unsigned long long current_idle = load1[CP_IDLE]; + // Next load times + unsigned long long next_user = load2[CP_USER]; + unsigned long long next_system = load2[CP_SYS]; + unsigned long long next_nice = load2[CP_NICE]; + unsigned long long next_idle = load2[CP_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; +} diff --git a/bsd/cpu.h b/bsd/cpu.h new file mode 100644 index 0000000..ebc0e8e --- /dev/null +++ b/bsd/cpu.h @@ -0,0 +1,24 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CPU_H_ +#define CPU_H_ + +float cpu_percentage( unsigned ); + +#endif diff --git a/bsd/getsysctl.h b/bsd/getsysctl.h new file mode 100644 index 0000000..58f6860 --- /dev/null +++ b/bsd/getsysctl.h @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on: github.com/freebsd/freebsd/blob/master/usr.bin/top/machine.c +// Based on: Apple.cpp for load_string/mem_string and apple's documentation + +#ifndef BSD_METER_COMMON_H_ +#define BSD_METER_COMMON_H_ + +#include +#include +#include +#include + +// CPU percentages stuff +#define CP_USER 0 +#define CP_NICE 1 +#define CP_SYS 2 +#define CP_INTR 3 +#define CP_IDLE 4 +#define CPUSTATES 5 + +#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) +static inline void getsysctl( const char *name, void *ptr, size_t len ) +{ + size_t nlen = len; + + if( sysctlbyname( name, ptr, &nlen, NULL, 0 ) == -1 ) + { + std::cerr << "sysctl(" << name << "...) failed: " << strerror( errno ) + << std::endl; + exit( 23 ); + } + + if( nlen != len ) + { + std::cerr << "sysctl(" << name << "...) expected " + << static_cast( len ) << " bytes, got " + << static_cast( nlen ) << " bytes\n"; + //exit( 23 ); + } +} + +#endif diff --git a/bsd/load.cc b/bsd/load.cc new file mode 100644 index 0000000..1ae14cc --- /dev/null +++ b/bsd/load.cc @@ -0,0 +1,81 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on: github.com/freebsd/freebsd/blob/master/usr.bin/top/machine.c +// Based on: Apple.cpp for load_string/mem_string and apple's documentation + +#include +#include +#include // getloadavg() +#include // floorf() +#include + +#include "getsysctl.h" +#include "load.h" +#include "../luts.h" + +// Load Averages +std::string load_string( bool use_colors = false ) +{ + std::stringstream ss; + // Get only 3 load averages + const int nelem = 3; + double averages[nelem]; + // based on: 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 + { + if( use_colors ) + { + // may not work + int32_t cpu_count = 0; + GETSYSCTL( "hw.ncpu", cpu_count ); + + unsigned load_percent = static_cast( averages[0] / + cpu_count * 0.5f * 100.0f ); + + if( load_percent > 100 ) + { + load_percent = 100; + } + + ss << load_lut[load_percent]; + } + + 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 << " "; + } + + if( use_colors ) + { + ss << "#[fg=default,bg=default]"; + } + + } + + return ss.str(); +} + diff --git a/bsd/load.h b/bsd/load.h new file mode 100644 index 0000000..f1bbc58 --- /dev/null +++ b/bsd/load.h @@ -0,0 +1,26 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOAD_H_ +#define LOAD_H_ + +#include + +std::string load_string( bool ); + +#endif diff --git a/bsd/memory.h b/bsd/memory.h new file mode 100644 index 0000000..3a123bb --- /dev/null +++ b/bsd/memory.h @@ -0,0 +1,26 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#include + +std::string mem_string( bool ); + +#endif diff --git a/bsd/memory_freebsd.cc b/bsd/memory_freebsd.cc new file mode 100644 index 0000000..23fe67f --- /dev/null +++ b/bsd/memory_freebsd.cc @@ -0,0 +1,76 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on: github.com/freebsd/freebsd/blob/master/usr.bin/top/machine.c +// Based on: Apple.cpp for load_string/mem_string and apple's documentation + +#include +#include +#include + +#include "getsysctl.h" +#include "memory.h" +#include "../luts.h" +#include "../conversions.h" + +std::string mem_string( bool use_colors = false ) +{ + // These values are in bytes + int32_t total_mem = 0; + int64_t used_mem = 0; + int64_t unused_mem = 0; + int32_t inactive_mem = 0; + int32_t active_mem = 0; + int32_t free_mem = 0; + int32_t wired_mem = 0; + int32_t page_size = 0; + int32_t cache_mem = 0; + std::ostringstream oss; + + // Get total physical memory, page size, and some other needed info + GETSYSCTL( "hw.realmem", total_mem ); + GETSYSCTL( "hw.pagesize", page_size ); + + GETSYSCTL( "vm.stats.vm.v_free_count", free_mem ); + GETSYSCTL( "vm.stats.vm.v_inactive_count", inactive_mem ); + GETSYSCTL( "vm.stats.vm.v_cache_count", cache_mem ); + GETSYSCTL( "vm.stats.vm.v_wire_count", wired_mem ); + GETSYSCTL( "vm.stats.vm.v_active_count", active_mem ); + + // Get all memory which can be allocated + //unused_mem = (cache_mem + free_mem) * page_size; + used_mem = ( static_cast( active_mem ) + + static_cast( inactive_mem ) + + static_cast( wired_mem ) ) * static_cast( page_size ); + + if( use_colors ) + { + oss << mem_lut[( 100 * used_mem ) / total_mem]; + } + + oss << convert_unit( used_mem, MEGABYTES ) << '/' + << convert_unit( total_mem, MEGABYTES ) << "MB"; + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} + diff --git a/bsd/memory_openbsd.cc b/bsd/memory_openbsd.cc new file mode 100644 index 0000000..69bdd03 --- /dev/null +++ b/bsd/memory_openbsd.cc @@ -0,0 +1,78 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on: github.com/freebsd/freebsd/blob/master/usr.bin/top/machine.c +// Based on: Apple.cpp for load_string/mem_string and apple's documentation + +#error ToDo: OpenBSD. This file is incomplete and likely will not compile if you remove this error (it is here to tell you it's unfinished) + +#include +#include +#include + +#include "getsysctl.h" +#include "memory.h" +#include "../luts.h" +#include "../conversions.h" + +std::string mem_string( bool use_colors = false ) +{ + // These values are in bytes + int64_t total_mem = 0; + int64_t used_mem = 0; + int64_t unused_mem = 0; + int32_t inactive_mem = 0; + int32_t active_mem = 0; + int32_t free_mem = 0; + int32_t wired_mem = 0; + int32_t page_size = 0; + int32_t cache_mem = 0; + std::ostringstream oss; + + // Get total physical memory, page size, and some other needed info + GETSYSCTL( "hw.realmem", total_mem ); + GETSYSCTL( "hw.pagesize", page_size ); + + GETSYSCTL( "vm.stats.vm.v_free_count", free_mem ); + GETSYSCTL( "vm.stats.vm.v_inactive_count", inactive_mem ); + GETSYSCTL( "vm.stats.vm.v_cache_count", cache_mem ); + GETSYSCTL( "vm.stats.vm.v_wire_count", wired_mem ); + + // Get all memory which can be allocated + //unused_mem = (inactive_mem + cache_mem + free_mem) * page_size; + used_mem = ( + static_cast( active_mem ) + static_cast( wired_mem ) + + static_cast( inactive_mem ) ) * static_cast( page_size ); + + if( use_colors ) + { + oss << mem_lut[( 100 * used_mem ) / total_mem]; + } + + oss << convert_unit( used_mem, MEGABYTES ) << '/' + << convert_unit( total_mem, MEGABYTES ) << "MB"; + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} + diff --git a/bsd/openBSD.txt b/bsd/openBSD.txt new file mode 100644 index 0000000..4a7c804 --- /dev/null +++ b/bsd/openBSD.txt @@ -0,0 +1,19 @@ +About OpenBSD Port +================== + +I've decided not to do OpenBSD port. Some preparations has been made both +by myself and (mainly) by Justin Crawford, so finish it shouldn't be difficult. +Personally, after installing OpenBSD and trying to finish the port I've +discovered that g++ supplied by OpenBSD (version 5.7) doesn't support c++11. +This means we lose the ability to use to_string() and stoi() functions. I could +write replacements for them, or try to get c++11 working on OpenBSD. But I +decided not to. At least for the moment. + +I don't know OpenBSD, it's unfamiliar ground for me. And while FreeBSD was easy +to get into, I have found OpenBSD a little bit more difficult. + +So, no OpenBSD port for now. If you are OpenBSD user and know a little bit c++ +finishing the port should be easy (once you get C++11 working). + +l0ner + diff --git a/conversions.h b/conversions.h new file mode 100644 index 0000000..701f177 --- /dev/null +++ b/conversions.h @@ -0,0 +1,35 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +enum +{ + BYTES = 0, + KILOBYTES = 1, + MEGABYTES = 2, + GIGABYTES = 3 +}; + +template +inline T convert_unit( T num, int to, int from = BYTES) +{ + for(from; from < to; from++) + { + num /= 1024; + } + return num; +} diff --git a/graph.cc b/graph.cc new file mode 100644 index 0000000..8491f21 --- /dev/null +++ b/graph.cc @@ -0,0 +1,62 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "graph.h" + +std::string get_graph_by_percentage( unsigned value, unsigned len ) +{ + unsigned step = 0; + std::string bars; + + unsigned bar_count = ( static_cast(value) / 99.9 * len ); + + for( step; step < bar_count; step++ ) + { + bars.append( "|" ); + } + for( step; step < len; step++ ) + { + bars.append( " " ); + } + + return bars; +} + + +std::string get_graph_by_value( unsigned value, unsigned max, unsigned len ) +{ + unsigned step = 0; + std::string bars; + + unsigned bar_count = ( static_cast( value / ( max - 0.1 ) ) * len ); + + for( step; step < bar_count; step++ ) + { + bars.append( "|" ); + } + for( step; step < len; step++ ) + { + bars.append( " " ); + } + + return bars; +} + diff --git a/graph.h b/graph.h new file mode 100644 index 0000000..4034161 --- /dev/null +++ b/graph.h @@ -0,0 +1,27 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GRAPH_H_ +#define GRAPH_H_ + +#include + +std::string get_graph_by_percentage( unsigned, unsigned len = 10 ); +std::string get_graph_by_value( unsigned, unsigned, unsigned len = 10 ); + +#endif diff --git a/linux/cpu.cc b/linux/cpu.cc new file mode 100644 index 0000000..e55ccb2 --- /dev/null +++ b/linux/cpu.cc @@ -0,0 +1,70 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include // usleep + +#include "cpu.h" +#include "../luts.h" + +float cpu_percentage( unsigned cpu_usage_delay ) +{ + std::string line; + size_t substr_start = 0; + size_t substr_len; + + // cpu stats + // user, nice, system, idle + // in that order + unsigned long long stats[4]; + + std::ifstream stat_file( "/proc/stat" ); + getline( stat_file, line ); + stat_file.close(); + + // skip "cpu" + substr_len = line.find_first_of( " ", 3 ); + // parse cpu line + for( unsigned i=0; i < 4; i++ ) + { + substr_start = line.find_first_not_of( " ", substr_len ); + substr_len = line.find_first_of( " ", substr_start ); + stats[i] = std::stoll( line.substr( substr_start, substr_len ) ); + } + + usleep( cpu_usage_delay ); + + stat_file.open( "/proc/stat" ); + getline( stat_file, line ); + stat_file.close(); + + // skip "cpu" + substr_len = line.find_first_of( " ", 3 ); + // parse cpu line + for( unsigned i=0; i < 4; i++ ) + { + substr_start = line.find_first_not_of( " ", substr_len ); + substr_len = line.find_first_of ( " ", substr_start ); + stats[i] = std::stoll( line.substr( substr_start, substr_len ) ) - stats[i]; + } + + return static_cast( stats[0] + stats[1] + stats[2]) / + static_cast( stats[0] + stats[1] + stats[2] + stats[3] ) * 100.0; +} + diff --git a/linux/cpu.h b/linux/cpu.h new file mode 100644 index 0000000..ebc0e8e --- /dev/null +++ b/linux/cpu.h @@ -0,0 +1,24 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CPU_H_ +#define CPU_H_ + +float cpu_percentage( unsigned ); + +#endif diff --git a/linux/load.cc b/linux/load.cc new file mode 100644 index 0000000..917a20b --- /dev/null +++ b/linux/load.cc @@ -0,0 +1,70 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include // sysconf()? +#include +#include // SI_LOAD_SHIFT + +#include "load.h" +#include "../luts.h" + +std::string load_string( bool use_colors = false ) +{ + std::ostringstream oss; + + float f = static_cast( 1 << SI_LOAD_SHIFT ); + + struct sysinfo sinfo; + sysinfo( &sinfo ); + + if( use_colors ) + { + // Likely does not work on BSD, but not tested + unsigned number_of_cpus = sysconf( _SC_NPROCESSORS_ONLN ); + + float recent_load = sinfo.loads[0] / f; + + // colors range from zero to twice the number of cpu's + // for the most recent load metric + unsigned load_percent = static_cast< unsigned int >( + recent_load / number_of_cpus * 0.5f * 100.0f ); + + if( load_percent > 100 ) + { + load_percent = 100; + } + + oss << load_lut[load_percent]; + } + + // set precision so we get results like "0.22" + oss.setf( std::ios::fixed ); + oss.precision( 2 ); + + oss << sinfo.loads[0] / f << " " << sinfo.loads[1] / f << " " + << sinfo.loads[2] / f; + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} diff --git a/linux/load.h b/linux/load.h new file mode 100644 index 0000000..f1bbc58 --- /dev/null +++ b/linux/load.h @@ -0,0 +1,26 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOAD_H_ +#define LOAD_H_ + +#include + +std::string load_string( bool ); + +#endif diff --git a/linux/memory.cc b/linux/memory.cc new file mode 100644 index 0000000..9f96b0d --- /dev/null +++ b/linux/memory.cc @@ -0,0 +1,105 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "memory.h" +#include "../luts.h" +#include "../conversions.h" + +std::string mem_string( bool use_colors = false ) +{ + using std::string; + using std::ifstream; + using std::stoi; + + std::ostringstream oss; + + string line, substr; + size_t substr_start; + size_t substr_len; + + unsigned int total_mem, used_mem; + + /* Since linux uses some RAM for disk caching, the actuall used ram is lower + * than what sysinfo(), top or free reports. htop reports the usage in a + * correct way. The memory used for caching doesn't count as used, since it + * can be freed in any moment. Usually it hapens automatically, when an + * application requests memory. + * In order to calculate the ram that's actually used we need to use the + * following formula: + * total_ram - free_ram - buffered_ram - cached_ram + * + * example data, junk removed, with comments added: + * + * MemTotal: 61768 kB old + * MemFree: 1436 kB old + * MemAvailable ????? kB ?? + * MemShared: 0 kB old (now always zero; not calculated) + * Buffers: 1312 kB old + * Cached: 20932 kB old + * SwapTotal: 122580 kB old + * SwapFree: 60352 kB old + */ + + ifstream memory_info("/proc/meminfo"); + + while( getline( memory_info, line ) ) + { + substr_start = 0; + substr_len = line.find_first_of( ':' ); + substr = line.substr( substr_start, substr_len ); + substr_start = line.find_first_not_of( " ", substr_len + 1 ); + substr_len = line.find_first_of( 'k' ) - substr_start; + if( substr.compare( "MemTotal" ) == 0 ) + { + // get total memory + total_mem = stoi( line.substr( substr_start, substr_len ) ); + } + else if( substr.compare( "MemFree" ) == 0 ) + { + used_mem = total_mem - stoi( line.substr( substr_start, substr_len ) ); + } + else if( substr.compare( "Buffers" ) == 0 || + substr.compare( "Cached" ) == 0 ) + { + used_mem -= stoi( line.substr( substr_start, substr_len ) ); + } + } + + if( use_colors ) + { + oss << mem_lut[(100 * used_mem) / total_mem]; + } + + // we want megabytes on output, but since the values already come as + // kilobytes we need to divide them by 1024 only once, thus we use + // KILOBYTES + oss << convert_unit(used_mem, MEGABYTES, KILOBYTES) << '/' + << convert_unit(total_mem, MEGABYTES, KILOBYTES) << "MB"; + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} + diff --git a/linux/memory.h b/linux/memory.h new file mode 100644 index 0000000..3a123bb --- /dev/null +++ b/linux/memory.h @@ -0,0 +1,26 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#include + +std::string mem_string( bool ); + +#endif diff --git a/osx/cpu.cc b/osx/cpu.cc new file mode 100644 index 0000000..f38fbe4 --- /dev/null +++ b/osx/cpu.cc @@ -0,0 +1,75 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include // usleep() + +#include "cpu.h" + +// 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; + + return static_cast( diff_user + diff_system + diff_nice ) / + static_cast( diff_user + diff_system + diff_nice + diff_idle ) * + 100.0; +} + diff --git a/osx/cpu.h b/osx/cpu.h new file mode 100644 index 0000000..1652c03 --- /dev/null +++ b/osx/cpu.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CPU_H_ +#define CPU_H_ + +float cpu_percentage ( unsigned ); + +#endif diff --git a/osx/load.cc b/osx/load.cc new file mode 100644 index 0000000..029add2 --- /dev/null +++ b/osx/load.cc @@ -0,0 +1,89 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include // floorf() + +#include +#include // getloadavg() + +#include "load.h" +#include "../luts.h" + +std::string load_string( bool use_colors = false ) +{ + std::ostringstream oss; + + // Both apple and BSD style systems have these api calls + // Only get 3 load averages + const int nelem = 3; + double averages[nelem]; + // 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( averages[i] ) * 100 + 0.5 ) / 100; + oss << avg << " "; + } + } + + std::string load_line( oss.str() ); + oss.str( "" ); + + if( use_colors ) + { + // Likely does not work on BSD, but not tested + unsigned number_of_cpus = sysconf( _SC_NPROCESSORS_ONLN ); + + std::istringstream iss( load_line.substr( 0, 4 ) ); + float recent_load; + iss >> recent_load; + // colors range from zero to twice the number of + // cpu's for the most recent load metric + + unsigned load_percent = static_cast< unsigned int >( + recent_load / number_of_cpus * 0.5f * 100.0f ); + + if( load_percent > 100 ) + { + load_percent = 100; + } + + oss << load_lut[load_percent]; + } + + oss << load_line.substr( 0, 14 ); + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} + diff --git a/osx/load.h b/osx/load.h new file mode 100644 index 0000000..16cd762 --- /dev/null +++ b/osx/load.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOAD_H_ +#define LOAD_H_ + +#include + +std::string load_string( bool ); + +#endif diff --git a/osx/memory.cc b/osx/memory.cc new file mode 100644 index 0000000..bacad9d --- /dev/null +++ b/osx/memory.cc @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include // for sysctl + +#include "memory.h" +#include "../luts.h" +#include "../conversions.h" + +std::string mem_string( bool use_colors ) +{ + std::ostringstream oss; + + // 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; + } + + if( use_colors ) + { + oss << mem_lut[( 100 * used_mem ) / total_mem]; + } + + oss << convert_unit( used_mem, MEGABYTES ) << '/' + << convert_unit( total_mem, MEGABYTES ) << "MB"; + + if( use_colors ) + { + oss << "#[fg=default,bg=default]"; + } + + return oss.str(); +} diff --git a/osx/memory.h b/osx/memory.h new file mode 100644 index 0000000..3d89aa3 --- /dev/null +++ b/osx/memory.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 Matthew McCormick + * Copyright 2013 Justin Crawford + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#include + +std::string mem_string( bool ); + +#endif diff --git a/tmux-mem-cpu-load.cpp b/tmux-mem-cpu-load.cpp index 44e9446..11180c2 100644 --- a/tmux-mem-cpu-load.cpp +++ b/tmux-mem-cpu-load.cpp @@ -1,4 +1,5 @@ -/* +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * * Copyright 2012 Matthew McCormick * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,412 +13,156 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ + */ #include -#include #include +#include #include #include -#include // sleep -#include // for floorf -#include // EXIT_SUCCESS +#include // EXIT_SUCCESS, atoi() +#include // getopt_long -// 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 +#include "version.h" +#include "graph.h" // 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(__APPLE__) && defined(__MACH__) + // Apple osx system + #include "osx/cpu.h" + #include "osx/memory.h" + #include "osx/load.h" +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + // BSD system + #define BSD_BASED 1 + #include "bsd/cpu.h" + #include "bsd/load.h" + #include "bsd/memory.h" +#else + // assume linux system + #include "linux/cpu.h" + #include "linux/memory.h" + #include "linux/load.h" +#endif - -#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() +std::string cpu_string( unsigned int cpu_usage_delay, unsigned int graph_lines, + bool use_colors = false ) { - 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; - size_t line_start_pos; - size_t line_end_pos; - unsigned long long current_user; - unsigned long long current_system; - unsigned long long current_nice; - unsigned long long current_idle; - unsigned long long next_user; - unsigned long long next_system; - unsigned long long next_nice; - unsigned long long next_idle; - unsigned long long diff_user; - unsigned long long diff_system; - unsigned long long diff_nice; - unsigned long long diff_idle; - std::istringstream iss; - - std::ifstream stat_file("/proc/stat"); - getline(stat_file, stat_line); - stat_file.close(); - - // skip "cpu" - line_start_pos = stat_line.find_first_not_of(" ", 3); - line_end_pos = stat_line.find_first_of(' ', line_start_pos); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - - iss.str( stat_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); - iss >> current_user >> current_nice >> current_system >> current_idle; - iss.clear(); - - usleep( cpu_usage_delay ); - - stat_file.open("/proc/stat"); - getline(stat_file, stat_line); - stat_file.close(); - - // skip "cpu" - line_start_pos = stat_line.find_first_not_of(" ", 3); - line_end_pos = stat_line.find_first_of(' ', line_start_pos); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - line_end_pos = stat_line.find_first_of(' ', line_end_pos + 1); - - iss.str( stat_line.substr( line_start_pos, line_end_pos - line_start_pos ) ); - iss >> next_user >> next_nice >> next_system >> next_idle; - iss.clear(); - - diff_user = next_user - current_user; - diff_system = next_system - current_system; - diff_nice = next_nice - current_nice; - diff_idle = next_idle - current_idle; -#endif // platform - - 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, - bool use_colors ) -{ - std::string meter( graph_lines + 2, ' ' ); - meter[0] = '['; - meter[meter.length() - 1] = ']'; - int meter_count = 0; float percentage; + + //output stuff std::ostringstream oss; oss.precision( 1 ); oss.setf( std::ios::fixed | std::ios::right ); + // get % 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++; - } if( use_colors ) - { + { oss << cpu_percentage_lut[static_cast( percentage )]; - } - oss << meter; + } + + if( graph_lines > 0) + { + oss << "["; + oss << get_graph_by_percentage( unsigned( percentage ), graph_lines ); + oss << "]"; + } oss.width( 5 ); oss << percentage; oss << "%"; if( use_colors ) - { + { oss << "#[fg=default,bg=default]"; - } + } return oss.str(); } - -std::string mem_string( bool use_colors ) +void print_help() { - 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::string mem_line; - - std::ifstream meminfo_file( "/proc/meminfo" ); - 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++ ) - { - getline( meminfo_file, mem_line ); - // accomodate MemAvailable potentially being in lines 2-4 of /proc/meminfo - // did this in a way to not break the original logic of the loop - if( mem_line.find("MemAvailable") == 0 ) - { - i--; - } - else - { - 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(); - -#endif // platform - - if( use_colors ) - { - oss << mem_lut[(100 * used_mem) / total_mem]; - } - oss << used_mem / 1024 << '/' << total_mem / 1024 << "MB"; - if( use_colors ) - { - oss << "#[fg=default,bg=default]"; - } - - return oss.str(); + using std::cout; + using std::endl; + + cout << "tmux-mem-cpu-load v" << tmux_mem_cpu_load_VERSION << endl + << "Usage: tmux-mem-cpu-load [OPTIONS]\n\n" + << "Available options:\n" + << "-h, --help\n" + << "\t Prints this help message\n" + << "--colors\n" + << "\tUse tmux colors in output\n" + << "-i , --interval \n" + << "\tSet tmux status refresh interval in seconds. Default: 1 second\n" + << "-g , --graph-lines \n" + << "\tSet how many lines should be drawn in a graph. Default: 10\n" + << endl; } - -std::string load_string( bool use_colors ) +int main( int argc, char** argv ) { - 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(averages[i]) * 100 + 0.5) / 100; - oss << avg << " "; - } - } - std::string load_line( oss.str() ); - oss.str( "" ); - -#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::ifstream stat_file( "/proc/stat" ); - std::string stat_line; - std::getline( stat_file, stat_line ); - // 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; - iss >> recent_load; - // colors range from zero to twice the number of cpu's for the most recent - // load metric - unsigned int load_percent = static_cast< unsigned int >( recent_load / number_of_cpus * 0.5f * 100.0f ); - if( load_percent > 100 ) - { - load_percent = 100; - } - oss << load_lut[load_percent]; - } - - 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; - int graph_lines = 10; + unsigned cpu_usage_delay = 990000; + short graph_lines = 10; // max 32767 should be enough bool use_colors = false; - try - { - std::istringstream iss; - iss.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); - std::string current_arg; - unsigned int arg_index = 1; - if( argc > arg_index ) - { - if( strcmp( argv[arg_index], "--colors" ) == 0 ) - { - use_colors = true; - ++arg_index; - } - } - if( argc > arg_index ) - { - iss.str( argv[arg_index] ); - int status_interval; - iss >> status_interval; - if( status_interval < 1 ) - { - std::cerr << "Status interval argument must be one or greater." << std::endl; - return EXIT_FAILURE; - } - cpu_usage_delay = status_interval * 1000000 - 100000; - ++arg_index; - } - if( argc > arg_index ) - { - iss.str( argv[arg_index] ); - iss.clear(); - iss >> graph_lines; - if( graph_lines < 1 ) - { - std::cerr << "Graph lines argument must be one or greater." << std::endl; - return EXIT_FAILURE; - } - } - } - catch(const std::exception &e) - { - std::cerr << "Usage: " << argv[0] << " [--colors] [tmux_status-interval(seconds)] [graph lines]" << std::endl; - return EXIT_FAILURE; - } - std::cout << mem_string( use_colors ) << ' ' << cpu_string( cpu_usage_delay, graph_lines, use_colors ) << ' ' << load_string( use_colors ); + static struct option long_options[] = + { + // Struct is a s follows: + // const char * name, int has_arg, int *flag, int val + // if *flag is null, val is option identifier to use in switch() + // otherwise it's a value to set the variable *flag points to + { "help", no_argument, NULL, 'h' }, + { "colors", no_argument, NULL, 'c' }, + { "interval", required_argument, NULL, 'i' }, + { "graph-lines", required_argument, NULL, 'g' }, + { 0, 0, 0, 0 } // used to handle unknown long options + }; + + int c; + // while c != -1 + while( (c = getopt_long( argc, argv, "hi:g:", long_options, NULL) ) != -1 ) + { + switch( c ) + { + case 'h': // --help, -h + print_help(); + return EXIT_FAILURE; + break; + case 'c': // --colors + use_colors = true; + break; + case 'i': // --interval, -i + if( atoi( optarg ) < 1 ) + { + std::cerr << "Status interval argument must be one or greater.\n"; + return EXIT_FAILURE; + } + cpu_usage_delay = atoi( optarg ) * 1000000 - 10000; + break; + case 'g': // --graph-lines, -g + if( atoi( optarg ) < 0 ) + { + std::cerr << "Graph lines argument must be zero or greater.\n"; + return EXIT_FAILURE; + } + graph_lines = atoi( optarg ); + break; + case '?': + // getopt_long prints error message automatically + return EXIT_FAILURE; + break; + default: + std::cout << "?? getopt returned character code 0 " << c << std::endl; + return EXIT_FAILURE; + } + } + + std::cout << mem_string( use_colors ) << ' ' + << cpu_string( cpu_usage_delay, graph_lines, use_colors ) << ' ' + << load_string( use_colors ); return EXIT_SUCCESS; } diff --git a/version.h.in b/version.h.in new file mode 100644 index 0000000..5268d15 --- /dev/null +++ b/version.h.in @@ -0,0 +1,24 @@ +/* vim: tabstop=2 shiftwidth=2 expandtab textwidth=80 linebreak wrap + * + * Copyright 2012 Matthew McCormick + * Copyright 2015 Pawel 'l0ner' Soltys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// the configured options and settings for sysstat +#define tmux_mem_cpu_load_VERSION_MAJOR @tmux-mem-cpu-load_VERSION_MAJOR@ +#define tmux_mem_cpu_load_VERSION_MINOR @tmux-mem-cpu-load_VERSION_MINOR@ +#define tmux_mem_cpu_load_VERSION_PATCH @tmux-mem-cpu-load_VERSION_PATCH@ +#define tmux_mem_cpu_load_VERSION "@tmux-mem-cpu-load_VERSION@" +