Skip to content
This repository has been archived by the owner on Aug 18, 2021. It is now read-only.

Commit

Permalink
Larger granularity on setting the time limit: microseconds
Browse files Browse the repository at this point in the history
  • Loading branch information
Claudiu Gheorghe committed Apr 9, 2010
1 parent 8bdf43b commit 9476dd8
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 34 deletions.
2 changes: 1 addition & 1 deletion testing/pa/dummy/c.timeout
@@ -1 +1 @@
2
2.5
2 changes: 1 addition & 1 deletion testing/pa/dummy/java.timeout
@@ -1 +1 @@
2
2.5
83 changes: 51 additions & 32 deletions testing/pa/tracker.c
Expand Up @@ -7,7 +7,7 @@
* limit on CPU execution time
*
* Arguments:
* argv[1]: timeout - currently in seconds
* argv[1]: timeout - float value in seconds
* argv[2]: input filename
* argv[3]: output filename
*/
Expand All @@ -18,6 +18,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
Expand All @@ -26,7 +27,10 @@
#define MAKEFILE "Makefile"
#define MAKEFILE_TARGET "run"

void setup_job(int timeout, char *in, char *out) {
#define UERR 1000
#define UFACT 1000000

This comment has been minimized.

Copy link
@luciang

luciang Apr 9, 2010

comment these please.


int setup_job(int timeout, char *in, char *out) {
struct rlimit limit;

/* set the processor time limit */
Expand All @@ -37,26 +41,27 @@ void setup_job(int timeout, char *in, char *out) {
/* redirect input and output */
int fd_in = open(in, O_RDONLY);
if (fd_in < 0) {
fprintf(stderr, "Error opening job input file `%s`: %s\n", in, strerror(errno));
exit(EXIT_FAILURE);
fprintf(stderr, "Error opening job input file `%s`: %s\n", in, strerror(errno));
return 1;
}

if (dup2(fd_in, STDIN_FILENO) < 0) {
fprintf(stderr, "Error duplicating input fd: %s\n", strerror(errno));
exit(EXIT_FAILURE);
fprintf(stderr, "Error duplicating input fd: %s\n", strerror(errno));
return 1;
}

int fd_out = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd_out < 0) {
fprintf(stderr, "Error opening job output file `%s`: %s\n", out, strerror(errno));
exit(EXIT_FAILURE);
fprintf(stderr, "Error opening job output file `%s`: %s\n", out, strerror(errno));
return 1;
}

if (dup2(fd_out, STDOUT_FILENO) < 0) {
fprintf(stderr, "Error duplicating output fd: %s\n", strerror(errno));
exit(EXIT_FAILURE);
fprintf(stderr, "Error duplicating output fd: %s\n", strerror(errno));
return 1;
}


return 0;
}

This comment has been minimized.

Copy link
@luciang

luciang Apr 9, 2010

these are all done for you from the shell if you use "<", ">" and "2>".

Why didn't you redirect stuff from the Makefile.checker?

This comment has been minimized.

Copy link
@claudiugh

claudiugh Apr 9, 2010

Owner

This redirections are made only in the child process, after fork() and right before execve()


int main(int argc, char *argv[], char *const envp[]) {
Expand All @@ -65,34 +70,48 @@ int main(int argc, char *argv[], char *const envp[]) {
char *childargv[] = {"make", "-s", "--no-print-directory", "-f", MAKEFILE, MAKEFILE_TARGET, NULL};

if (argc != 4) {
fprintf(stderr, "Usage: ./tracker <timeout_seconds> <input_file> <output_file> \n");
exit(EXIT_FAILURE);
fprintf(stderr, "Usage: ./tracker <timeout_seconds> <input_file> <output_file> \n");
exit(EXIT_FAILURE);
}

int timeout = atoi(argv[1]);
float ftimeout;
int timeout;
sscanf(argv[1], "%f", &ftimeout);
timeout = (int)ceil(ftimeout);

child_pid = fork();
if (-1 == child_pid) {
fprintf(stderr, "Error in fork(): %s\n", strerror(errno));
exit(EXIT_FAILURE);
fprintf(stderr, "Error in fork(): %s\n", strerror(errno));
exit(EXIT_FAILURE);
} else if (0 == child_pid) {
setup_job(timeout, argv[2], argv[3]);
execve("/usr/bin/make", childargv, envp);
/* should not be here */
fprintf(stderr, "Error in execve(): %s\n", strerror(errno));
exit(EXIT_FAILURE);
if (setup_job(timeout, argv[2], argv[3])) {
exit(EXIT_FAILURE);
}
execve("/usr/bin/make", childargv, envp);
/* should not be here */
fprintf(stderr, "Error in execve(): %s\n", strerror(errno));
exit(EXIT_FAILURE);
} else {
struct rusage accounting;
w = wait4(child_pid, &status, 0, &accounting);
if (WEXITSTATUS(status)) {
/* we got an error */
return WEXITSTATUS(status);
} else {
/* print some stats */
fprintf(stdout, "time: %d.%d seconds\n",
(int)accounting.ru_utime.tv_sec + (int)accounting.ru_stime.tv_sec,
(int)accounting.ru_utime.tv_usec + (int)accounting.ru_stime.tv_usec);
}
struct rusage accounting;
w = wait4(child_pid, &status, 0, &accounting);
if (WEXITSTATUS(status)) {
/* we got an error */
return WEXITSTATUS(status);
} else {
/* print some stats */
int seconds = (int)accounting.ru_utime.tv_sec + (int)accounting.ru_stime.tv_sec;
int useconds = (int)accounting.ru_utime.tv_usec + (int)accounting.ru_stime.tv_usec;
if (seconds == timeout - 1) {
int utimeout = (int)((ftimeout - (float)(timeout - 1)) * UFACT);
if (useconds - utimeout > UERR) {
fprintf(stderr, "CPU time limit exceeded\n");
return 1;
}
}
/* success */
float ftime = (float)seconds + (float)useconds / UFACT;
fprintf(stdout, "time: %f seconds\n", ftime);
}
}

This comment has been minimized.

Copy link
@luciang

luciang Apr 9, 2010

  1. this measures wall time. If there's something else running on the machine (the guest or the host), the student's homework will be taxed for it.
  2. Why don't you run these from a shell script with "time", which can give you wall time, CPU time and other kinky things?

This comment has been minimized.

Copy link
@luciang

luciang Apr 9, 2010

I take that back. Didn't see you used wait4().


return 0;
Expand Down

0 comments on commit 9476dd8

Please sign in to comment.