中断并发程序的静态分析

最近得研究下多任务并发程序的静态分析(包括中断),于是看了这篇文章
这篇文章是国防科大的团队在15年,16年所做的工作

主要是分析中断导致的并发程序,通过将程序顺序化,然后重用经典的抽象解释方法进行分析;当然,还设计了抽象域专门处理IDPs的特性

术语

  • IDPs, Interrupted-Driven Programs: 中断驱动程序

  • ISR, Interrupt Rervice Routine: 中断子程序

  • IMR, Interrupt Mask Register: 中断寄存器;支持中断的硬件特性

中断驱动程序(IDP)的静态分析

​ 这篇文章主要参考了国防科大团队在 EMSOFT’2015 上的报告[1]。那篇报告专注中断驱动程序的数值缺陷分析。我看那篇报告主要是想了解中断驱动程序的相关工作,所以略过数值程序分析部分。

1. 为什么单独研究中断驱动程序分析

​ 为什么需要对中断驱动程序(Interrupt-Driven Programs, IDPs)进行单独的静态分析?

​ 中断在嵌入式软件中常常用于引入并发控制。如果用常规的静态分析来分析中断驱动的程序,可能会导致分析结果unsound。

​ 下面是个例子:

int x, y, z; // 全局变量

void ISR() { // 中断函数
  x++;
  y--;
  return;
}

void TASK() {
  if (x < y) {   // 程序点1
    z = 1/(x-y)  // 程序点2
  }
}

​ 利用静态分析分析TASK函数,可以知道,x < y条件恒成立,所以x-y作为分母不会发生除0错误。

​ 然而当该程序是中断驱动程序时,若程序点1发生中断,ISR函数对x,y进行修改。若在1处中断前x,y满足x+1=y,那么中断函数返回时,程序点2可能发生除零错误。

​ 可以看到利用传统的顺序(Sequential)程序分析可能导致unsound。所以当分析中断驱动程序时,需要对程序的并发行为进行建模。

2. 什么是中断驱动程序

IDPs的特点:

  • IDP是由有限个任务(tasks)和中断(interrupts)的集合组成的
  • 任务按顺序配合进行调度的,而中断是通过优先级调度的

IDPs的应用场景:

  • 航空航天嵌入式程序
  • 嵌入式操作系统
  • 机器人
3. 挑战
  • Scalability:状态空间爆炸
  • Precision:中断是由硬件控制的: 中断周期,中断寄存器(Interrupt Mask Register, IMR)
    • TODO: IMR, 需要补一下背景知识
4. 方法

​ 因为使用顺序地静态分析方法,不能够保证sound,所以要提出sound的静态分析方法。然后对相关的挑战进行trade-off (Scalability,Precision)

4.1 方法1: 串行化

并发程序的顺序化(Sequentialization methods),相关的工作有[1] [2] [3] [4]等

​ 通过对中断驱动程序进行建模/转换,变成顺序化程序,然后复用已有的针对顺序程序的抽象解释方法,进行静态分析。

4.1.1 对程序进行建模

​ (1). M个任务,N个中断。每个中断优先级最多有一个中断TODO: 需要再考察一下真实场景下是不是一个优先级最多只有一个中断

​ (2). 对全局共享变量的读写操作为:l = g (写), g = l (读)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5OPOzAo9-1649482842826)(./imgs/model.png)]

​ 上图中, NV表示非共享变量,SV表示共享变量;ISR为中断子程序,<entry, p> 表示该子程序的语句和优先级

​ 我的理解:建模简化了中断驱动程序; 简化问题的描述, 简化算法的描述;

4.1.2 对建模后程序的预设

​ (1). 全局共享变量的读写操作是原子(atomic)的; 前人的大多数有关并发程序分析的工作都是这么假设的)

​ (2). 中断子程序(ISR)内,IMR是完好无损的(intact); 例如,IMR(entry, ISR[i]) = IMR(exit, ISR[i]) 表示第i个中断子程序的入口处的IMR 等于 出口处的IMR

​ 我的理解:降低复杂度;我们容忍一些静态分析难以处理的情况。(妥协, 没办法的事…就如Java中的反射, C语言中的指针分析对指针算数的处理一样)

4.1.3 中断程序串行化基本思想

​ (1). 观察:中断的触发能够被函数调用来模拟

​ (2). 基本思想: 在每个task的(原子)语句前添加一个schedule()函数;schedule函数非确定性地(non-deterministically)调度更高优先级的中断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xdYUCQxs-1649482842827)(./imgs/sq_basic.png)]

​ 从图上看,这样无条件地插入schedule,会导致转换后的程序变大,静态分析时内存开销很大,不够Scale。所以需要再优化。

​ 进一步再观察可以知道,中断(interrupts)和任务(tasks)之间是通过共享变量进行通信的,也就是说,中断只会影响任务中访问共享变量的语句

​ 所以,进一步,我们将之前无条件地插入schedule的方法改为:考虑数据依赖的情况下插入schedule

4.1.4 考虑数据依赖的串行化

