Browse Source

add inotify watchers script

Josh Bicking 1 year ago
parent
commit
4bcbe4d51d
1 changed files with 121 additions and 0 deletions
  1. 121 0
      inotify-consumers.sh

+ 121 - 0
inotify-consumers.sh

@@ -0,0 +1,121 @@
+#!/bin/bash
+
+# Get the procs sorted by the number of inotify watches
+# @author Carl-Erik Kopseng
+# @latest https://github.com/fatso83/dotfiles/blob/master/utils/scripts/inotify-consumers
+# Discussion leading up to answer: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
+#
+# If you need ultimate speed, use https://github.com/fatso83/dotfiles/commit/inotify-consumers-v1-fastest
+# # Speed enhancements by Simon Matter <[email protected]>
+#
+# A later PR introduced a significant slowdown to gain better output, but it is insignificant on most machines
+# See this for details: https://github.com/fatso83/dotfiles/pull/10#issuecomment-1122374716
+
+main(){
+    printf "\n%${WLEN}s  %${WLEN}s\n" "INOTIFY" "INSTANCES"
+    printf "%${WLEN}s  %${WLEN}s\n" "WATCHES" "PER   "
+    printf "%${WLEN}s  %${WLEN}s  %s\n" " COUNT " "PROCESS "    "PID USER         COMMAND"
+    printf -- "------------------------------------------------------------\n"
+    generateData
+}
+
+usage(){
+    cat << EOF
+Usage: $0 [--help|--limits]
+    -l, --limits    Will print the current related limits and how to change them
+    -h, --help      Show this help
+
+FYI:  Check out Michael Sartain's C++ take on this script. The native executable
+      is much faster, modern and feature rich. It can be found at
+      https://github.com/mikesart/inotify-info
+EOF
+}
+
+limits(){
+    printf "\nCurrent limits\n-------------\n"
+    sysctl fs.inotify.max_user_instances fs.inotify.max_user_watches
+
+    cat <<- EOF
+Changing settings permanently
+-----------------------------
+echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
+sudo sysctl -p # re-read config
+EOF
+}
+
+generateData() {
+    local -i PROC
+    local -i PID
+    local -i CNT
+    local -i INSTANCES
+    local -i TOT
+    local -i TOTINSTANCES
+    # read process list into cache
+    local PSLIST="$(ps ax -o pid,user=WIDE-COLUMN,command $COLSTRING)"
+    local INOTIFY="$(find /proc/[0-9]*/fdinfo -type f 2>/dev/null | xargs grep ^inotify 2>/dev/null)"
+    local INOTIFYCNT="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" "  -f 3 |uniq -c | sed -e 's/:.*//')"
+    # unique instances per process is denoted by number of inotify FDs
+    local INOTIFYINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" "   -f 3,5 | sed -e 's/:.*//'| uniq |awk '{print $1}' |uniq -c)"
+    local INOTIFYUSERINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" "   -f 3,5 | sed -e 's/:.*//' | uniq |
+    	     while read PID FD; do echo $PID $FD $(grep -e "^ *${PID} " <<< "$PSLIST"|awk '{print $2}'); done | cut -d" "  -f 3 | sort | uniq -c |sort -nr)"
+    set -e
+
+    cat <<< "$INOTIFYCNT" |
+        {
+            while read -rs CNT PROC; do   # count watches of processes found
+                echo "${PROC},${CNT},$(echo "$INOTIFYINSTANCES" | grep " ${PROC}$" |awk '{print $1}')"
+            done
+        } |
+        grep -v ",0," |                  # remove entires without watches
+        sort -n -t "," -k 2,3 -r |         # sort to begin with highest numbers
+        {                                # group commands so that $TOT is visible in the printf
+	    IFS=","
+            while read -rs PID CNT INSTANCES; do   # show watches and corresponding process info
+                printf "%$(( WLEN - 2 ))d  %$(( WLEN - 2 ))d     %s\n" "$CNT" "$INSTANCES" "$(grep -e "^ *${PID} " <<< "$PSLIST")"
+                TOT=$(( TOT + CNT ))
+		TOTINSTANCES=$(( TOTINSTANCES + INSTANCES))
+            done
+	    # These stats should be per-user as well, since inotify limits are per-user..
+            printf "\n%$(( WLEN - 2 ))d  %s\n" "$TOT" "WATCHES TOTAL COUNT"
+# the total across different users is somewhat meaningless, not printing for now.
+#            printf "\n%$(( WLEN - 2 ))d  %s\n" "$TOTINSTANCES" "TOTAL INSTANCES COUNT"
+        }
+    echo ""
+    echo "INotify instances per user (e.g. limits specified by fs.inotify.max_user_instances): "
+    echo ""
+    (
+      echo "INSTANCES    USER"
+      echo "-----------  ------------------"
+      echo "$INOTIFYUSERINSTANCES"
+    ) | column -t
+    echo ""
+    exit 0
+}
+
+# get terminal width
+declare -i COLS=$(tput cols 2>/dev/null || echo 80)
+declare -i WLEN=10
+declare COLSTRING="--columns $(( COLS - WLEN ))" # get terminal width
+
+if [ "$1" = "--limits" -o "$1" = "-l" ]; then
+    limits
+    exit 0
+fi
+
+if [ "$1" = "--help" -o "$1" = "-h" ]; then
+    usage
+    exit 0
+fi
+
+# added this line and moved some declarations to allow for the full display instead of a truncated version
+if [ "$1" = "--full" -o "$1" = "-f" ]; then
+    unset COLSTRING
+    main
+fi
+
+if [ -n "$1" ]; then
+    printf "\nUnknown parameter '$1'\n" >&2
+    usage
+    exit 1
+fi
+main