Created
October 28, 2013 19:13
-
-
Save ubergeek42/7202772 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 785c5f2946fcb57db5c6473269200ae8c2f95575 Mon Sep 17 00:00:00 2001 | |
From: Keith Johnson <kj@ubergeek42.com> | |
Date: Thu, 18 Jul 2013 08:52:28 -0400 | |
Subject: [PATCH 1/2] Use performance counters for more information | |
Count the number of instructions a submission used, this could be used | |
for fair "timelimits" independent of judging hardware | |
This also makes the child wait until the parent has started the timer | |
before letting them actually run. | |
--- | |
configure.ac | 12 ++++++ | |
etc/runguard-config.h.in | 2 + | |
judge/runguard.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ | |
paths.mk.in | 1 + | |
4 files changed, 110 insertions(+) | |
diff --git a/configure.ac b/configure.ac | |
index 9bbe434..14b3a6e 100644 | |
--- a/configure.ac | |
+++ b/configure.ac | |
@@ -164,6 +164,17 @@ else | |
AC_SUBST(USE_CGROUPS,0) | |
fi | |
+# Use performance counters(instruction count limits) | |
+AC_ARG_ENABLE(perfcounters,AS_HELP_STRING([--enable-perfcounters], | |
+ [Use hardware performance counters for instruction count based limits (default: disabled)]), [], []) | |
+if test "x$enable_perfcounters" = xyes; then | |
+ use_perfcounters=yes | |
+ AC_SUBST(USE_PERFCOUNTERS,1) | |
+else | |
+ use_perfcounters=no | |
+ AC_SUBST(USE_PERFCOUNTERS,0) | |
+fi | |
+ | |
# }}} | |
# {{{ FHS directory structure | |
@@ -340,6 +351,7 @@ echo " * runguard user.......: $RUNUSER" | |
echo " * webserver group.....: $WEBSERVER_GROUP" | |
echo "" | |
echo " * use Linux cgroups...: $use_cgroups" | |
+echo " * use Perfcounters....: $use_perfcounters" | |
echo "" | |
if test "x$CHECKTESTDATA_ENABLED" = xyes ; then | |
echo " * checktestdata.......: enabled" | |
diff --git a/etc/runguard-config.h.in b/etc/runguard-config.h.in | |
index e0e620b..6f91084 100644 | |
--- a/etc/runguard-config.h.in | |
+++ b/etc/runguard-config.h.in | |
@@ -10,4 +10,6 @@ | |
#define USE_CGROUPS @USE_CGROUPS@ | |
+#define USE_PERFCOUNTERS @USE_PERFCOUNTERS@ | |
+ | |
#endif /* _RUNGUARD_CONFIG_ */ | |
diff --git a/judge/runguard.c b/judge/runguard.c | |
index 08d29b6..7252278 100644 | |
--- a/judge/runguard.c | |
+++ b/judge/runguard.c | |
@@ -80,6 +80,16 @@ | |
#undef USE_CGROUPS | |
#endif | |
+/* perf_events headers */ | |
+#if ( USE_PERFCOUNTERS == 1 ) | |
+#include <sys/ioctl.h> | |
+#include <linux/perf_event.h> | |
+#include <asm/unistd.h> | |
+#else | |
+#undef USE_PERFCOUNTERS | |
+#endif | |
+ | |
+ | |
#define PROGRAM "runguard" | |
#define VERSION DOMJUDGE_VERSION "/" REVISION | |
#define AUTHORS "Jaap Eldering" | |
@@ -328,6 +338,26 @@ void output_exit_time(int exitcode, double timediff) | |
} | |
} | |
+#ifdef USE_PERFCOUNTERS | |
+/* glibc doesn't include a wrapper for this syscall */ | |
+long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) | |
+{ | |
+ int ret; | |
+ ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); | |
+ return ret; | |
+} | |
+void output_perfcounter_stats(int perf_fd) { | |
+ long long perf_count; | |
+ int ret; | |
+ ret = read(perf_fd, &perf_count, sizeof(long long)); | |
+ if ( ret!=-1 ) { | |
+ fprintf(stderr, "Total instructions used: %lld\n", perf_count); | |
+ } else { | |
+ fprintf(stderr, "Unable to determine instruction count"); | |
+ } | |
+} | |
+#endif | |
+ | |
#ifdef USE_CGROUPS | |
void output_cgroup_stats() | |
{ | |
@@ -639,6 +669,14 @@ int main(int argc, char **argv) | |
#ifdef USE_CGROUPS | |
int ret; | |
#endif | |
+#ifdef USE_PERFCOUNTERS | |
+ struct perf_event_attr pe; | |
+ int perf_fd; | |
+#endif | |
+ /* pipes for sync(make the child wait for the parent before exec'ing) */ | |
+ int child_ready_pipe[2], go_pipe[2]; | |
+ char pipe_buf; | |
+ | |
int status; | |
int exitcode; | |
char *valid_users; | |
@@ -827,10 +865,21 @@ int main(int argc, char **argv) | |
unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM); | |
#endif | |
+ | |
+ /* Set-up some pipes for child-parent sync */ | |
+ if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { | |
+ error(errno, "Failed to create pipes"); | |
+ exit(1); | |
+ } | |
+ | |
switch ( child_pid = fork() ) { | |
case -1: /* error */ | |
error(errno,"cannot fork"); | |
case 0: /* run controlled command */ | |
+ /* Closed unused pipes for sync */ | |
+ close(child_ready_pipe[PIPE_OUT]); | |
+ close(go_pipe[PIPE_IN]); | |
+ | |
/* Connect pipes to command (stdin/)stdout/stderr and close unneeded fd's */ | |
for(i=1; i<=2; i++) { | |
if ( dup2(child_pipefd[i][PIPE_IN],i)<0 ) { | |
@@ -854,6 +903,14 @@ int main(int argc, char **argv) | |
/* Apply all restrictions for child process. */ | |
setrestrictions(); | |
+ /* Tell parent we are ready to go */ | |
+ close(child_ready_pipe[PIPE_IN]); | |
+ | |
+ // Now wait for parent to indicate they are ready for us to go | |
+ if ( read(go_pipe[PIPE_OUT], &pipe_buf, 1)==-1 ) | |
+ error(errno, "failed to read from go_pipe"); | |
+ close(go_pipe[PIPE_OUT]); | |
+ | |
/* And execute child command. */ | |
execvp(cmdname,cmdargs); | |
error(errno,"cannot start `%s'",cmdname); | |
@@ -868,6 +925,36 @@ int main(int argc, char **argv) | |
verbose("watchdog using user ID `%d'",getuid()); | |
} | |
+ | |
+ /* Close unused pipes for sync */ | |
+ close(child_ready_pipe[PIPE_IN]); | |
+ close(go_pipe[PIPE_OUT]); | |
+ | |
+ /* Wait for child to indicate they are ready */ | |
+ if (read(child_ready_pipe[PIPE_OUT], &pipe_buf, 1) == -1) | |
+ error(errno, "error reading child_ready_pipe"); | |
+ close(child_ready_pipe[PIPE_OUT]); | |
+ | |
+#ifdef USE_PERFCOUNTERS | |
+ /* Set up an instruction counter */ | |
+ memset(&pe, 0, sizeof(struct perf_event_attr)); | |
+ pe.size = sizeof(struct perf_event_attr); | |
+ pe.type = PERF_TYPE_HARDWARE; | |
+ pe.config = PERF_COUNT_HW_INSTRUCTIONS; | |
+ | |
+ pe.inherit = 1; /* count any forks/threads/children */ | |
+ pe.exclude_kernel = 1; /* only count instructions in user-mode */ | |
+ pe.disabled = 1; /* start disabled */ | |
+ pe.enable_on_exec = 1; /* enable when the next exec is called */ | |
+ | |
+ /* Attach the performance counter */ | |
+ perf_fd = perf_event_open(&pe, child_pid, -1, -1, 0); | |
+ if ( perf_fd==-1 ) { | |
+ error(1,"perf_event_open failed\n"); | |
+ exit(1); | |
+ } | |
+#endif | |
+ | |
if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); | |
/* Close unused file descriptors */ | |
@@ -934,6 +1021,9 @@ int main(int argc, char **argv) | |
error(errno,"getting start clock ticks"); | |
} | |
+ /* Ok, now let the child process go */ | |
+ close(go_pipe[PIPE_IN]); | |
+ | |
/* Wait for child data or exit. */ | |
while ( 1 ) { | |
@@ -1006,6 +1096,11 @@ int main(int argc, char **argv) | |
exitcode = WEXITSTATUS(status); | |
} | |
+#ifdef USE_PERFCOUNTERS | |
+ output_perfcounter_stats(perf_fd); | |
+ close(perf_fd); | |
+#endif | |
+ | |
#ifdef USE_CGROUPS | |
output_cgroup_stats(); | |
cgroup_delete(); | |
diff --git a/paths.mk.in b/paths.mk.in | |
index 82ee2b1..a1dc4bc 100644 | |
--- a/paths.mk.in | |
+++ b/paths.mk.in | |
@@ -171,6 +171,7 @@ define substconfigvars | |
-e 's,@BEEP[@],@BEEP@,g' \ | |
-e 's,@RUNUSER[@],@RUNUSER@,g' \ | |
-e 's,@USE_CGROUPS[@],@USE_CGROUPS@,g' \ | |
+ -e 's,@USE_PERFCOUNTERS[@],@USE_PERFCOUNTERS@,g' \ | |
-e 's,@SUBMIT_DEFAULT[@],@SUBMIT_DEFAULT@,g' \ | |
-e 's,@SUBMIT_ENABLE_CMD[@],@SUBMIT_ENABLE_CMD@,g' \ | |
-e 's,@SUBMIT_ENABLE_WEB[@],@SUBMIT_ENABLE_WEB@,g' \ | |
-- | |
1.7.9.5 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 5af459264dc6b93c4a84b4823683d604f35178cf Mon Sep 17 00:00:00 2001 | |
From: Keith Johnson <kj@ubergeek42.com> | |
Date: Mon, 22 Jul 2013 14:30:12 -0400 | |
Subject: [PATCH 2/2] Add instruction limit handling | |
New settings to choose whether to use instruction limits or timelimits. | |
Timelimits are still enforced when instruction limits are in | |
place(violating either will result in a TIMELIMIT result). | |
cgroups now report 'memorylimit exceeded' in the output | |
Code could use some improvement(currently it does polling every 0.5s) to | |
check if the instruction limit has been exceeded. There is support for | |
receiving a SIGIO signal when a threshold is reached on a performance | |
counter, but in my limited testing it seemed to be somewhat unreliable, | |
hence the polling method. | |
--- | |
judge/compile.sh | 13 ++++++-- | |
judge/judgedaemon.main.php | 6 +++- | |
judge/runguard.c | 74 +++++++++++++++++++++++++++++++++++------- | |
judge/testcase_run.sh | 13 ++++++-- | |
sql/mysql_db_defaultdata.sql | 2 ++ | |
5 files changed, 91 insertions(+), 17 deletions(-) | |
diff --git a/judge/compile.sh b/judge/compile.sh | |
index 2c520c3..bf06214 100755 | |
--- a/judge/compile.sh | |
+++ b/judge/compile.sh | |
@@ -49,13 +49,18 @@ cleanexit () | |
CPUSET="" | |
CPUSET_OPT="" | |
+INSTLIMIT="" | |
+INSTLIMIT_OPT="" | |
# Do argument parsing | |
OPTIND=1 # reset if necessary | |
-while getopts "n:" opt; do | |
+while getopts "n:i:" opt; do | |
case $opt in | |
n) | |
CPUSET="$OPTARG" | |
;; | |
+ i) | |
+ INSTLIMIT="$OPTARG" | |
+ ;; | |
:) | |
echo "Option -$OPTARG requires an argument." >&2 | |
;; | |
@@ -72,6 +77,10 @@ else | |
LOGFILE="$DJ_LOGDIR/judge.`hostname | cut -d . -f 1`.log" | |
fi | |
+if [ -n "$INSTLIMIT" ]; then | |
+ INSTLIMIT_OPT="-i $INSTLIMIT" | |
+fi | |
+ | |
# Logging: | |
LOGLEVEL=$LOG_DEBUG | |
PROGNAME="`basename $0`" | |
@@ -123,7 +132,7 @@ logmsg $LOG_INFO "starting compile" | |
# First compile to 'source' then rename to 'program' to avoid problems with | |
# the compiler writing to different filenames and deleting intermediate files. | |
exitcode=0 | |
-"$RUNGUARD" ${DEBUG:+-v} $CPUSET_OPT -t $COMPILETIME -c -f 65536 -T "$WORKDIR/compile.time" -- \ | |
+"$RUNGUARD" ${DEBUG:+-v} $CPUSET_OPT $INSTLIMIT_OPT -t $COMPILETIME -c -f 65536 -T "$WORKDIR/compile.time" -- \ | |
"$COMPILE_SCRIPT" program "$MEMLIMIT" "$@" >"$WORKDIR/compile.tmp" 2>&1 || \ | |
exitcode=$? | |
diff --git a/judge/judgedaemon.main.php b/judge/judgedaemon.main.php | |
index f386c2f..7d7fd2a 100644 | |
--- a/judge/judgedaemon.main.php | |
+++ b/judge/judgedaemon.main.php | |
@@ -312,6 +312,10 @@ function judge($mark, $row, $judgingid) | |
putenv('FILELIMIT=' . dbconfig_get_rest('filesize_limit')); | |
putenv('PROCLIMIT=' . dbconfig_get_rest('process_limit')); | |
+ $instlimit_opt = ''; | |
+ if (dbconfig_get('use_instructionlimit')) | |
+ $instlimit_opt = "-i " . dbconfig_get('instruction_limit'); | |
+ | |
$cpuset_opt = ""; | |
if ( isset($options['daemonid']) ) $cpuset_opt = "-n ${options['daemonid']}"; | |
@@ -442,7 +446,7 @@ function judge($mark, $row, $judgingid) | |
if ( $retval!=0 ) error("Could not copy program to '$programdir'"); | |
// do the actual test-run | |
- system(LIBJUDGEDIR . "/testcase_run.sh $cpuset_opt $tcfile[input] $tcfile[output] " . | |
+ system(LIBJUDGEDIR . "/testcase_run.sh $cpuset_opt $instlimit_opt $tcfile[input] $tcfile[output] " . | |
"$row[maxruntime] '$testcasedir' " . | |
"'$row[special_run]' '$row[special_compare]'", $retval); | |
diff --git a/judge/runguard.c b/judge/runguard.c | |
index 7252278..81156e0 100644 | |
--- a/judge/runguard.c | |
+++ b/judge/runguard.c | |
@@ -153,6 +153,9 @@ rlim_t memsize; | |
rlim_t filesize; | |
rlim_t nproc; | |
size_t streamsize; | |
+#ifdef USE_PERFCOUNTERS | |
+long long instruction_limit = 10000; | |
+#endif | |
pid_t child_pid; | |
@@ -269,7 +272,8 @@ Run COMMAND with restrictions.\n\ | |
-t, --time=TIME kill COMMAND after TIME seconds (float)\n\ | |
-C, --cputime=TIME set maximum CPU time to TIME seconds (float)\n\ | |
-m, --memsize=SIZE set all (total, stack, etc) memory limits to SIZE kB\n\ | |
- -f, --filesize=SIZE set maximum created filesize to SIZE kB;\n"); | |
+ -f, --filesize=SIZE set maximum created filesize to SIZE kB;\n\ | |
+ -i, --instlimit=SIZE set maximum number of instructions to execute\n"); | |
printf("\ | |
-p, --nproc=N set maximum no. processes to N\n\ | |
-P, --cpuset=ID use only processor number ID\n\ | |
@@ -346,11 +350,22 @@ long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int g | |
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); | |
return ret; | |
} | |
-void output_perfcounter_stats(int perf_fd) { | |
- long long perf_count; | |
+long long check_perflimit(int perf_fd) { | |
int ret; | |
+ long long perf_count; | |
ret = read(perf_fd, &perf_count, sizeof(long long)); | |
if ( ret!=-1 ) { | |
+ return perf_count; | |
+ } else { | |
+ return -1; | |
+ } | |
+} | |
+void output_perfcounter_stats(int perf_fd) { | |
+ long long perf_count; | |
+ perf_count = check_perflimit(perf_fd); | |
+ if ( perf_count!=-1 ) { | |
+ if ( perf_count>instruction_limit ) | |
+ fprintf(stderr, "timelimit exceeded\ninstruction limit exceeded(%lld > %lld)\n", perf_count, instruction_limit); | |
fprintf(stderr, "Total instructions used: %lld\n", perf_count); | |
} else { | |
fprintf(stderr, "Unable to determine instruction count"); | |
@@ -362,7 +377,7 @@ void output_perfcounter_stats(int perf_fd) { | |
void output_cgroup_stats() | |
{ | |
int ret; | |
- int64_t max_usage; | |
+ int64_t max_usage, failcnt; | |
struct cgroup *cg; | |
struct cgroup_controller *cg_controller; | |
@@ -379,6 +394,15 @@ void output_cgroup_stats() | |
error(0,"get cgroup value: %s(%d)", cgroup_strerror(ret), ret); | |
} | |
+ /* Check if the memory limit was exceeded */ | |
+ ret = cgroup_get_value_int64(cg_controller, "memory.failcnt", &failcnt); | |
+ if ( ret!=0 ) { | |
+ error(0,"get cgroup value - %s(%d)", cgroup_strerror(ret), ret); | |
+ } | |
+ if ( failcnt>0 ) { | |
+ verbose("memorylimit exceeded\n"); | |
+ } | |
+ | |
verbose("total memory used: %" PRId64 " kB\n", max_usage/1024); | |
cgroup_free(&cg); | |
@@ -528,12 +552,12 @@ int groupid(char *name) | |
return (int) grp->gr_gid; | |
} | |
-inline long readoptarg(const char *desc, long minval, long maxval) | |
+long long readoptargll(const char *desc, long long minval, long long maxval) | |
{ | |
- long arg; | |
+ long long arg; | |
char *ptr; | |
- arg = strtol(optarg,&ptr,10); | |
+ arg = strtoll(optarg,&ptr,10); | |
if ( errno || *ptr!='\0' || arg<minval || arg>maxval ) { | |
error(errno,"invalid %s specified: `%s'",desc,optarg); | |
} | |
@@ -541,6 +565,10 @@ inline long readoptarg(const char *desc, long minval, long maxval) | |
return arg; | |
} | |
+long readoptarg(const char *desc, long minval, long maxval) { | |
+ return (long) readoptargll(desc, minval, maxval); | |
+} | |
+ | |
void setrestrictions() | |
{ | |
char *path; | |
@@ -672,6 +700,7 @@ int main(int argc, char **argv) | |
#ifdef USE_PERFCOUNTERS | |
struct perf_event_attr pe; | |
int perf_fd; | |
+ struct timespec timeout; | |
#endif | |
/* pipes for sync(make the child wait for the parent before exec'ing) */ | |
int child_ready_pipe[2], go_pipe[2]; | |
@@ -694,11 +723,14 @@ int main(int argc, char **argv) | |
/* Parse command-line options */ | |
use_root = use_time = use_cputime = use_user = outputexit = outputtime = no_coredump = 0; | |
memsize = filesize = nproc = RLIM_INFINITY; | |
+#ifdef USE_PERFCOUNTERS | |
+ instruction_limit = LLONG_MAX; | |
+#endif | |
redir_stdout = redir_stderr = limit_streamsize = 0; | |
be_verbose = be_quiet = 0; | |
show_help = show_version = 0; | |
opterr = 0; | |
- while ( (opt = getopt_long(argc,argv,"+r:u:g:t:C:m:f:p:P:co:e:s:E:T:vq",long_opts,(int *) 0))!=-1 ) { | |
+ while ( (opt = getopt_long(argc,argv,"+r:u:g:t:C:m:f:i:p:P:co:e:s:E:T:vq",long_opts,(int *) 0))!=-1 ) { | |
switch ( opt ) { | |
case 0: /* long-only option */ | |
break; | |
@@ -751,6 +783,13 @@ int main(int argc, char **argv) | |
filesize *= 1024; | |
} | |
break; | |
+ case 'i': /* instruction limit option */ | |
+ #ifdef USE_PERFCOUNTERS | |
+ instruction_limit = readoptargll("instruction limit",1,LLONG_MAX); | |
+ #else | |
+ error(1,"option `-i' is only supported when compiled with Performance counter support"); | |
+ #endif | |
+ break; | |
case 'p': /* nproc option */ | |
nproc = (rlim_t) readoptarg("process limit",1,LONG_MAX); | |
break; | |
@@ -951,12 +990,9 @@ int main(int argc, char **argv) | |
perf_fd = perf_event_open(&pe, child_pid, -1, -1, 0); | |
if ( perf_fd==-1 ) { | |
error(1,"perf_event_open failed\n"); | |
- exit(1); | |
} | |
#endif | |
- if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); | |
- | |
/* Close unused file descriptors */ | |
for(i=1; i<=2; i++) { | |
if ( close(child_pipefd[i][PIPE_IN])!=0 ) { | |
@@ -1021,6 +1057,8 @@ int main(int argc, char **argv) | |
error(errno,"getting start clock ticks"); | |
} | |
+ if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); | |
+ | |
/* Ok, now let the child process go */ | |
close(go_pipe[PIPE_IN]); | |
@@ -1036,7 +1074,11 @@ int main(int argc, char **argv) | |
} | |
} | |
- r = pselect(nfds+1, &readfds, NULL, NULL, NULL, &emptymask); | |
+ memset(&timeout, 0, sizeof(struct timespec)); | |
+ timeout.tv_sec = 0; | |
+ timeout.tv_nsec = 500000000; /* (0.5 seconds)*/ | |
+ | |
+ r = pselect(nfds+1, &readfds, NULL, NULL, &timeout, &emptymask); | |
if ( r==-1 && errno!=EINTR ) error(errno,"waiting for child data"); | |
if ( received_SIGCHLD ) { | |
@@ -1044,6 +1086,14 @@ int main(int argc, char **argv) | |
if ( pid==child_pid ) break; | |
} | |
+#ifdef USE_PERFCOUNTERS | |
+ /* Check if it hit an instruction limit, and kill it if necessary */ | |
+ long long instruction_count = check_perflimit(perf_fd); | |
+ if ((instruction_count<0) || (instruction_count>instruction_limit)) { | |
+ terminate(SIGTERM); | |
+ } | |
+#endif | |
+ | |
/* Check to see if data is available and pass it on */ | |
for(i=1; i<=2; i++) { | |
if ( child_pipefd[i][PIPE_OUT] != -1 && FD_ISSET(child_pipefd[i][PIPE_OUT],&readfds) ) { | |
diff --git a/judge/testcase_run.sh b/judge/testcase_run.sh | |
index 82259ef..f5ad2a5 100755 | |
--- a/judge/testcase_run.sh | |
+++ b/judge/testcase_run.sh | |
@@ -76,13 +76,18 @@ runcheck () | |
CPUSET="" | |
CPUSET_OPT="" | |
+INSTLIMIT="" | |
+INSTLIMIT_OPT="" | |
# Do argument parsing | |
OPTIND=1 # reset if necessary | |
-while getopts "n:" opt; do | |
+while getopts "n:i:" opt; do | |
case $opt in | |
n) | |
CPUSET="$OPTARG" | |
;; | |
+ i) | |
+ INSTLIMIT="$OPTARG" | |
+ ;; | |
:) | |
echo "Option -$OPTARG requires an argument." >&2 | |
;; | |
@@ -99,6 +104,10 @@ else | |
LOGFILE="$DJ_LOGDIR/judge.`hostname | cut -d . -f 1`.log" | |
fi | |
+if [ -n "$INSTLIMIT" ]; then | |
+ INSTLIMIT_OPT="-i $INSTLIMIT" | |
+fi | |
+ | |
# Logging: | |
LOGLEVEL=$LOG_DEBUG | |
PROGNAME="`basename $0`" | |
@@ -195,7 +204,7 @@ $GAINROOT cp -pR /dev/null ../dev/null | |
logmsg $LOG_INFO "running program (USE_CHROOT = ${USE_CHROOT:-0})" | |
runcheck ./run testdata.in program.out \ | |
- $GAINROOT $RUNGUARD ${DEBUG:+-v} $CPUSET_OPT ${USE_CHROOT:+-r "$PWD/.."} -u "$RUNUSER" \ | |
+ $GAINROOT $RUNGUARD ${DEBUG:+-v} $CPUSET_OPT $INSTLIMIT_OPT ${USE_CHROOT:+-r "$PWD/.."} -u "$RUNUSER" \ | |
-C $TIMELIMIT -t $((2*TIMELIMIT)) -m $MEMLIMIT -f $FILELIMIT -p $PROCLIMIT \ | |
-c -s $FILELIMIT -e program.err -E program.exit -T program.time -- \ | |
$PREFIX/$PROGRAM 2>error.tmp | |
diff --git a/sql/mysql_db_defaultdata.sql b/sql/mysql_db_defaultdata.sql | |
index f0b436c..14c0932 100644 | |
--- a/sql/mysql_db_defaultdata.sql | |
+++ b/sql/mysql_db_defaultdata.sql | |
@@ -27,6 +27,8 @@ INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('re | |
INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('lazy_eval_results', '1', 'bool', 'Lazy evaluation of results? If enabled, stops judging as soon as a highest priority result is found, otherwise always all testcases will be judged.'); | |
INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('enable_printing', '0', 'bool', 'Enable teams and jury to send source code to a printer via the DOMjudge web interface.'); | |
INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('time_format', '"H:i"', 'string', 'The format used to print times. For formatting options see the PHP \'date\' function.'); | |
+INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('use_instructionlimit', '0', 'bool', 'Use a limit on instructions executed rather than strictly wall time.'); | |
+INSERT INTO `configuration` (`name`, `value`, `type`, `description`) VALUES ('instruction_limit', '20000000', 'int', 'The maximum number of instructions to allow a submission to execute.'); | |
-- | |
-- Dumping data for table `language` | |
-- | |
1.7.9.5 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Should use
PERF_COUNT_HW_REF_CPU_CYCLES
instead of instructions. Independent of frequency scaling/processor. Would be handy, see here: http://man7.org/linux/man-pages/man2/perf_event_open.2.html