| #!/bin/sh |
| # Copyright (C) 2013-2015, Parallels, Inc. All rights reserved. |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU General Public License |
| # as published by the Free Software Foundation; either version 2 |
| # of the License, or (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program; if not, write to the Free Software |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| # |
| # |
| # This script checks oversell levels for memory and swap |
| # for VSwap-based container. Think of it as a replacement |
| # for vzmemcheck. |
| |
| ram=$(awk '/^MemTotal:/ {print $2/4}' < /proc/meminfo) |
| swap=$(awk '/^SwapTotal:/ {print $2/4}' < /proc/meminfo) |
| |
| procbc=$1 |
| test -z "$1" && procbc=/proc/bc/resources |
| |
| awk -v ram=$ram -v swap=$swap < $procbc ' |
| |
| # converts a value to human-readable form |
| # v: value |
| # m: 1 if value is in 4K pages, 0 if in bytes |
| function hr(v, m) { |
| if ((v == 9223372036854775807) || (v == 2147483647) || (v == 0)) |
| return "- "; |
| i=1 |
| # translate pages to KB |
| if (m) { |
| v = v*4 |
| i++ |
| } |
| while (v >= 1024) { |
| v=v/1024 |
| i++ |
| } |
| fmt="%d%c" |
| if (v < 100) |
| fmt="%.3g%c" |
| return sprintf(fmt, v, substr(" KMGTPEZY", i, 1)) |
| } |
| |
| # hr() for pages |
| function hp(v) { |
| return hr(v, 1); |
| } |
| |
| # hr() for bytes |
| function hb(v) { |
| return hr(v, 0); |
| } |
| |
| function dp(p, d) { |
| if ((d == 0) || (d == 9223372036854775807) || (d == 2147483647)) |
| return "- " |
| r = sprintf("%.1f", p / d * 100); |
| fmt="%d" |
| if (r < 10) |
| fmt="%.1g" |
| r = sprintf(fmt, r) |
| if (r == 0) |
| return "- " |
| return r "%" |
| } |
| |
| function header() { |
| printf(" --------- RAM --------- -------- Swap --------- Flags\n"); |
| printf(" used peak limit fails used peak limit fails\n"); |
| } |
| |
| function footer() { |
| printf(" ----- ----- ----- ----- ----- ----- ----- -----\n"); |
| printf(" TOTAL %5s %5s %5s %5s %5s %5s %5s %5s\n\n", |
| hp(t_ram_held), hp(t_ram_maxheld), |
| hp(t_ram_limit), hb(t_ram_failcnt), |
| hp(t_swap_held), hp(t_swap_maxheld), |
| hp(t_swap_limit), hb(t_swap_failcnt)); |
| |
| printf("RAM available: %5s allocated: %5s oversell: %s\n", |
| hp(ram), hp(t_ram_limit), dp(t_ram_limit, ram)); |
| printf("Swap available: %5s allocated: %5s oversell: %s\n", |
| hp(swap), hp(t_swap_limit), dp(t_swap_limit, swap)); |
| printf("RAM+Swap available: %5s allocated: %5s oversell: %s\n", |
| hp(ram+swap), hp(t_ram_limit+t_swap_limit), |
| dp(t_ram_limit+t_swap_limit, ram+swap)); |
| |
| if (t_flags != "") { |
| printf("\nFlags:\n"); |
| if (t_flags ~ "R") |
| printf(" R: non-VSwap container, RAM limit guessed " \ |
| "based on privvmpages\n"); |
| if (t_flags ~ "U") |
| printf(" U: unlimited container, RAM limit " \ |
| "not included into totals\n"); |
| if (t_flags ~ "S") |
| printf(" S: unlimited swap (ok for non-vswap), " \ |
| "not counted into total swap limit\n"); |
| if (t_flags ~ "f") |
| printf(" f: RAM failctl > 0 (swap used), use vzubc " \ |
| "to check details\n"); |
| if (t_flags ~ "F") |
| printf(" F: beancounter failctl > 0, use vzubc " \ |
| "to check details\n"); |
| } |
| |
| } |
| |
| function process_ct() { |
| if (bcid <= 0) |
| return |
| |
| flags="" |
| |
| if (ram_limit == 0 || ram_limit == 2147483647 || ram_limit == 9223372036854775807) { |
| if (vm_limit == 2147483647 || vm_limit == 9223372036854775807) { |
| # Unlimited container? |
| flags="U" |
| ram_limit=0 |
| } else { |
| # Non-VSwap config! |
| flags="R" |
| # Roughly guess limit based on privvmpages / vm_overcommit |
| ram_limit=vm_limit/2 |
| } |
| } |
| if (swap_limit == 2147483647 || swap_limit == 9223372036854775807) { |
| # Hmm, unlimited swap? |
| flags=flags"S" |
| swap_limit = 0 |
| } |
| if (failcnt > 0) |
| if (failctl == ram_failcnt) |
| flags=flags"f" |
| else |
| flags=flags"F" |
| |
| t_ram_held += ram_held; |
| t_ram_maxheld += ram_maxheld; |
| t_ram_limit += ram_limit; |
| t_ram_failcnt += ram_failcnt; |
| t_swap_held += swap_held; |
| t_swap_maxheld += swap_maxheld; |
| t_swap_limit += swap_limit; |
| t_swap_failcnt += swap_failcnt; |
| |
| t_flags = t_flags flags; |
| |
| printf("%10d %5s %5s %5s %5s %5s %5s %5s %5s %s\n", |
| bcid, |
| hp(ram_held), hp(ram_maxheld), |
| hp(ram_limit), hb(ram_failcnt), |
| hp(swap_held), hp(swap_maxheld), |
| hp(swap_limit), hb(swap_failcnt), |
| flags); |
| } |
| |
| BEGIN { |
| bcid=-1 |
| t_flags="" |
| header() |
| } |
| /^Version: / { |
| if ($2 != "2.5") { |
| print "Error: unknown version:", |
| $2 > "/dev/stderr" |
| exit 1 |
| } |
| next |
| } |
| /^[[:space:]]*uid / { |
| next |
| } |
| /^[[:space:]]*dummy/ { |
| next |
| } |
| /^[[:space:]]*[0-9]+:/ { |
| bcid=int($1) |
| failcnt=$7 |
| next |
| } |
| /^[[:space:]]*privvmpages/ { |
| vm_held=$2 |
| vm_maxheld=$3 |
| vm_limit=$5 |
| vm_failcnt=$6 |
| failcnt += $6 |
| next |
| } |
| /^[[:space:]]*physpages/ { |
| ram_held=$2 |
| ram_maxheld=$3 |
| ram_limit=$5 |
| ram_failcnt=$6 |
| failcnt += $6 |
| next |
| } |
| |
| { |
| if (bcid > 0) |
| failcnt += $6 |
| } |
| |
| /^[[:space:]]*swappages/ { |
| swap_held=$2 |
| swap_maxheld=$3 |
| swap_limit=$5 |
| swap_failcnt=$6 |
| |
| process_ct() |
| } |
| END { |
| footer() |
| }' |