HOME
BLOG
TALKS
Mantra Introduction
May 12 2023

Slides: PDF | SPA

大家好。今天来给大家介绍一篇变异测试相关的工作。

变异测试大家都知道,但对于 硬件设计 的变异测试可能了解不多。

事实也正是如此。虽然变异测试在功能验证方面作用很大,但硬件领域的变异测试研究仍然很少。


本篇工作就是从硬件设计代码的变异测试出发,提出了 Mantra,这是第一个基于真实硬件错误的开源代码级变异测试工具。


为什么变异测试很少应用于硬件设计?因为硬件设计和软件设计有很大不同。

具体来说,首先,硬件设计比软件设计更容易收到物理世界的限制,比如硬件系统的运行需要特定的环境、系统内复杂的组件需要协调配合;其次,不同于软件测试,由于在硬件制造后修复错误的成本极高,所以传统的硬件开发将大量资源投入到基于仿真的测试和形式验证上,以便在硬件制造前消除错误。


既然对于硬件的测试如此重要,那么如何在硬件设计的过程中进行测试呢?

首先,和软件测试类似,在硬件设计周期中检测错误需要满足两个条件。

第一是可激活性,也就是说相应硬件设计代码必须被执行。

第二是可观察性,也就是说出错代码的影响必须被传播到可观察点。

要解决第一个问题 activatable,可以利用行为覆盖率来记录代码的执行情况。但如何解决第二个问题呢?这也是传统的硬件测试方法不足之处,普遍存在可观察性的问题。

本篇工作就是用变异测试来解决这种可观察性问题。


对于硬件设计代码的变异测试,目前的研究仍处于早期阶段,主要存在以下限制。

首先,目前缺少对于硬件描述语言的系统研究,因为硬件描述语言和软件编程语言的差异很大。包括 HDL 独特的语法和数据类型,以及特殊的模块声明、IO 端口声明还有模块实例化等特性。

其次,现有的硬件变异测试的变异算子都不是基于真实错误的。只有当变异测试使用了基于真实错误的变异算子,它才有意义,才能满足现实需求。

然后,目前的硬件变异测试很少考虑降低成本的技术。因为执行大量变异体会花费大量时间,导致开发效率降低。

最后,目前还没有硬件变异测试的开源工具。不仅仅是开源工具的缺失,整个硬件领域的开源现状相比于软件领域也并不理想。

针对这四种限制,本篇工作进行了解决。

具体来说,

  1. 本篇工作根据硬件设计代码的并行性,提出了一种快速检测变异体被杀死的机制,它区别于传统方式,可以减少硬件变异测试的时间,解决了第 3 个问题。

  2. 本篇工作通过分析真实硬件错误,提出了 19 个基于真实错误的变异算子,解决了第 2 个问题。

  3. 本篇工作提出了 Mantra 这个开源硬件设计代码变异工具,实现了上述变异算子,可以进行代码质量评估和缺陷错误定位,解决第 1 个问题和第 4 个问题。


本篇工作的第 1 个贡献是提出了一种高效的检测变异体被杀死的机制。

原理很简单,根据左图所示,变异体在第 30 个时刻出现错误,所以第 30 个时刻就可以判定变异体被杀死,而不需要等待完全执行完毕。

算法如右图所示,重点是第 3 行提前通过仿真得到原始待测系统的预期输出,在第 10 行实时观察变异体的输出 mi 并对比。


本篇工作的第 2 个贡献是提出了 19 个基于真实错误的变异算子。

如这张表所示,这 19 个变异算子分为 4 类,分别是数据错误访问、通信、时序和语义。

最右侧一列 Uniqueness 代表变异算子的独特性,其中 U 和 U- 代表为 HDL 定制的变异算子;U 表示变异算子是 HDL 独有的,不能应用于其他编程语言;U- 表示变异算子可以应用于其他编程语言,但效果会不同;S 表示变异算子可以应用于其他编程语言,且形式和效果类似。

在数据错误访问的变异算子中,DMO 是修改访问偏移量导致访问缓冲区越界、DMS 是修改赋值时的移位、DMI 是修改变量索引、DIE 是改变字节序(大端序和小端序互换)。

在关于通信的变异算子中,SMA 是修改模块或其他 API 参数、CGA 是生成多个信号源造成多重赋值、CRV 是移除数据验证语句、CMP 是修改实例化端口的参数、CDP 是生成悬空的实例化端口。

