[
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nCopyright (c) 2017 Alexey Samoshkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "readme.md",
    "content": "\nTmux sysstat plugin\n===================\nAllow to print CPU usage, memory & swap, load average, net I/O metrics in Tmux status bar\n\n![intro](/screenshots/intro.png)\n\nYou might checkout [tmux-config](https://github.com/samoshkin/tmux-config) repo to see this plugin in action.\n\nFeatures\n--------\n- CPU usage\n- Memory available/free, used, total (KiB,MiB,GiB), free/used %\n- Swap used, free, total, free/used %\n- load average for last 1,5,15 minutes\n- configurable thresholds (low, medium, stress) with custom colors\n- tweak each metric output using templates (e.g, 'used 10% out of 16G')\n- configurable size scale (K,M,G)\n- OSX, Linux support\n- [ ] **TODO:** network I/O metric support\n\nTested on: OS X El Capitan 10.11.5, Ubuntu 14 LTS, CentOS 7, FreeBSD 11.1.\n\n\nInstallation\n------------\nBest installed through [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (TMP). Add following line to your `.tmux.conf` file:\n\n```\nset -g @plugin 'samoshkin/tmux-plugin-sysstat'\n```\n\nUse `prefix + I` from inside tmux to install all plugins and source them. If you prefer, same effect can be achieved from [command line](https://github.com/tmux-plugins/tpm/blob/master/docs/managing_plugins_via_cmd_line.md):\n\n```\n$ ~.tmux/plugins/tpm/bin/install_plugins\n```\n\nBasic usage\n-----------\n\nOnce plugged in, tmux `status-left` or `status-right` options can be configured with following placeholders. Each placeholder will be expanded to metric's default output.\n\n- `#{sysstat_cpu}`, CPU usage - `CPU:40.2%`\n- `#{sysstat_mem}`, memory usage - `MEM:73%`\n- `#{sysstat_swap}`, swap usage - `SW:66%`\n- `#{sysstat_loadavg}`, system load average - `0.25 0.04 0.34`\n\nFor example:\n```\nset -g status-right \"#{sysstat_cpu} | #{sysstat_mem} | #{sysstat_swap} | #{sysstat_loadavg} | #[fg=cyan]#(echo $USER)#[default]@#H\"\n```\n\nChanging default output\n------------------------\n\nYou can change default output for CPU and memory metrics, if you need more fields to show, or you want to provide custom template. In your `.tmux.conf`:\n\nFor example, to get `Used 4.5G out of 16G` output for memory metric:\n\n```\nset -g @sysstat_mem_view_tmpl '#Used [fg=#{mem.color}]#{mem.used}#[default] out of #{mem.total}'\n```\n\nIf you don't want `CPU:` prefix and don't like colored output for CPU metric:\n\n```\nset -g @sysstat_cpu_view_tmpl '#{cpu.pused}'\n```\n\n### Supported fields\n\nAs you can see, each metric can be configured with template, containing fixed text (`CPU:`), color placeholder (`#[fg=#{mem.color}]`) and field placeholder (`#{mem.used}`). This approach gives you the ultimate control over the output for each metric. Following field placeholders are supported:\n\n<table>\n    <th>CPU</th>\n    <tr>\n        <td><code>#{cpu.color}</code></td>\n        <td>main metric color</td>\n    </tr>\n    <tr>\n        <td><code>#{cpu.pused}</code></td>\n        <td>CPU usage percentage</td>\n    </tr>\n</table>\n\n<table>\n    <th>Memory</th>\n    <tr>\n        <td><code>#{mem.color}</code></td>\n        <td>main metric color</td>\n    </tr>\n    <tr>\n        <td><code>#{mem.free}</code></td>\n        <td>free/available memory</td>\n    </tr>\n    <tr>\n        <td><code>#{mem.pfree}</code></td>\n        <td>free memory percentage against total</td>\n    </tr>\n    <tr>\n        <td><code>#{mem.used}</code></td>\n        <td>used memory</td>\n    </tr>\n    <tr>\n        <td><code>#{mem.pused}</code></td>\n        <td>used memory percentage against total</td>\n    </tr>\n    <tr>\n        <td><code>#{mem.total}</code></td>\n        <td>total installed memory</td>\n    </tr>\n</table>\n\n<table>\n    <th>Swap</th>\n    <tr>\n        <td><code>#{swap.color}</code></td>\n        <td>main swap metric color</td>\n    </tr>\n    <tr>\n        <td><code>#{swap.free}</code></td>\n        <td>free swap memory</td>\n    </tr>\n    <tr>\n        <td><code>#{swap.pfree}</code></td>\n        <td>free swap memory percentage against total swap space</td>\n    </tr>\n    <tr>\n        <td><code>#{swap.used}</code></td>\n        <td>used swap memory</td>\n    </tr>\n    <tr>\n        <td><code>#{swap.pused}</code></td>\n        <td>used swap memory percentage against total swap space</td>\n    </tr>\n    <tr>\n        <td><code>#{swap.total}</code></td>\n        <td>total swap space</td>\n    </tr>\n</table>\n\n### Change size scale\n\nfree/used/total memory can be shown both in absolute and relative units. When it comes to absolute units, you can choose *size scale factor* to choose between GiB, MiB, KiB. Default is GiB. If you have less than 3-4G memory installed, it makes sense to use MiB. KiB option is less practical, because it yields pretty lengthy output, which does not fit status bar limited estate.\n\n```\nset -g @sysstat_mem_size_unit \"G\"\n```\n\nIf you choose `G` for size scale, output will have `%.1f` (1 digit after floating point), otherwise size is integer (4.5G, 1024M, 1232345K).\n\nThresholds and colored output\n---------------\nEach metric output is colored by default. Colors vary depending on metric value.\n\n<table>\n    <tr>\n      <td><b>Threshold</b></td>\n      <td><b>CPU</b></td>\n      <td><b>Memory</b></td>\n      <td><b>Swap</b></td>\n      <td><b>Default color</b></td>\n    </tr>\n    <tr>\n        <td>low</td>\n        <td>x &lt; 30%</td>\n        <td>x &lt; 75%</td>\n        <td>x &lt; 25%</td>\n        <td>green</td>\n    </tr>\n    <tr>\n        <td>medium</td>\n        <td>30% &lt; x &lt; 80%</td>\n        <td>75% &lt; x &lt; 90%</td>\n        <td>25% &lt; x &lt; 75%</td>\n        <td>yellow</td>\n    </tr>\n    <tr>\n        <td>high</td>\n        <td>x &gt; 80%</td>\n        <td>x &gt; 90%</td>\n        <td>x &gt; 75%</td>\n        <td>red</td>\n    </tr>\n</table>\n\nYou can change thresholds in your `.tmux.conf`:\n\n```\nset -g @sysstat_cpu_medium_threshold \"75\"\nset -g @sysstat_cpu_stress_threshold \"95\"\n\nset -g @sysstat_mem_medium_threshold \"85\"\nset -g @sysstat_mem_stress_threshold \"95\"\n\nset -g @sysstat_swap_medium_threshold \"80\"\nset -g @sysstat_swap_stress_threshold \"90\"\n```\n\nYou can change colors for each threshold individually. You can use ANSI basic colors (red, cyan, green) or if your terminal supports 256 colors (and most do nowadays), use `colourXXX` format.\n\n```\nset -g @sysstat_cpu_color_low \"colour076\"\nset -g @sysstat_cpu_color_medium \"colour220\"\nset -g @sysstat_cpu_color_stress \"colour160\"\nset -g @sysstat_mem_color_low \"green\"\nset -g @sysstat_mem_color_medium \"blue\"\nset -g @sysstat_mem_color_stress \"cyan\"\n```\n\n`#{(mem|cpu|swap).color}` placeholder in your `@sysstat_(mem|cpu|swap)_view_tmpl` would be replaced by corresponding color, depending on whether metric value falls in particular threshold.\n\n### 256 color palette support\n\nFor 256 color palette support, make sure that `tmux` and parent terminal are configured with correct terminal type. See [here](https://unix.stackexchange.com/questions/1045/getting-256-colors-to-work-in-tmux) and [there](https://github.com/tmux/tmux/wiki/FAQ)\n\n```\n# ~/.tmux.conf\nset -g default-terminal \"screen-256color\"\n```\n\n```\n# parent terminal\n$ echo $TERM\nxterm-256color\n\n# jump into a tmux session\n$ tmux new\n$ echo $TERM\nscreen-256color\n```\n\n\n\n### Multiple colors for each threshold\n\nYou can have up to *3* colors configured for each threshold. To understand why you might need this, let tackle this task. Note, this is rather advanced use case.\n\n> I want `CPU: #{cpu.pused}` metric output, have green and yellow text colors at \"low\" and \"medium\" threshold, and finally, for \"high\" threshold, I want to use red color, but reverse foreground and background, that is use red for background, and white for text. More over I want \"CPU:\" text colored apart in red\n\nLike this:\n\n![cpu threshold with custom colors](/screenshots/cpu_thresholds.png)\n\nYou can achieve the result using following configuration:\n\n```\nset -g @sysstat_cpu_view_tmpl '#[fg=#{cpu.color3}]CPU:#[default] #[fg=#{cpu.color},bg=#{cpu.color2}]#{cpu.pused}#[default]'\n\nset -g @sysstat_cpu_color_low \"$color_level_ok default default\"\nset -g @sysstat_cpu_color_medium \"$color_level_warn default default\"\nset -g @sysstat_cpu_color_stress \"white,bold $color_level_stress $color_level_stress\"\n```\n\nTmux status-interval setting\n-----------------------------\nYou can configure status refresh interval, increasing or reducing frequency of `tmux-plugin-sysstat` command invocations.\n\n```\nset -g status-interval 5\n```\n\nIt's adviced to set `status-interval` to some reasonable value, like 5-10 seconds. More frequent updates (1 second) are useless, because they distract, and results in extra resource stress spent on metrics calculation itself.\n\n\n\nInternals: CPU calculation\n--------------------------------------------------\n<span style=\"color: blue\">**NOTE:** Stop here if you want to just use this plugin without making your feet wet. If you're hardcore tmux user and are curious about internals, keep reading</span>\n\nInternally, we use `iostat` and `top` on OSX, and `vmstat` and `top` on Linux to collect metric value. Neither requires you to install extra packages. These commands are run in sampling mode to report stats every N seconds M times. First sample include average values since the system start. Second one is the average CPU per second for last N seconds (exactly what we need)\n\nFor example:\n\n```\n$ iostat -c 2 -w 5\n          disk0       cpu     load average\n    KB/t tps  MB/s  us sy id   1m   5m   15m\n   44.22   6  0.26   3  2 95  1.74 1.90 2.15\n    5.47   8  0.04   4  5 91  1.84 1.92 2.16  << use this row, 2nd sample\n```\n\nWe align CPU calculation intervals (`-w`) with tmux status bar refresh interval (`status-interval` setting).\n\nInternals: memory calculation\n----------------------------\nYou might ask what we treat as `free` memory and how it's calculated.\n\n### OSX\nLet's start with OSX. We use `vm_stat` command (not same as `vmstat` on Linux), which reports following data (number of memory pages, not KB):\n\n```\n$ vm_stat\nPages free:                               37279\nPages active:                           1514200\nPages inactive:                         1152997\nPages speculative:                         6214\nPages throttled:                              0\nPages wired down:                       1174408\nPages purgeable:                          15405\nPages stored in compressor:             1615663\nPages occupied by compressor:            306717\n```\n\nTotal installed memory formula is:\n```\nTotal = free + active + inactive + speculative + occupied by compressor + wired\n```\n\nwhere\n- `free`, completely unused memory by the system\n- `wired`, critical information stored in RAM by system, kernel and key applications. Never swapped to the hard drive, never replaced with user-level data.\n- `active`, information currently in use or very recently used by applications. When this kind of memory is not used for long (or application is closed), it's move to inactive memory.\n- `inactive`, like buffers/cached memory in Linux. Memory for applications, which recently exited, retained for faster start-up of same application in future.\n\nSo the question what constitutes `free` and `used` memory. It turns out, that various monitoring and system statistics tools on OSX each calculate it differently.\n\n- htop: `used = active + wired`, `free` = `total - used`\n- top. Used = `used = active + inactive + occupied by compressor + wired`; Free = `free + speculative` Resident set size (RSS) = `active`\n- OSX activity Monitor. Used = `app memory + wired + compressor`. Note, it's not clear what is app memory.\n\nIn general, they either treat currently used memory, which can be reclaimed in case of need (cached, inactive, occupied by compressor), as `used` or `free`. \n\nIt makes sense to talk about `available` memory rather than `free` one. Available memory is unused memory + any used memory which can be reclaimed for application needs.\n\nSo, `tmux-plugin-sysstat`, uses following formula:\n\n```\nused = active + wired\navailable/free = free/unused + inactive + speculative + occupied by compressor\n```\n\n### Linux\n\nSame thinking can be applied to Linux systems.\n\nUsually commands like `free` report free/unused, used, buffers, cache memory kinds.\n\n```\n$ free\n             total       used       free     shared    buffers     cached\nMem:       1016464     900236     116228      21048      93448     241544\n-/+ buffers/cache:     565244     451220\nSwap:      1046524     141712     904812\n```\n\nSecond line indicates available memory (free + buffers + cache), with an assumption that buffers and cache can be 100% reclaimed in case of need.\n\nHowever, we're not using free, because its output varies per system. For example on RHEL7, there is no `-/+ buffers/cache`, and `available` memory is reported in different way. We read directly from `/proc/meminfo`\n\n```\n$ cat /proc/meminfo\n\nMemTotal:        1016232 kB\nMemFree:          152672 kB\nMemAvailable:     637832 kB\nBuffers:               0 kB\nCached:           529040 kB\n```\n\n`tmux-plugin-sysstat` uses following formula:\n\n```\nfree/available = MemAvailable;  // if MemAvailable present\nfree/available = MemFree + Buffers + Cached;\nused = MemTotal - free/avaialble \n```\n\nUsing `MemAvailable` is more accurate way of getting available memory, rather than manual calculation `free + buffers + cache`, because the assumption that `buffers + cache` can be 100% reclaimed for new application needs might be wrong. When using `MemAvailable`, OS calculates available memory for you, which is apparently better and accurate approach.\n\nSee [this topic](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773) on more reasoning about `MemAvailable` field.\n"
  },
  {
    "path": "scripts/cpu.sh",
    "content": "#!/usr/bin/env bash\n\nset -u\nset -e\n\nLC_NUMERIC=C\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/helpers.sh\"\n\ncpu_tmp_dir=$(tmux show-option -gqv \"@sysstat_cpu_tmp_dir\")\n\ncpu_view_tmpl=$(get_tmux_option \"@sysstat_cpu_view_tmpl\" 'CPU:#[fg=#{cpu.color}]#{cpu.pused}#[default]')\n\ncpu_medium_threshold=$(get_tmux_option \"@sysstat_cpu_medium_threshold\" \"30\")\ncpu_stress_threshold=$(get_tmux_option \"@sysstat_cpu_stress_threshold\" \"80\")\n\ncpu_color_low=$(get_tmux_option \"@sysstat_cpu_color_low\" \"green\")\ncpu_color_medium=$(get_tmux_option \"@sysstat_cpu_color_medium\" \"yellow\")\ncpu_color_stress=$(get_tmux_option \"@sysstat_cpu_color_stress\" \"red\")\n\nget_cpu_color(){\n  local cpu_used=$1\n\n  if fcomp \"$cpu_stress_threshold\" \"$cpu_used\"; then\n    echo \"$cpu_color_stress\";\n  elif fcomp \"$cpu_medium_threshold\" \"$cpu_used\"; then\n    echo \"$cpu_color_medium\";\n  else\n    echo \"$cpu_color_low\";\n  fi\n}\n\nprint_cpu_usage() {\n  local cpu_pused=$(get_cpu_usage_or_collect)\n  local cpu_color=$(get_cpu_color \"$cpu_pused\")\n  \n  local cpu_view=\"$cpu_view_tmpl\"\n  cpu_view=\"${cpu_view//'#{cpu.pused}'/$(printf \"%.1f%%\" \"$cpu_pused\")}\"\n  cpu_view=\"${cpu_view//'#{cpu.color}'/$(echo \"$cpu_color\" | awk '{ print $1 }')}\"\n  cpu_view=\"${cpu_view//'#{cpu.color2}'/$(echo \"$cpu_color\" | awk '{ print $2 }')}\"\n  cpu_view=\"${cpu_view//'#{cpu.color3}'/$(echo \"$cpu_color\" | awk '{ print $3 }')}\"\n\n  echo \"$cpu_view\"\n}\n\nget_cpu_usage_or_collect() {\n  local collect_cpu_metric=\"$cpu_tmp_dir/cpu_collect.metric\"\n\n  # read cpu metric from file, otherwise 0 as a temporary null value, until first cpu metric is collected\n  [ -f \"$collect_cpu_metric\" ] && cat \"$collect_cpu_metric\" || echo \"0.0\"\n\n  start_cpu_collect_if_required >/dev/null 2>&1\n}\n\nstart_cpu_collect_if_required() {\n  local collect_cpu_pidfile=\"$cpu_tmp_dir/cpu_collect.pid\"\n\n  # check if cpu collect process is running, otherwise start it in background\n  if [ -f \"$collect_cpu_pidfile\" ] && ps -p \"$(cat \"$collect_cpu_pidfile\")\" > /dev/null 2>&1; then\n    return;\n  fi\n  \n  jobs >/dev/null 2>&1\n  \"$CURRENT_DIR/cpu_collect.sh\" &>/dev/null &\n  if [ -n \"$(jobs -n)\" ]; then\n    echo \"$!\" > \"${collect_cpu_pidfile}\"\n  else\n    echo \"Failed to start CPU collect job\" >&2\n    exit 1\n  fi\n}\n\nmain(){\n  print_cpu_usage\n}\n\nmain\n"
  },
  {
    "path": "scripts/cpu_collect.sh",
    "content": "#!/usr/bin/env bash\n\nLC_NUMERIC=C\n\nset -u\nset -e\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/helpers.sh\"\n\nrefresh_interval=$(get_tmux_option \"status-interval\" \"5\")\nsamples_count=\"60\"\ncpu_metric_file=\"$(get_tmux_option \"@sysstat_cpu_tmp_dir\" \"/dev/null\")/cpu_collect.metric\"\n\nget_cpu_usage() {\n  if is_osx; then\n    if command_exists \"iostat\"; then\n      iostat -w \"$refresh_interval\" -c \"$samples_count\" \\\n        | stdbuf -o0 awk 'NR > 2 { print 100-$(NF-3); }'\n    else\n      top -l \"$samples_count\" -s \"$refresh_interval\" -n 0 \\\n        | sed -u -nr '/CPU usage/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*idle.*/\\1/p' \\\n        | stdbuf -o0 awk '{ print 100-$0 }'\n    fi\n  elif ! command_exists \"vmstat\"; then\n    if is_freebsd; then\n      vmstat -n \"$refresh_interval\" -c \"$samples_count\" \\\n        | stdbuf -o0 awk 'NR>2 {print 100-$(NF-0)}'\n    else\n      vmstat -n \"$refresh_interval\" \"$samples_count\" \\\n        | stdbuf -o0 awk 'NR>2 {print 100-$(NF-2)}'\n    fi\n  else\n    if is_freebsd; then\n      top -d\"$samples_count\" \\\n        | sed -u -nr '/CPU:/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*id.*/\\1/p' \\\n        | stdbuf -o0 awk '{ print 100-$0 }'\n    else\n      top -b -n \"$samples_count\" -d \"$refresh_interval\" \\\n        | sed -u -nr '/%Cpu/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)[[:space:]]*id.*/\\1/p' \\\n        | stdbuf -o0 awk '{ print 100-$0 }'\n    fi\n  fi\n}\n\nmain() {\n  get_cpu_usage | while read -r value; do\n    echo \"$value\" | tee \"$cpu_metric_file\"\n  done\n}\n\nmain\n\n"
  },
  {
    "path": "scripts/helpers.sh",
    "content": "\nget_tmux_option() {\n  local option=\"$1\"\n  local default_value=\"$2\"\n  local option_value=\"$(tmux show-option -gqv \"$option\")\"\n  if [ -z \"$option_value\" ]; then\n    echo \"$default_value\"\n  else\n    echo \"$option_value\"\n  fi\n}\n\nset_tmux_option() {\n  local option=\"$1\"\n  local value=\"$2\"\n  tmux set-option -gq \"$option\" \"$value\"\n}\n\nis_osx() {\n  [ $(uname) == \"Darwin\" ]\n}\n\nis_linux(){\n  [ $(uname -s) == \"Linux\" ]\n}\n\nis_freebsd() {\n    [ $(uname) == FreeBSD ]\n}\n\ncommand_exists() {\n  local command=\"$1\"\n  type \"$command\" >/dev/null 2>&1\n}\n\n# because bash does not support floating-point math\n# but awk does\ncalc() {\n  local stdin;\n  read -d '' -u 0 stdin;\n  awk \"BEGIN { print $stdin }\";\n}\n\n# \"<\" math operator which works with floats, once again based on awk\nfcomp() {\n  awk -v n1=\"$1\" -v n2=\"$2\" 'BEGIN {if (n1<n2) exit 0; exit 1}'\n}\n\n# get_mem_usage* function returns values in KiB\n# 1 - scale to KiB\n# 1024 - scale to MiB\n# 1048576 - scale to GiB\nfunction get_size_scale_factor(){\n  local size_unit=\"$1\"\n  case \"$size_unit\" in \n    G) echo 1048576;;\n    M) echo 1024;;\n    K) echo 1;;\n  esac\n}\n\n# Depending on scale factor, change precision\n# 12612325K - no digits after floating point\n# 1261M - no digits after floating point\n# 1.1G  - 1 digit after floating point \nfunction get_size_format(){\n  local size_unit=\"$1\"\n  case \"$size_unit\" in \n    G) echo '%.1f%s';;\n    M) echo '%.0f%s';;\n    K) echo '%.0f%s';;\n  esac\n}\n  \n  \n\n"
  },
  {
    "path": "scripts/loadavg.sh",
    "content": "#!/usr/bin/env bash\n\nset -u\nset -e\n\nLC_NUMERIC=C\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/helpers.sh\"\n\nloadavg_per_cpu_core=$(get_tmux_option \"@sysstat_loadavg_per_cpu_core\" \"true\")\n\nget_num_of_cores(){\n  is_osx && sysctl -n hw.ncpu || nproc\n}\n\nmain(){ \n  local num_cores=$([ \"$loadavg_per_cpu_core\" == \"true\" ]  && get_num_of_cores || echo 1)\n\n  uptime | awk -v num_cores=\"$num_cores\" '{ \n    sub(/,$/, \"\", $(NF-2));\n    sub(/,$/, \"\", $(NF-1));\n    sub(/,$/, \"\", $NF);\n    printf \"%.2f %.2f %.2f\", $(NF-2)/num_cores, $(NF-1)/num_cores, $NF/num_cores\n  }'\n}\n\nmain\n"
  },
  {
    "path": "scripts/mem.sh",
    "content": "#!/usr/bin/env bash\n\nset -u\nset -e\n\nLC_NUMERIC=C\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/helpers.sh\"\n\nmem_view_tmpl=$(get_tmux_option \"@sysstat_mem_view_tmpl\" 'MEM:#[fg=#{mem.color}]#{mem.pused}#[default]')\n\nmem_medium_threshold=$(get_tmux_option \"@sysstat_mem_medium_threshold\" \"75\")\nmem_stress_threshold=$(get_tmux_option \"@sysstat_mem_stress_threshold\" \"90\")\n\nmem_color_low=$(get_tmux_option \"@sysstat_mem_color_low\" \"green\")\nmem_color_medium=$(get_tmux_option \"@sysstat_mem_color_medium\" \"yellow\")\nmem_color_stress=$(get_tmux_option \"@sysstat_mem_color_stress\" \"red\")\n\nsize_unit=$(get_tmux_option \"@sysstat_mem_size_unit\" \"G\")\n\nget_mem_color() {\n  local mem_pused=$1\n\n  if fcomp \"$mem_stress_threshold\" \"$mem_pused\"; then\n    echo \"$mem_color_stress\";\n  elif fcomp \"$mem_medium_threshold\" \"$mem_pused\"; then\n    echo \"$mem_color_medium\";\n  else\n    echo \"$mem_color_low\";\n  fi\n}\n\nprint_mem() {\n  local mem_usage\n  local scale\n  local size_format\n  \n  if is_osx; then\n    mem_usage=$(get_mem_usage_osx)\n  elif is_linux; then \n    mem_usage=$(get_mem_usage_linux)\n  elif is_freebsd; then\n    mem_usage=$(get_mem_usage_freebsd)\n  fi\n\n  local size_scale=\"$(get_size_scale_factor \"$size_unit\")\"\n  local size_format=\"$(get_size_format \"$size_unit\")\"\n\n  # Extract free and used memory in MiB, calculate total and percentage\n  local mem_free=$(echo $mem_usage | awk -v scale=\"$size_scale\" '{ print $1/scale }')\n  local mem_used=$(echo $mem_usage | awk -v scale=\"$size_scale\" '{ print $2/scale }')\n  local mem_total=$(echo \"$mem_free + $mem_used\" | calc)\n  local mem_pused=$(echo \"($mem_used / $mem_total) * 100\" | calc)\n  local mem_pfree=$(echo \"($mem_free / $mem_total) * 100\" | calc)\n  \n  # Calculate colors for mem and swap\n  local mem_color=$(get_mem_color \"$mem_pused\")\n  \n  local mem_view=\"$mem_view_tmpl\"\n  mem_view=\"${mem_view//'#{mem.used}'/$(printf \"$size_format\" \"$mem_used\" \"$size_unit\")}\"\n  mem_view=\"${mem_view//'#{mem.pused}'/$(printf \"%.0f%%\" \"$mem_pused\")}\"\n  mem_view=\"${mem_view//'#{mem.free}'/$(printf \"$size_format\" \"$mem_free\" \"$size_unit\")}\"\n  mem_view=\"${mem_view//'#{mem.pfree}'/$(printf \"%.0f%%\" \"$mem_pfree\")}\"\n  mem_view=\"${mem_view//'#{mem.total}'/$(printf \"$size_format\" \"$mem_total\" \"$size_unit\")}\"  \n  mem_view=\"${mem_view//'#{mem.color}'/$(echo \"$mem_color\" | awk '{ print $1 }')}\"\n  mem_view=\"${mem_view//'#{mem.color2}'/$(echo \"$mem_color\" | awk '{ print $2 }')}\"\n  mem_view=\"${mem_view//'#{mem.color3}'/$(echo \"$mem_color\" | awk '{ print $3 }')}\"\n\n  echo \"$mem_view\"\n}\n\n\n# Report like it does htop on OSX:\n# used = active + wired\n# free = free + inactive + speculative + occupied by compressor\n# see `vm_stat` command\nget_mem_usage_osx(){\n  \n  local page_size=$(sysctl -nq \"vm.pagesize\")\n  vm_stat | awk -v page_size=$page_size -F ':' '\n    BEGIN { free=0; used=0 }\n    \n    /Pages active/ || \n    /Pages wired/ { \n      gsub(/^[ \\t]+|[ \\t]+$/, \"\", $2); used+=$2;\n    }\n    /Pages free/ || \n    /Pages inactive/ || \n    /Pages speculative/ || \n    /Pages occupied by compressor/ { \n      gsub(/^[ \\t]+|[ \\t]+$/, \"\", $2); free+=$2;\n    }\n\n    END { print (free * page_size)/1024, (used * page_size)/1024 }\n  '\n}\n\n# Relies on vmstat, but could also be done with top on FreeBSD\nget_mem_usage_freebsd(){\n  vmstat -H | tail -n 1 | awk '{ print $5, $4 }'\n}\n\n# Method #1. Sum up free+buffers+cached, treat it as \"available\" memory, assuming buff+cache can be reclaimed. Note, that this assumption is not 100% correct, buff+cache most likely cannot be 100% reclaimed, but this is how memory calculation is used to be done on Linux\n\n# Method #2. If \"MemAvailable\" is provided by system, use it. This is more correct method, because we're not relying on fragile \"free+buffer+cache\" equation. \n\n# See: Interpreting /proc/meminfo and free output for Red Hat Enterprise Linux 5, 6 and 7 - Red Hat Customer Portal - https://access.redhat.com/solutions/406773\n\n# See: kernel/git/torvalds/linux.git - /proc/meminfo: provide estimated available memory - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773\nget_mem_usage_linux(){\n  </proc/meminfo awk '\n    BEGIN { total=0; free=0; }\n      /MemTotal:/ { total=$2; }\n      \n      /MemFree:/ { free+=$2; }\n      /Buffers:/ { free+=$2; }\n      /Cached:/ { free+=$2; }\n\n      /MemAvailable:/ { free=$2; exit;}\n    END { print free, total-free }\n  '\n}\n\nmain() {\n  print_mem\n}\n\nmain\n\n"
  },
  {
    "path": "scripts/swap.sh",
    "content": "#!/usr/bin/env bash\n\nset -u\nset -e\n\nLC_NUMERIC=C\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/helpers.sh\"\n\nswap_view_tmpl=$(get_tmux_option \"@sysstat_swap_view_tmpl\" 'SW:#[fg=#{swap.color}]#{swap.pused}#[default]')\n\nswap_medium_threshold=$(get_tmux_option \"@sysstat_swap_medium_threshold\" \"25\")\nswap_stress_threshold=$(get_tmux_option \"@sysstat_swap_stress_threshold\" \"75\")\n\nswap_color_low=$(get_tmux_option \"@sysstat_swap_color_low\" \"green\")\nswap_color_medium=$(get_tmux_option \"@sysstat_swap_color_medium\" \"yellow\")\nswap_color_stress=$(get_tmux_option \"@sysstat_swap_color_stress\" \"red\")\n\nsize_unit=$(get_tmux_option \"@sysstat_swap_size_unit\" \"G\")\n\nget_swap_color() {\n  local swap_pused=$1\n\n  if fcomp \"$swap_stress_threshold\" \"$swap_pused\"; then\n    echo \"$swap_color_stress\";\n  elif fcomp \"$swap_medium_threshold\" \"$swap_pused\"; then\n    echo \"$swap_color_medium\";\n  else\n    echo \"$swap_color_low\";\n  fi\n}\n\nprint_swap() {\n  local swap_usage\n  \n  \n  if is_osx; then\n    swap_usage=$(get_swap_usage_osx)\n  elif is_linux; then \n    swap_usage=$(get_swap_usage_linux)\n  fi\n\n  local size_scale=\"$(get_size_scale_factor \"$size_unit\")\"\n  local size_format=\"$(get_size_format \"$size_unit\")\"\n\n  # Extract swap free and used in MiB, calculate total and percentage\n  local swap_free=$(echo $swap_usage | awk -v scale=\"$size_scale\" '{ print $1/scale }')\n  local swap_used=$(echo $swap_usage | awk -v scale=\"$size_scale\" '{ print $2/scale }')\n  local swap_total=$(echo \"$swap_free + $swap_used\" | calc)\n  local swap_pused=$(echo \"($swap_used / $swap_total) * 100\" | calc)\n  local swap_pfree=$(echo \"($swap_free / $swap_total) * 100\" | calc)\n  \n  # Calculate colors for mem and swap\n  local swap_color=$(get_swap_color \"$swap_pused\")\n  \n  local swap_view=\"$swap_view_tmpl\"\n  swap_view=\"${swap_view//'#{swap.used}'/$(printf \"$size_format\" \"$swap_used\" \"$size_unit\")}\"\n  swap_view=\"${swap_view//'#{swap.pused}'/$(printf \"%.0f%%\" \"$swap_pused\")}\"\n  swap_view=\"${swap_view//'#{swap.free}'/$(printf \"$size_format\" \"$swap_free\" \"$size_unit\")}\"\n  swap_view=\"${swap_view//'#{swap.pfree}'/$(printf \"%.0f%%\" \"$swap_pfree\")}\"\n  swap_view=\"${swap_view//'#{swap.total}'/$(printf \"$size_format\" \"$swap_total\" \"$size_unit\")}\"\n  swap_view=\"${swap_view//'#{swap.color}'/$(echo \"$swap_color\" | awk '{ print $1 }')}\"\n  swap_view=\"${swap_view//'#{swap.color2}'/$(echo \"$swap_color\" | awk '{ print $2 }')}\"\n  swap_view=\"${swap_view//'#{swap.color3}'/$(echo \"$swap_color\" | awk '{ print $3 }')}\"\n\n  echo \"$swap_view\"\n}\n\nget_swap_usage_osx(){\n  \n  # assume swap size in MB\n  local swap_used=$(sysctl -nq vm.swapusage | awk -F '  ' '{ print $2 }' | awk -F '=' '{gsub(/^[ ]|[M]$/, \"\", $2); printf \"%d\", $2 * 1024 }')\n  local swap_free=$(sysctl -nq vm.swapusage | awk -F '  ' '{ print $3 }' | awk -F '=' '{gsub(/^[ ]|[M]$/, \"\", $2); printf \"%d\", $2 * 1024 }')\n\n  printf \"%s %s\" \"$swap_free\" \"$swap_used\"\n}\n\nget_swap_usage_linux(){\n  </proc/meminfo awk '\n    BEGIN { total=0; free=0; }\n      /SwapTotal:/ { total=$2; }\n      /SwapFree:/ { free=$2; }\n    END { print free, total-free }\n  '\n}\n\nmain() {\n  print_swap\n}\n\nmain\n\n\n\n"
  },
  {
    "path": "sysstat.tmux",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nsource \"$CURRENT_DIR/scripts/helpers.sh\"\n\nplaceholders=(\n  \"\\#{sysstat_cpu}\"\n  \"\\#{sysstat_mem}\"\n  \"\\#{sysstat_swap}\"\n  \"\\#{sysstat_loadavg}\"\n)\n\ncommands=(\n  \"#($CURRENT_DIR/scripts/cpu.sh)\"\n  \"#($CURRENT_DIR/scripts/mem.sh)\"\n  \"#($CURRENT_DIR/scripts/swap.sh)\"\n  \"#($CURRENT_DIR/scripts/loadavg.sh)\"\n)\n\ndo_interpolation() {\n  local all_interpolated=\"$1\"\n  for ((i=0; i<${#commands[@]}; i++)); do\n    all_interpolated=${all_interpolated//${placeholders[$i]}/${commands[$i]}}\n  done\n  echo \"$all_interpolated\"\n}\n\nupdate_tmux_option() {\n  local option=\"$1\"\n  local option_value=\"$(get_tmux_option \"$option\")\"\n  local new_option_value=\"$(do_interpolation \"$option_value\")\"\n  set_tmux_option \"$option\" \"$new_option_value\"\n}\n\nmain() {\n  cpu_tmp_dir=$(mktemp -d)\n  tmux set-option -gq \"@sysstat_cpu_tmp_dir\" \"$cpu_tmp_dir\"\n\n  update_tmux_option \"status-right\"\n  update_tmux_option \"status-left\"\n}\n\nmain"
  }
]