程序员遇到过的最难兼容性BUG

20151231102225

小伙伴们,在过年前Bird开辟了一个全新专栏【鸟事儿】,咱们但愿把网络上或身边的各类有趣的开发故事,放到这个专栏当中。欢迎关注Bird的每一位小伙伴把你本身产品开发、测试过程当中好玩的、悲催的、刻骨铭心的经历发送给 TestBird公众号。字数不限,Bird会按期整理并在这个专栏中发表,根据故事的精彩程度,被选中的开发者能够获得50元~1000元不等的分享基金,金额很少但心意无价。不要吝惜你的故事,把故事分享给你们,生活也会变得更加有趣。今天给你们看一个来自国外网站Quora上的热门帖子《What’s the hardest bug you’ve debugged? | 你调试过的最难 BUG 是?》这个帖子的原文做者叫作Dave Baggett,伯乐在线 – 熊铎 翻译。如下是故事正文:

回想起这个BUG,仍然让我有些痛苦。做为一个程序员,在发现BUG时,你学会了首先在本身代码中找问题,或许在测试一万次以后,你会把问题归咎于编译器。只有在这全部的都不起做用以后,你才会把问题归咎于硬件。程序员

这是我遭遇一个硬件bug的故事。web

抛开别的不说,我曾为《Crash Bandicoot》写存储卡(读写)代码。对于一个自大的游戏程序员,这就像是在公园里散步同样轻松愉快,我认为只要几天就写完了,最终调试用了六个礼拜。在此期间我想尽了各类方法,但有个BUG始终没有被修复——每隔几个小时就会发生一次。这实在是个烦人的BUG。编程

这个BUG的症状是,当你须要保存你的进度时,代码会访问存储卡,而大部分状况下没有什么问题…可是偶尔读写会超时…没有任何明显的缘由。一个短小的写入常常毁掉存储卡。玩家要保存进度,程序不只不保存,还擦除他们存储卡上的所有东西。天哪。网络

过了一段时间,咱们在Sony的制做人Connie Booth慌了。咱们显然不能带着这个BUG发布游戏,而六个星期以后我对于问题出在哪一点线索都没有。经过Connie咱们向其余 PS1 开发者求助:有没有人出现过像咱们这样的状况?没有。绝对没有任何人在存储卡系统上出现任何问题。学习

在你绞尽脑汁以后,你能作的惟一一个调试方法就是分而治之:一点点去除程序中的代码,直到留下的代码不多但你仍然出问题。像木雕同样去除没有问题的代码,留下的就是你的BUG所在。测试

在这样的背景下挑战在于,视频游戏是很难去除某一部分的。在你删除模拟重力或者显示字符的代码后,如何运行游戏?网站

你必须作的是用一个伪装作真正的事情,但实际上只是作很简单的不会出现BUG事情的东西来替换掉整个模块。你必须写新的支撑代码来让这些玩意正常工做。这是一个缓慢而痛苦的过程。翻译

长话短说:我作完了。我移除了大片大片的代码,至关多,只留下了初始化代码——就是准备游戏运行系统,初始化底层硬件等等。固然,我不能显示加载/保存菜单,由于我截除了全部的图像代码。可是我可以伪装用户使用(不可见的)加载/保存屏幕而且请求保存,而后写入卡中。debug

我最终以一个带有这个bug的不多量的代码结束——但问题仍然随机出现!在大多数状况下没啥问题,可是偶尔会失效。基本上全部的Crash的实际代码都被移除了,但仍是这样。这实在是莫名其妙:留下来的代码基本上都没作什么事。设计

在那时——估计是凌晨3点——一个想法蹦了出来。读写(I/O)涉及精肯定时。不管是硬盘、存储卡、蓝牙发送器——随便啥——作读写的底层代码都是根据时钟来的。

时钟让不直接链接到CPU的硬件设备和CPU运行的代码同步。时钟决定了波特率——数据从一头传到另外一头的速率。若是计时有什么问题,硬件或者软件或者二者都会乱七八糟的。这真的,真的很糟糕,而且一般致使数据损坏。

若是咱们的初始化代码以某种方式弄乱了计时会怎么样?我又看了一遍测试程序中和计时有关的代码,并注意到咱们将PS1上的可编程计时器设置到了1kHz(1000跳每秒)。这是比较快了,当PS1启动的时候,默认状态大概是100Hz。所以,大多数游戏将他们的计时器设置为100Hz。

这个游戏的带头(和除我外的惟一)开发者Andy,将计时器设置为1kHz,使得Crash的动做计算更加准确。Andy喜欢这样作,若是咱们要模拟重力,咱们应该尽量的提升精度!

然而若是提升计时器频率莫名其妙的干扰了整个程序的计时,故而将这个计时器设置到存储卡的波特率上会怎样呢?

我将计时器代码注释掉。而后我就没法复原这个BUG了。可是这并不表示BUG被修复了,这个问题是随机发生的。万一我只是运气好呢?

几天过去了,我仍是在玩个人测试程序。BUG没有再出现。我回到所有的Crash代码中,修改了加载/保存代码,在访问存储卡以前将可编程计时器重置为默认设置(100Hz),以后设置回1kHz。今后以后没有发现问题再次出现。

可是…为何?

我从新回到测试程序上,试着检测当计时器设置为1kHz时出现的那些错误的模式。终于,我注意到这些错误出如今使用PS1手柄的人身上。由于我本身不多这样作,因此我没有注意到(为啥我要在测试加载/保存代码的时候用手柄)。可是有一天咱们的美工等我去完成测试(我肯定那时候我在爆粗口),而他紧张的摆弄着手柄。卡损坏了。“等下,怎么回事?喂,再来一次!”

一旦我发现了这两件事是联系着的,就很容易重现BUG:开始写入存储卡,动一下手柄,存储卡损坏。在我看来彻底是硬件BUG。

我去找Connie告诉他个人发现。她转述给设计过PS1的硬件工程师。她被告知:“不可能,这不多是硬件问题。”我跟她说问一下我能不能直接和他说。

那个工程师给我打电话了,他用着他的烂英语,我用着我更烂的日语,咱们争论一会。我最后说:“我给你一个30行的测试程序,让你在动手柄的时候可以出现这问题。”他答应了。他向我保证,这是浪费时间,而他正在一个新项目上很忙,但由于咱们是Sony很重要的开发者,他会试的。

次日晚上(咱们在洛杉矶,而他在东京,因此对于我来讲是晚上而他是到了次日),他给我打电话,很差意思的向我道歉。这是个硬件问题。

我仍是没有彻底搞清楚问题到底在哪,可是个人印象中,从Sony总部的反馈听到的是,若是将可编程计时器设置到足够高的时钟频率,会影响到主板上时钟晶振附近的一些东西。这些东西之一就是存储卡的波特率控制器,同时也设置手柄的波特率。我不是搞硬件的,因此对于细节我至关模糊。

可是主旨是主板上两个独立部分的串扰,以及手柄接口和存储卡接口数据发送的结合在 1kHz 的时钟频率下会致使丢位,从而数据丢失,以至卡损坏。

这是我所有编程生涯中,惟一一次由于量子力学而Debug的问题。

鸟语:PS1时代的索尼在游戏开发者心目中同今天的苹果无异,故事的主人,本文做者Dave Baggett以及Sony的硬件工程师在对待问题时的严谨与专业精神应该值得全部开发者们学习与借鉴。只有认真对待每个BUG,才能让游戏获得玩家的喜好,才能让本身获得同行的尊重。为此,TestBird和咱们的6000多个合做伙伴们一直以来都在不断努力着。

相关文章
相关标签/搜索