( ESNUG 210 Item 3 ) ---------------------------------------------- [2/24/95]
From: sgolson@trilobyte.com (Steve Golson)
Subject: Synopsys Design Compiler Watchlog Utility
Hi John,
Here is a favorite utility of mine. It monitors the log file being generated
by any process and annotates it with the elapsed CPU time. For Synopsys runs
it generates a CPU timestamped output like:
Beginning Resource Allocation (constraint driven)
-----------------------------
Allocating blocks in 'r1'
25:03 Allocating blocks in 'fifo'
Beginning Mapping Optimizations (Medium effort)
-------------------------------
26:02 Structuring 'fifo'
32:33 Mapping 'fifo'
In this example you can see that "Structuring 'fifo'" took (32:33 - 26:02)
6:31 CPU minutes. (It's great for long compiles; you can see what soaks up
all the time!)
Start watchlog after you start your dc_shell run, and pass it the name
of your logfile and the PID:
csh> dc_shell -f myscript.ss >& myscript.log &
[1] 1234
csh> watchlog myscript.log 1235 >& myscript.watchlog &
Note that the PID returned by csh when you start up dc_shell is the PID of
dc_shell (makes sense!) but the process that we want to watch is
dc_shell_exec, which is typically the next PID in sequence. Your OS may vary.
(To be sure you could invoke dc_shell_exec directly.)
Watchlog builds a sed script; after the monitored process exits it runs "sed"
on the log file and spits the resulting watchlog file to stdout.
Comments, bug reports, etc. are much appreciated.
- Steve Golson
Trilobyte Systems
#! /bin/sh
#
# watchlog 1.5 -- annotates a logfile w/cpu time of the process creating it
#
# Usage: watchlog logfile pid [hostname] [sleep_time]
# where
# pid = id of the process to monitor
# logfile = the logfile being created by the process
# hostname = host running the process to monitor (optional)
# sleep_time = seconds to sleep between timestamps (defaults to 60)
#
# watchlog monitors the logfile length and the elapsed cpu time of the
# process. It generates a sed script that is used to create the annotated
# log after the monitored process exits.
myname="`basename $0`"
# get args
if [ $# -lt 2 ]
then
echo "Usage: $myname logfile pid [hostname] [sleep_time]" 1>&2
exit 1
fi
logfile=$1
pid=$2
if [ $# -ge 3 -a "$3" ]
then
hostname=$3
fi
if [ $# -ge 4 ]
then
# sleep_time must be a positive integer
expr "$4" : '[0-9]*[0-9]$' > /dev/null || {
echo "$myname: bad sleep_time value: $4" 1>&2
exit 1
}
fi
# time in seconds between ps runs, defaults to 60
sleep_time=${4-60}
# file where the sed commands go
sed_script="${myname}.$$.sed"
# the ps command, using rsh if hostname exists
ps="${hostname+rsh -n} ${hostname-} /usr/bin/ps $pid"
# make a tab character to use with sed
tab=`echo 't' | tr 't' '\011'`
# make sure we can read logfile
test -r $logfile || {
echo "$myname: cannot read $logfile" 1>&2
exit 1
}
# make sure ps works
$ps > /dev/null &&
ps_info=`$ps | egrep -v "PID"` &&
test "$ps_info" || {
echo "$myname: $ps failed" 1>&2
exit 1
}
# initialize the sed script
echo "# sed script for: $myname $@" > $sed_script &&
echo "# created on `date`" >> $sed_script || {
echo "$myname: cannot write to $sed_script" 1>&2
exit 1
}
### done with initialization
# prepend a tab to every line of logfile
echo "s/^/${tab}/" >> $sed_script || {
echo "$myname: cannot write to $sed_script" 1>&2
exit 1
}
# setup prev_line_num for first time through the while loop
wc_result=`wc -l $logfile`
prev_line_num=`expr "$wc_result" : ' *\([0-9]*\)'`
while
# while the process still exists
ps_info=`$ps | egrep -v "PID"`
test "$ps_info"
do
# get the number of lines in logfile
wc_result=`wc -l $logfile`
line_num=`expr "$wc_result" : ' *\([0-9]*\)'`
# get the cpu time used by the process so far
time=`expr "$ps_info" : '.*[^0-9]\([0-9]*:[0-9][0-9]\).*'`
# format it nicely to fit in 8 spaces "1234:56 "
time=`expr " ${time}" : \
'.*\([ 0-9][ 0-9][ 0-9][ 0-9]:[0-9][0-9]\)'`
# if logfile has grown
if expr "$line_num" != "$prev_line_num" > /dev/null
then
# mark previous line with current time
echo "${prev_line_num}s/^/${time}/" >> $sed_script || {
echo "$myname: cannot write to $sed_script" 1>&2
exit 1
}
# time has been used
time=""
fi
prev_line_num=$line_num
sleep $sleep_time
done
# process has finished
# if time hasn't been used then put it on the last line found
if [ "$time" ]
then
echo "${line_num}s/^/${time}/" >> $sed_script || {
echo "$myname: cannot write to $sed_script" 1>&2
exit 1
}
fi
# run sed to make annotated logfile
# unfortunately sed has a bogus 200 command limit, so...
# split up sed_script
split -190 $sed_script ${sed_script}.
# build up a pipe of multiple sed commands
notfirst=""
for file in `/bin/ls ${sed_script}.??`
do
if [ "$notfirst" ]
then
# add to the pipe
command="$command | sed -f $file"
else
# first sed in the pipe, so add logfile
command="sed -f $file $logfile"
notfirst="true"
fi
done
# execute the pipe
eval $command
# cleanup
/bin/rm -f $sed_script ${sed_script}.??
exit 0
|
|