6
5
2015
2

使用fork函数的自动评测系统

最近无聊看了看gty的Gena感觉非常 的高大上。

其实我非常早的就想自己弄一个自动评测软件了,于是学习了以下开始动手。

然后发现有非常多的问题,大部分问题都是用黑科技解决,比如fork之后堆栈不再共用没办法互相传递信息,那么我们就开一个文件来传递信息。

不过还是不少地方借鉴了以下,比如得到内存信息,和时间记录的方式(clock函数会出现一些奇怪的问题)

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <ctime>
#include <sys/stat.h>
#include <sys/wait.h>
#include <vector>
#include "My_checker.hpp"
using namespace std;

/*
this program is to check a OI program with specific testcases
./checker [-t Time_limit(ms)]{default : 1000} [-T Time_limit(s)] [-m memory_limit(b)]{default:256Mb} [-M memory_limit(mb)] [-f path of programm and testcases]{default: current path} [-F initial file] [-I input files]{default: a.in} [-O output files] {default: a.out} 
*/
void init_file(char *s1);
void show_help();
void work();
vector<string>list;
int init(int argv,char *argc[]){
	for (int i=1;i<argv;i+=2){
		if (!strcmp(argc[i],"--help")){
			show_help();
			return -1;
		}
		if (!strcmp(argc[i],"-t")) sscanf(argc[i+1],"%d",&Time_limit);
		else if (!strcmp(argc[i],"-T")) sscanf(argc[i+1],"%d",&Time_limit),Time_limit*=1000;
		else if (!strcmp(argc[i],"-m")) sscanf(argc[i+1],"%d",&Memory_limit);
		else if (!strcmp(argc[i],"-M")) sscanf(argc[i+1],"%d",&Memory_limit),Memory_limit*=1024*1024;
		else if (!strcmp(argc[i],"-f")){
			sscanf(argc[i+1],"%s",path);
			used_path=1;
		}else if (!strcmp(argc[i],"-F")){
			init_file(argc[i+1]);
			return 1;
		}else if (!strcmp(argc[i],"-I") || !strcmp(argc[i],"-i")){
			Infile=1;
			sscanf(argc[i+1],"%s",input_file);
		}else if (!strcmp(argc[i],"-O") || !strcmp(argc[i],"-o")){
			Outfile=1;
			sscanf(argc[i+1],"%s",output_file);
		}
	} 
	return 0;
}
int type=-1;
int make_file(){
	sprintf(cmd,"ls %s >cur_files_list.ckr",path);
	system(cmd);
	f1=fopen("cur_files_list.ckr","r");
	while (fscanf(f1,"%s",cur)!=EOF){
		list.push_back(string(cur));
	}
	fclose(f1); 
	system("rm -r cur_files_list.ckr");
	sort(list.begin(),list.end());
	 //0 for cpp 1 for c 2 for pas
	char tmp[110];
	for (int i=0;i<list.size();i++){
		int pos=-1;
		if (list[i]==string("cur_files_list.ckr")){
			list.erase(list.begin()+i);
			i--;
			continue;
		}
		if (list[i]==string("My_checker.cpp")){
			list.erase(list.begin()+i);
			i--;
			continue;
		}
		if (list[i]==string("My_checker")){
			list.erase(list.begin()+i);
			i--;
			continue;
		}
		for (int j=0;j<list[i].length();j++){
			if (list[i][j]=='.'){
				pos=j;
				memset(tmp,0,sizeof(tmp));
				for (int k=pos+1;k<list[i].length();k++){
					tmp[k-pos-1]=list[i][k];
				}
				if (!strcmp(tmp,"cpp")){
					if (type!=-1){
						printf("Error : multiple program included\nautochecker failed,please use file style");
						return -1;
					}
					printf("%d\n",pos);
					for (int k=0;k<pos;k++) program_name[k]=list[i][k];
					type=0;
					list.erase(list.begin()+i);
					i--;
				}else if (!strcmp(tmp,"pas")){
					if (type!=-1){
						printf("Error : multiple program included\nautochecker failed,please use file style");
						return -1;
					}
					for (int k=0;k<pos;k++) program_name[k]=list[i][k];
					type=1;
					list.erase(list.begin()+i);
					i--;
				}else if (!strcmp(tmp,"c")){
					if (type!=-1){
						printf("Error : multiple program included\nautochecker failed,please use file style");
						return -1;
					}
					for (int k=0;k<pos;k++) program_name[k]=list[i][k];
					type=2;
					list.erase(list.begin()+i);
					i--;
				}else if (strcmp(tmp,"in") && strcmp(tmp,"out")){
					list.erase(list.begin()+i);
					i--;
				}
				break;
			}
		}
		if (pos==-1){
			list.erase(list.begin()+i);
			i--;
		}
	}
#ifdef DEBUG
	printf("list begin! with %d\n",list.size());
	for (int i=0;i<list.size();i++){
		cout<<list[i]<<endl;
	}
	puts("list end");
#endif
	if (type==-1){
		printf("Error: No program found!\n checker failed");
		return -1;
	}
}
int Result,Running;
inline int testcase(string input,string output,string program_name){
#ifdef DEBUG
	printf("check(%s,%s)\n",input.c_str(),output.c_str());
#endif
	if (used_path) sprintf(cmd,"cat %s/%s > %s",path,input.c_str(),input_file);
	else sprintf(cmd,"cat %s > %s",input.c_str(),input_file);
#ifdef DEBUGcmd
	puts(cmd);
#endif
	system(cmd);
	timeb times,timet;
	ftime(×);
	int stat;
	int pid=fork();
	if (pid<0){
		printf("checker failed!\n");
		return 5;
	}
	if (pid==0){
		char In[22],Out[22];
	//	if (!Infile) sprintf(In," <%s.in",program_name.c_str());
	//	if (!Outfile) sprintf(Out," >%s.out",program_name.c_str());
		if (used_path) sprintf(cmd,"cd %s && ./%s",path,program_name.c_str());
		else sprintf(cmd,"./%s",program_name.c_str());
	#ifdef DEBUGcmd
		puts(cmd);
	#endif
		int id=system(cmd);
		f2=fopen("finished_running_time.ckr","w");
		fprintf(f2,"finished!");
		fclose(f2);
	#ifdef DEBUG
		printf("son progress return ed normally");
	#endif
		while (1);
		return id;
	}else{
		mem=0; Rtime=0;
		while (1){
			ftime(&timet);
			mem=max(mem,getmemory(pid));
			Rtime=(timet.time - times.time) * 1000 + (timet.millitm - times.millitm);
			if (Rtime>Time_limit){
				Result=2;
				kill_judge(pid);
				Running=0;
			#ifdef DEBUG
				printf("parent progress return ed TLE");
			#endif
				return 0;
			}else if (mem>Memory_limit){
			//	Result=3;
			//	kill_judge(pid);
			//	Running=0;
			#ifdef DEBUG
				printf("parent progress return ed MLE");
			#endif
			//	return 0;
			}
			f1=fopen("finished_running_time.ckr","r");
			if (f1==NULL) continue;
			kill_judge(pid);
			Running=0;
			system("rm -r finished_running_time.ckr");
			break;
		}
	#ifdef DEBUG
		printf("parent progress return ed nomally");
	#endif
		wait(&stat);
		int i=WEXITSTATUS(stat);
	//	printf("son program returned %d\n",i);
		if (i){
			Running=0;
			Result=4;
			return 0;
		}
		Running=0;
		Result=check(output);
		return 0;
	}
}
inline void sleep_with_limit(int T){
	timeb s,t;
	ftime(&s);
	while (1){
		if (Running==0) return;
		ftime(&t);
		if (t.time-s.time>T+1 || t.time-s.time) return;
	}
}
int work_auto()
{
	int tmp=make_file();
	if (tmp==-1){
		return -1;
	}
	int Compile_id;
	if (type==0){
		if (used_path)
			sprintf(cmd,"g++ -o2 %s/%s.cpp -o %s/%s",path,program_name.c_str(),path,program_name.c_str());
		else 
			sprintf(cmd,"g++ -o2 %s.cpp -o %s",program_name.c_str(),program_name.c_str());
		Compile_id=system(cmd);
	}else if (type==1){
		if (used_path)
			sprintf(cmd,"fpc -o2 %s/%s.pas",path,program_name.c_str());
		else sprintf(cmd,"fpc -o2 %s.pas",program_name.c_str());
		Compile_id=system(cmd);
	}else if (type==2){
		if (used_path)
			sprintf(cmd,"gcc -o2 %s/%s.c -o %s/%s",path,program_name.c_str(),path,program_name.c_str());
		else 
			sprintf(cmd,"gcc -o2 %s.c -o %s",program_name.c_str(),program_name.c_str());
		Compile_id=system(cmd);
	}
	if (Compile_id){
		puts(result[5]);
		return 5;
	}
	int Id=0,now;
	if (!Infile){
		if (used_path) sprintf(input_file,"%s/%s.in",path,program_name.c_str());
		else sprintf(input_file,"%s.in",program_name.c_str());
	}
	if (!Outfile){
		if (used_path) sprintf(output_file,"%s/%s.out",path,program_name.c_str());
		sprintf(output_file,"%s.out",program_name.c_str());
	}
	int ip;
	int pre;
	for (ip=0;ip<list.size();ip=pre+2){
		pre=ip;
		Running=1;
		testcase(list[ip],list[ip+1],program_name);
		sleep_with_limit(Time_limit/1000);
		if (!Id) Id=Result;
		printf("%s time:%d memory:%d\n",result[Result],Rtime,mem);
		sprintf(cmd,"rm -r %s",input_file);
		system(cmd);
		if (used_path) sprintf(cmd,"rm -r %s/%s",path,output_file);
		else sprintf(cmd,"rm -r %s",output_file);
		system(cmd);
	}
	return Id;
}
int main(int argv,char *argc[])
{
	int tmp=init(argv,argc);
	if (tmp==-1) return 0;
	else if (tmp==1){
		printf("Error!\n"),show_help();
		return 0;
	}else if (tmp==2){
		work();
	}else{
		int ret=work_auto();
	}
	return 0;
}
//coder : davidwang
#include <string>
using namespace std;
const int DefaultTime_limit=1000;
const int DefaultMemory_limit=256*2048*2048;
int Time_limit=DefaultTime_limit,Memory_limit=DefaultMemory_limit;
char cmd[1000],cur[110];
char input_file[1000],output_file[1000];
string program_name;
int Infile,Outfile;
FILE *a1,*f1,*f2;
int mem,Rtime;
char path[2500];
int used_path;
char result[100][100]={"Accepted","Wrong Answer","Time Limit Exceeded","Memory Limit Exceeded","Runtime Error","Compile Error"};

