I wrote a simple (meta)program to run two analogous programs, 'cat' and 'dog', back-to-back and calculate the total time for each over several (five) passes of a file.
It is really quite a simple script, but the speed-testing idea seems interesting, and there are a couple of points in it that were worth learning.
Code:
#=======================================================================#
# NAME: speed_test: 'cat' vs 'dog'
# DESCRIPTION: runs two programs, 'cat and 'dog', one after the
# other, timing the duration of run-time over five
# runs, and outputs total times (and possibly,
# eventually, averages).
# ARTHUR: G O Free =:)
# FOR: bashscripts.org
# DATE: February 1, 2010
#=======================================================================#
#
# This method uses the 'reserved word' in the bash shell, 'time', as
# opposed to the external GNU command of the same name. It is like a
# built-in and is formatted using the environment variable 'TIMEFORMAT'.
# --> Default format: TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
# --> Format for Real Time in Seconds (No labels): TIMEFORMAT='%3R'
#
# The line, '{ time [command] > /dev/null 2>&1 ; } 2>> time.txt',
# suppresses the output of the command (eg. 'cat' or 'dog') to standard
# output and redirects the output of 'time' to a file record.
#
# Alternatively use the line,
# '{ time cat $TEST_FILE ; } 2>> cattime.txt', if you wish to view the
# outputs of 'cat' and 'dog'. If you do, try it with 'more' or 'less'.
#
# This script also uses the GNU "arbitrary precision numeric processing
# language", 'bc', to do the math. Variables in 'bash' script are piped to 'bc'
# which makes the required calculations.
#
# Display name of program
echo; echo "speed_test: 'cat' vs 'dog'"
# Set the format for 'time'
# output (real time only, in
# seconds, no letters/labels)
TIMEFORMAT='%3R'
# Test that a filename was
# given and the file exists
TEST_FILE=${1:?"No file given: Usage: speed_test [filename]"}
if [ ! -e $TEST_FILE ]; then echo "FILE DOES NOT EXIST"; exit 0; fi
# Display name of test file
echo "TEST_FILE: $TEST_FILE"; echo
### Run test with 'cat' first
# Remove previous records and
# start new record for first
# program, 'cat'
if [ -e cattime.txt ]; then rm cattime.txt; fi
touch cattime.txt
# Signal start of 'cat' test
echo "CAT"
echo "time cat $TEST_FILE:"
# Run 'cat' on test file five
# times
for (( i = 1; i <= 5; i++)); do
# Identify run number
echo -n -e "$i)\t "
# Run 'cat' on test file,
# Suppress 'cat' display,
# and record run-times
{ time cat $TEST_FILE > /dev/null 2>&1 ; } 2>> cattime.txt
# Use this line to display
# 'cat' output
# { time cat $TEST_FILE ; } 2>> cattime.txt
# Display run-time
cat cattime.txt | tail -n 1
done
echo
# Start count of recorded
# run-times
let -i COUNT=1
# Start run-time total at zero,
# sending value to 'bc' for
# decimal numbers
CAT_TOTAL=$(echo "0" | bc)
# Signal start of summary
echo "total time for 'cat':"
# Read each run-time in
# recorded list
for TIME in $(cat cattime.txt); do
# Convert recorded times to
# decimal numbers with 'bc'
DECT=$(echo "$TIME" | bc)
# Display times and decimal
# values
echo -e "$COUNT) TIME: $TIME\t DECT: $DECT"
# Use 'bc' to calculate the sum
# of 'cat' run-times
CAT_TOTAL=$(echo "$CAT_TOTAL+$DECT" | bc)
let COUNT=$COUNT+1
done
# Display run-time total,
# '$CAT_TOTAL'
echo -e "\t\tTOTAL: $CAT_TOTAL"
echo
### Run the test a second time with 'dog'
# Remove previous records and
# start new record for second
# program, 'dog'
if [ -e dogtime.txt ]; then rm dogtime.txt; fi
touch dogtime.txt
# Signal start of 'dog' test
echo "DOG"
echo "time dog $TEST_FILE:"
# Run 'dog' on test file five
# times
for (( i = 1; i <= 5; i++)); do
# Identify run number
echo -n -e "$i)\t "
# Run 'dog' on test file,
# Suppress 'dog' display,
# and record run-times
{ time dog $TEST_FILE > /dev/null 2>&1 ; } 2>> dogtime.txt
# Use this line to display
# 'dog' output
# { time dog $TEST_FILE ; } 2>> dogtime.txt
# Display run-time
dog dogtime.txt | tail -n 1
done
echo
# Start count of recorded
# run-times
let -i COUNT=1
# Start run-time total at zero,
# sending value to 'bc' for
# decimal numbers
DOG_TOTAL=$(echo "0" | bc)
# Signal start of summary
echo "total time for 'dog':"
# Read each run-time in
# recorded list
for TIME in $(dog dogtime.txt); do
# Convert recorded times to
# decimal numbers with 'bc'
DECT=$(echo "$TIME" | bc)
# Display times and decimal
# values
echo -e "$COUNT) TIME: $TIME\t DECT: $DECT"
# Use 'bc' to calculate the sum
# of run-times
DOG_TOTAL=$(echo "$DOG_TOTAL+$DECT" | bc)
let COUNT=$COUNT+1
done
# Display run-time total,
# '$DOG_TIME'
echo -e "\t\tTOTAL: $DOG_TOTAL"
echo
### Results
# Decide which program had
# shorter total run time
# Display total time
# difference, if any
if [ $(echo "$CAT_TOTAL<$DOG_TOTAL" | bc) = 1 ]; then
DIFF=$(echo "$DOG_TOTAL-$CAT_TOTAL" | bc)
echo "'cat' took $DIFF seconds less time than 'dog'"
elif [ $(echo "$DOG_TOTAL<$CAT_TOTAL" | bc) = 1 ]; then
DIFF=$(echo "$CAT_TOTAL-$DOG_TOTAL" | bc)
echo "'dog' took $DIFF seconds less time than 'cat'"
else
echo "'cat' and 'dog' took the same time"
fi
# Reset default 'time' format
TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
# Signal end of program
echo "done"; echo
exit 0
Although this comparison between 'dog' and 'cat' seems somewhat... what?... trivial?... I can see how the test itself could be useful elsewhere.
G O Free
