blog正式转移到了这里:

http://blog.phoeagon.cz.cc



I know

phoeagon啲01世界

2009 年 7 月 26 日  星期日   晴天


用交互库实现程序评测计时 分類: Code Storage

 

用交互库实现程序评测计时

 phoeagon

 

众所周知,用cena的卡时有相当的不准确性。常常时限设置为1s时超时的程序在调高时限后评测,测出来的时间只有0.8s。而且具有相当的不稳定性,在时间边缘附近常常“飘忽不定”。

考虑到USACO等评测平台,1s时限,实际结束程序运行的等待时间为1.5s。基本上解决了这一问题。

但如何在cena上实现呢?一种手工的办法是调高时限,然后记录时手工剔除时间数据超过1s的分。但这样做工作量大准确性不足。有没有不更改cena而自动实现的办法呢?

联系到cena提供了自定义评测工具,辅以交互库可以解决这一问题。

首先,创建一个交互库:

unit testlib;

interface

       var

              ans:int64; //用于给用户的程序提交答案

implementation

       const

              title='HelloWorld'; //试题名

       var

              tt:int64;

              fin:string=title+'.in';

              fout:string=title+'.out';

//接下来是一个计时函数,利用汇编指令获取CPU时间,返回一个64位整数

       function gettime:int64;assembler;

              asm

                     RDTSC

              end;

       procedure ioset;

              begin

                     assign(input, fin);reset(input);

                     assign(output, fout);rewrite(output);

                     tt := gettime; //文件配置完成,开始计时

              end;

       procedure report;

              begin

                     tt:=gettime-tt; //结束计时

                     close(input);

//向输出文件写入用户程序传送的答案和本单元的计时结果

                     writeln(ans);

                     writeln(tt);

                     close(output);

              end;

initialization //初始化,程序调用后自动设置文件配置

       ioset;

finalization //用户程序完成,调用单元的收尾工作

       report;

end.

那么,如果为了一台机器上获得时限对应的cpu周期呢?我们大概可以这样算出一个大概的周期:

CPU_cycles = Cpu主频*时间(s)

或者:

Program testtimer;

uses crt;

const times=5; //测试次数

var z,s:int64;i:longint;//:longint;

       function gettime:int64;assembler;

                     asm

                            RDTSC

                     end;

begin

       readln;

       for i:=1 to times do

 

       begin     

                     z:=gettime;

                     delay(1000); //延时1s

                     z:=gettime-z;

                     writeln(i,': ',z);

                     inc(s,z);

       end;

       writeln('a: ',s div times); //输出平均周期

end.

之后,利用cena内附的libcheck单元,编写自定义判别程序。

由于int64不能直接读入,测试程序利用字符串读入并与标准周期的字符串比较。

//Judge

uses

  libcheck;

const

       sttime:string='2512738375'{*1}; //标准测试CPU周期

       fin:string=      'HelloWorld.in'; //输入输出文件名

       fout:string='HelloWorld.out';

var

 

       tt:string; 

       progans,stdans: string;

 

      

       procedure judge;

              begin

                     writeln(rep,'Your Answer: ',progans);

                     if stdans=progans then

                       begin

                            writeln(rep,'Answer Correct');

                            if (length(tt)<length(sttime))or(tt<=sttime) then //字符串时间比较

                                   begin

                                          writeln(rep,'Case solved within Time Limit');

                                          writeln(rep,'Test Case OK [',tt,' CPU cycles]');

                                          Score(fsco); //fscolibcheck单元定义的测试点分值变量

                                          exit;

                                   end

                            else writeln(rep,'Time Limit Exceeded[',tt,'  CPU cycles]');

                       end

                       else begin

                            writeln(rep,'Wrong Answer');

                     end;

                     Score(0);

              end;

begin

  assign(input, fout); { 试题的输出文件名,由选手程序输出 }

  reset(input);

  readln(progans);

  readln(tt);

  close(input);

  readln(std,stdans); { 从标准输出文件中读取标准答案 }

 

 

  judge;

 

  Finish;

end.

之后呢,要求选手:

本题属于交互式问题。

你的程序应该在开头声明

uses  testlib;

程序使用标准输入

结果输出到testlibans变量 32位有符号整数)。如:

 

testlib.ans:=10; {replace 10 with your variable}

并将pending程序编译好放在cenaTEST\data\目录下。

testlib.pas复制到%Cena_Path%\compilers\bin目录下。

最后,在cena中选择评测pas程序,以较高的时间限制评测。(如果评测机完成指定周期约1s,尝试2s时限)

 

便可以利用交互库+自定义评测器 实现基于CPU周期的计时。

另外,这个评测方法利用了标准输入输出,更便于选手调试。(华丽的删除线

 

这个方法还为更多的类似方法提供了思路。例如,在win32平台下还可以用API函数获得进程的CPU时间。

 

注:RDTSC指令需要CPU支持,与操作系统无关。目前常见CPU均支持此指令。







訪客留言 (返回 phoeagon 的日誌)


Mickey 於 2009-07-26 08:59 PM 發表:
什么时候把这东西搬到竞赛班去
[ 回覆 ] [ 封鎖 ] [ 刪除 ]

網主回覆

其实需要的代码都全部在这里了~
接下来需要的就是一点点操作cena的经验技巧了~
 
Posted at 2009-07-27 09:49 AM   [ 編輯 ] [ 刪除 ]



phoeagon 於 2009-07-26 04:44 PM 發表:
自己顺便补充一句:
许多优化软件能查看“开机以来经历的时间”,其实也就是利用这个CPU周期数。
[ 回覆 ] [ 封鎖 ] [ 刪除 ]


訪客名稱:
電郵地址: (不會公開)
驗證碼:  按此更新驗證碼 (如看不清楚驗證碼請點擊圖片刷新)
俏俏話: (必需 登入 後才能使用此功能)
[ 開啟多功能編輯器 ]







人氣:79343
暱稱: phoeagon
性別: 男
MORE...  
« June 2024 »
SMTWTFS
1
2345678
9101112131415
16171819202122
23242526272829
30
» 最新日誌
Blog Moved!
跨站jsMath实现
路由表是个好东西
Twitter Fav列表达陈100...
搞定了公式显示
» 日誌分類
全部 (175)
Code Storage (11)
Math&Phy@Chem@MM (8)
Music Anyway (5)
Programming Impossible (28)
RSS提示 (2)
StorageBox (5)
'Bout Here (12)
滑鼠人生 (42)
碎屑 (51)
未分類 (11)
» 訪客留言
最近三個月尚無任何留言
» 最近訪客
最近沒有訪客
» 每月文章
» 日誌訂閱
尚未訂閱任何日誌
» 我的好友
» 我的連結
Ink Mark --Jlim
StarKirby
|S||S||S|
「流年祭」
» 日誌統計
文章總數: 175
留言總數: 86
今日人氣: 113
累積人氣: 79343
» 站內搜索
RSS Feed