#!/bin/bash OWNNAME=`basename $0` if [ "$1" = "-h" ]; then cat <<-EOF Usage: $OWNNAME [ -n | -p | -s ] | -t | -v Show informations about processes with huge memory pages allocated. Without giving any option, $OWNNAME will output a process-oriented list sorted by PID. Options for process-oriented listing: -n sort by NUMA node -p sort by page size -s sort by size -t CPU-topology oriented output, sorted by NUMA-node and core -v output version information and exit -h this cruft. Any processname starting with "qemu-system" will be replaced by the username of the process. $OWNNAME assumes that all huge pages of a process are allocated from a single NUMA-node. Processes with huge pages spread over more than one node may cause $OWNNAME to produce errors or even incorrect results. EOF exit fi if [ "$1" = "-v" ]; then cat <<- EOF This is lshugemem.sh rev.0.1 by Kadir Mueller (kadir.mueller@theflatnet.de), distributed in 2018 under the terms of version 2 of the GNU public license. There may be updates avalable at: http://www.theflatnet.de/pub/stuff/numa/ Any feedback according this script is highly appreciated. EOF exit fi PIDS=`grep -w huge /proc/[0-9]*/numa_maps 2>/dev/null | cut -d / -f 3 | sort | uniq` declare -a PROCS declare -a PAGESIZES declare -a PAGES declare -a SIZES declare -a CPUS declare -a NODES declare -a CORES declare -a CPUNPROCS declare -a CPUNPROCNAMES MAXPROCNAMELEN=0 NCPUS=0 while [ "$NCPUS" != `ls -d /sys/devices/system/cpu/cpu[0-9]* | wc -l` ]; do CPUNPROCS[$NCPUS]=0 let NCPUS=$NCPUS+1 done for PID in $PIDS; do PROCS[$PID]=`ps -edaf | grep -vw grep | awk '$2=='$PID' { print $8 }'` PAGESIZES[$PID]="`grep -w huge /proc/$PID/numa_maps | awk -F= '{ print $NF }' | sort | uniq`" if [ "${PAGESIZES[$PID]}" != "" ]; then echo ${PROCS[$PID]} | grep -q ^qemu-system && PROCS[$PID]="`ls -ld /proc/$PID | awk '{ print $3 }'`" [ `echo -n ${PROCS[$PID]} | wc -c` -gt $MAXPROCNAMELEN ] && MAXPROCNAMELEN=`echo -n ${PROCS[$PID]} | wc -c` PAGES[$PID]=`grep -w huge /proc/$PID/numa_maps | tr ' ' '\n' | grep ^N[0-9]\*= | cut -d = -f 2 | tr '\n' + | sed 's/+$//'` PAGES[$PID]=`echo ${PAGES[$PID]} | bc` let PAGESIZES[$PID]=${PAGESIZES[$PID]}/1024 let SIZES[$PID]=${PAGES[$PID]}\*${PAGESIZES[$PID]} CPUS[$PID]=`taskset -cp $PID | awk '{ print $NF }' | tr , ' '` for CPU in ${CPUS[$PID]}; do let CPUNPROCS[$CPU]=${CPUNPROCS[$CPU]}+1 CPUNPROCNAMES[$CPU]="${CPUNPROCNAMES[$CPU]} ${PROCS[$PID]}" done NODES[$PID]=`for CPU in ${CPUS[$PID]}; do cat /sys/devices/system/cpu/cpu$CPU/topology/physical_package_id done | sort | uniq | tr '\n' ' '| sed 's/ $//'` CORES[$PID]=`for CPU in ${CPUS[$PID]}; do cat /sys/devices/system/cpu/cpu$CPU/topology/core_id done | sort | uniq | tr '\n' ' ' | sed 's/ $//'` fi done if [ "$1" != "-t" ]; then printf " PID %${MAXPROCNAMELEN}s Size PgSzM Pges On CPU(s) Core(s) Node(s)\n" Name printf " ----- %${MAXPROCNAMELEN}s ------ ----- ---- ------------ ------- -------\n" "`printf "%${MAXPROCNAMELEN}s" " " | tr ' ' -`" for PID in $PIDS; do SORT=$PID [ "$1" = "-n" ] && SORT="${NODES[$PID]}" [ "$1" = "-s" ] && SORT="${SIZES[$PID]}" [ "$1" = "-p" ] && SORT="${PAGESIZES[$PID]}" printf "%20s %6i %${MAXPROCNAMELEN}s %6i %5i %4i %12s %7s %6s\n" $SORT $PID "${PROCS[$PID]}" ${SIZES[$PID]} ${PAGESIZES[$PID]} ${PAGES[$PID]} "${CPUS[$PID]}" "${CORES[$PID]}" "${NODES[$PID]}" done | sort -n | cut -c 22- else echo "Node Core CPU Cnt Names" for CPUPATH in `ls -d /sys/devices/system/node/node[0-9]*/cpu[0-9]*`; do CPU=`echo $CPUPATH | awk -F/ '{ print $NF }' | sed 's/cpu//'` NODE=`echo $CPUPATH | awk -F/ '{ print $6 }' | sed 's/node//'` printf "%.3i%.3i%.3i%4i %4i %4i %3i%s\n" $NODE `cat /sys/devices/system/cpu/cpu$CPU/topology/core_id` $CPU $NODE `cat /sys/devices/system/cpu/cpu$CPU/topology/core_id` $CPU ${CPUNPROCS[$CPU]} "${CPUNPROCNAMES[$CPU]}" done | sort -n | cut -c 10- fi