Paper Reading Note:Delta Debugging

Delta Debugging

原作者:Andreas Zeller

Motivation

土豆明码力强劲一夜改千行,黄老仙觉得他思路清晰逻辑通顺犇得不行!

18000行的小明带飞龙这波,要做这个优化轻而易举啊。

哎呀,奶不死的啊,这怎么奶死嘛?**老子是专业码农好吗?这怎么奶死嘛?专业码农这种局面还看不懂啊?

F5了!F5了!FFFF5了,让你们看看什么叫专业码农好吗?直接骑脸了好吗。什么叫飞龙骑脸。

测试集选得好有什么用嘛?

…吔?…别啊?!哎~!呀~!这解说不下去了,哎呀这!!呃啊!

为什么会这样?别打那么惊险呐!!你别害我呀!

**这个罪名我背不起呀!!我背不住这个罪名啊我凑!!哎呀...遭不住啦...

现在问题来了,黄老仙奶死了土豆明,他得想个办法帮土豆明debug,但他又懒得亲自上手,那他该咋办呢?

传统解决方案的缺陷

Regression Containment使用了线性测试的方法,在很多情形下都是非常有效。但是也有以下几个方面表现并不好

  • interference:每一个改动自己的工作都ok,但是合起来就会出错了(合作开发的时候经常有这种事)
  • inconsistency:一些改动的组合加进去,没准就没办法生成一个可以用于检测的程序了(比如编译不通过)
  • granularity:一处逻辑改动可能影响到几千行代码,但其中的仅仅有几行实际引发了这个错误。仅仅把这一大块指出来并没有什么卵用,要更精细的找到错误位置才行

作者称,他的dd+(这个简写让人浮想联翩)算法能够

  • 在线性时间检测出interference
  • 在log时间内检测出独立的错误改动
  • 高效的处理inconsistency,从而可以支持输入更细致的改动(fine-granular)

基本定义

配置:全改动集合C的子集c被称为一个configuration

基准:若c是一个空的configuration被称c为一个baseline

三种输出的可能:

  • Pass ✔
  • Fail ✖
  • Unresolved

测试:一个把configuration映射到三种可能输出的函数被称为test

肇谬集:若对于任意一个C子集c’,只要包含c,那么c’的测试结果均不为✔,那么称c为 f a i l u r e − i n d u c i n g   c h a n g e   s e t failure-inducing\ change\ set failureinducing change set

最小肇谬集:对于一个肇谬集B,假如它的任何子集都不再被测试为✖,那么称它为最小肇谬集

  • 显然,最小肈谬集就是我们要搜索的目标

最理想情况

Monotony(单调性):假如configuration c的测试结果为✖,那么所有包含c的configuration的测试结果也为✖

  • 推论:此时若c的测试结果为✔,那么它的所有子集测试结果不为✖

Unambiguity(无二义性,即本质上引发错误的configuration是唯一的):若 c 1 c_1 c1 c 2 c_2 c2的测试结果均为✖,那么他们交集的测试结果不为✔

  • 无二义性不允许两个或多个无交集的configuration分别产生错误,也就是说错误的原因在一定程度上可以说是唯一的
  • 这个可以节约很多开销,当你在C的子集c中发现了错误,你就不必再考虑c的补集了(c的补集测试结果一定为✔,否则就推出baseline的测试结果为✖了)

Consistency(一致性):任何configuration的测试结果不为**?**

最理想情况的处置方法

所谓的最理想情况,就是测试集是单调、无二义且一致的。这时,我们基于二分法去发现错误。

  • 当test(left)=✖,在左半个集合继续查找
  • 当test(right)=✖,在右半个集合继续查找
  • 当两个测试都是✔,说明是一些改变合在一起导致了错误(interference)
    • 此时先保持一侧全部applied,找到另一侧中引发错误所必须的changes;再保持另一侧全部applied,找到这一侧引发错误所必须的changes
    • 将两个必须的部分合并,就找到了检测目标

非理想情况的处理方法

ambiguous

当引发问题的改变有多组,dd会正确返回其中的一个

此时只要在全集中删去这一组,调用dd就可以再获取其他的错误,重复这个过程以获得所有肈谬集

not monotone

