New memcheck.sh program for new Mem_tracker plug-in.

This script is used to calculate memory usage for each process
and generate a comma-separated value file.

Addressed review comments.

Change-Id: I683e76c895c4909c96a03185cb810720b64129b2
Signed-off-by: sangeri-us  <sangeri@us.ibm.com>
diff --git a/bin/plug_ins/Mem_tracker/memcheck.sh b/bin/plug_ins/Mem_tracker/memcheck.sh
new file mode 100755
index 0000000..836604e
--- /dev/null
+++ b/bin/plug_ins/Mem_tracker/memcheck.sh
@@ -0,0 +1,149 @@
+#!/bin/bash
+
+# This program will calculate memory usage for each process and generate a
+# comma-separated value (CSV) output file named output.csv in the current
+# directory.  The output will consist of 2 lines.  The first is a comma-
+# separated list of process names.  The second is a list of comma-separated
+# memory usage values (expressed in bytes). Here is an abbrieviated example of
+# the output:
+# python(9),/lib/systemd/systemd-journald,/usr/bin/python,/sbin/init,
+# phosphor-hwmon-readd(4),ipmid,phosphor-ledcontroller(4)
+# 57896960,11789312,4434944,2893824,1900544,1764352
+
+program_name=${0##*/}
+temp_file_path_1=/tmp/${program_name}_results_1
+temp_file_path_2=/tmp/${program_name}_results_2
+temp_file_path_3=/tmp/${program_name}_results_3
+
+temp_file_list="${temp_file_path_1} ${temp_file_path_2} ${temp_file_path_3}"
+csv_file_path="output.csv"
+
+# Description of argument(s):
+# pid  The pid for which you desire statistics. If this is not specified,
+# statistics will be gathered for all active pids.
+
+function get_parms {
+
+  # Get program parms.
+
+  pids="${1:-$(ls /proc | grep -v [A-Za-z])}" ; shift
+
+  return 0
+
+}
+
+
+function exit_function {
+
+  # Used to clean up tmp files.
+
+  rm -f ${temp_file_list}
+  return
+
+}
+
+
+function validate_parms {
+
+  # Validate program parameters.
+
+  # Making sure only root can run our script.
+  if [ "${USER}" != "root" ] ; then
+    echo "This script must be run as root" 1>&2
+    return 1
+  fi
+
+  trap "exit_function $signal \$?" EXIT
+  return 0
+
+}
+
+
+function get_process_mem {
+
+  local pid="${1}" ; shift
+  # Count memory statistic for passed pid.
+
+  # Description of argument(s):
+  # pid  The process ID for which you desire statistics.
+  [ ! -f /proc/${pid}/status -o ! -f /proc/${pid}/smaps ] && return 0
+
+  # pss_total      Total proportional set size of a process.
+  # private_total  Total number of clean and dirty private pages in the
+  #                mapping.
+  # shared_total   The difference between pss_total and private_total.
+
+  local pss_total private_total shared_total sum name
+  pss_total=$(grep -e "^Pss:" /proc/${pid}/smaps | awk '{print $2}' | awk '{sum += $1} END {print sum}')
+  private_total=$(grep -e "^Private" /proc/${pid}/smaps | awk '{print $2}' | awk '{sum += $1} END {print sum}')
+
+  [ -z "${pss_total}" -o -z "${private_total}" ] && return 0
+  (( shared_total=pss_total-private_total ))
+  name=$(cut -d "" -f 1 /proc/${pid}/cmdline)
+  (( sum=shared_total+private_total ))
+  echo -e "${private_total} + ${shared_total} = ${sum} ${name}"
+
+}
+
+
+function mainf {
+
+  get_parms "$@" || return 1
+
+  validate_parms || return 1
+
+  # To ensure temp files not exist.
+  rm -f ${temp_file_list}
+
+  for pid in ${pids} ; do
+    get_process_mem ${pid} >> ${temp_file_path_1}
+  done
+
+  # This is used to sort results by memory usage.
+  sort -gr -k 5 ${temp_file_path_1} > ${temp_file_path_2}
+
+  # Find duplicates in the process list output and combine them.  In such
+  # cases, adjust the process name by including a (<count>) suffix.  In the
+  # following example of output, 4 instances of "phosphor-hwmon-readd" have
+  # been combined.
+  # 974848 + 925696 = 1900544       phosphor-hwmon-readd(4)
+  for proc_name in $(awk '{print $6}' ${temp_file_path_2} | sort -u) ; do
+    count=$(awk -v src=${proc_name} '{if ($6==src) {print $6}}' ${temp_file_path_2} | wc -l)
+    [ "${count}" = "1" ] && count_string="" || count_string="(${count})"
+    vmsize_in_kb=$(awk -v src=${proc_name} '{if ($6==src) {print $1}}' ${temp_file_path_2} | awk '{sum += $1} END {print sum}')
+    vmrss_in_kb=$(awk -v src=${proc_name} '{if ($6==src) {print $3}}' ${temp_file_path_2} | awk '{sum += $1} END {print sum}')
+    total=$(awk '{print $5}' ${temp_file_path_2} | awk '{sum += $1} END {print sum}')
+    (( sum=vmrss_in_kb+vmsize_in_kb ))
+    echo -e "${vmsize_in_kb}  + ${vmrss_in_kb} = ${sum} \t ${proc_name}${count_string}" >> ${temp_file_path_3}
+  done
+
+  # Sort once more.
+  sort -gr -k 5 ${temp_file_path_3} > ${temp_file_path_1}
+
+  # Read results from temp file and convert it to csv.
+  csv_line1=""
+  csv_line2=""
+  while read line ; do
+    while read private plus_operator shared equal_sign sum name ; do
+      (( sum == 0 )) && continue
+      csv_line1+=",${name}"
+      csv_line2+=",${sum}"
+    done<<<${line}
+  done < ${temp_file_path_1}
+
+  # Strip leading commas.
+  csv_line1="${csv_line1#,}"
+  csv_line2="${csv_line2#,}"
+  { echo "${csv_line1}" ; echo "${csv_line2}" ; } >> ${csv_file_path}
+
+  return 0
+
+}
+
+# Main
+
+  mainf "${@}"
+  rc="${?}"
+  exit "${rc}"
+
+