2016年4月13日 西米奇

Simics测试的有效使用

作者:Jérôme Lambourg,高级软件工程师,AdaCore

jlombourg

如我们所见以前的博客文章,骗子严重依赖虚拟化来执行其测试GNAT Pro产品VxWorks

这涉及每天运行的大约350,000个测试,包括运行的60,000个测试风河系统公司西米奇。一个典型的测试包括以下步骤:

  1. 汇编示例,使用测试中定义的交换机和源;
  2. 启动一个模拟器,在上面传输已编译的模块或RTP,可能带有一些支持文件;
  3. 运行模块或RTP;
  4. 检索输出,可能是在目标上创建的文件;
  5. 退出模拟器。

与在本地平台上运行的等价测试相比,这些步骤显示了两个挑战:

  1. 可行性:我们需要添加适当的支持来启用这些步骤,特别是主机和模拟目标之间的文件传输,并可靠地实现。
  2. 效率:运行模拟器并来回传输文件会导致巨大的开销,与时间限制不兼容(最大测试时间为24小时)。因此,需要一些改进的技术来加快这些关键步骤。

仪器概述

为了完成这个测试,我们需要在主机端(例如模拟器上)和客户端本身(VxWorks内核)上进行检测。要求是:

  • 能够在客户和主机之间来回传输文件;
  • 能够检索输出;
  • 在目标上自动执行测试场景。

文件传输

要支持从/到主机传输文件,我们使用SIMICS的SIMICS Builder模块。这使我们可以创建一个专用的外设,我们可以在主机和目标上的RAM驱动器之间进行交互。

我们选择这个解决方案是因为它非常有效(与使用模拟网络传输文件相反),同时为各种测试提供了非常高的灵活性。

模拟外设采用一小组寄存器和一个缓冲区的形式。像Simics插件这样的外设的实现是非常简单的。然而,必须注意以下几点:

  • 单个寄存器的大小(根据目标系统为32位或64位)
  • 这些寄存器的字节序

为了来回复制文件,设备响应系统调用,具有以下功能:

  • 开放的,
  • 关闭
  • 拆开
  • LSEEK
  • 关闭

设备第一个寄存器上的任何写操作都会触发系统调用。

其他3个寄存器包含参数,它们期望的内容取决于特定的系统调用。

以下是实现模拟设备的系统调用,作为Simics插件实现的示例提供:

static REG_TYPE do_syscall(hostfs_device_t *hfs)

{

REG_TYPE ID = hfs->regs[SYSCALL_ID].value;

REG_TYPE arg1 = HFS-> REGS [ARG1] .VALUE;

REG_TYPE arg2 = hfs->regs[arg2].value;

REG_TYPE arg3 = hfs->regs[arg3].value;

REG_TYPE ret = 0;

char * host_buf = null;

REG_TYPE guest_buf;

REG_TYPE len;

开关(ID)

{

案例syscall_open:

guest_buf = __arg1;

len = 1024;/* XXX:文件名字符串的最大长度*/

最长= open_flags(最长);

host_buf = malloc (len);

/*将客户缓冲区转换为主机缓冲区*/

Copy_from_target (hfs, guest_buf, -1, (uint8_t *)host_buf);

Ret = open(host_buf, arg2, arg3);

免费(host_buf);

返回受潮湿腐烂;

打破;

在VxWorks端,这个调用是在内核中实现的:

物理addr _to_physical_addr(VIRT_ADDR virtualAddr) {

PHYS_ADDR physicalAddr;

vmTranslate (NULL, virtualAddr &physicalAddr);

返回probalityaddr;

}

#定义TO_PHY (addr) _to_physical_addr (addr) (VIRT_ADDR)

静态uintptr_t

hfs_generic (uintptr_t syscall_id

uintptr_t __arg1、

uintptr_t最长,

uintptr_t长度)

{

uintptr_t * hostfs_register =(uintptr_t *)hostfs_addr();

If (hostfs_register == 0) return -1;

hostfs_register [1] = __arg1;

hostfs_register[2] =最长;

hostfs_register[3] =长度;

/*写入syscall_id启动系统调用*/

hostfs_register [0] = syscall_id;

返回hostfs_register [1];

}

hfs_open (const char *pathname, Uint32_t flags, Uint32_t mode)

{

VIRT_ADDR tmp = ensure_physical((VIRT_ADDR)路径名,strlen(路径名)+ 1);

VIRT_ADDR缓冲区;

if(tmp!= =(drive_addr)null){

Memcpy ((void*)tmp,路径名,strlen(路径名)+ 1);

buf = tmp;

其他}{

buf =(virt_addr)pathname;

}

/ /返回一个主节点

模式);

}

性能考虑

在典型的服务器上,我们的目标是在不到45分钟的时间内运行大约6000个测试,这意味着大约每秒2个测试。

要实现这个目标,首先要做的是最大限度地提高测试执行的并行性:每个测试通常可以彼此独立地运行,而且通常也需要单个核心。这意味着在一个16核的服务器上,我们应该能够并行执行16个测试。这也意味着要在45分钟内实现全球6000个测试的目标,在这样的服务器上,每个测试的目标执行时间应该少于8秒(测试套件的8 * 6000 / 16 = 3000秒的总执行时间,所以是50分钟)。

我们对Simics的第一次实验与这个目标相差甚远:根据所模拟的平台,启动VxWorks可能需要15秒到近1分钟。当尝试并行运行几个Simics实例时,数字变得更糟,因为启动模拟需要大量服务器资源。

从我们所看到的,这是由于SIMICS的高度可配置和可编写的性质,在启动时建立了完整的模拟环境。此类时间与我们的目标总执行时间不兼容。

为了解决这个问题,Simics工程师向我们介绍了一个非常好的特性:Simics检查点。基本上,这是一种让我们能够保存Simics模拟状态并随意恢复它的机制。

恢复非常快。

因此,当我们构建VxWorks内核时,我们现在要做的是在VxWorks内核刚刚启动的地方创建一个通用Simics检查点。在Simics脚本中,我们使用如下内容:

script-branch {

本地$con = $system.console

反对美元。wait-for-string“Run_shell”

停止

编写配置“检查点”- z

辞职

}

就是这样。要在测试中加载检查点,请执行以下操作:

读取配置“检查点”

恢复VxWorks已经启动的模拟。

这种机制预先阐述了模拟环境,并大大减少了服务器上的负载和总启动时间。

结论

利用这个测试环境,我们可以成功地、有效地测试VxWorks的编译器。例如,在一个快速的linux服务器上,包含约3700个测试(ACATS测试套件是Ada语言的标准测试套件)的ACATS测试套件的完整运行大约需要31分钟,这满足了我们每秒2个测试的目标性能。

通过使用Simics, AdaCore现在可以在引入由其GNAT Pro产品支持的新的VxWorks目标时迅速地建立一个有效的质量保证基础设施,提高产品的上市时间和整体质量。

以前的VxWorks的可伸缩图形
下一个风河技术力量空中客车直升机集成模块化航空电子系统