95 lines
2.6 KiB
Bash
Executable File
95 lines
2.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# time-and-mem-limit
|
|
# Ralph Becket <rafe@csse.unimelb.edu.au>
|
|
# Tue Feb 10 12:21:58 EST 2009
|
|
#
|
|
# usage: time-and-mem-limit N M cmd ...
|
|
#
|
|
# Kill cmd ... if it does not terminate after N seconds of wallclock time or if
|
|
# it uses more than M megabytes of memory. Either "EXCEEDED TIME LIMIT" or
|
|
# "EXCEEDED MEMORY LIMIT" is printed on stderr as appropriate if cmd ... is
|
|
# killed for one of these reasons.
|
|
|
|
USAGE="usage: time-and-mem-limit num-seconds num-megabytes cmd ..."
|
|
|
|
if [ "$*" = "-h" -o "$*" = "--help" ]
|
|
then
|
|
echo $USAGE >&2
|
|
exit 0
|
|
fi
|
|
|
|
if [ $# -lt 3 ]
|
|
then
|
|
echo $USAGE >&2
|
|
exit 1
|
|
fi
|
|
|
|
# CMDPID: we exec the command so it gets the current PID.
|
|
CMDPID=$$
|
|
# TIMELIMIT: the time limit in seconds.
|
|
TIMELIMIT=$1
|
|
# MEMLIMIT: the memory limit in megabytes.
|
|
MEMLIMITMB=$2
|
|
MEMLIMITKB=$(($MEMLIMITMB << 10))
|
|
shift 2
|
|
# CMD: anything else on the command line is the command to be executed.
|
|
CMD=$@
|
|
|
|
declare TimeoutOrig=$(ulimit -t)
|
|
declare MemoryOrig=$(ulimit -v)
|
|
|
|
# Using ulimit like this doesn't work on Cygwin.
|
|
#
|
|
if test ! -e /bin/cygpath.exe
|
|
then
|
|
ulimit -S -t ${TIMELIMIT}
|
|
ulimit -S -v ${MEMLIMITKB}
|
|
else ### Only on Cygwin: Ubuntu 15 does not allow to delete output files and reports wrong exit result
|
|
# Check the time and memory limits every ten seconds in a background
|
|
# process. If either limit is reached, kill the process.
|
|
(
|
|
for (( i=0 ; i<$TIMELIMIT ; i+=1 ))
|
|
do
|
|
# Sleep for 1 seconds.
|
|
sleep 1
|
|
# Obtain the process memory usage in kilobytes.
|
|
# (We use this form of ps arguments for portability).
|
|
CMDMEMUSAGEKB=`ps -p $CMDPID -o vsize=""`
|
|
# Quit if the process has already terminated.
|
|
if [ -z $CMDMEMUSAGEKB ]
|
|
then
|
|
exit 0
|
|
fi
|
|
# Kill the process if it has exceeded its memory limit.
|
|
if [ $CMDMEMUSAGEKB -gt $MEMLIMITKB ]
|
|
then
|
|
kill -KILL $CMDPID >/dev/null 2>&1
|
|
echo "" >&2
|
|
echo "EXCEEDED MEMORY LIMIT OF $MEMLIMITMB Mbytes" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
# Kill the process if it has exceeded its time limit.
|
|
if ps -p $CMDPID >/dev/null 2>&1
|
|
then
|
|
kill -KILL $CMDPID >/dev/null 2>&1
|
|
echo "" >&2
|
|
echo "EXCEEDED TIME LIMIT OF $TIMELIMIT s" >&2
|
|
exit 1
|
|
fi
|
|
) &
|
|
|
|
# The background process above sometimes does not seem to fire or does not
|
|
# kill all subprocesses. "ulimit" is more reliable, but it is not clear how
|
|
# to get useful, specific error messages. Thus for now we use both methods.
|
|
fi
|
|
|
|
# Run the command.
|
|
exec $CMD
|
|
|
|
if test ! -e /bin/cygpath.exe
|
|
then
|
|
ulimit -S -t ${TimeoutOrig}
|
|
ulimit -S -v ${MemoryOrig}
|
|
fi
|