​ 程序 {S1; S2; ... ; Sn}, 其中只有Sn读取共享变量。按照之前的方法,我们会将程序转换为:{schedule(); S1; schedule(); S2; ... ; schedule(); Sn}

​ 利用数据依赖的串行化,可以将上述所有的n-1个schedule调用都聚集到Sn语句的前面,这样做与之前对程序的转换影响是等效的;转换后的程序为:{ S1; S2; ... ; S(n-1) ; K个连续的Schedule() ; Sn }

​ 这有点像基本块的定义:程序中最长连续非跳转指令序列组成的代码块

​ 那么我们定义:程序中最长连续未读写共享变量的指令可以不需要插入schedule,直到遇到读/写共享变量的语句,往它前面/后面插入Schedule;具体往前还是往后插入,怎么去scheduleG_K,下面一一介绍。

​ 核心思想:只schedule对访问共享变量语句相关的中断。具体来说有两种情况:

(1). 当Sn为l = g时(读取共享变量);Schedule那些可能影响g值的中断 (往语句前插入scheduleG_K)

(2). 当Sn为g = l时(写入共享变量); Schedule那些执行结果可能被g值影响的中断 (往语句后插入scheduleG_K)

​ 上述K个连续的Schedule()我们定义如下:

void scheduleG_K(group: int set){
	for(int i = 1; i <= K; i++) { // K为每个ISR触发次数的上界,它能被设置成指定值或者 +∞
		scheduleG(group);					  
  }
}

​ 我们需要考虑触发中断的数量K,否则可能unsound。

​ 下面是一个例子:
在这里插入图片描述

​ 该例子程序中有3个共享变量x,y,z;其中蓝色框为ISR1相关的共享变量读写,红色是ISR2相关的共享变量读写。

​ 转换后的程序中,可以看到:

(1). 对共享变量进行写操作的语句,往其后插入相关的Schedule;

(2). 对共享变量进行读操作的语句,往其前插入相关的Schedule;

4.1.5 串行化IDPs后的静态分析

​ 可以使用通用的抽象解释去分析串行化后的程序。

​ 但是仍然需要考虑IDPs的特性。(1). 触发中断次数(K值)会影响分析结果。 (2). 中断周期特性。这些需要特定的抽象域去对这些特性进行处理,以提高分析精度(Precision)

​ 提出最多触发一次(At-most-once)周期性中断的概念:

(1). 周期性中断:固定时间间隔触发

(2). 中断周期比task周期更长 (我的理解:中断周期比单个串行函数执行时间更长, )

​ 基于At-most-once firing periodic interrupts概念,我们使用bool flag变量来标识ISRs是否触发。

在这里插入图片描述

​ 我对At-most-once的理解:作者认为中断周期比task执行时间更长,所以在单个函数内(task)内,如果执行了某个中断,那么其它中断也会触发。所以用一个flag来表示是否触发了中断。

4.1.6 串行化IDPs总结

(1). 利用数据依赖提升Scalability

(2). 利用At-most-once firing periodic interrupts提升Precision

4.2 方法2: Thread-Modular + Value Flow

​ 针对多线程的方法:https://blog.csdn.net/qq_37206105/article/details/123973253,应该也能用到中断中。

5. 实验

​ 对于中断驱动程序分析器,需要进行怎么样的实验去衡量静态分析器的能力?有一些基准测试集:

(1). Goblint项目[5]中提供OSEK程序

(2). LEGO机器人控制程序 (Nxt_gs)

(3). universal asynchronous receive and transmitter (UART)

(6). 一些真实的卫星控制程序…

​ 测试的目的:

(1). 检查IDPs的运行时错误 (误报/漏报)

(2). 顺序化程序的大小与源程序大小进行比较

6. 参考

[1] Xueguang Wu, Liqian Chen, Antoine Miné, Wei Dong, and Ji Wang. 2016. Static Analysis of Runtime Errors in Interrupt-Driven Programs via Sequentialization. ACM Trans. Embed. Comput. Syst. 15, 4, Article 70 (August 2016), 26 pages. DOI:https://doi.org/10.1145/2914789

[2] Shaz Qadeer and Dinghao Wu. 2004. KISS: keep it simple and sequential. In Proceedings of the ACM SIGPLAN 2004 conference on Programming language design and implementation (PLDI '04). Association for Computing Machinery, New York, NY, USA, 14–24. DOI:https://doi.org/10.1145/996841.996845

[3] N. Kidd, S. Jagannathan, and J. Vitek. One stack to run them all - reducing concurrent analysis to sequential analysis under priority scheduling. In SPIN’10, volume 6349 of LNCS, pages 245–261. Springer, 2010.

[4] A. Min´e. Relational thread-modular static value analysis by abstract interpretation. In VMCAI’14, volume 8318 of LNCS, pages 39–58. Springer, 2014.

[5] M. D. Schwarz, H. Seidl, V. Vojdani, P. Lammich, and M. Muller-Olm. Static analysis of interrupt-driven programs synchronized via the priority ceiling protocol. In POPL’11, pages 93–104. ACM, 2011.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值