2016年4月13日 西米奇

Simics在测试中的有效使用

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

jlombourg

正如我们在以前的博客文章AdaCore严重依赖虚拟化来执行其测试小昆虫专业产品VxWorks.

这涉及每天运行的大约350,000个测试,其中包括60,000个运行的测试风河模拟。典型测试涉及以下步骤:

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

与在本地平台上运行的等效测试相比,这些步骤呈现出两个挑战:

  1. 可行性:我们需要添加适当的支持来启用这些步骤,特别是在主机和模拟目标之间的文件传输,并可靠地这样做。
  2. 效率:运行仿真器并来回传输文件可以导致大量的开销,与时间约束不兼容(24h最大测试时间)。因此需要一些增强的技术来加速这些关键步骤。

仪表概述

为了完成此测试,我们需要在主机侧(例如,在模拟器上)和访客本身(VxWorks内核)上的仪器。要求是:

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

文件传输

为了支持文件从主机传输到主机,我们使用了Simics的Simics Builder模块。这允许我们创建一个专用的外设,我们可以用它交互,在主机和目标上的RAM驱动器之间传输文件。

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

模拟外设采用一小组寄存器和缓冲器的形式。作为SIMICS插件的这种外围设备的实现非常简单。但是,必须注意:

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

要来回复制文件,设备响应Syscalls,可提供以下功能:

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

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

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

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

静态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);

/*将来宾缓冲区转换为主机缓冲区*/

-1, (uint8_t *)host_buf (uint8_t *);

RET =打开(host_buf,arg2,arg3);

免费(host_buf);

返回受潮湿腐烂;

休息;

在VxWorks侧,此调用在内核中实现:

PHYS_ADDR _to_physical_addr(VIRT_ADDR virtualAddr) {

phys_addr probalyAddr;

vmtranslate(null,VirtualAddr和PromicyAddr);

返回physicalAddr;

}

#define to_phy(addr)_to_physical_addr((virt_addr)addr)

静态UINTPTR_T.

HFS_GENERIC(UINTPTR_T SYSCALL_ID,

Uintptr_t arg1,

uintptr_t arg2,

UIntptr_t arg3)

{

Uintptr_t *hostfs_register = (Uintptr_t *)hostfs_addr();

if(hostfs_register == 0)return -1;

hostfs_register [1] = arg1;

hostfs_register [2] = arg2;

hostfs_register[3] =长度;

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

hostfs_register [0] = syscall_id;

返回hostfs_register [1];

}

UINT32_T HFS_OPEN(const char * pathname,uint32_t标志,uint32_t模式)

{

Virt_addr TMP = ASHEAS_PHYSICAL((VIST_ADDR)路径名,strlen(pathname)+ 1);

Virt_addr Buf;

if (tmp != (VIRT_ADDR)NULL) {

Memcpy ((void*)tmp, pathname, strlen(pathname) + 1);

buf = tmp;

} 别的 {

buf = (VIRT_ADDR)路径名;

}

return h_generic (uintptr_t) TO_PHY(buf), flags,

模式);

}

绩效考虑因素

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

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

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

从我们所看到的来看,这是由于Simics的高度可配置和可编写脚本的特性,其中完整的模拟环境是在启动时构建的。这样的时间与我们的目标总执行时间是不兼容的。

为了解决这个问题,Simics工程师将我们指向一个非常好的功能:Simics检查点。基本上,它是一种机制,使我们能够拯救模拟模拟的状态并恢复它。

恢复的速度很快。

所以我们现在在构建VxWorks内核时所做的事情是在vxworks内核刚刚引导的地方创建一个通用的Simics检查点。在Simics脚本中,我们使用这看起来像:

脚本 - 分支{

本地$con = $system.console

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

停止

写入配置“CheckPoint”-Z

退出

}

就是这样。在我们的测试中加载检查点:

读取配置“检查点”

以恢复已经启动的VxWorks模拟。

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

结论

通过此测试环境,我们可以成功和有效地测试VxWorks的编译器。作为示例,ACATS测试套件的完整运行,包含〜3700测试(ACATS TestSuite是ADA语言的标准测试套件)在快速的Linux服务器上大约需要31分钟,这符合每次2次测试的目标性能第二。

通过使用SIMICS,adacore现在可以在引入其GNAT Pro产品的新VxWorks目标时,快速建立高效的质量保证基础设施,从而提高上市时间和产品的整体质量。

以前的VxWorks可扩展图形
下一个风河科技为空客直升机的集成模块化航空电子系统提供动力