inotify-consumers.sh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/bin/bash
  2. # Get the procs sorted by the number of inotify watches
  3. # @author Carl-Erik Kopseng
  4. # @latest https://github.com/fatso83/dotfiles/blob/master/utils/scripts/inotify-consumers
  5. # Discussion leading up to answer: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
  6. #
  7. # If you need ultimate speed, use https://github.com/fatso83/dotfiles/commit/inotify-consumers-v1-fastest
  8. # # Speed enhancements by Simon Matter <[email protected]>
  9. #
  10. # A later PR introduced a significant slowdown to gain better output, but it is insignificant on most machines
  11. # See this for details: https://github.com/fatso83/dotfiles/pull/10#issuecomment-1122374716
  12. main(){
  13. printf "\n%${WLEN}s %${WLEN}s\n" "INOTIFY" "INSTANCES"
  14. printf "%${WLEN}s %${WLEN}s\n" "WATCHES" "PER "
  15. printf "%${WLEN}s %${WLEN}s %s\n" " COUNT " "PROCESS " "PID USER COMMAND"
  16. printf -- "------------------------------------------------------------\n"
  17. generateData
  18. }
  19. usage(){
  20. cat << EOF
  21. Usage: $0 [--help|--limits]
  22. -l, --limits Will print the current related limits and how to change them
  23. -h, --help Show this help
  24. FYI: Check out Michael Sartain's C++ take on this script. The native executable
  25. is much faster, modern and feature rich. It can be found at
  26. https://github.com/mikesart/inotify-info
  27. EOF
  28. }
  29. limits(){
  30. printf "\nCurrent limits\n-------------\n"
  31. sysctl fs.inotify.max_user_instances fs.inotify.max_user_watches
  32. cat <<- EOF
  33. Changing settings permanently
  34. -----------------------------
  35. echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
  36. sudo sysctl -p # re-read config
  37. EOF
  38. }
  39. generateData() {
  40. local -i PROC
  41. local -i PID
  42. local -i CNT
  43. local -i INSTANCES
  44. local -i TOT
  45. local -i TOTINSTANCES
  46. # read process list into cache
  47. local PSLIST="$(ps ax -o pid,user=WIDE-COLUMN,command $COLSTRING)"
  48. local INOTIFY="$(find /proc/[0-9]*/fdinfo -type f 2>/dev/null | xargs grep ^inotify 2>/dev/null)"
  49. local INOTIFYCNT="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3 |uniq -c | sed -e 's/:.*//')"
  50. # unique instances per process is denoted by number of inotify FDs
  51. local INOTIFYINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3,5 | sed -e 's/:.*//'| uniq |awk '{print $1}' |uniq -c)"
  52. local INOTIFYUSERINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3,5 | sed -e 's/:.*//' | uniq |
  53. 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)"
  54. set -e
  55. cat <<< "$INOTIFYCNT" |
  56. {
  57. while read -rs CNT PROC; do # count watches of processes found
  58. echo "${PROC},${CNT},$(echo "$INOTIFYINSTANCES" | grep " ${PROC}$" |awk '{print $1}')"
  59. done
  60. } |
  61. grep -v ",0," | # remove entires without watches
  62. sort -n -t "," -k 2,3 -r | # sort to begin with highest numbers
  63. { # group commands so that $TOT is visible in the printf
  64. IFS=","
  65. while read -rs PID CNT INSTANCES; do # show watches and corresponding process info
  66. printf "%$(( WLEN - 2 ))d %$(( WLEN - 2 ))d %s\n" "$CNT" "$INSTANCES" "$(grep -e "^ *${PID} " <<< "$PSLIST")"
  67. TOT=$(( TOT + CNT ))
  68. TOTINSTANCES=$(( TOTINSTANCES + INSTANCES))
  69. done
  70. # These stats should be per-user as well, since inotify limits are per-user..
  71. printf "\n%$(( WLEN - 2 ))d %s\n" "$TOT" "WATCHES TOTAL COUNT"
  72. # the total across different users is somewhat meaningless, not printing for now.
  73. # printf "\n%$(( WLEN - 2 ))d %s\n" "$TOTINSTANCES" "TOTAL INSTANCES COUNT"
  74. }
  75. echo ""
  76. echo "INotify instances per user (e.g. limits specified by fs.inotify.max_user_instances): "
  77. echo ""
  78. (
  79. echo "INSTANCES USER"
  80. echo "----------- ------------------"
  81. echo "$INOTIFYUSERINSTANCES"
  82. ) | column -t
  83. echo ""
  84. exit 0
  85. }
  86. # get terminal width
  87. declare -i COLS=$(tput cols 2>/dev/null || echo 80)
  88. declare -i WLEN=10
  89. declare COLSTRING="--columns $(( COLS - WLEN ))" # get terminal width
  90. if [ "$1" = "--limits" -o "$1" = "-l" ]; then
  91. limits
  92. exit 0
  93. fi
  94. if [ "$1" = "--help" -o "$1" = "-h" ]; then
  95. usage
  96. exit 0
  97. fi
  98. # added this line and moved some declarations to allow for the full display instead of a truncated version
  99. if [ "$1" = "--full" -o "$1" = "-f" ]; then
  100. unset COLSTRING
  101. main
  102. fi
  103. if [ -n "$1" ]; then
  104. printf "\nUnknown parameter '$1'\n" >&2
  105. usage
  106. exit 1
  107. fi
  108. main