// 0: Accepted 1: Wrong Answer 2: TLE 3: MLE 4: RE 5: CE
inline int getmemory(int pid)
{
    sprintf(cmd, "ps -eo pid,rss | grep %d", pid);
    FILE *f = popen(cmd, "r");
    int a;
    fscanf(f, "%d%d", &a, &a);
    pclose(f);
    return a;
}
void kill_judge(int pid)
{
    sprintf(cmd, "kill -s 9 %d", pid);
    system(cmd);
}
void init_file(char *s1){

}
void show_help(){
	printf("this program is to check a OI program with specific testcases\n./checker [-t Time_limit(ms)]{default : 1000} [-T Time_limit(s)] [-m memory_limit(b)]{default:256Mb} [-M memory_limit(mb)] [-f path of programm and testcases]{default: current path} [-F initial file] [-I input files]{default: (s).in} [-O output files] {default: (s).out}\n");
	return;
}
void work()
{
}
char s1[1000010],s2[1000010];
char o1[1000],o2[1000];
inline int check(string output,string checker=string("cmp"))
{
	FILE *fout,*fstd;
//	printf("checker runned!");
	if (used_path) sprintf(o1,"%s/%s",path,output.c_str());
	else sprintf(o1,"%s",output.c_str());
	if (used_path) sprintf(o2,"%s/%s",path,output_file);
	else sprintf(o2,"%s",output_file);
	fstd=fopen(o1,"r");
	fout=fopen(o2,"r");
//	puts(output_file);
//	puts(output.c_str());
	int t=0;
	while (fscanf(fstd,"%s",s1)!=EOF){
		if (fscanf(fout,"%s",s2)==EOF){
			printf("checker log: your output is shorter than standard output\n");
			return 1;
		}
		t++;
	//	puts(s1);
	//	puts(s2);
		if (strcmp(s1,s2)){
			printf("checker log: Wrong with the %d segment!\n",t);
			printf("%s %s\n",s1,s2);
			return 1;
		}
	}
	if (fscanf(fout,"%s",s2)!=EOF){
		printf("checker log: Your output is longer than standard output!\n");
		return 1;
	}
	return 0;
}

放在一个目录下编译就可以用了,暂时只支持linux……

 

 

Category: 未分类 | Tags: | Read Count: 629

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com