CodeCraft背后的故事:程序究竟有多快?

华为软件精英挑战赛

华为第二届校园软件大赛的题目,是图论中的寻路算法题 。题目要求在一个有向图中,找出经过特定节点集合并且权重最小的路径。大赛吸引了数万名大学生报名参加,如何判断出优胜者呢?首先看寻找到的路径的权重,权重小的胜出;如果权重一样,那么就要比较程序的运行效率,算法效率更高的胜出。

这到题目相当的高大上,而且极有挑战性,属于一个NP-Complete问题。

作为赛事承办方,我们承担了大赛官网平台以及后台实时判题系统的开发工作,其中一项开发任务就是要度量出选手提交的程序的运行时间,以此来评判其算法的效率。现在赛事已经结束了,可以来扒一扒我们是怎么来度量进程运行时间的故事了。

选手提交的程序都运行在Linux上的docker虚拟容器中,每一个容器都虚拟出一个纯净的Linux环境。我们首先想到的就是使用Linux系统自带的 time 命令,例如:
yuhou@Lenovo:~/$ time ping -c 3 localhost > /dev/null
real 0m2.001s
user 0m0.004s
sys 0m0.004s
yuhou@Lenovo:~/$

这个命令返回三个时间,real是进程存在的总时间(也叫wallclock,等同于墙上的挂钟流逝的时间),user态下进程占用CPU的时间,以及内核态下进程占用CPU的时间。判题程序直接用real时间,来判断程序运行的效率;判题系统在执行每一个选手提交的程序的时候,设置了10秒的超时时间,如果程序运行超过10秒,会被强制Kill掉。并且我们的对外宣传也提出了:程序最长的运行时间是10秒,超时会被判为0分。

判题系统安然度过了两天的挑战。3月24日,为了禁止考生使用多核并发来提速,我们将运行沙箱的容器设置为单核模式,结果,这个小小的改动,却让我们的判题系统很快就遇到了挑战。当天晚上,有考生在向官网提交程序后,向我们反馈:我的程序绝对不可能超时的,但是你们的判题系统却为何说我超时了呢?

凌晨,我们开始紧急排除故障,经过分析发现,原来部分选手为了充分利用这10秒的计算时间,使得他们找到路径的权重尽可能的低,在程序中设置了一段检查超时的代码,只要还没有超时,那么就进行进一步深入的搜索和计算,其逻辑类似如下:
while (true) {
    clock_t  t1= clock();
    /* find the path ,and refine it ... */
    clock_t  t2 = clock();
    if ((t2 - t1)/CLOCKS_PER_SEC > 9) {
        break;
    }
}

我们分析了 clock 函数的说明,原来,clock函数返回的是一个硬件tick数,它描述了本进程真正被调度到CPU上被执行的时间。上面的这段代码,就能够确保程序占用CPU的时间不会超过10秒钟;但是,因为Linux是一个多任务操作系统,进程在执行过程中是有可能被抢占的,所以,这个进程真正生存的时间,是很有可能超过10秒的。如果当判题程序发现进程存在超过10秒后就立刻Kill这个进程,实际上其真正被调度到CPU上执行的时间,是不足10秒的。这就造成了误杀。

这从 time 命令的返回结果可以看出, real 时间一般是大于user时间和sys时间和的。那为什么在docker容器没有修改为单核模式前,就没有这种误杀的情况出现呢?这其实很好理解,如果docker容器中的Linux是多核的,那么具有更多的CPU可被使用,选手提交的程序是很少被抢占的,其real time和 cpu time是几乎相等的,所以就不存在误杀的情况。但是一旦修改为单核,选手提交的程序就会被经常抢占,其CPU时间会远远小于real time,所以就很容易被误杀了。

找到原因之后,我们马上修改了判题程序的逻辑,延长了判断超时的时间长度,并且使用 user time + sys time 的和,来作为程序真正运行时间的标准。这样修改之后,问题就马上消失了。

最后再对这个问题深入探讨一下。使用 time 命令返回的结果作为程序运行时间,也是存在误差的。按照POSIX标准,clock函数的计时精度是10ms,如果我们要较真的话,应该提供微秒级别精度的计时器,那有没有准确到微秒的计时方法呢?答案是可以做到,但是没有像 time命令这样现成的方法,需要自己动手来实现。一种方法是用进程注入技术,以及clock_gettime 函数,来自己写一个类似 micro_time 的命令,用这个命令就可以度量进程的精确到微秒级别的CPU时间消耗。这个实现起来稍有难度,而且进程占用CPU的时间受到很多不确定因素的影响,比如进程的切换,缓存的失效等。精确到微秒级别并无太大的意义。

我们在实际判卷的时候,所有进程的耗时都精确到10ms。实践证明,精确到10ms已经能够很好的区分出选手的算法差异了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容