#!/bin/bash

TAIL="tail -10"

usage() {
  echo "  Get current swap/mem usage for all running processes
  -s for SWAP with option KB, MB or GB, default KB
  -m for MEMORY with option KB, MB or GB, default KB
  -f provides full output instead of 10 lines
  e.g.: ngcp-memory-usage -m KB"
  exit 1
}

set_units() {
  case "$1" in
    GiB|GB)
      UNIT='GiB'
      UNIT_DIV=1024/1024
      UNIT_LEN=6
      FREE_UNIT_OPT=-g
      ;;
    MiB|MB)
      UNIT='MiB'
      UNIT_DIV=1024
      UNIT_LEN=9
      FREE_UNIT_OPT=-m
      ;;
     *)
      UNIT='KiB'
      UNIT_DIV=1
      UNIT_LEN=12
      FREE_UNIT_OPT=-k
      ;;
  esac
}

get_proc_mem() {
  local sum=0
  local pid progname

  while read -r piddir ; do
    pid=$(echo "${piddir}" | cut -d / -f 3)
    progname=$(cat "${piddir}/comm" 2>/dev/null)

    sum=0
    while read -r mem ; do
      sum=$((sum + mem))
    done < <(grep "${FIELD_PROC}" "${piddir}"/smaps 2>/dev/null | awk '{print $2}')

    sum=$(awk 'BEGIN {printf ("%.2f\n", '"${sum}"/"${UNIT_DIV}"')}')

    # Ignore processes without memory usage.
    if [[ "${sum}" = "0.00" ]]; then
      continue
    fi

    printf "PID=%5s - %s used: %${UNIT_LEN}s %s - %s \n" \
           "${pid}" "${FIELD_PROC}" "${sum}" "${UNIT}" "(${progname})"
  done < <(find /proc/[0-9]* -maxdepth 0 -type d)
}

get_used_mem() {
  local used
  used=$(free "${FREE_UNIT_OPT}" | grep "${FIELD_FREE}" | awk '{print $3}')

  echo
  echo "Overall ${FIELD_PROC} used: ${used} ${UNIT}"
}

if [ $# -lt 1 ] ; then
  usage
fi

if [[ "${*^^}" != -* || "${*^^}" == -F ]] ; then
  usage
fi

if [[ "${*^^}" == *-M* && "${*^^}" == *-S* ]] ; then
  usage
fi

while getopts "smf" opt ; do
  eval "nextopt=\${$OPTIND}"
  case $opt in
    s)
      if [[ -n "$nextopt" && $nextopt != -* ]] ; then
        OPTIND=$((OPTIND + 1))
        set_units "${nextopt}"
      else
        set_units "KiB"
      fi
      FIELD_FREE='Swap'
      FIELD_PROC='Swap'
      ;;
    m)
      if [[ -n "$nextopt" && $nextopt != -* ]] ; then
        OPTIND=$((OPTIND + 1))
        set_units "${nextopt}"
      else
        set_units "KiB"
      fi
      FIELD_FREE='Mem'
      FIELD_PROC='Rss'
      ;;
    f)
      TAIL="cat"
      ;;
    *)
      usage
      ;;
  esac
done

get_proc_mem | sort -t":" -k2n | $TAIL
get_used_mem

exit 0