假如test(a)=✖,但存在b包含a,test(b)=✔,那严格意义上就不能说a是错的了(configuration a的bug在configuration b中已经被修复了)。但包含b的C仍然是错误的,这说明引发错误的部分理应在C-b中啊(或为interference)。刨除所有被修复了的错误,剩下的错误是可以通过dd找到的。

inconsistency(复杂)

任意选取configuration很容易产生inconsistency的问题,下面给出了几个原因

  • 融合失败:一个change不能被应用。有可能这个change他是基于一些更早的change的,但那个change并没有被加入到configuration;有可能change a和change b是冲突的,本来写了解决冲突的change c,但c并没有被加入刀configuration
  • 生成失败:尽管所选的change都丢进去了,但可能引发了语法或语义错误,因而没办法生成程序
  • 执行错误:缺少某些部分,程序可能没办法正确执行。test的输出是不确定的。

先期验证所有组合是否consistency是不现实的,接下来我们考虑如何应对unresolve的情况。

考虑最糟糕的情形,即我们把C分成子集之后,所有的子集测试结果都是unresolved,那么我们应该考虑什么样的组合来尽快找到有效结果呢?

  • 尽量少加改动(靠近yesterday)(分的子集越多,子集size越小,得到consistent结果的可能就越大)
  • 尽量多加改动(靠近today)

在进一步考虑dd+算法前,我们定义以下三种情况

  • Found:如果 t e s t ( c i ) = ✖ test(c_i)=✖ test(ci)=,那么 c i c_i ci就包含了一个肈谬集,这和dd是一样的
  • Interference:如果任意一个c和它的补集测试结果都为✔,那么c和c的补集构成了干扰关系,这也和dd一样
  • Preference(优先):假如c不确定,c的补集pass了,那么接下来优先搜索 d , d = c ‾ ∪ c ′ d,d=\overline c \cup c' d,d=cc其中 c ′ ⊆ c c'\sube c cc。相当于以c的补集为baseline,去搜索c的子集(这样可以有效缩小肈谬集的可能范围)
  • Try again:如果上述情况都不满足,那么我们将子集个数提升为2n,重新进行一次划分,然后再跑一遍
    • 每次跑完,假如ci pass了,那么ci就可以从C中拿掉了,因为他们不可能是引发错误的configuration。
    • 类似地,假如c的补集没有通过测试,那么c就可以一直被置于applied的了

Avoid Inconsistency

重新考虑一下inconsistency的问题,假如我们一开始就怀疑一些change彼此相关,那我们就可以早早地把他们视为一个change,或者总是放在一个子集里,这样就可以减少很多unresolved test cases了

先验知识
  • 更改时间相近、更改来源相近的change更可能相关
  • 对同一个文件或同一个目录进行操作的change更可能相关
  • 使用相同的引用或使用类似标识符的change更可能相关
  • 影响相同函数(function)、模块(module)等语句实体的change更可能相关
  • 语义上产生类似影响的change更可能相关
Predicting Test Outcomes
  1. 假如我们一开始就知道某些change之间有相互联结的关系,那实际上我们就可以预测一些**?**结果,而没必要实实在在的去测试
  2. 假如我们的changes是有序且总是要利用前置修改的,那么我们能发现很多configuration没必要去测试

时间复杂度总结

三种好性质都具备

最差:O(n)
错误集合仅有一个改动:O(logn)

Ambiguous(有多个错误)

dd算法仍在O(n)时间内返回其中一个错误

Not Monotone

设a错,a是b的子集,b对,则dd算法在O(n)时间内返回c-b中的一个错误

inconsisitent

作者似乎没有给出分析

Future Work

进一步解决Avoid Inconsistency

利用域知识(by exploiting domain knowledge,我完全不能理解这是啥意思)

使用完备的change档案管理限制系统(不知所云)

主要的可以改进的方向还是利用语义层面的相关性。对于一个程序我们可以容易的维护一张PDG(Program Dependency Graph)来描述代码函数、模块间的关系,这样,当我们将一个change应用到某一个模块时,我们很容易发现这将与哪些部分相关。根据change和节点的相关性,我们可以把整张图分成很多slice。在同一个slice(也就是具有语义相关性)的change将被置于同一个subset

删除灰色代码

一些change部分在运行中并不会被执行,作者想利用code coverage tool来把这些changes给直接排除掉

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值