#!/bin/ksh ## ## SCRIPT: ps_parents_children_tree_bygui ## ## Where: in $FEDIR/scripts where $FEDIR=/apps/nns_com/fea ## ###################################################################### ## PURPOSE: This script assembles a 'tree' of processes from ## the output of a 'ps -e' command on an SGI-IRIX host. ## ## And for EVERY process on the specified host ## ... 'ps' info for the process and its parents is shown. ## ## A Tcl-Tk script presents a GUI that prompts for hostid. ## The entry field is initialized with the hostname of the ## SGI host on which this script is running. ############################################################################ ## CALLED BY: 'perftools' in $FEDIR/scripts ## actually, by 'perftools.chestdef' in $FEDIR/scripts ## ## and 'abq6.4_tools.chestdef' ## and 'abq6.4_ddam_tools.chestdef' ###################################################################### ## METHOD: ## 0) Captures the output of 'ps -ef' or 'ps -e -o ' in var PS_OUT. ## 2) Uses 'awk' to get the list of unique PID's from col 2. ## 3) In a 'for' loop, processes each PID. ## 4) In a 'while' loop, within the 'for' loop: ## For a PID, gets its PPID, from a unique PID rec in var PS_OUT. ## Then, for that PID (PPID), gets its PPID the same way, from PS_OUT. ## Then the PPID of that ID ... until no more parents in PS_OUT. ## ## As the PPID's are gathered, for a given PID, 'ps' info for each ## (parent) process is output to a report file. ## ## As the PPID's are gathered, for a given PID, a string of ## (parent) processes is assembled, in var PPIDS_LINE. ## ## At the completion of each 'while' loop (for a PID), the ## PPIDS_LINE is appended to a PID_TREE var. ## ## 5) At the completion of the 'for' loop, ## a process-tree, held in PID_TREE var, is put in the report file. ## ###################################################################### ## MAINTENANCE HISTORY: ## Written by: Blaise Montandon 12apr2004 Based on scripts ## 'ps_pidsort_starttimes_anyhost_bygui' ## and ## 'ps_elapsedtimesort_anyhost_bygui' ## in $FEDIR/scripts. ## ## Updated by: Blaise Montandon 15apr2004 Put padding (spaces) between PID ## and owner-userid in $PPIDS_LINE. ## ## Updated by: Blaise Montandon 16apr2004 Reduce number of awk-scans of ## the PS_OUT var, to try to reduce ## query time. Modest improvement. ## Updated by: Blaise Montandon 27apr2004 Chg extract of PID_CMD to start at ## column 82, instead of 81, in $0. ############################################################################ if test "$FEDIR" = "" then export FEDIR=/apps/nns_com/fea fi THISHOST=`hostname` ########################################################################## ## PROMPT FOR HOSTNAME. ########################################################################## WINTITLE="Processes Tree Report @AnyHost (Can take quite a few seconds)" export WINTITLE WIN_INFO="\ INPUT: Enter the name of an SGI host on the NNS network ... and click OK. (You can enter an IP address, if necessary.) ------ OUTPUT: This utility shows 1) the process IDs (PID's) on the specified host --- sorted in numeric order. 2) for each process ID (PID) , process info for the PID and all its parents. 3) a process-tree, each branch of which is a PID and its PPID's (parent process ID's). Item 2 is optional. Items 1 and 3 constitute an 'overview'. Item 2 adds 'detail'. You will be asked whether you want the 'detail'. -------- RUN-TIME: The run times of this report are approximately as follows. The run times are not quite linearly proportional to the number of processes --- rather, somewhat like a quadratic relationship. Approx. Report Number of Run-time Type Processes (seconds) -------- --------- --------- overview 100 10 overview 400 60 detail 100 15 detail 400 120 This is FAR, FAR FASTER than you could trace the parents for each process ID (or even just a few PID's) 'manually'. ----- USAGE: The report is shown with the site 'xpg' text utility. You can enter a search string, like a userid, and click on the 'Show All Matches' button, to see all the report lines that contain the userid. --- This report is helpful, for example, to quickly determine the parent processes for any given process, on a specified host. This can be helpful when a process needs to be killed --- because the process is accumulating a lot of CPU time, wasting resources --- or because the process has application licenses tied up. This report can help determine whether there are parent processes, of the 'errant process', that need to be killed. --- If such 'surprise' processes exist, you may want to start other displays --- like a license-status-query --- or queries for the SAME HOST --- like 'top' or 'gr_osview' or other process-resources-usage displays. Or you may want to open a window, on the specified host, in which to kill processes with the 'kill' command. --- Note that you can do queries on MULTIPLE HOSTS and bring the report windows side-by-side for comparison --- to look for abnormal conditions. " export WIN_INFO HOST_ID="`hostname`" export HOST_ID # HOST_ID=`$FEDIR/tkGUIs/enter_hostid.tk` # HOST_ID=`$FEDIR/tkGUIs/enter_hostid_optmenu.tk` HOST_ID=`$FEDIR/tkGUIs/enter_hostid_optmenu_toghelp-scroll.tk` if test "$HOST_ID" = "" then exit fi ######################################################################## ## ASK USER IF HE/SHE WANTS an ## (1) overview or (2) detail. ######################################################################## REPTTYPE=`xconfirm -c \ -header "Processes TREE -- Overview or Detail?" \ -b detail -B overview -b Cancel \ -t "Do you want the report to" \ -t "" \ -t "1) be a tree-OVERVIEW" \ -t "" \ -t "or" \ -t "" \ -t "2) include DETAIL on parent processes for each PID?" \ -t "" \ -t "" \ -t "'overview' or 'detail' or 'Cancel'?" \ -icon question` if test "$REPTTYPE" = "Cancel" then exit fi ########################################################################### ## Set an temp-filename in var $OUTLIST. ########################################################################### . $FEDIR/scripts/set_localoutlist ## FOR TESTING (output to screen, instead of to file): # OUTLIST="" ########################################################################## ## SET INDICATOR OF Local or Remote host. ########################################################################## THISHOST=`hostname` LOCALHOST="N" if test "$HOST_ID" = "$THISHOST" then LOCALHOST="Y" fi ###################################################################### ## PUT 'ps -ef' or 'ps -e -o' output in var PS_OUT. ###################################################################### ## NOTE: We expect the PID to be in column 2 ## and the PPID to be in column 3, in an 'awk' below. ###################################################################### # TEST_YN="TEST_YES" TEST_YN="TEST_NO" # PS_TYPE="ef" PS_TYPE="eo" if test "$PS_TYPE" = "ef" then PS_COLHEAD="\ UID PID PPID C STIME TTY TIME CMD" if test "$LOCALHOST" = "Y" then PS_OUT=`ps -ef` else ############################################## ## MAKE .rhosts FILE FOR THE USER, if needed. ############################################## # echo "+ $USER" > $HOME/.rhosts . $FEDIR/scripts/mak_rhosts PS_OUT=`rsh $HOST_ID ps -ef` # . $FEDIR/scripts/mv_rhosts fi if test "$TEST_YN" = "TEST_YES" then PS_OUT="\ UID PID PPID C STIME TTY TIME CMD root 1 0 0 Mar 29 ? 0:13 /etc/init root 109648 1 0 Apr 08 ? 0:00 xwsh -name winterm -name winterm -title fealis -geometry 80x43+010+350 -bg midn root 406 1 0 Mar 29 ? 0:01 /usr/etc/inetd bmo01 113792 113840 0 Apr 08 pts/20 0:00 -ksh bmo01 110611 109648 0 Apr 08 pts/22 0:00 -ksh root 112746 1 0 Apr 08 ? 0:00 xwsh -name winterm -name winterm -title catprd00_2 -geometry 80x43+010+350 -bg root 2112 1 0 Mar 29 ? 2:50 /usr/etc/mediad -n root 113840 1 0 Apr 08 ? 0:00 xwsh -name winterm -name winterm -title HOME -geometry 80x43+010+350 -bg midnig root 2127 406 0 Mar 29 ? 0:35 fam" fi else PS_OPTS="ruser pid ppid etime stime time pcpu vsz state cpu args" PS_COLHEAD="\ ------------------------------------------------------------------------------------------------------------------------------- UserID PID PPID Elapsed-Time StartTime CPUtime %CPU VirtMem Command/Program and arguments (up to 79 chars) - State CPU# HH:MM:SS - -- -------- --------- --------- ----------- -------- --------- --- ----- ------------------------------------------------" if test "$LOCALHOST" = "Y" then PS_OUT=`ps -e -o "$PS_OPTS"` else ############################################## ## MAKE .rhosts FILE FOR THE USER, if needed. ############################################## # echo "+ $USER" > $HOME/.rhosts . $FEDIR/scripts/mak_rhosts ## FOR TESTING: # set -x PS_OUT=`rsh $HOST_ID ps -e -o \"$PS_OPTS\"` ## FOR TESTING: # set - # . $FEDIR/scripts/mv_rhosts fi if test "$TEST_YN" = "TEST_YES" then PS_OUT="\ RUSER PID PPID ELAPSED STIME TIME %CPU VSZ S P COMMAND rkc04 153703 153638 12:25:20 07:58:32 0:00 0 768 S * /bin/sh ./exec153638.cmds root 1315 1 6-13:54:58 Apr 06 0:21 0 1760 S * /usr/sbin/numastatd -n 35 root 1321 1 6-13:54:58 Apr 06 0:00 0 2960 S * /usr/sbin/sesdaemon /etc/config/sesdaemon.options root 1349 1 6-13:54:58 Apr 06 1:14 0 3376 S * /usr/etc/mediad -n root 1351 314 6-13:54:58 Apr 06 8:37 0 4992 S * fam cjs05 153793 153797 12:17:02 08:06:50 0:00 0 720 S * -ksh root 153797 314 12:17:02 08:06:50 0:00 0 2128 S * telnetd -h root 1408 1 6-13:54:57 Apr 06 0:01 0 4528 S * /usr/etc/pmcd" fi fi ###################################################################### ## Extract the (unique) PID's from var PS_OUT. ###################################################################### if test "$TEST_YN" = "TEST_YES" then set -x fi PIDS=`echo "$PS_OUT" | tail +2 | awk '{print $2}' | sort +0 -1n` if test "$TEST_YN" = "TEST_YES" then set - fi PIDS_COUNT=`echo "$PIDS" | wc -l` PIDS_COUNT=`echo $PIDS_COUNT` ###################################################################### ## Prepare the report HEADING. ###################################################################### REPT_DESC="Overview WITH detail." if test "$REPTTYPE" = "overview" then REPT_DESC="Overview withOUT detail." fi echo "\ .......................... `date '+%Y %b %d %a %T%p %Z'` ................. PROCESSES-TREE - INFORMATION FOR EACH PROCESS - ON HOST $HOST_ID $REPT_DESC ========================================================================= The following $PIDS_COUNT process IDs were found, near the time indicated above. These PID's are sorted numerically. NOTE: The process-tree (parent-child hierarchy) is summarized in a 'PROCESSES TREE:' section below. " > $OUTLIST echo $PIDS | fold -s -w70 >> $OUTLIST # echo "$PIDS" >> $OUTLIST # echo " # NOTE: # The process-tree (parent-child hierarchy) is summarized # at the bottom of this report. # " >> $OUTLIST ###################################################################### ## Loop to store parent processes --- related to each PID --- ## in var PPIDS_LINE. ## ## This is done in a 'WHILE-there-are-parents' loop, ## within the 'FOR-each PID' loop. ## ## Also write out 'ps -f' or 'ps -o ' lines for PID and its parents. ## ## At the completion of processing for each PID, ## store the PPIDS_LINE in var PID_TREE. ###################################################################### PID_TREE="" for PID in $PIDS do if test "$REPTTYPE" = "detail" then echo " ****************************** Parent Processes Info for PID: $PID ******************************" >> $OUTLIST fi ## FOR TESTING: # echo " # ************************************** # Getting Parent Processes Info for PID: $PID # **************************************" PID_NEXT="$PID" PPIDS_LINE="$PID" PIDS_INFOLINES="" while test "$PID_NEXT" != "" do ###################################################################### ## On the first time thru this while loop (when $PID_NEXT=$PID), ## put the line of 'ps'-info for $PID in the var PS_OUT4PID. ## ## Then extract two info items from $PS_OUT4PID: ## 1) the USERID and 2) CMD. ## ###################################################################### if test "$PID_NEXT" = "$PID" then ## INEFFICIENT 1st draft METHOD: (extracts PID-info-line from many-line $PS_OUT multiple times) ## # PID_OWNER=`echo "$PS_OUT" | awk '{if ( $2 == PID ) {print $1}}' PID="$PID_NEXT"` # PID_CMD=`echo "$PS_OUT" | awk '{if ( $2 == PID ) {LEN0=length($0) ; print substr($0,81,LEN0 - 80)}}' PID="$PID_NEXT"` ## BETTER METHOD: (extracts PID-info-line from many-line $PS_OUT *once*) ## PS_OUT4PID=`echo "$PS_OUT" | awk '{if ( $2 == PID ) {print $0 ; exit}}' PID="$PID"` PID_OWNER=`echo "$PS_OUT4PID" | awk '{print $1}'` # PID_CMD=`echo "$PS_OUT4PID" | awk '{LEN0=length($0) ; print substr($0,81,LEN0 - 80)}'` # PID_CMD=`echo "$PS_OUT4PID" | awk '{LEN0=length($0) ; print substr($0,82,LEN0 - 81)}'` PID_CMD=`echo "$PS_OUT4PID" | awk '{print substr($0,82)}'` fi ###################################################################### ## For the 'detail' report, catenate the 'ps' info ## for the current PID, $PID_NEXT, onto $PIDS_INFOLINES. ###################################################################### if test "$REPTTYPE" = "detail" then if test "$PID_NEXT" = "$PID" then PID_INFOLINE="$PS_OUT4PID" else PID_INFOLINE=`echo "$PS_OUT" | awk '{if ( $2 == PID ) {print $0 ; exit}}' PID="$PID_NEXT"` fi PIDS_INFOLINES="$PIDS_INFOLINES $PID_INFOLINE" fi ###################################################################### ## Get the PPID for the current PID, $PID_NEXT. Put it in PID_HOLD. ###################################################################### PID_HOLD=`echo "$PS_OUT" | awk '{if ( $2 == PID ) {print $3}}' PID="$PID_NEXT"` ###################################################################### ## Add the PPID, $PID_HOLD, to the LEFT side of $PPIDS_LINE. ###################################################################### PPIDS_LINE="$PID_HOLD $PPIDS_LINE" ###################################################################### ## Use $PID_HOLD to set the next (parent) PID to process --- ## in $PID_NEXT (the object of the 'while' check). ###################################################################### PID_NEXT="$PID_HOLD" done ## END OF while test "$PID_NEXT" != "" ###################################################################### ## Add USERID & CMD to the RIGHT side of $PPIDS_LINE. ## Add at least 5 spaces to $PPIDS_LINE before adding USERID --- ## and pad shorter lines so that USERID starts about column 31. ###################################################################### LEN_PIDS=`echo "$PPIDS_LINE" | wc -c` LEN_PIDS=`expr $LEN_PIDS - 1` ## NOTE: 26 is used in the 'if' and 31=26+5 is used in 'cut'. ## If you change 26, change it in both places. if test $LEN_PIDS -ge 26 then PPIDS_LINE="$PPIDS_LINE " else PPIDS_LINE=`echo "${PPIDS_LINE} " | cut -c1-31` fi PPIDS_LINE="$PPIDS_LINE $PID_OWNER" PPIDS_LINE="$PPIDS_LINE $PID_CMD" ###################################################################### ## For the 'detail' report, write out $PIDS_INFOLINES for $PID, ## with header-separator. ###################################################################### if test "$REPTTYPE" = "detail" then echo " Parent-Processes-Chain for PID = $PID (with owner & cmd): $PPIDS_LINE \ " >> $OUTLIST echo " PROCESS INFO for PID=$PID and its parents: $PS_COLHEAD \ $PIDS_INFOLINES " >> $OUTLIST fi ## END OF if test "$REPTTYPE" = "detail" ###################################################################### ## Add $PPIDS_LINE to $PID_TREE ###################################################################### PID_TREE="$PID_TREE $PPIDS_LINE" done ## END OF for PID in $PIDS ################################################################### ## Add a Trailer to the 'PROCESSES-TREE' REPORT. ################################################################### PID_TREE_SORTED=`echo "$PID_TREE" | sort -k1n -k2n -k3n -k4n -k5n -k6n -k7n -k8n -k9n -k10n` # PID_TREE_SORTED_NUMBED=`echo "$PID_TREE_SORTED" | nl` echo " ========================================================================= PROCESSES TREE: ( for host $HOST_ID ) 'TREE' of processes (PID's) and their parents (PPID's): [Each 'tree branch' (line) below corresponds to a 'subject' PID. The 'subject' PID is the right-most process number in each line. The process owner is shown to the right of the PID. The owner (userid) is followed by the command/program corresponding to the PID --- and followed by arguments, if any --- up to 79 chars. The PPID's of the PID are to the left of the PID, with the 'top-most' parent on the far left. These lines are sorted by the PPID's and PID, thus grouping together processes with common parents.] PID PPID's and 'subject' PID Owner PID command/program ------------------------------- ------ ------------------------------------ $PID_TREE_SORTED .......................... `date '+%Y %b %d %a %T%p %Z'` ................. The output above is from script $0 which was run from host $THISHOST . --- The report file is shown with the site 'xpg' text utility. You can enter a search string, like a userid, and click on the 'Show All Matches' button, to see all the report lines that contain the userid. ............................................................................. " >> $OUTLIST if test "$REPTTYPE" = "detail" then echo " Column heading meanings --- for process-info in the 'detail' listing: UserID The login name of the process owner. PID The process ID of the process. PPID The process ID of the parent process. ElapsedTime The time elapsed since the process started. The format is -HH:MM:SS, where HH denotes hours, MM denotes minutes, and SS denotes seconds. StartTime The start-time of the process, given in hours, minutes, and seconds. (For a process begun more than twenty-four hours before the ps inquiry is executed, start-time is given as month and day.) CPUtime The cumulative execution time for the process (mins:secs) --- CPU-time, not 'wall-clock time' --- which is given by ElapsedTime. %CPU The ratio of CPU time used recently to the CPU time available in the same period, expressed as a percentage. This is calculated by ps over a short period of time, and as such, is only an approximation. VirtMem Total size (in pages) of the process. This typicallly includes code, data, shared memory, mapped files, shared libraries and stack. This number is meant to give an idea of the relative sizes of the processes, in terms of the memory they consume. The page size can either be 4096 or 16384 bytes. In general, the larger page is used on the newer SGI machines --- more specifically, on systems where the 'uname' command returns 'IRIX64'. State The state of the process: 0 Process is running on a processor. S Process is sleeping, at this instant, waiting for a resource. R Process is running. Z Process is terminated and parent not waiting (see 'man wait'). T Process is stopped. I Process is in intermediate state of creation. X Process is waiting for memory. C Process is creating core image after error. CPU# The processor that the process is currently executing on. Numbering starts with zero (0). An asterisk (*) may be shown if the process is not currently running. On a single-processor host, zero is the only the number that will be seen in this column. Cmd/Program The full command (or program) name and its arguments (up to 79 chars). A process that has exited and has a parent, but has not yet been waited for by the parent, is marked , in the CMD column. See 'man ps' for further information. ............................................................................. " >> $OUTLIST fi ## END OF if test "$REPTTYPE" = "detail" echo "\ IMPLEMENTATION METHODS: This 'Processes-Tree-Report' script can be accessed via a drawer in a command toolchest-utility, like 'Perf Tools' --- which is available as a drawer in the command/toolchest utility 'Handy Tools'. A site SGI toolchest-drawer path is SGI Toolchest -> Handy Tools -> Any Host - Perf Tools (Processes) -> Processes TREE Report @AnyHost Also available via SGI Toolchest -> nnsFEAmenu -> ABAQUS 6.4 Tools -> Any Host - PROCESSES QUERIES -> Processes TREE @AnyHost Or, you can implement the script (or the 'perftools' script or the 'handytools' script) as - a command alias, via your .profile file; examples: alias ptree='$0' alias ptools='$FEDIR/scripts/perftools' alias htools='$FEDIR/scripts/handytools' - a desktop icon, via the 'Find, File QuickFind' tool drawers; - a drawer in the SGI toolchest, via your .auxchestrc file. .......................... `date '+%Y %b %d %a %T%p %Z'` ................. " >> $OUTLIST # $PID_TREE_SORTED_NUMBED ################################################################### ## SHOW/PRINT 'PROCESSES-TREE' REPORT. ################################################################### $FEDIR/scripts/shofil $OUTLIST