在关于时序的变异算子中,TAA 是在异步操作中添加赋值语句、TMD 是修改延时、TRA 是删除 always 块。

在关于语义的变异算子中,SRC 是删除 case 分支、SRI 是删除 if 分支、SRE 是删除 else 分支、SME 是修改表达式、SRA 是删除赋值、SRR 是删除 reg 声明语句、SRW 是删除 wire 声明语句。


本篇工作的第 3 个贡献是提出了 Mantra,一个开源硬件变异测试工具。

Mantra 使用 Python 3.8 开发,适用于 Verilog 实现的硬件设计代码。

它的实现方式是使用 AST 解析 Verilog 代码,通过 PyVerilog 将错误注入代码。之后将修改后的 AST 转换为 Verilog 代码,完成变异体的生成。

Mantra 提供了集成新的变异算子的接口,供未来的开发者使用。


然后来看一下实验结果。

在实验前,Mantra 通过实现变异算子来生成变异体。因为不是所有变异算子都适用每个项目,所以会为适用的变异算子保留更多变异体,而且排除了等价变异体。

最后在所有变异体中随机选择 70% 的变异体进行实验。

本篇工作在 CirFix 数据集的 11 个项目和 OpenCores 数据集的 8 个项目上进行了评估,其中有 6 个超过 3000 行的大型项目,其中最大的项目代码行数达到 72,993。实验结果取 3 轮后的平均值。

首先,这种检测变异体是否被杀死的机制对硬件变异测试是否有意义呢?实验结果显示,在 benchmark 中,可杀死的变异体被这种机制检测出来的平均时间是运行全部 testbench 的 0.01%。这表明提出的机制可以有效地降低变异测试的时间开销,本篇工作提出的机制是高效的。

其次,哪些变异算子比较特殊呢?如这张表所示,$\lambda$ 代表被杀死的变异体中 susceptible 变异体的比例,$\epsilon$ 代表 resistant 变异体的比例。(什么是 susceptible / resistant?设置阈值 p = 0.1,被杀死的时间小于总时间 10% 的是 susceptible,大于总时间 90% 的是 resistant。)只有 DMI、TMD 和 SRW 产生了 susceptible 变异体,大多数变异算子都产生了 resistant 变异体。说明本篇工作提出的变异算子产生的变异体都很难检测出来,也证明了从真实错误得到的变异算子的优越性。另一方面,$\lambda$ 值越高,说明变异算子产生的错误更容易被检测出来,说明变异算子暴露潜在错误的能力较弱。同样,TAA、TMD 和 SRE 的 $\epsilon$ 值较高,表明它们可以产生更多 resistant 变异体。这说明本篇工作提出的变异算子的质量很高。

最后,Mantra 如何区分不同质量的测试集呢?为此,本篇工作设计了两个测试集,一个是强测试集,使用实验项目提供的测试数据;另一个是弱测试集,使用人为构建的测试数据。由此得到对“灵敏度”的定义,公式为 |MS(Strong) - MS(Weak)| / MS(Strong),表示从弱测试集转移到强测试集时变异分数的相对变化,这个指标决定了在对测试集质量的变化做出反应时,两个工具哪个更敏感。如这张图所示,对于所有 19 个测试集,Mantra 比 Certitude 能更好地分辨出测试集的质量。而且和 Certitude 相比,Mantra 在很大程度上提高了灵敏度,平均达到 56.25%,最高达到 83.44%。这是由于 Mantra 的变异算子是基于真实的错误,这些错误会影响硬件系统的性能。同时说明本篇工作提出的 Mantra 工具是更有效的。


最后,本篇工作仍有一些不足之处。

关于外部的威胁,目前测试集的数量和规模有限,不能保证在其他项目主题上的泛化能力。此外,提出的变异算子在应用于 Verilog 之外的其他硬件描述语言时也需要调整。

关于内部的威胁,提出的变异算子只是基于两项已有的工作,不能涵盖所有的硬件相关错误实例。

关于构造的威胁,目前计算变异分数利用的是经典的方法(杀死的变异体数量 除以 总变异体数量 减去 等价变异体数量),在实践中可能有更符合 HDL 特点的计算方法,还有待探索。


谢谢大家!

talks